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