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