Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/bin/sh/memalloc.c
39475 views
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
45
static void
46
badalloc(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
56
pointer
57
ckmalloc(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
74
pointer
75
ckrealloc(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
85
void
86
ckfree(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
98
char *
99
savestr(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
123
struct stack_block {
124
struct stack_block *prev;
125
/* Data follows */
126
};
127
#define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block)))
128
129
static struct stack_block *stackp;
130
char *stacknxt;
131
int stacknleft;
132
char *sstrend;
133
134
135
static void
136
stnewblock(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
157
pointer
158
stalloc(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
172
void
173
stunalloc(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
184
char *
185
stsavestr(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
197
void
198
setstackmark(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
209
void
210
popstackmark(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
240
static void
241
growstackblock(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
303
static char *
304
growstrstackblock(int n, int min)
305
{
306
growstackblock(min);
307
return stackblock() + n;
308
}
309
310
char *
311
growstackstr(void)
312
{
313
int len;
314
315
len = stackblocksize();
316
return (growstrstackblock(len, 0));
317
}
318
319
320
/*
321
* Called from CHECKSTRSPACE.
322
*/
323
324
char *
325
makestrspace(int min, char *p)
326
{
327
int len;
328
329
len = p - stackblock();
330
return (growstrstackblock(len, min));
331
}
332
333
334
char *
335
stputbin(const char *data, size_t len, char *p)
336
{
337
CHECKSTRSPACE(len, p);
338
memcpy(p, data, len);
339
return (p + len);
340
}
341
342
char *
343
stputs(const char *data, char *p)
344
{
345
return (stputbin(data, strlen(data), p));
346
}
347
348