1 /* $NetBSD: mem1.c,v 1.43 2021/04/02 12:16:50 rillig Exp $ */ 2 3 /* 4 * Copyright (c) 1994, 1995 Jochen Pohl 5 * All Rights Reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jochen Pohl for 18 * The NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #if HAVE_NBTOOL_CONFIG_H 35 #include "nbtool_config.h" 36 #endif 37 38 #include <sys/cdefs.h> 39 #if defined(__RCSID) && !defined(lint) 40 __RCSID("$NetBSD: mem1.c,v 1.43 2021/04/02 12:16:50 rillig Exp $"); 41 #endif 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "lint1.h" 50 51 /* 52 * Filenames allocated by record_filename are shared. 53 */ 54 struct filename { 55 char *fn_name; 56 size_t fn_len; 57 int fn_id; 58 struct filename *fn_next; 59 }; 60 61 static struct filename *filenames; /* null-terminated array */ 62 63 /* Find the given filename, or return NULL. */ 64 static const struct filename * 65 search_filename(const char *s, size_t len) 66 { 67 const struct filename *fn; 68 69 for (fn = filenames; fn != NULL; fn = fn->fn_next) { 70 if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0) 71 break; 72 } 73 return fn; 74 } 75 76 struct filename_replacement { 77 char *orig; 78 size_t orig_len; 79 char *repl; 80 struct filename_replacement *next; 81 }; 82 83 static struct filename_replacement *filename_replacements; 84 85 void 86 add_directory_replacement(char *arg) 87 { 88 struct filename_replacement *r = xmalloc(sizeof(*r)); 89 90 char *sep = strchr(arg, '='); 91 if (sep == NULL) 92 err(1, "Bad replacement directory spec `%s'", arg); 93 *sep = '\0'; 94 95 r->orig = arg; 96 r->orig_len = sep - arg; 97 r->repl = sep + 1; 98 r->next = filename_replacements; 99 filename_replacements = r; 100 } 101 102 const char * 103 transform_filename(const char *name, size_t len) 104 { 105 static char buf[MAXPATHLEN]; 106 const struct filename_replacement *r; 107 108 for (r = filename_replacements; r != NULL; r = r->next) 109 if (r->orig_len < len && 110 memcmp(name, r->orig, r->orig_len) == 0) 111 break; 112 if (r == NULL) 113 return name; 114 snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->orig_len); 115 return buf; 116 } 117 118 static int 119 next_filename_id(void) 120 { 121 static int next_id = 0; 122 123 return next_id++; 124 } 125 126 /* 127 * Return a copy of the filename s with unlimited lifetime. 128 * If the filename is new, write it to the output file. 129 */ 130 const char * 131 record_filename(const char *s, size_t slen) 132 { 133 const struct filename *existing_fn; 134 struct filename *fn; 135 136 if (s == NULL) 137 return NULL; 138 139 if ((existing_fn = search_filename(s, slen)) != NULL) 140 return existing_fn->fn_name; 141 142 fn = xmalloc(sizeof(*fn)); 143 /* Do not use strdup() because s is not NUL-terminated.*/ 144 fn->fn_name = xmalloc(slen + 1); 145 (void)memcpy(fn->fn_name, s, slen); 146 fn->fn_name[slen] = '\0'; 147 fn->fn_len = slen; 148 fn->fn_id = next_filename_id(); 149 fn->fn_next = filenames; 150 filenames = fn; 151 152 /* Write the ID of this filename to the output file. */ 153 outclr(); 154 outint(fn->fn_id); 155 outchar('s'); 156 outstrg(transform_filename(fn->fn_name, fn->fn_len)); 157 158 return fn->fn_name; 159 } 160 161 /* Get the ID of a filename. */ 162 int 163 get_filename_id(const char *s) 164 { 165 const struct filename *fn; 166 167 if (s == NULL || (fn = search_filename(s, strlen(s))) == NULL) 168 return -1; 169 return fn->fn_id; 170 } 171 172 /* 173 * Memory for declarations and other things which must be available 174 * until the end of a block (or the end of the translation unit) 175 * is associated with the corresponding mem_block_level, which may be 0. 176 * Because this memory is allocated in large blocks associated with 177 * a given level it can be freed easily at the end of a block. 178 */ 179 #define ML_INC ((size_t)32) /* Increment for length of *mblks */ 180 181 typedef struct memory_block { 182 void *start; /* beginning of memory block */ 183 void *first_free; /* first free byte */ 184 size_t nfree; /* # of free bytes */ 185 size_t size; /* total size of memory block */ 186 struct memory_block *next; 187 } memory_block; 188 189 /* 190 * Array of pointers to lists of memory blocks. mem_block_level is used as 191 * index into this array. 192 */ 193 static memory_block **mblks; 194 195 /* number of elements in *mblks */ 196 static size_t nmblks; 197 198 /* free list for memory blocks */ 199 static memory_block *frmblks; 200 201 /* length of new allocated memory blocks */ 202 static size_t mblklen; 203 204 static void *xgetblk(memory_block **, size_t); 205 static void xfreeblk(memory_block **); 206 static memory_block *xnewblk(void); 207 208 static memory_block * 209 xnewblk(void) 210 { 211 memory_block *mb = xmalloc(sizeof(*mb)); 212 213 /* use mmap instead of malloc to avoid malloc's size overhead */ 214 mb->start = xmapalloc(mblklen); 215 mb->size = mblklen; 216 217 return mb; 218 } 219 220 /* Allocate new memory, initialized with zero. */ 221 static void * 222 xgetblk(memory_block **mbp, size_t s) 223 { 224 memory_block *mb; 225 void *p; 226 size_t t = 0; 227 228 /* 229 * If the first block of the list has not enough free space, 230 * or there is no first block, get a new block. The new block 231 * is taken from the free list or, if there is no block on the 232 * free list, is allocated using xnewblk(). 233 * 234 * If a new block is allocated it is initialized with zero. 235 * Blocks taken from the free list are zero'd in xfreeblk(). 236 */ 237 238 s = WORST_ALIGN(s); 239 if ((mb = *mbp) == NULL || mb->nfree < s) { 240 if ((mb = frmblks) == NULL || mb->size < s) { 241 if (s > mblklen) { 242 t = mblklen; 243 mblklen = s; 244 } 245 mb = xnewblk(); 246 #ifndef BLKDEBUG 247 (void)memset(mb->start, 0, mb->size); 248 #endif 249 if (t > 0) 250 mblklen = t; 251 } else { 252 frmblks = mb->next; 253 } 254 mb->first_free = mb->start; 255 mb->nfree = mb->size; 256 mb->next = *mbp; 257 *mbp = mb; 258 } 259 p = mb->first_free; 260 mb->first_free = (char *)mb->first_free + s; 261 mb->nfree -= s; 262 #ifdef BLKDEBUG 263 (void)memset(p, 0, s); 264 #endif 265 return p; 266 } 267 268 /* 269 * Move all blocks from list *fmbp to free list. For each block, set all 270 * used memory to zero. 271 */ 272 static void 273 xfreeblk(memory_block **fmbp) 274 { 275 memory_block *mb; 276 277 while ((mb = *fmbp) != NULL) { 278 *fmbp = mb->next; 279 mb->next = frmblks; 280 frmblks = mb; 281 (void)memset(mb->start, ZERO, mb->size - mb->nfree); 282 } 283 } 284 285 void 286 initmem(void) 287 { 288 int pgsz; 289 290 pgsz = getpagesize(); 291 mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz; 292 293 mblks = xcalloc(nmblks = ML_INC, sizeof(*mblks)); 294 } 295 296 297 /* Allocate memory associated with level l. */ 298 void * 299 getlblk(size_t l, size_t s) 300 { 301 302 while (l >= nmblks) { 303 mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof(*mblks)); 304 (void)memset(&mblks[nmblks], 0, ML_INC * sizeof(*mblks)); 305 nmblks += ML_INC; 306 } 307 return xgetblk(&mblks[l], s); 308 } 309 310 void * 311 getblk(size_t s) 312 { 313 314 return getlblk(mem_block_level, s); 315 } 316 317 /* Free all memory associated with level l. */ 318 void 319 freelblk(int l) 320 { 321 322 xfreeblk(&mblks[l]); 323 } 324 325 void 326 freeblk(void) 327 { 328 329 freelblk(mem_block_level); 330 } 331 332 static memory_block *tmblk; 333 334 /* 335 * Return zero-initialized memory that is freed at the end of the current 336 * expression. 337 */ 338 void * 339 expr_zalloc(size_t s) 340 { 341 342 return xgetblk(&tmblk, s); 343 } 344 345 /* 346 * Return a freshly allocated tree node that is freed at the end of the 347 * current expression. 348 */ 349 tnode_t * 350 expr_zalloc_tnode(void) 351 { 352 tnode_t *tn = expr_zalloc(sizeof(*tn)); 353 tn->tn_from_system_header = in_system_header; 354 return tn; 355 } 356 357 /* Free all memory which is allocated by the current expression. */ 358 void 359 expr_free_all(void) 360 { 361 362 xfreeblk(&tmblk); 363 } 364 365 /* 366 * Save the memory which is used by the current expression. This memory 367 * is not freed by the next expr_free_all() call. The pointer returned can be 368 * used to restore the memory. 369 */ 370 memory_block * 371 expr_save_memory(void) 372 { 373 memory_block *tmem; 374 375 tmem = tmblk; 376 tmblk = NULL; 377 return tmem; 378 } 379 380 /* 381 * Free all memory used for the current expression and the memory used 382 * be a previous expression and saved by expr_save_memory(). The next call to 383 * expr_free_all() frees the restored memory. 384 */ 385 void 386 expr_restore_memory(memory_block *tmem) 387 { 388 389 expr_free_all(); 390 if (tmblk != NULL) { 391 free(tmblk->start); 392 free(tmblk); 393 } 394 tmblk = tmem; 395 } 396