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