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