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