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