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 if (stacknleft != 0) 231 sstrend = stacknxt + stacknleft; 232 else 233 sstrend = stacknxt; 234 INTON; 235 } 236 237 238 /* 239 * When the parser reads in a string, it wants to stick the string on the 240 * stack and only adjust the stack pointer when it knows how big the 241 * string is. Stackblock (defined in stack.h) returns a pointer to a block 242 * of space on top of the stack and stackblocklen returns the length of 243 * this block. Growstackblock will grow this space by at least one byte, 244 * possibly moving it (like realloc). Grabstackblock actually allocates the 245 * part of the block that has been used. 246 */ 247 248 static void 249 growstackblock(int min) 250 { 251 char *p; 252 int newlen; 253 char *oldspace; 254 int oldlen; 255 struct stack_block *sp; 256 struct stack_block *oldstackp; 257 258 if (min < stacknleft) 259 min = stacknleft; 260 if ((unsigned int)min >= 261 INT_MAX / 2 - ALIGN(sizeof(struct stack_block))) 262 error("Out of space"); 263 min += stacknleft; 264 min += ALIGN(sizeof(struct stack_block)); 265 newlen = 512; 266 while (newlen < min) 267 newlen <<= 1; 268 oldspace = stacknxt; 269 oldlen = stacknleft; 270 271 if (stackp != NULL && stacknxt == SPACE(stackp)) { 272 INTOFF; 273 oldstackp = stackp; 274 stackp = oldstackp->prev; 275 sp = ckrealloc((pointer)oldstackp, newlen); 276 sp->prev = stackp; 277 stackp = sp; 278 stacknxt = SPACE(sp); 279 stacknleft = newlen - (stacknxt - (char*)sp); 280 sstrend = stacknxt + stacknleft; 281 INTON; 282 } else { 283 newlen -= ALIGN(sizeof(struct stack_block)); 284 p = stalloc(newlen); 285 if (oldlen != 0) 286 memcpy(p, oldspace, oldlen); 287 stunalloc(p); 288 } 289 } 290 291 292 293 /* 294 * The following routines are somewhat easier to use that the above. 295 * The user declares a variable of type STACKSTR, which may be declared 296 * to be a register. The macro STARTSTACKSTR initializes things. Then 297 * the user uses the macro STPUTC to add characters to the string. In 298 * effect, STPUTC(c, p) is the same as *p++ = c except that the stack is 299 * grown as necessary. When the user is done, she can just leave the 300 * string there and refer to it using stackblock(). Or she can allocate 301 * the space for it using grabstackstr(). If it is necessary to allow 302 * someone else to use the stack temporarily and then continue to grow 303 * the string, the user should use grabstack to allocate the space, and 304 * then call ungrabstr(p) to return to the previous mode of operation. 305 * 306 * USTPUTC is like STPUTC except that it doesn't check for overflow. 307 * CHECKSTACKSPACE can be called before USTPUTC to ensure that there 308 * is space for at least one character. 309 */ 310 311 static char * 312 growstrstackblock(int n, int min) 313 { 314 growstackblock(min); 315 return stackblock() + n; 316 } 317 318 char * 319 growstackstr(void) 320 { 321 int len; 322 323 len = stackblocksize(); 324 return (growstrstackblock(len, 0)); 325 } 326 327 328 /* 329 * Called from CHECKSTRSPACE. 330 */ 331 332 char * 333 makestrspace(int min, char *p) 334 { 335 int len; 336 337 len = p - stackblock(); 338 return (growstrstackblock(len, min)); 339 } 340 341 342 char * 343 stputbin(const char *data, size_t len, char *p) 344 { 345 CHECKSTRSPACE(len, p); 346 memcpy(p, data, len); 347 return (p + len); 348 } 349 350 char * 351 stputs(const char *data, char *p) 352 { 353 return (stputbin(data, strlen(data), p)); 354 } 355