mem1.c revision 1.27 1 /* $NetBSD: mem1.c,v 1.27 2021/03/17 01:15:31 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.27 2021/03/17 01:15:31 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 fnalloc() and fnnalloc() are shared.
53 */
54 typedef struct fn {
55 char *fn_name;
56 size_t fn_len;
57 int fn_id;
58 struct fn *fn_next;
59 } fn_t;
60
61 static fn_t *fnames;
62
63 static fn_t *srchfn(const char *, size_t);
64
65 /* Find the given filename, or return NULL. */
66 static fn_t *
67 srchfn(const char *s, size_t len)
68 {
69 fn_t *fn;
70
71 for (fn = fnames; fn != NULL; fn = fn->fn_next) {
72 if (fn->fn_len == len && memcmp(fn->fn_name, s, len) == 0)
73 break;
74 }
75 return fn;
76 }
77
78 /* Return a copy of the filename s with unlimited lifetime. */
79 const char *
80 fnalloc(const char *s)
81 {
82
83 return s != NULL ? fnnalloc(s, strlen(s)) : NULL;
84 }
85
86 struct repl {
87 char *orig;
88 char *repl;
89 size_t len;
90 struct repl *next;
91 };
92
93 struct repl *replist;
94
95 void
96 fnaddreplsrcdir(char *arg)
97 {
98 struct repl *r = xmalloc(sizeof(*r));
99
100 r->orig = arg;
101 if ((r->repl = strchr(arg, '=')) == NULL)
102 err(1, "Bad replacement directory spec `%s'", arg);
103 r->len = r->repl - r->orig;
104 *(r->repl)++ = '\0';
105 if (replist == NULL) {
106 r->next = NULL;
107 } else
108 r->next = replist;
109 replist = r;
110 }
111
112 const char *
113 fnxform(const char *name, size_t len)
114 {
115 static char buf[MAXPATHLEN];
116 struct repl *r;
117
118 for (r = replist; r != NULL; r = r->next)
119 if (r->len < len && memcmp(name, r->orig, r->len) == 0)
120 break;
121 if (r == NULL)
122 return name;
123 snprintf(buf, sizeof(buf), "%s%s", r->repl, name + r->len);
124 return buf;
125 }
126
127 const char *
128 fnnalloc(const char *s, size_t len)
129 {
130 fn_t *fn;
131
132 static int nxt_id = 0;
133
134 if (s == NULL)
135 return NULL;
136
137 if ((fn = srchfn(s, len)) == NULL) {
138 fn = xmalloc(sizeof (fn_t));
139 /* Do not use strdup() because s is not NUL-terminated.*/
140 fn->fn_name = xmalloc(len + 1);
141 (void)memcpy(fn->fn_name, s, len);
142 fn->fn_name[len] = '\0';
143 fn->fn_len = len;
144 fn->fn_id = nxt_id++;
145 fn->fn_next = fnames;
146 fnames = fn;
147 /* Write id of this filename to the output file. */
148 outclr();
149 outint(fn->fn_id);
150 outchar('s');
151 outstrg(fnxform(fn->fn_name, fn->fn_len));
152 }
153 return fn->fn_name;
154 }
155
156 /* Get the ID of a filename. */
157 int
158 getfnid(const char *s)
159 {
160 fn_t *fn;
161
162 if (s == NULL || (fn = srchfn(s, strlen(s))) == NULL)
163 return -1;
164 return fn->fn_id;
165 }
166
167 /*
168 * Memory for declarations and other things which must be available
169 * until the end of a block (or the end of the translation unit)
170 * are associated with the level (mem_block_level) of the block (or with 0).
171 * Because this memory is allocated in large blocks associated with
172 * a given level it can be freed easily at the end of a block.
173 */
174 #define ML_INC ((size_t)32) /* Increment for length of *mblks */
175
176 typedef struct mbl {
177 void *blk; /* beginning of memory block */
178 void *ffree; /* first free byte */
179 size_t nfree; /* # of free bytes */
180 size_t size; /* total size of memory block */
181 struct mbl *nxt; /* next block */
182 } mbl_t;
183
184 /*
185 * Array of pointers to lists of memory blocks. mem_block_level is used as
186 * index into this array.
187 */
188 static mbl_t **mblks;
189
190 /* number of elements in *mblks */
191 static size_t nmblks;
192
193 /* free list for memory blocks */
194 static mbl_t *frmblks;
195
196 /* length of new allocated memory blocks */
197 static size_t mblklen;
198
199 static void *xgetblk(mbl_t **, size_t);
200 static void xfreeblk(mbl_t **);
201 static mbl_t *xnewblk(void);
202
203 static mbl_t *
204 xnewblk(void)
205 {
206 mbl_t *mb = xmalloc(sizeof (mbl_t));
207
208 /* use mmap instead of malloc to avoid malloc's size overhead */
209 mb->blk = xmapalloc(mblklen);
210 mb->size = mblklen;
211
212 return mb;
213 }
214
215 /* Allocate new memory, initialized with zero. */
216 static void *
217 xgetblk(mbl_t **mbp, size_t s)
218 {
219 mbl_t *mb;
220 void *p;
221 size_t t = 0;
222
223 /*
224 * If the first block of the list has not enough free space,
225 * or there is no first block, get a new block. The new block
226 * is taken from the free list or, if there is no block on the
227 * free list, is allocated using xnewblk().
228 *
229 * If a new block is allocated it is initialized with zero.
230 * Blocks taken from the free list are zero'd in xfreeblk().
231 */
232
233 s = WORST_ALIGN(s);
234 if ((mb = *mbp) == NULL || mb->nfree < s) {
235 if ((mb = frmblks) == NULL || mb->size < s) {
236 if (s > mblklen) {
237 t = mblklen;
238 mblklen = s;
239 }
240 mb = xnewblk();
241 #ifndef BLKDEBUG
242 (void)memset(mb->blk, 0, mb->size);
243 #endif
244 if (t > 0)
245 mblklen = t;
246 } else {
247 frmblks = mb->nxt;
248 }
249 mb->ffree = mb->blk;
250 mb->nfree = mb->size;
251 mb->nxt = *mbp;
252 *mbp = mb;
253 }
254 p = mb->ffree;
255 mb->ffree = (char *)mb->ffree + s;
256 mb->nfree -= s;
257 #ifdef BLKDEBUG
258 (void)memset(p, 0, s);
259 #endif
260 return p;
261 }
262
263 /*
264 * Move all blocks from list *fmbp to free list. For each block, set all
265 * used memory to zero.
266 */
267 static void
268 xfreeblk(mbl_t **fmbp)
269 {
270 mbl_t *mb;
271
272 while ((mb = *fmbp) != NULL) {
273 *fmbp = mb->nxt;
274 mb->nxt = frmblks;
275 frmblks = mb;
276 (void)memset(mb->blk, ZERO, mb->size - mb->nfree);
277 }
278 }
279
280 void
281 initmem(void)
282 {
283 int pgsz;
284
285 pgsz = getpagesize();
286 mblklen = ((MBLKSIZ + pgsz - 1) / pgsz) * pgsz;
287
288 mblks = xcalloc(nmblks = ML_INC, sizeof (mbl_t *));
289 }
290
291
292 /* Allocate memory associated with level l. */
293 void *
294 getlblk(size_t l, size_t s)
295 {
296
297 while (l >= nmblks) {
298 mblks = xrealloc(mblks, (nmblks + ML_INC) * sizeof (mbl_t *));
299 (void)memset(&mblks[nmblks], 0, ML_INC * sizeof (mbl_t *));
300 nmblks += ML_INC;
301 }
302 return xgetblk(&mblks[l], s);
303 }
304
305 void *
306 getblk(size_t s)
307 {
308
309 return getlblk(mem_block_level, s);
310 }
311
312 /* Free all memory associated with level l. */
313 void
314 freelblk(int l)
315 {
316
317 xfreeblk(&mblks[l]);
318 }
319
320 void
321 freeblk(void)
322 {
323
324 freelblk(mem_block_level);
325 }
326
327 static mbl_t *tmblk;
328
329 /*
330 * Return zero-initialized memory that is freed at the end of the current
331 * expression.
332 */
333 void *
334 tgetblk(size_t s)
335 {
336
337 return xgetblk(&tmblk, s);
338 }
339
340 /* Return a freshly allocated tree node. */
341 tnode_t *
342 getnode(void)
343 {
344 tnode_t *tn = tgetblk(sizeof *tn);
345 tn->tn_from_system_header = in_system_header;
346 return tn;
347 }
348
349 /* Free all memory which is allocated by the current expression. */
350 void
351 tfreeblk(void)
352 {
353
354 xfreeblk(&tmblk);
355 }
356
357 /*
358 * Save the memory which is used by the current expression. This memory
359 * is not freed by the next tfreeblk() call. The pointer returned can be
360 * used to restore the memory.
361 */
362 mbl_t *
363 tsave(void)
364 {
365 mbl_t *tmem;
366
367 tmem = tmblk;
368 tmblk = NULL;
369 return tmem;
370 }
371
372 /*
373 * Free all memory used for the current expression and the memory used
374 * be a previous expression and saved by tsave(). The next call to
375 * tfreeblk() frees the restored memory.
376 */
377 void
378 trestor(mbl_t *tmem)
379 {
380
381 tfreeblk();
382 if (tmblk != NULL) {
383 free(tmblk->blk);
384 free(tmblk);
385 }
386 tmblk = tmem;
387 }
388