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