1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 ** Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** cpphash.c
26 **
27 ** Pre-processor hash table. Derived from gnu cpp.
28 */
29
30 /* Part of CPP library. (Macro hash table support.)
31 Copyright (C) 1986, 87, 89, 92-95, 1996 Free Software Foundation, Inc.
32 Written by Per Bothner, 1994.
33 Based on CCCP program by by Paul Rubin, June 1986
34 Adapted to ANSI C, Richard Stallman, Jan 1987
35
36 This program is free software; you can redistribute it and/or modify it
37 under the terms of the GNU General Public License as published by the
38 Free Software Foundation; either version 2, or (at your option) any
39 later version.
40
41 This program is distributed in the hope that it will be useful,
42 but WITHOUT ANY WARRANTY; without even the implied warranty of
43 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
44 GNU General Public License for more details.
45
46 You should have received a copy of the GNU General Public License
47 along with this program; if not, write to the Free Software
48 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
49
50 In other words, you are welcome to use, share and improve this program.
51 You are forbidden to forbid anyone else to use, share and improve
52 what you give them. Help stamp out software-hoarding! */
53
54 # include "splintMacros.nf"
55 # include "basic.h"
56 # include <string.h>
57 # include "cpplib.h"
58 # include "cpphash.h"
59
60 typedef /*@null@*/ /*@only@*/ hashNode o_hashNode;
61 typedef /*@null@*/ /*@only@*/ hashNode n_hashNode;
62
63 static o_hashNode hashtab[CPP_HASHSIZE];
64 static o_hashNode ohashtab[CPP_HASHSIZE];
65
66 static void hashNode_delete (/*@null@*/ /*@only@*/ hashNode);
67
68 /* p_prev need not be defined, but isn't defined by hashNode_copy */
69
70 /*@function static unsigned int hashStep (unsigned, char) modifies nothing ; @*/
71 # define hashStep(old, c) (((old) << 2) + (unsigned int) (c))
72
73 /*@function static unsigned int makePositive (unsigned int) modifies nothing ; @*/
74 # define makePositive(v) ((v) & 0x7fffffff) /* make number positive */
75
76 static /*@null@*/ hashNode hashNode_copy (/*@null@*/ hashNode,
77 /*@null@*/ /*@dependent@*/ n_hashNode *p_hdr,
78 /*@dependent@*/ /*@null@*/ /*@special@*/ hashNode p_prev)
79 /*@*/ ;
80
cppReader_saveHashtab()81 void cppReader_saveHashtab ()
82 {
83 int i;
84
85 for (i = 0; i < CPP_HASHSIZE; i++)
86 {
87 ohashtab[i] = hashNode_copy (hashtab[i], &ohashtab[i], NULL);
88 }
89 }
90
cppReader_restoreHashtab()91 void cppReader_restoreHashtab ()
92 {
93 int i;
94
95 for (i = 0; i < CPP_HASHSIZE; i++) {
96 /* hashNode_delete (hashtab[i]); */
97 hashtab[i] = hashNode_copy (ohashtab[i], &hashtab[i], NULL);
98 }
99 }
100
hashNode_delete(hashNode node)101 static void hashNode_delete (/*@only@*/ /*@null@*/ hashNode node)
102 {
103 if (node == NULL)
104 {
105 ;
106 }
107 else
108 {
109 hashNode_delete (node->next);
110
111 if (node->type == T_MACRO)
112 {
113 DEFINITION *d = node->value.defn;
114 struct reflist *ap, *nextap;
115
116 for (ap = d->pattern; ap != NULL; ap = nextap)
117 {
118 nextap = ap->next;
119 sfree (ap);
120 }
121
122 if (d->nargs >= 0)
123 {
124 sfree (d->args.argnames);
125 }
126
127 sfree (d);
128 }
129
130 cstring_free (node->name);
131 sfree (node);
132 }
133 }
134
hashNode_copy(hashNode node,hashNode * hdr,hashNode prev)135 /*@null@*/ hashNode hashNode_copy (hashNode node, hashNode *hdr,
136 /*@dependent@*/ hashNode prev)
137 {
138 if (node == NULL)
139 {
140 return NULL;
141 }
142 else
143 {
144 hashNode res = dmalloc (sizeof (*res));
145
146 res->next = hashNode_copy (node->next, hdr, res);
147 res->prev = prev;
148
149 res->bucket_hdr = hdr;
150 res->type = node->type;
151 res->length = node->length;
152 res->name = cstring_copy (node->name);
153
154 if (node->type == T_MACRO)
155 {
156 DEFINITION *d = node->value.defn;
157 DEFINITION *nd = dmalloc (sizeof (*nd));
158
159 res->value.defn = nd;
160 nd->nargs = d->nargs;
161
162 nd->length = d->length;
163 nd->predefined = d->predefined;
164 nd->expansion = d->expansion;
165 nd->line = d->line;
166 nd->file = d->file;
167
168 if (d->pattern != NULL)
169 {
170 struct reflist *ap, *nextap;
171 struct reflist **last = &nd->pattern;
172
173 for (ap = d->pattern; ap != NULL; ap = nextap)
174 {
175 struct reflist *npattern = dmalloc (sizeof (* (nd->pattern)));
176
177 nextap = ap->next;
178
179 if (ap == d->pattern)
180 {
181 *last = npattern;
182 /*@-branchstate@*/
183 } /*@=branchstate@*/ /* npattern is propagated through loop */
184
185 last = & (npattern->next);
186 npattern->next = NULL; /* will get filled in */
187 npattern->stringify = d->pattern->stringify;
188 npattern->raw_before = d->pattern->raw_before;
189 npattern->raw_after = d->pattern->raw_after;
190 npattern->rest_args = d->pattern->rest_args;
191 npattern->argno = d->pattern->argno;
192 /*@-mustfree@*/
193 }
194 /*@=mustfree@*/
195 }
196 else
197 {
198 nd->pattern = NULL;
199 }
200
201 if (d->nargs >= 0)
202 {
203 llassert (d->args.argnames != NULL);
204
205 nd->args.argnames = mstring_copy (d->args.argnames);
206 }
207 else
208 {
209 /*
210 ** This fix found by:
211 **
212 ** Date: Mon, 31 May 1999 15:10:50 +0900 (JST)
213 ** From: "N.Komazaki" <koma@focs.sei.co.jp>
214 */
215
216 /*! why doesn't splint report an error for this? */
217 nd->args.argnames = mstring_createEmpty ();
218 }
219 }
220 else
221 {
222 if (node->type == T_CONST)
223 {
224 res->value.ival = node->value.ival;
225 }
226 else if (node->type == T_PCSTRING)
227 {
228 res->value.cpval = mstring_copy (node->value.cpval);
229 llassert (res->value.cpval != NULL);
230 }
231 else
232 {
233 res->value = node->value;
234 }
235 }
236
237 /*@-uniondef@*/ /*@-compdef@*/ /* res->prev is not defined */
238 return res;
239 /*@=uniondef@*/ /*@=compdef@*/
240 }
241 }
242
243 /* Return hash function on name. must be compatible with the one
244 computed a step at a time, elsewhere */
245
246 int
cpphash_hashCode(const char * name,size_t len,int hashsize)247 cpphash_hashCode (const char *name, size_t len, int hashsize)
248 {
249 unsigned int r = 0;
250
251 while (len-- != 0)
252 {
253 r = hashStep (r, *name++);
254 }
255
256 return (int) (makePositive (r) % hashsize);
257 }
258
259 /*
260 ** Find the most recent hash node for name name (ending with first
261 ** non-identifier char) cpphash_installed by install
262 **
263 ** If len is >= 0, it is the length of the name.
264 ** Otherwise, compute the length by scanning the entire name.
265 **
266 ** If hash is >= 0, it is the precomputed hash code.
267 ** Otherwise, compute the hash code.
268 */
269
cpphash_lookup(char * name,int len,int hash)270 /*@null@*/ hashNode cpphash_lookup (char *name, int len, int hash)
271 {
272 const char *bp;
273 hashNode bucket;
274
275 if (len < 0)
276 {
277 for (bp = name; isIdentifierChar (*bp); bp++)
278 {
279 ;
280 }
281
282 len = bp - name;
283 }
284
285 if (hash < 0)
286 {
287 hash = cpphash_hashCode (name, size_fromInt (len), CPP_HASHSIZE);
288 }
289
290 bucket = hashtab[hash];
291
292 while (bucket != NULL)
293 {
294 if (bucket->length == size_fromInt (len) &&
295 cstring_equalLen (bucket->name, cstring_fromChars (name), size_fromInt (len)))
296 {
297 return bucket;
298 }
299
300 bucket = bucket->next;
301 }
302
303 return NULL;
304 }
305
cpphash_lookupExpand(char * name,int len,int hash,bool forceExpand)306 /*@null@*/ hashNode cpphash_lookupExpand (char *name, int len, int hash, bool forceExpand)
307 {
308 hashNode node = cpphash_lookup (name, len, hash);
309
310 DPRINTF (("Lookup expand: %s", name));
311
312 if (node != NULL)
313 {
314 if (node->type == T_MACRO)
315 {
316 DEFINITION *defn = (DEFINITION *) node->value.defn;
317
318 DPRINTF (("Check macro..."));
319
320 if (defn->noExpand && !forceExpand) {
321 DPRINTF (("No expand!"));
322 return NULL;
323 }
324 }
325 }
326
327 return node;
328 }
329
330 /*
331 * Delete a hash node. Some weirdness to free junk from macros.
332 * More such weirdness will have to be added if you define more hash
333 * types that need it.
334 */
335
336 /* Note that the DEFINITION of a macro is removed from the hash table
337 but its storage is not freed. This would be a storage leak
338 except that it is not reasonable to keep undefining and redefining
339 large numbers of macros many times.
340 In any case, this is necessary, because a macro can be #undef'd
341 in the middle of reading the arguments to a call to it.
342 If #undef freed the DEFINITION, that would crash. */
343
344 void
cppReader_deleteMacro(hashNode hp)345 cppReader_deleteMacro (hashNode hp)
346 {
347 if (hp->prev != NULL)
348 {
349 /*@-mustfree@*/
350 hp->prev->next = hp->next;
351 /*@=mustfree@*/
352 /*@-branchstate@*/
353 } /*@=branchstate@*/
354
355 if (hp->next != NULL)
356 {
357 hp->next->prev = hp->prev;
358 }
359
360 /* make sure that the bucket chain header that
361 the deleted guy was on points to the right thing afterwards. */
362
363 llassert (hp != NULL);
364 llassert (hp->bucket_hdr != NULL);
365
366 if (hp == *hp->bucket_hdr) {
367 *hp->bucket_hdr = hp->next;
368 }
369
370 if (hp->type == T_MACRO)
371 {
372 DEFINITION *d = hp->value.defn;
373 struct reflist *ap, *nextap;
374
375 for (ap = d->pattern; ap != NULL; ap = nextap)
376 {
377 nextap = ap->next;
378 sfree (ap);
379 }
380
381 if (d->nargs >= 0)
382 {
383 sfree (d->args.argnames);
384 }
385 }
386
387 /*@-dependenttrans@*/ /*@-exposetrans@*/ /*@-compdestroy@*/
388 sfree (hp);
389 /*@=dependenttrans@*/ /*@=exposetrans@*/ /*@=compdestroy@*/
390 }
391
392 /* Install a name in the main hash table, even if it is already there.
393 name stops with first non alphanumeric, except leading '#'.
394 caller must check against redefinition if that is desired.
395 cppReader_deleteMacro () removes things installed by install () in fifo order.
396 this is important because of the `defined' special symbol used
397 in #if, and also if pushdef/popdef directives are ever implemented.
398
399 If LEN is >= 0, it is the length of the name.
400 Otherwise, compute the length by scanning the entire name.
401
402 If HASH is >= 0, it is the precomputed hash code.
403 Otherwise, compute the hash code. */
404
cpphash_install(char * name,int len,enum node_type type,int ivalue,char * value,int hash)405 hashNode cpphash_install (char *name, int len, enum node_type type,
406 int ivalue, char *value, int hash)
407 {
408 hashNode hp;
409 int bucket;
410 char *p;
411
412 DPRINTF (("Install: %s / %d", name, len));
413
414 if (len < 0) {
415 p = name;
416
417 while (isIdentifierChar (*p))
418 {
419 p++;
420 }
421
422 len = p - name;
423 }
424
425 if (hash < 0)
426 {
427 hash = cpphash_hashCode (name, size_fromInt (len), CPP_HASHSIZE);
428 }
429
430 hp = (hashNode) dmalloc (sizeof (*hp));
431 bucket = hash;
432 hp->bucket_hdr = &hashtab[bucket];
433
434 hp->next = hashtab[bucket];
435 hp->prev = NULL;
436
437 if (hp->next != NULL)
438 {
439 hp->next->prev = hp;
440 }
441
442 hashtab[bucket] = hp;
443
444 hp->type = type;
445 hp->length = size_fromInt (len);
446
447 if (hp->type == T_CONST)
448 {
449 hp->value.ival = ivalue;
450 llassert (value == NULL);
451 }
452 else
453 {
454 hp->value.cpval = value;
455 }
456
457 hp->name = cstring_clip (cstring_fromCharsNew (name), size_fromInt (len));
458
459 DPRINTF (("Name: *%s*", hp->name));
460 /*@-mustfree@*/ /*@-uniondef@*/ /*@-compdef@*/ /*@-compmempass@*/
461 return hp;
462 /*@=mustfree@*/ /*@=uniondef@*/ /*@=compdef@*/ /*@=compmempass@*/
463 }
464
cpphash_installMacro(char * name,size_t len,struct definition * defn,int hash)465 hashNode cpphash_installMacro (char *name, size_t len,
466 struct definition *defn, int hash)
467 {
468 DPRINTF (("install macro: %s", name));
469 return cpphash_install (name, size_toInt (len), T_MACRO, 0, (char *) defn, hash);
470 }
471
472 void
cppReader_hashCleanup(void)473 cppReader_hashCleanup (void)
474 {
475 int i;
476
477 for (i = CPP_HASHSIZE; --i >= 0; )
478 {
479 while (hashtab[i] != NULL)
480 {
481 cppReader_deleteMacro (hashtab[i]);
482 }
483 }
484 }
485