Sun Feb 27 06:55:13 2022 UTC ()
lint: remove custom free list for memory blocks

Trust the system memory allocator to do its thing, including marking the
memory as fresh or freed.  One less thing to worry about.


(rillig)
diff -r1.57 -r1.58 src/usr.bin/xlint/lint1/mem1.c

cvs diff -r1.57 -r1.58 src/usr.bin/xlint/lint1/mem1.c (switch to unified diff)

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