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 #ifndef lint 36 #if 0 37 static char sccsid[] = "@(#)memalloc.c 8.3 (Berkeley) 5/4/95"; 38 #endif 39 #endif /* not lint */ 40 #include <sys/cdefs.h> 41 #include <sys/param.h> 42 #include "shell.h" 43 #include "output.h" 44 #include "memalloc.h" 45 #include "error.h" 46 #include "mystring.h" 47 #include "expand.h" 48 #include <stdlib.h> 49 #include <unistd.h> 50 51 static void 52 badalloc(const char *message) 53 { 54 write(2, message, strlen(message)); 55 abort(); 56 } 57 58 /* 59 * Like malloc, but returns an error when out of space. 60 */ 61 62 pointer 63 ckmalloc(size_t nbytes) 64 { 65 pointer p; 66 67 if (!is_int_on()) 68 badalloc("Unsafe ckmalloc() call\n"); 69 p = malloc(nbytes); 70 if (p == NULL) 71 error("Out of space"); 72 return p; 73 } 74 75 76 /* 77 * Same for realloc. 78 */ 79 80 pointer 81 ckrealloc(pointer p, int nbytes) 82 { 83 if (!is_int_on()) 84 badalloc("Unsafe ckrealloc() call\n"); 85 p = realloc(p, nbytes); 86 if (p == NULL) 87 error("Out of space"); 88 return p; 89 } 90 91 void 92 ckfree(pointer p) 93 { 94 if (!is_int_on()) 95 badalloc("Unsafe ckfree() call\n"); 96 free(p); 97 } 98 99 100 /* 101 * Make a copy of a string in safe storage. 102 */ 103 104 char * 105 savestr(const char *s) 106 { 107 char *p; 108 size_t len; 109 110 len = strlen(s); 111 p = ckmalloc(len + 1); 112 memcpy(p, s, len + 1); 113 return p; 114 } 115 116 117 /* 118 * Parse trees for commands are allocated in lifo order, so we use a stack 119 * to make this more efficient, and also to avoid all sorts of exception 120 * handling code to handle interrupts in the middle of a parse. 121 * 122 * The size 496 was chosen because with 16-byte alignment the total size 123 * for the allocated block is 512. 124 */ 125 126 #define MINSIZE 496 /* minimum size of a block. */ 127 128 129 struct stack_block { 130 struct stack_block *prev; 131 /* Data follows */ 132 }; 133 #define SPACE(sp) ((char*)(sp) + ALIGN(sizeof(struct stack_block))) 134 135 static struct stack_block *stackp; 136 char *stacknxt; 137 int stacknleft; 138 char *sstrend; 139 140 141 static void 142 stnewblock(int nbytes) 143 { 144 struct stack_block *sp; 145 int allocsize; 146 147 if (nbytes < MINSIZE) 148 nbytes = MINSIZE; 149 150 allocsize = ALIGN(sizeof(struct stack_block)) + ALIGN(nbytes); 151 152 INTOFF; 153 sp = ckmalloc(allocsize); 154 sp->prev = stackp; 155 stacknxt = SPACE(sp); 156 stacknleft = allocsize - (stacknxt - (char*)sp); 157 sstrend = stacknxt + stacknleft; 158 stackp = sp; 159 INTON; 160 } 161 162 163 pointer 164 stalloc(int nbytes) 165 { 166 char *p; 167 168 nbytes = ALIGN(nbytes); 169 if (nbytes > stacknleft) 170 stnewblock(nbytes); 171 p = stacknxt; 172 stacknxt += nbytes; 173 stacknleft -= nbytes; 174 return p; 175 } 176 177 178 void 179 stunalloc(pointer p) 180 { 181 if (p == NULL) { /*DEBUG */ 182 write(STDERR_FILENO, "stunalloc\n", 10); 183 abort(); 184 } 185 stacknleft += stacknxt - (char *)p; 186 stacknxt = p; 187 } 188 189 190 char * 191 stsavestr(const char *s) 192 { 193 char *p; 194 size_t len; 195 196 len = strlen(s); 197 p = stalloc(len + 1); 198 memcpy(p, s, len + 1); 199 return p; 200 } 201 202 203 void 204 setstackmark(struct stackmark *mark) 205 { 206 mark->stackp = stackp; 207 mark->stacknxt = stacknxt; 208 mark->stacknleft = stacknleft; 209 /* Ensure this block stays in place. */ 210 if (stackp != NULL && stacknxt == SPACE(stackp)) 211 stalloc(1); 212 } 213 214 215 void 216 popstackmark(struct stackmark *mark) 217 { 218 struct stack_block *sp; 219 220 INTOFF; 221 while (stackp != mark->stackp) { 222 sp = stackp; 223 stackp = sp->prev; 224 ckfree(sp); 225 } 226 stacknxt = mark->stacknxt; 227 stacknleft = mark->stacknleft; 228 if (stacknleft != 0) 229 sstrend = stacknxt + stacknleft; 230 else 231 sstrend = stacknxt; 232 INTON; 233 } 234 235 236 /* 237 * When the parser reads in a string, it wants to stick the string on the 238 * stack and only adjust the stack pointer when it knows how big the 239 * string is. Stackblock (defined in stack.h) returns a pointer to a block 240 * of space on top of the stack and stackblocklen returns the length of 241 * this block. Growstackblock will grow this space by at least one byte, 242 * possibly moving it (like realloc). Grabstackblock actually allocates the 243 * part of the block that has been used. 244 */ 245 246 static void 247 growstackblock(int min) 248 { 249 char *p; 250 int newlen; 251 char *oldspace; 252 int oldlen; 253 struct stack_block *sp; 254 struct stack_block *oldstackp; 255 256 if (min < stacknleft) 257 min = stacknleft; 258 if ((unsigned int)min >= 259 INT_MAX / 2 - ALIGN(sizeof(struct stack_block))) 260 error("Out of space"); 261 min += stacknleft; 262 min += ALIGN(sizeof(struct stack_block)); 263 newlen = 512; 264 while (newlen < min) 265 newlen <<= 1; 266 oldspace = stacknxt; 267 oldlen = stacknleft; 268 269 if (stackp != NULL && stacknxt == SPACE(stackp)) { 270 INTOFF; 271 oldstackp = stackp; 272 stackp = oldstackp->prev; 273 sp = ckrealloc((pointer)oldstackp, newlen); 274 sp->prev = stackp; 275 stackp = sp; 276 stacknxt = SPACE(sp); 277 stacknleft = newlen - (stacknxt - (char*)sp); 278 sstrend = stacknxt + stacknleft; 279 INTON; 280 } else { 281 newlen -= ALIGN(sizeof(struct stack_block)); 282 p = stalloc(newlen); 283 if (oldlen != 0) 284 memcpy(p, oldspace, oldlen); 285 stunalloc(p); 286 } 287 } 288 289 290 291 /* 292 * The following routines are somewhat easier to use that the above. 293 * The user declares a variable of type STACKSTR, which may be declared 294 * to be a register. The macro STARTSTACKSTR initializes things. Then 295 * the user uses the macro STPUTC to add characters to the string. In 296 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 297 * grown as necessary. When the user is done, she can just leave the 298 * string there and refer to it using stackblock(). Or she can allocate 299 * the space for it using grabstackstr(). If it is necessary to allow 300 * someone else to use the stack temporarily and then continue to grow 301 * the string, the user should use grabstack to allocate the space, and 302 * then call ungrabstr(p) to return to the previous mode of operation. 303 * 304 * USTPUTC is like STPUTC except that it doesn't check for overflow. 305 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 306 * is space for at least one character. 307 */ 308 309 static char * 310 growstrstackblock(int n, int min) 311 { 312 growstackblock(min); 313 return stackblock() + n; 314 } 315 316 char * 317 growstackstr(void) 318 { 319 int len; 320 321 len = stackblocksize(); 322 return (growstrstackblock(len, 0)); 323 } 324 325 326 /* 327 * Called from CHECKSTRSPACE. 328 */ 329 330 char * 331 makestrspace(int min, char *p) 332 { 333 int len; 334 335 len = p - stackblock(); 336 return (growstrstackblock(len, min)); 337 } 338 339 340 char * 341 stputbin(const char *data, size_t len, char *p) 342 { 343 CHECKSTRSPACE(len, p); 344 memcpy(p, data, len); 345 return (p + len); 346 } 347 348 char * 349 stputs(const char *data, char *p) 350 { 351 return (stputbin(data, strlen(data), p)); 352 } 353