1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#include <sys/param.h>
36#include "shell.h"
37#include "output.h"
38#include "memalloc.h"
39#include "error.h"
40#include "mystring.h"
41#include "expand.h"
42#include <stdlib.h>
43#include <unistd.h>
44
45static void
46badalloc(const char *message)
47{
48	write(2, message, strlen(message));
49	abort();
50}
51
52/*
53 * Like malloc, but returns an error when out of space.
54 */
55
56pointer
57ckmalloc(size_t nbytes)
58{
59	pointer p;
60
61	if (!is_int_on())
62		badalloc("Unsafe ckmalloc() call\n");
63	p = malloc(nbytes);
64	if (p == NULL)
65		error("Out of space");
66	return p;
67}
68
69
70/*
71 * Same for realloc.
72 */
73
74pointer
75ckrealloc(pointer p, int nbytes)
76{
77	if (!is_int_on())
78		badalloc("Unsafe ckrealloc() call\n");
79	p = realloc(p, nbytes);
80	if (p == NULL)
81		error("Out of space");
82	return p;
83}
84
85void
86ckfree(pointer p)
87{
88	if (!is_int_on())
89		badalloc("Unsafe ckfree() call\n");
90	free(p);
91}
92
93
94/*
95 * Make a copy of a string in safe storage.
96 */
97
98char *
99savestr(const char *s)
100{
101	char *p;
102	size_t len;
103
104	len = strlen(s);
105	p = ckmalloc(len + 1);
106	memcpy(p, s, len + 1);
107	return p;
108}
109
110
111/*
112 * Parse trees for commands are allocated in lifo order, so we use a stack
113 * to make this more efficient, and also to avoid all sorts of exception
114 * handling code to handle interrupts in the middle of a parse.
115 *
116 * The size 496 was chosen because with 16-byte alignment the total size
117 * for the allocated block is 512.
118 */
119
120#define MINSIZE 496		/* minimum size of a block. */
121
122
123struct stack_block {
124	struct stack_block *prev;
125	/* Data follows */
126};
127#define SPACE(sp)	((char*)(sp) + ALIGN(sizeof(struct stack_block)))
128
129static struct stack_block *stackp;
130char *stacknxt;
131int stacknleft;
132char *sstrend;
133
134
135static void
136stnewblock(int nbytes)
137{
138	struct stack_block *sp;
139	int allocsize;
140
141	if (nbytes < MINSIZE)
142		nbytes = MINSIZE;
143
144	allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes);
145
146	INTOFF;
147	sp = ckmalloc(allocsize);
148	sp->prev = stackp;
149	stacknxt = SPACE(sp);
150	stacknleft = allocsize - (stacknxt - (char*)sp);
151	sstrend = stacknxt + stacknleft;
152	stackp = sp;
153	INTON;
154}
155
156
157pointer
158stalloc(int nbytes)
159{
160	char *p;
161
162	nbytes = ALIGN(nbytes);
163	if (nbytes > stacknleft)
164		stnewblock(nbytes);
165	p = stacknxt;
166	stacknxt += nbytes;
167	stacknleft -= nbytes;
168	return p;
169}
170
171
172void
173stunalloc(pointer p)
174{
175	if (p == NULL) {		/*DEBUG */
176		write(STDERR_FILENO, "stunalloc\n", 10);
177		abort();
178	}
179	stacknleft += stacknxt - (char *)p;
180	stacknxt = p;
181}
182
183
184char *
185stsavestr(const char *s)
186{
187	char *p;
188	size_t len;
189
190	len = strlen(s);
191	p = stalloc(len + 1);
192	memcpy(p, s, len + 1);
193	return p;
194}
195
196
197void
198setstackmark(struct stackmark *mark)
199{
200	mark->stackp = stackp;
201	mark->stacknxt = stacknxt;
202	mark->stacknleft = stacknleft;
203	/* Ensure this block stays in place. */
204	if (stackp != NULL && stacknxt == SPACE(stackp))
205		stalloc(1);
206}
207
208
209void
210popstackmark(struct stackmark *mark)
211{
212	struct stack_block *sp;
213
214	INTOFF;
215	while (stackp != mark->stackp) {
216		sp = stackp;
217		stackp = sp->prev;
218		ckfree(sp);
219	}
220	stacknxt = mark->stacknxt;
221	stacknleft = mark->stacknleft;
222	if (stacknleft != 0)
223		sstrend = stacknxt + stacknleft;
224	else
225		sstrend = stacknxt;
226	INTON;
227}
228
229
230/*
231 * When the parser reads in a string, it wants to stick the string on the
232 * stack and only adjust the stack pointer when it knows how big the
233 * string is.  Stackblock (defined in stack.h) returns a pointer to a block
234 * of space on top of the stack and stackblocklen returns the length of
235 * this block.  Growstackblock will grow this space by at least one byte,
236 * possibly moving it (like realloc).  Grabstackblock actually allocates the
237 * part of the block that has been used.
238 */
239
240static void
241growstackblock(int min)
242{
243	char *p;
244	int newlen;
245	char *oldspace;
246	int oldlen;
247	struct stack_block *sp;
248	struct stack_block *oldstackp;
249
250	if (min < stacknleft)
251		min = stacknleft;
252	if ((unsigned int)min >=
253	    INT_MAX / 2 - ALIGN(sizeof(struct stack_block)))
254		error("Out of space");
255	min += stacknleft;
256	min += ALIGN(sizeof(struct stack_block));
257	newlen = 512;
258	while (newlen < min)
259		newlen <<= 1;
260	oldspace = stacknxt;
261	oldlen = stacknleft;
262
263	if (stackp != NULL && stacknxt == SPACE(stackp)) {
264		INTOFF;
265		oldstackp = stackp;
266		stackp = oldstackp->prev;
267		sp = ckrealloc((pointer)oldstackp, newlen);
268		sp->prev = stackp;
269		stackp = sp;
270		stacknxt = SPACE(sp);
271		stacknleft = newlen - (stacknxt - (char*)sp);
272		sstrend = stacknxt + stacknleft;
273		INTON;
274	} else {
275		newlen -= ALIGN(sizeof(struct stack_block));
276		p = stalloc(newlen);
277		if (oldlen != 0)
278			memcpy(p, oldspace, oldlen);
279		stunalloc(p);
280	}
281}
282
283
284
285/*
286 * The following routines are somewhat easier to use than the above.
287 * The user declares a variable of type STACKSTR, which may be declared
288 * to be a register.  The macro STARTSTACKSTR initializes things.  Then
289 * the user uses the macro STPUTC to add characters to the string.  In
290 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is
291 * grown as necessary.  When the user is done, she can just leave the
292 * string there and refer to it using stackblock().  Or she can allocate
293 * the space for it using grabstackstr().  If it is necessary to allow
294 * someone else to use the stack temporarily and then continue to grow
295 * the string, the user should use grabstack to allocate the space, and
296 * then call ungrabstr(p) to return to the previous mode of operation.
297 *
298 * USTPUTC is like STPUTC except that it doesn't check for overflow.
299 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there
300 * is space for at least one character.
301 */
302
303static char *
304growstrstackblock(int n, int min)
305{
306	growstackblock(min);
307	return stackblock() + n;
308}
309
310char *
311growstackstr(void)
312{
313	int len;
314
315	len = stackblocksize();
316	return (growstrstackblock(len, 0));
317}
318
319
320/*
321 * Called from CHECKSTRSPACE.
322 */
323
324char *
325makestrspace(int min, char *p)
326{
327	int len;
328
329	len = p - stackblock();
330	return (growstrstackblock(len, min));
331}
332
333
334char *
335stputbin(const char *data, size_t len, char *p)
336{
337	CHECKSTRSPACE(len, p);
338	memcpy(p, data, len);
339	return (p + len);
340}
341
342char *
343stputs(const char *data, char *p)
344{
345	return (stputbin(data, strlen(data), p));
346}
347