From d0e5b01f276f977e213ea8859faeca399d826769 Mon Sep 17 00:00:00 2001 From: drl7x Date: Wed, 2 Aug 2000 21:34:05 +0000 Subject: [PATCH] Put files created for constraint handling in the repository. --- src/Headers/constraint.h | 46 ++ src/Headers/environmentTable.h | 113 ++++ src/Headers/exprData.h | 14 + src/Headers/rangeTable.h | 108 ++++ src/constraintList.c | 441 +++++++++++++ src/environmentTable.c | 1074 ++++++++++++++++++++++++++++++++ src/exprData.c | 40 ++ src/rangeTable.c | 829 ++++++++++++++++++++++++ 8 files changed, 2665 insertions(+) create mode 100644 src/Headers/constraint.h create mode 100644 src/Headers/environmentTable.h create mode 100644 src/Headers/exprData.h create mode 100644 src/Headers/rangeTable.h create mode 100644 src/constraintList.c create mode 100644 src/environmentTable.c create mode 100644 src/exprData.c create mode 100644 src/rangeTable.c diff --git a/src/Headers/constraint.h b/src/Headers/constraint.h new file mode 100644 index 0000000..1cd0378 --- /dev/null +++ b/src/Headers/constraint.h @@ -0,0 +1,46 @@ +typedef enum +{ + LT, LTE, GT, GTE, EQ, NONNEGATIVE, POSITIVE +} +arithType; + +typedef enum +{ + BUFFSIZE, STRINGLEN, VALUE +} +constraintType; + +typedef struct constraint { + exprNode expr1; + exprNode expr2; + arithType restriction; + constraintType kind; +} constraint; + + +#define max_constraints 10 + +struct _constraintList { + constraint constraints[max_constraints]; + int numconstraints; +} ; + +typedef struct _constraintList *constraintList; +typedef struct _constraintList constraintList_; + +/*@constant null constraintList constraintList_undefined; @*/ +# define constraintList_undefined ((constraintList) NULL) +# define constraintList_isDefined(s) ((s) != constraintList_undefined) +# define constraintList_isUndefined(s) ((s) == constraintList_undefined) +//# define constraintList_isEmpty(s) (constraint_size(s) == 0) + +constraintList constraintList_new (); +constraintList constraintList_init (constraintList); +constraintList constraintList_add (constraintList, constraint); +constraintList constraintList_merge (constraintList, constraintList); +constraintList constraintList_exprNodemerge (exprNode, exprNode); + +void constraintList_print (constraintList); + +constraint constraint_create (exprNode e1, exprNode e2, arithType restriction, constraintType kind); +extern cstring exprNode_generateConstraints (exprNode e); diff --git a/src/Headers/environmentTable.h b/src/Headers/environmentTable.h new file mode 100644 index 0000000..7249abe --- /dev/null +++ b/src/Headers/environmentTable.h @@ -0,0 +1,113 @@ +/* +** Copyright (C) University of Virginia, Massachusetts Institue of Technology 1994-2000. +** See ../LICENSE for license information. +** +*/ +/* +** environmentTable.h +*/ + +# ifndef environmentTable_H +# define environmentTable_H + +//typedef /*@only@*/ sRefSet o_sRefSet; +//typedef /*@exposed@*/ sRef e_sRef; + +typedef struct environmentAt_ { + int max; + int min; +} * environmentAt; + + +typedef struct rangeAt_ { + int max; + int min; + bool isRelative; + bool unknown; + bool isReferenced; +} rangeAt; + + +struct _environmentTable +{ + int nelements; + int nspace; + /*@reldef@*/ /*@only@*/ e_sRef * keys; + /*@reldef@*/ /*@only@*/ o_sRefSet * values; + /*@reldef@*/ /*@only@*/ rangeAt * rangeValues; +}; + + + +/* extern rangeAt getEnvironment (key); */ +/* extern boolean inRange (int, range); */ + +/* extern void setMinium (key, min); */ +/* extern void setMaximum (key, min); */ + +environmentTable +environmentTable_addExactValue (/*@returned@*/ environmentTable s, /*@exposed@*/ sRef sr, int val); + +extern /*@unused@*/ /*@truenull@*/ bool environmentTable_isUndefined (environmentTable p_s); +extern /*@unused@*/ /*@truenull@*/ bool + environmentTable_isEmpty (/*@sef@*/ environmentTable p_s); +extern /*@falsenull@*/ bool environmentTable_isDefined (environmentTable p_s); + +/*@constant null environmentTable environmentTable_undefined; @*/ +# define environmentTable_undefined ((environmentTable) NULL) +# define environmentTable_isDefined(s) ((s) != environmentTable_undefined) +# define environmentTable_isUndefined(s) ((s) == environmentTable_undefined) +# define environmentTable_isEmpty(s) (environmentTable_size(s) == 0) + +extern int environmentTable_size (/*@sef@*/ environmentTable p_s); +# define environmentTable_size(s) (environmentTable_isDefined (s) ? (s)->nelements : 0) + +/*@iter environmentTable_elements (sef environmentTable t, yield exposed sRef key, yield exposed sRefSet values); @*/ +# define environmentTable_elements(t, m_key, m_value) \ + { if (environmentTable_isDefined (t)) \ + { int m_ind; sRef *m_keys = &((t)->keys[0]); \ + sRefSet *m_values = &((t)->values[0]); \ + for (m_ind = 0 ; m_ind < (t)->nelements; m_ind++) \ + { sRef m_key = *(m_keys++); sRefSet m_value = *(m_values++); + +# define end_environmentTable_elements }}} + +extern environmentTable environmentTable_new (void) /*@*/ ; + +extern void environmentTable_clearEnvironmentes (environmentTable p_s, sRef p_sr) + /*@modifies p_s, p_sr@*/ ; + +extern /*@only@*/ sRefSet environmentTable_canEnvironment (environmentTable p_s, sRef p_sr) /*@*/ ; +extern environmentTable environmentTable_copy (environmentTable p_s) /*@*/ ; + +extern /*@only@*/ cstring environmentTable_unparse (environmentTable p_s) /*@*/ ; +extern void environmentTable_free (/*@only@*/ environmentTable p_s) ; + +extern environmentTable + environmentTable_addMustEnvironment (/*@returned@*/ environmentTable p_s, /*@exposed@*/ sRef p_sr, sRef p_al) + /*@modifies p_s@*/ ; + +extern environmentTable + environmentTable_levelUnion (/*@returned@*/ environmentTable p_t1, environmentTable p_t2, int p_level) + /*@modifies p_t1@*/ ; + +extern environmentTable + environmentTable_levelUnionNew (environmentTable p_t1, environmentTable p_t2, int p_level) + /*@modifies nothing*/ ; + +extern void environmentTable_checkGlobs (environmentTable p_t) /*@modifies g_msgstream@*/ ; +extern /*@only@*/ sRefSet environmentTable_environmentedBy (environmentTable p_s, sRef p_sr) /*@*/ ; +extern void environmentTable_fixSrefs (environmentTable p_s); +extern environmentTable environmentTable_levelUnionSeq (/*@returned@*/ environmentTable p_t1, + /*@only@*/ environmentTable p_t2, int p_level); + +/*@constant int environmentTableBASESIZE; @*/ +# define environmentTableBASESIZE MIDBASESIZE + +# else +# error "Multiple include" +# endif + + + + diff --git a/src/Headers/exprData.h b/src/Headers/exprData.h new file mode 100644 index 0000000..4f816f5 --- /dev/null +++ b/src/Headers/exprData.h @@ -0,0 +1,14 @@ +/* ;-*-C-*-; */ + +/* +** freeShallow: free exprData created from exprNode_effect calls. +** All but the innermost storage is free'd. +*/ + +/*@only@*/ exprData exprData_makeLiteral (/*@only@*/ cstring s); + +/*@only@*/ exprData exprData_makeId (/*@temp@*/ uentry id); + +/*@only@*/ exprData exprData_makePair (/*@keep@*/ exprNode a, /*@keep@*/ exprNode b); + + diff --git a/src/Headers/rangeTable.h b/src/Headers/rangeTable.h new file mode 100644 index 0000000..829df88 --- /dev/null +++ b/src/Headers/rangeTable.h @@ -0,0 +1,108 @@ +/* +** Copyright (C) University of Virginia, Massachusetts Institue of Technology 1994-2000. +** See ../LICENSE for license information. +** +*/ +/* +** rangeTable.h +*/ + +# ifndef rangeTable_H +# define rangeTable_H + +typedef /*@only@*/ sRefSet o_sRefSet; +typedef /*@exposed@*/ sRef e_sRef; +typedef struct rangeAt_ { + int max; + int min; +} * rangeAt; + +struct _environmentTable +{ + int nelements + int nspace; + /*@reldef@*/ /*@only@*/ e_sRef * keys; + /*@reldef@*/ /*@only@*/ o_sRefSet * values; + /*@reldef@*/ /*@only@*/ rangeAt * rangeValues; + +} + +extern rangeAt_ getRange (key); +extern boolean inRange (int, range); + +extern void setMinium (key, min); +extern void setMaximum (key, min); + +struct _rangeTable +{ + int nelements; + int nspace; + /*@reldef@*/ /*@only@*/ e_sRef *keys; + /*@reldef@*/ /*@only@*/ o_sRefSet *values; +/*@reldef@*/ /*@only@*/ rangeAt *ranges; + +} ; + +extern /*@unused@*/ /*@truenull@*/ bool rangeTable_isUndefined (rangeTable p_s); +extern /*@unused@*/ /*@truenull@*/ bool + rangeTable_isEmpty (/*@sef@*/ rangeTable p_s); +extern /*@falsenull@*/ bool rangeTable_isDefined (rangeTable p_s); + +/*@constant null rangeTable rangeTable_undefined; @*/ +# define rangeTable_undefined ((rangeTable) NULL) +# define rangeTable_isDefined(s) ((s) != rangeTable_undefined) +# define rangeTable_isUndefined(s) ((s) == rangeTable_undefined) +# define rangeTable_isEmpty(s) (rangeTable_size(s) == 0) + +extern int rangeTable_size (/*@sef@*/ rangeTable p_s); +# define rangeTable_size(s) (rangeTable_isDefined (s) ? (s)->nelements : 0) + +/*@iter rangeTable_elements (sef rangeTable t, yield exposed sRef key, yield exposed sRefSet values); @*/ +# define rangeTable_elements(t, m_key, m_value) \ + { if (rangeTable_isDefined (t)) \ + { int m_ind; sRef *m_keys = &((t)->keys[0]); \ + sRefSet *m_values = &((t)->values[0]); \ + for (m_ind = 0 ; m_ind < (t)->nelements; m_ind++) \ + { sRef m_key = *(m_keys++); sRefSet m_value = *(m_values++); + +# define end_rangeTable_elements }}} + +extern rangeTable rangeTable_new (void) /*@*/ ; + +extern void rangeTable_clearRangees (rangeTable p_s, sRef p_sr) + /*@modifies p_s, p_sr@*/ ; + +extern /*@only@*/ sRefSet rangeTable_canRange (rangeTable p_s, sRef p_sr) /*@*/ ; +extern rangeTable rangeTable_copy (rangeTable p_s) /*@*/ ; + +extern /*@only@*/ cstring rangeTable_unparse (rangeTable p_s) /*@*/ ; +extern void rangeTable_free (/*@only@*/ rangeTable p_s) ; + +extern rangeTable + rangeTable_addMustRange (/*@returned@*/ rangeTable p_s, /*@exposed@*/ sRef p_sr, sRef p_al) + /*@modifies p_s@*/ ; + +extern rangeTable + rangeTable_levelUnion (/*@returned@*/ rangeTable p_t1, rangeTable p_t2, int p_level) + /*@modifies p_t1@*/ ; + +extern rangeTable + rangeTable_levelUnionNew (rangeTable p_t1, rangeTable p_t2, int p_level) + /*@modifies nothing*/ ; + +extern void rangeTable_checkGlobs (rangeTable p_t) /*@modifies g_msgstream@*/ ; +extern /*@only@*/ sRefSet rangeTable_rangeedBy (rangeTable p_s, sRef p_sr) /*@*/ ; +extern void rangeTable_fixSrefs (rangeTable p_s); +extern rangeTable rangeTable_levelUnionSeq (/*@returned@*/ rangeTable p_t1, + /*@only@*/ rangeTable p_t2, int p_level); + +/*@constant int rangeTableBASESIZE; @*/ +# define rangeTableBASESIZE MIDBASESIZE + +# else +# error "Multiple include" +# endif + + + + diff --git a/src/constraintList.c b/src/constraintList.c new file mode 100644 index 0000000..2b4ea75 --- /dev/null +++ b/src/constraintList.c @@ -0,0 +1,441 @@ +/* +** constraintList.c +*/ + +# include /* for isdigit */ +# include "lclintMacros.nf" +# include "basic.h" +# include "cgrammar.h" +# include "cgrammar_tokens.h" + +# include "exprChecks.h" +# include "aliasChecks.h" +# include "exprNodeSList.h" +# include "exprData.i" + + +/*@notnull@*/ constraintList constraintList_new () { +constraintList ret; + +ret = dmalloc ( sizeof (constraintList_) ); +llassert ( ret != NULL); +ret->numconstraints = 0; +return ret; +} + +cstring parse_restriction (arithType at) +{ + switch (at) + { + case LT: return "<"; + case LTE: return "<="; + case GT: return ">"; + case GTE: return ">="; + case EQ: return "="; + case NONNEGATIVE: return " >= 0"; + case POSITIVE: return " > 0"; + } +} +cstring constraint_parseKind (constraintType kind) +{ + switch (kind) + { + case BUFFSIZE: return "BufferSize"; + case STRINGLEN: return "StringLength"; + case VALUE: return "value"; + } +} + +void constraint_print (constraint c) +{ +#if 0 + printf ("Constraint: %s of %s %s %s\n", constraint_parseKind (c.kind), + exprNode_unparse(c.expr1), parse_restriction(c.restriction), exprNode_unparse(c.expr2) ); + #endif +} +void constraintList_print (constraintList cl) +{ +#if o + int i; + if (constraintList_isUndefined (cl) ) + { + printf("Constraint List undefined\n"); + return; + } + for (i = 0; i < cl->numconstraints; i++) + { + constraint_print (cl->constraints[i]); + } +#endif +} + + +constraint constraint_create (exprNode e1, exprNode e2, arithType restriction, constraintType kind) +{ + constraint ret; + ret.expr1 = e1; + ret.expr2 = e2; + ret.restriction = restriction; + ret.kind = kind; + return ret; +} + +constraintList constraintList_get (exprNode e1 ) +{ + return e1->constraints; +} + +constraintList constraintList_exprNodemerge (exprNode e1, exprNode e2) +{ + constraintList ret; + if ( (e1 != NULL) && (e2 != NULL) ) + { + ret = constraintList_merge (e1->constraints, e2->constraints); + } + else if ( (e1 == NULL) && (e2 == NULL) ) + ret = constraintList_merge ( (constraintList)NULL, (constraintList)NULL ); + else if (e1 == NULL) + ret = constraintList_merge ( (constraintList)NULL, e2->constraints); + else + ret = constraintList_merge (e1->constraints, (constraintList)NULL ); + return ret; +} + + +constraintList constraintList_merge (constraintList cl1, constraintList cl2) +{ + constraintList ret; + int i; + ret = constraintList_undefined; + if (constraintList_isDefined (cl1) ) + { + for (i = 0; i < cl1->numconstraints; i++) + { + ret = constraintList_add (ret, cl1->constraints[i]); + } + } + if (constraintList_isDefined (cl2) ) + { + for (i = 0; i < cl2->numconstraints; i++) + { + ret = constraintList_add (ret, cl2->constraints[i]); + } + } + return ret; + + +} + +constraintList constraintList_add (constraintList constraints, constraint newconstr) +{ + constraintList ret; + + if ( constraintList_isUndefined(constraints) ) + { + ret = constraintList_new (); + } + else + { + ret = constraints; + } + llassert (constraintList_isDefined (ret) ); + llassert (ret->numconstraints < max_constraints); + ret->constraints[ret->numconstraints] = newconstr; + ret->numconstraints++; + return ret; +} + +cstring exprNode_generateConstraints (exprNode e) +{ + static int temp = 0; + cstring ret; + exprData data; + + if (exprNode_isError (e)) + { + static /*@only@*/ cstring error = cstring_undefined; + + if (!cstring_isDefined (error)) + { + error = cstring_makeLiteral (""); + } + + return error; + } + + data = e->edata; + + switch (e->kind) + { + case XPR_PARENS: + ret = message ("(%s)", exprNode_generateConstraints (exprData_getUopNode (e->edata))); + break; + case XPR_ASSIGN: + ret = message ("%s %s %s", + exprNode_generateConstraints (exprData_getOpA (data)), + lltok_unparse (exprData_getOpTok (data)), + exprNode_generateConstraints (exprData_getOpB (data))); + e->constraints = constraintList_exprNodemerge (exprData_getOpA (data), exprData_getOpB (data) ); + break; + case XPR_CALL: + ret = message ("%s(%q)", + exprNode_generateConstraints (exprData_getFcn (data)), + exprNodeList_unparse (exprData_getArgs (data))); + break; + case XPR_INITBLOCK: + ret = message ("{ %q }", exprNodeList_unparse (exprData_getArgs (data))); + break; + case XPR_EMPTY: + ret = cstring_undefined; + break; + case XPR_LABEL: + ret = message ("%s:", exprData_getId (data)); + break; + case XPR_CONST: + case XPR_VAR: + ret = cstring_copy (exprData_getId (data)); + break; + case XPR_FETCH: + ret = message ("%s[%s]", exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + // printf("Making constraint that size %s > %s\n",exprNode_generateConstraints (exprData_getPairA (data)), + // exprNode_generateConstraints (exprData_getPairB (data))); + e->constraints = constraintList_add (e->constraints, constraint_create (exprData_getPairA (data),exprData_getPairB (data) , GT, BUFFSIZE ) ); + e->constraints = constraintList_add (e->constraints, constraint_create (exprData_getPairB (data), exprNode_undefined, NONNEGATIVE, VALUE) ); + /* crude test to see if this is an lvalue */ + if ( sRefSet_isEmpty(e->sets) ) + { + /* if its not an lvalue we assume it's an rvalue*/ + /* of course if its am lvalue we assume its not an rvalue + should put in a more accurate test sometime...*/ + + // printf("Making constraint that length %s > %s\n",exprNode_generateConstraints (exprData_getPairA (data)), + // exprNode_generateConstraints (exprData_getPairB (data))); + e->constraints = constraintList_add (e->constraints, constraint_create (exprData_getPairA (data),exprData_getPairB (data) , GT, STRINGLEN ) ); + } + break; + case XPR_BODY: + ret = message (""); + break; + case XPR_OP: + ret = message ("%s %s %s", + exprNode_generateConstraints (exprData_getOpA (data)), + lltok_unparse (exprData_getOpTok (data)), + exprNode_generateConstraints (exprData_getOpB (data))); + break; + + case XPR_PREOP: + ret = message ("%s%s", + lltok_unparse (exprData_getUopTok (data)), + exprNode_generateConstraints (exprData_getUopNode (data))); + /*handle * pointer access */ + if (lltok_isMult( exprData_getUopTok (data) ) ) + { + e->constraints = constraintList_add (e->constraints, constraint_create (exprData_getUopNode (data), exprNode_undefined, POSITIVE, BUFFSIZE ) ); + /* crude test to see if this is an lvalue */ + if ( sRefSet_isEmpty(e->sets) ) + { + /* if its not an lvalue we assume it's an rvalue*/ + /* of course if its am lvalue we assume its not an rvalue + should put in a more accurate test sometime...*/ + e->constraints = constraintList_add (e->constraints, constraint_create (exprData_getUopNode (data), exprNode_undefined, POSITIVE, STRINGLEN ) ); + } + } + break; + + case XPR_POSTOP: + ret = message ("%s%s", + exprNode_generateConstraints (exprData_getUopNode (data)), + lltok_unparse (exprData_getUopTok (data))); + break; + + case XPR_OFFSETOF: + ret = message ("offsetof(%s,%q)", + ctype_unparse (qtype_getType (exprData_getOffsetType (data))), + cstringList_unparseSep (exprData_getOffsetName (data), cstring_makeLiteralTemp ("."))); + break; + + case XPR_SIZEOFT: + ret = message ("sizeof(%s)", ctype_unparse (qtype_getType (exprData_getType (data)))); + break; + + case XPR_SIZEOF: + ret = message ("sizeof(%s)", exprNode_generateConstraints (exprData_getSingle (data))); + break; + + case XPR_ALIGNOFT: + ret = message ("alignof(%s)", ctype_unparse (qtype_getType (exprData_getType (data)))); + break; + + case XPR_ALIGNOF: + ret = message ("alignof(%s)", exprNode_generateConstraints (exprData_getSingle (data))); + break; + + case XPR_VAARG: + ret = message ("va_arg(%s, %q)", + exprNode_generateConstraints (exprData_getCastNode (data)), + qtype_unparse (exprData_getCastType (data))); + break; + + case XPR_ITERCALL: + ret = message ("%q(%q)", + uentry_getName (exprData_getIterCallIter (data)), + exprNodeList_unparse (exprData_getIterCallArgs (data))); + break; + case XPR_ITER: + ret = message ("%q(%q) %s %q", + uentry_getName (exprData_getIterSname (data)), + exprNodeList_unparse (exprData_getIterAlist (data)), + exprNode_generateConstraints (exprData_getIterBody (data)), + uentry_getName (exprData_getIterEname (data))); + break; + case XPR_CAST: + ret = message ("(%q)%s", + qtype_unparse (exprData_getCastType (data)), + exprNode_generateConstraints (exprData_getCastNode (data))); + break; + + case XPR_FOR: + ret = message ("%s %s", + exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + break; + + case XPR_FORPRED: + ret = message ("for (%s; %s; %s)", + exprNode_generateConstraints (exprData_getTripleInit (data)), + exprNode_generateConstraints (exprData_getTripleTest (data)), + exprNode_generateConstraints (exprData_getTripleInc (data))); + break; + + case XPR_GOTO: + ret = message ("goto %s", exprData_getLiteral (data)); + break; + + case XPR_CONTINUE: + ret = cstring_makeLiteral ("continue"); + break; + + case XPR_BREAK: + ret = cstring_makeLiteral ("break"); + break; + + case XPR_RETURN: + ret = message ("return %s", exprNode_generateConstraints (exprData_getSingle (data))); + break; + + case XPR_NULLRETURN: + ret = cstring_makeLiteral ("return"); + break; + + case XPR_COMMA: + ret = message ("%s, %s", + exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + break; + + case XPR_COND: + ret = message ("%s ? %s : %s", + exprNode_generateConstraints (exprData_getTriplePred (data)), + exprNode_generateConstraints (exprData_getTripleTrue (data)), + exprNode_generateConstraints (exprData_getTripleFalse (data))); + break; + case XPR_IF: + ret = message ("if (%s) %s", + exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + break; + + case XPR_IFELSE: + ret = message ("if (%s) %s else %s", + exprNode_generateConstraints (exprData_getTriplePred (data)), + exprNode_generateConstraints (exprData_getTripleTrue (data)), + exprNode_generateConstraints (exprData_getTripleFalse (data))); + break; + case XPR_WHILE: + ret = message ("while (%s) %s", + exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + break; + + case XPR_WHILEPRED: + ret = cstring_copy (exprNode_generateConstraints (exprData_getSingle (data))); + break; + + case XPR_TOK: + ret = cstring_copy (lltok_unparse (exprData_getTok (data))); + break; + + case XPR_DOWHILE: + ret = message ("do { %s } while (%s)", + exprNode_generateConstraints (exprData_getPairB (data)), + exprNode_generateConstraints (exprData_getPairA (data))); + break; + + case XPR_BLOCK: + ret = message ("{ %s }", exprNode_generateConstraints (exprData_getSingle (data))); + e->constraints = (exprData_getSingle (data))->constraints; + break; + + case XPR_STMT: + ret = cstring_copy (exprNode_generateConstraints (exprData_getSingle (data))); + e->constraints = (exprData_getSingle (data))->constraints; + break; + + case XPR_STMTLIST: + ret = message ("%s;%d %s", + exprNode_generateConstraints (exprData_getPairA (data)), temp++, + exprNode_generateConstraints (exprData_getPairB (data))); + e->constraints = constraintList_exprNodemerge (exprData_getPairA (data), exprData_getPairB (data) ); + break; + + case XPR_FTDEFAULT: + case XPR_DEFAULT: + ret = cstring_makeLiteral ("default:"); + break; + + case XPR_SWITCH: + ret = message ("switch (%s) %s", + exprNode_generateConstraints (exprData_getPairA (data)), + exprNode_generateConstraints (exprData_getPairB (data))); + break; + + case XPR_FTCASE: + case XPR_CASE: + ret = message ("case %s:", + exprNode_generateConstraints (exprData_getSingle (data))); + break; + + case XPR_INIT: + ret = message ("%s = %s", + idDecl_getName (exprData_getInitId (data)), + exprNode_generateConstraints (exprData_getInitNode (data))); + break; + + case XPR_FACCESS: + ret = message ("%s.%s", + exprNode_generateConstraints (exprData_getFieldNode (data)), + exprData_getFieldName (data)); + break; + + case XPR_ARROW: + ret = message ("%s->%s", + exprNode_generateConstraints (exprData_getFieldNode (data)), + exprData_getFieldName (data)); + break; + + case XPR_STRINGLITERAL: + ret = cstring_copy (exprData_getLiteral (data)); + break; + + case XPR_NUMLIT: + ret = cstring_copy (exprData_getLiteral (data)); + break; + + case XPR_NODE: + ret = cstring_makeLiteral (""); + break; + } + + return ret; +} diff --git a/src/environmentTable.c b/src/environmentTable.c new file mode 100644 index 0000000..842c87a --- /dev/null +++ b/src/environmentTable.c @@ -0,0 +1,1074 @@ +/* +** LCLint - annotation-assisted static program checker +** Copyright (C) 1994-2000 University of Virginia, +** Massachusetts Institute of Technology +** +** This program is free software; you can redistribute it and/or modify it +** under the terms of the GNU General Public License as published by the +** Free Software Foundation; either version 2 of the License, or (at your +** option) any later version. +** +** This program is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** The GNU General Public License is available from http://www.gnu.org/ or +** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +** MA 02111-1307, USA. +** +** For information on lclint: lclint-request@cs.virginia.edu +** To report a bug: lclint-bug@cs.virginia.edu +** For more information: http://lclint.cs.virginia.edu +*/ +/* +** environmentTable.c +*/ + +# include "lclintMacros.nf" +# include "basic.h" + +//#include "environmentTable.h" + +/*@constant int ATINVALID; @*/ +# define ATINVALID -1 + +#define ENVIRONMENTSEARCHLIMIT ALIASSEARCHLIMIT +#define FLG_GLOBENVIRONMENT FLG_GLOBALIAS +#define NOENVIRONMENT NOALIAS + +static sRefSet + environmentTable_canEnvironmentAux (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ; +static sRefSet + environmentTable_aliasedByLimit (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ; +static sRefSet + environmentTable_aliasedByAux (environmentTable p_s, sRef p_sr, int p_lim) /*@*/ ; + +environmentTable +environmentTable_new () +{ + return (environmentTable_undefined); +} + +static /*@only@*/ /*@notnull@*/ environmentTable +environmentTable_newEmpty (void) +{ + environmentTable s = (environmentTable) dmalloc (sizeof (*s)); + + s->nelements = 0; + s->nspace = environmentTableBASESIZE; + s->keys = (sRef *) dmalloc (sizeof (*s->keys) * environmentTableBASESIZE); + s->values = (sRefSet *) dmalloc (sizeof (*s->values) * environmentTableBASESIZE); + s->rangeValues = (rangeAt*) dmalloc (sizeof (*s->rangeValues) * environmentTableBASESIZE); + return (s); +} + +static void +environmentTable_grow (/*@notnull@*/ environmentTable s) +{ + int i; + o_sRefSet *oldvalues = s->values; + sRef *oldkeys = s->keys; + rangeAt *oldranges = s->rangeValues; + + s->nspace += environmentTableBASESIZE; + + s->values = (sRefSet *) dmalloc (sizeof (*s->values) + * (s->nelements + s->nspace)); + s->keys = (sRef *) dmalloc (sizeof (*s->keys) * (s->nelements + environmentTableBASESIZE)); + + s->rangeValues = (rangeAt *) dmalloc (sizeof (*s->rangeValues) * (s->nelements + environmentTableBASESIZE)); + + + if (s->keys == (sRef *) 0 || s->values == (sRefSet *)0 || s->rangeValues == (rangeAt*) 0 ) + { + llfatalerror (cstring_makeLiteral ("environmentTable_grow: out of memory!")); + } + + for (i = 0; i < s->nelements; i++) + { + s->values[i] = oldvalues[i]; + s->keys[i] = oldkeys[i]; + s->rangeValues[i] = oldranges[i]; + } + // s->rangeValues[i] = dmalloc (sizeof (rangeAt)); + sfree (oldvalues); + sfree (oldkeys); + sfree (oldranges); +} + + + +static int environmentTable_lookupRefs (/*@notnull@*/ environmentTable s, sRef sr) +{ + int i; + + + for (i = 0; i < environmentTable_size (s); i++) + { + if (sRef_same (sr, s->keys[i])) + { + return i; + } + } + + return ATINVALID; +} + +environmentTable +environmentTable_postOpvar (/*@returned@*/ environmentTable s, sRef sr) +{ + int ind; + // printf("doing postop\n"); + if (environmentTable_isUndefined (s) ) + { + s = environmentTable_newEmpty(); + } + + ind = environmentTable_lookupRefs (s, sr); + if (ind == ATINVALID) + { + s = environmentTable_addRelativeRange (s, sr); + ind = s->nelements; + } + // assume it ++ we'll do -- later + + s->rangeValues[ind].max++; + s->rangeValues[ind].min++; + + return s; +} + +environmentTable +environmentTable_mergeEnvironments (environmentTable s1, environmentTable s2) +{ + int i; + environmentTable t1; + t1 = environmentTable_copy (s1); + if (environmentTable_isUndefined (s2) ) + return t1; + + for (i = 0; i < s2->nelements; i++) + { + int ind = environmentTable_lookupRefs ( t1, s1->keys[i]); + if (s2->rangeValues[i].isRelative) + { + if (ind == ATINVALID) + { + t1 = environmentTable_insertRelativeRange(t1, s2->keys[i], s2->rangeValues[i].max, s2->rangeValues[i].min); + } + else + { + t1->rangeValues[ind].min += s2->rangeValues[i].min; + t1->rangeValues[ind].max += s2->rangeValues[i].max; + } + } + else + { + /* we want to overwrite old value .. */ + t1 = environmentTable_addExactValue (t1, s2->keys[i], s2->rangeValues[i].max); + /*should fix this to do min and max ... */ + } + + } +} + +rangeAt +rangeAt_createRelativeRange () +{ + rangeAt tmp; + tmp.isRelative = TRUE; + tmp.unknown = FALSE; + tmp.max = 0; + tmp.min = 0; + return tmp; +} + +rangeAt rangeAt_createExactRange (int min, int max) +{ + rangeAt tmp; + tmp.isRelative = FALSE; + tmp.unknown = FALSE; + tmp.min = min; + tmp.max = max; + return tmp; +} + +environmentTable +environmentTable_addRelativeRange (/*@returned@*/ environmentTable s, + /*@exposed@*/ sRef sr) +{ + int ind; + sRefSet ss; + rangeAt range; + + if (environmentTable_isUndefined (s)) + { + s = environmentTable_newEmpty (); + ind = ATINVALID; + } + else + { + ind = environmentTable_lookupRefs (s, sr); + } + + if (ind == ATINVALID) + { + if (s->nspace <= 0) { + environmentTable_grow (s); + } + + s->nspace--; + s->keys[s->nelements] = sr; + /*fix this */ + // s->values[s->nelements] = sRefSet_single (al); + ind = s->nelements; + s->nelements++; + } + range = rangeAt_createRelativeRange(); + + s->rangeValues[ind] = range; + return s; +} + +void +environmentTable_testInRange ( environmentTable s, /*@exposed@*/ sRef sr, int index) +{ + int ind; + sRefSet ss; + rangeAt range; + if (environmentTable_isUndefined (s)) + { + fprintf(stderr,"environmentTable not defined\n"); + return; + } + + ind = environmentTable_lookupRefs (s, sr); + if (ind == ATINVALID) + { + fprintf (stderr,"range not known\n"); + return; + } + if ( &s->rangeValues[ind] ) + { + if ( (s->rangeValues[ind].min <= index ) && (s->rangeValues[ind].max >= index) ) + { + printf("The value %d is in the range for this variable \n", index); + } + else + printf("The value %d is NOT in the range for this variable \n", index); + } + +} + + +environmentTable +environmentTable_addExactValue (/*@returned@*/ environmentTable s, + /*@exposed@*/ sRef sr, + int val) +{ + int ind; + sRefSet ss; + rangeAt range; + + if (environmentTable_isUndefined (s)) + { + s = environmentTable_newEmpty (); + ind = ATINVALID; + } + else + { + ind = environmentTable_lookupRefs (s, sr); + } + + if (ind == ATINVALID) + { + if (s->nspace <= 0) { + environmentTable_grow (s); + } + + s->nspace--; + s->keys[s->nelements] = sr; + /*fix this */ + // s->values[s->nelements] = sRefSet_single (al); + ind = s->nelements; + s->nelements++; + } + + else + { + /* s->values[ind] = sRefSet_insert (s->values[ind], al); */ + } + /* + if ( (s->rangeValues[ind]) == 0 ) + { + s->rangeValues[ind] = dmalloc(sizeof(rangeAt) ); + } + */ + range.min = val; + range.max = val; + + s->rangeValues[ind] = range; + return s; +} + +environmentTable +environmentTable_insertRelativeRange (/*@returned@*/ environmentTable s, + /*@exposed@*/ sRef sr, + int min, int max) +{ + int ind; + sRefSet ss; + rangeAt range; + + if (environmentTable_isUndefined (s)) + { + s = environmentTable_newEmpty (); + ind = ATINVALID; + } + else + { + ind = environmentTable_lookupRefs (s, sr); + } + + if (ind == ATINVALID) + { + if (s->nspace <= 0) { + environmentTable_grow (s); + } + + s->nspace--; + s->keys[s->nelements] = sr; + /*fix this */ + // s->values[s->nelements] = sRefSet_single (al); + ind = s->nelements; + s->nelements++; + } + + range = rangeAt_createRelativeRange(); + range.min = min; + range.max = max; + + s->rangeValues[ind] = range; + return s; +} + +environmentTable +environmentTable_addMustAlias (/*@returned@*/ environmentTable s, + /*@exposed@*/ sRef sr, + sRef al) +{ + int ind; + sRefSet ss; + + llassert (NOENVIRONMENT (sr, al)); + + if (environmentTable_isUndefined (s)) + { + s = environmentTable_newEmpty (); + ind = ATINVALID; + } + else + { + ind = environmentTable_lookupRefs (s, sr); + } + + ss = environmentTable_canEnvironment (s, al); + + + if (ind == ATINVALID) + { + if (s->nspace <= 0) { + environmentTable_grow (s); + } + + s->nspace--; + s->keys[s->nelements] = sr; + s->values[s->nelements] = sRefSet_single (al); + ind = s->nelements; + s->nelements++; + } + else + { + s->values[ind] = sRefSet_insert (s->values[ind], al); + } + + s->values[ind] = sRefSet_unionExcept (s->values[ind], ss, s->keys[ind]); + + sRefSet_free (ss); + return s; +} + +static environmentTable + environmentTable_addSet (/*@returned@*/ environmentTable s, + /*@exposed@*/ sRef key, /*@only@*/ sRefSet value) +{ + if (!sRefSet_isEmpty (value)) + { + if (environmentTable_isUndefined (s)) + { + s = environmentTable_newEmpty (); + } + else + { + if (s->nspace <= 0) + { + environmentTable_grow (s); + } + } + + s->nspace--; + s->keys[s->nelements] = key; + s->values[s->nelements] = value; + s->nelements++; + } + else + { + sRefSet_free (value); + } + + return s; +} + +/* +** When environmentes are cleared: +** +** o remove all entries for sr +** o replace all environmentes for things which environment sr with sr's environmentes +** +** Clear environmentes for sr; if sr is a direct param reference, clear its environmentes too. +*/ + +static void environmentTable_clearEnvironmentesAux (/*@notnull@*/ environmentTable p_s, sRef p_sr) + /*@modifies p_s@*/ ; + +void environmentTable_clearEnvironmentes (environmentTable s, sRef sr) +{ + if (environmentTable_isUndefined (s)) + { + return; + } + else + { + sRef rb = sRef_getRootBase (sr); + + + if (!sRef_isCvar (sr) && sRef_isLocalVar (rb)) + { + int ind = environmentTable_lookupRefs (s, rb); + + if (ind != ATINVALID) + { + sRefSet al = s->values[ind]; + + + sRefSet_realElements (al, el) + { + + if (sRef_isParam (el)) + { + if (sRef_sameName (el, rb)) + { + sRef fb = sRef_fixBase (sr, el); + + environmentTable_clearEnvironmentesAux (s, fb); + } + } + } end_sRefSet_realElements ; + } + } + + environmentTable_clearEnvironmentesAux (s, sr); + } +} + +static +void environmentTable_clearEnvironmentesAux (/*@notnull@*/ environmentTable s, sRef sr) +{ + int i; + + for (i = 0; i < s->nelements; i++) + { + sRef key = s->keys[i]; + + if (sRef_includedBy (key, sr)) + { + sRefSet_clear (s->values[i]); + } + else + { + (void) sRefSet_deleteBase (s->values[i], sr); + } + } +} + +/* +** returns set of all sRefs that must environment sr (but are different from sr) +*/ + +static /*@only@*/ sRefSet environmentTable_environmentedByAux (environmentTable s, sRef sr, int lim) +{ + static bool hadWarning = FALSE; + sRefSet res = sRefSet_undefined; + int i; + + llassert (!sRef_isConj (sr)); + + + if (environmentTable_isUndefined (s) || lim >= ENVIRONMENTSEARCHLIMIT) + { + if (lim >= ENVIRONMENTSEARCHLIMIT && !hadWarning) + { + llquietbug + (message ("Environment search limit exceeded, checking %q. " + "This either means there is a variable with at least " + "%d indirections, or there is a bug in LCLint.", + sRef_unparse (sr), + ENVIRONMENTSEARCHLIMIT)); + + hadWarning = TRUE; + } + + return sRefSet_undefined; + } + else + { + sRefSet abl; + + if (sRef_isPointer (sr)) + { + abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_addIndirection (abl); + } + else if (sRef_isAddress (sr)) + { + abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_removeIndirection (abl); + } + else if (sRef_isField (sr)) + { + abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_accessField (abl, sRef_getField (sr)); + } + else if (sRef_isArrayFetch (sr)) + { + abl = environmentTable_environmentedByLimit (s, sRef_getBase (sr), lim); + + if (sRef_isIndexKnown (sr)) + { + int idx = sRef_getIndex (sr); + + res = sRefSet_fetchKnown (abl, idx); + } + else + { + res = sRefSet_fetchUnknown (abl); + } + } + else + { + abl = sRefSet_undefined; + } + + sRefSet_free (abl); + } + + for (i = 0; i < s->nelements; i++) + { + sRef elem = s->keys[i]; + + if (!sRef_same (sr, elem)) /* was sameName */ + { + + sRefSet_realElements (s->values[i], current) + { + + if (sRef_similar (sr, current)) + { + res = sRefSet_insert (res, sRef_fixOuterRef (elem)); + /*@innerbreak@*/ break; + } + } end_sRefSet_realElements; + } + } + + return res; +} + +static /*@only@*/ sRefSet environmentTable_environmentedByLimit (environmentTable s, sRef sr, int lim) +{ + sRefSet res; + + + if (sRef_isConj (sr)) + { + res = sRefSet_unionFree (environmentTable_environmentedByLimit (s, sRef_getConjA (sr), lim), + environmentTable_environmentedByLimit (s, sRef_getConjB (sr), lim)); + } + else + { + res = environmentTable_environmentedByAux (s, sr, lim + 1); + } + + return res; +} + +/*@only@*/ sRefSet environmentTable_environmentedBy (environmentTable s, sRef sr) +{ + if (sRef_isConj (sr)) + { + return (sRefSet_unionFree (environmentTable_environmentedBy (s, sRef_getConjA (sr)), + environmentTable_environmentedBy (s, sRef_getConjB (sr)))); + } + + return (environmentTable_environmentedByAux (s, sr, 0)); +} + +/*@only@*/ sRefSet environmentTable_canEnvironment (environmentTable s, sRef sr) +{ + sRefSet res; + + + if (sRef_isConj (sr)) + { + res = sRefSet_unionFree (environmentTable_canEnvironment (s, sRef_getConjA (sr)), + environmentTable_canEnvironment (s, sRef_getConjB (sr))); + } + else + { + res = environmentTable_canEnvironmentAux (s, sr, 0); + } + + return res; +} + +/* +** need to limit the depth of environmenting searches +*/ + +static /*@only@*/ sRefSet environmentTable_canEnvironmentLimit (environmentTable s, sRef sr, int lim) +{ + sRefSet res; + + if (sRef_isConj (sr)) + { + sRefSet a = environmentTable_canEnvironmentLimit (s, sRef_getConjA (sr), lim); + sRefSet b = environmentTable_canEnvironmentLimit (s, sRef_getConjB (sr), lim); + + res = sRefSet_unionFree (a, b); + } + else + { + res = environmentTable_canEnvironmentAux (s, sr, lim + 1); + } + + return res; +} + +static /*@only@*/ sRefSet + environmentTable_canEnvironmentAux (environmentTable s, sRef sr, int lim) +{ + static bool hadWarning = FALSE; + llassert (!sRef_isConj (sr)); + + + if (environmentTable_isUndefined (s) || lim >= ALIASSEARCHLIMIT) + { + if (lim >= ALIASSEARCHLIMIT && !hadWarning) + { + llquietbug + (message ("Environment search limit exceeded, checking %q. " + "This either means there is a variable with at least " + "%d indirections, or there is a bug in LCLint.", + sRef_unparse (sr), + ENVIRONMENTSEARCHLIMIT)); + + hadWarning = TRUE; + } + + return sRefSet_undefined; + } + else + { + int ind = environmentTable_lookupRefs (s, sr); + + if (sRef_isPointer (sr) || sRef_isAddress (sr) || sRef_isField (sr) + || sRef_isArrayFetch (sr)) + { + sRef base = sRef_getBase (sr); + sRefSet tmp = environmentTable_canEnvironmentLimit (s, base, lim); + sRefSet ret; + + if (sRef_isPointer (sr)) + { + ret = sRefSet_addIndirection (tmp); + } + else if (sRef_isAddress (sr)) + { + ret = sRefSet_removeIndirection (tmp); + } + else if (sRef_isField (sr)) + { + ret = sRefSet_accessField (tmp, sRef_getField (sr)); + } + else if (sRef_isArrayFetch (sr)) + { + if (sRef_isIndexKnown (sr)) + { + ret = sRefSet_fetchKnown (tmp, sRef_getIndex (sr)); + } + else + { + ret = sRefSet_fetchUnknown (tmp); + } + } + else + { + BADBRANCH; + } + + if (ind != ATINVALID) + { + ret = sRefSet_union (ret, s->values[ind]); + } + + sRefSet_free (tmp); + return ret; + } + + if (ind == ATINVALID) return sRefSet_undefined; + + return sRefSet_newCopy (s->values[ind]); + } +} + +environmentTable environmentTable_copy (environmentTable s) +{ + if (environmentTable_isEmpty (s)) + { + return environmentTable_undefined; + } + else + { + environmentTable t = (environmentTable) dmalloc (sizeof (*s)); + int i; + + t->nelements = s->nelements; + t->nspace = 0; + t->keys = (sRef *) dmalloc (sizeof (*s->keys) * s->nelements); + t->values = (sRefSet *) dmalloc (sizeof (*s->values) * t->nelements); + t->rangeValues = (rangeAt *) dmalloc (sizeof (*s->rangeValues) * t->nelements); + + for (i = 0; i < s->nelements; i++) + { + t->keys[i] = s->keys[i]; + t->values[i] = sRefSet_newCopy (s->values[i]); + t->rangeValues[i] = s->rangeValues[i]; + } + + return t; + } +} + +static void +environmentTable_levelPrune (environmentTable s, int lexlevel) +{ + + + if (environmentTable_isEmpty (s)) + { + return; + } + else + { + int i; + int backcount = s->nelements - 1; + + for (i = 0; i <= backcount; i++) + { + sRef key = s->keys[i]; + + if (sRef_lexLevel (key) > lexlevel) + { + int j; + for (j = backcount; j > i; j--) + { + backcount--; + s->nelements--; + s->nspace++; + + if (sRef_lexLevel (s->keys[j]) <= lexlevel) + { + s->keys[i] = s->keys[j]; + s->values[i] = s->values[j]; + sRefSet_levelPrune (s->values[i], lexlevel); + /*@innerbreak@*/ break; + } + } + if (backcount == i) + s->nelements--; + } + else + { + sRefSet_levelPrune (s->values[i], lexlevel); + } + } + } +} + +/* +** levelUnionSeq +** +** like level union, but know that t2 was executed after t1. So if +** t1 has x -> { a, b } and t2 has x -> { a }, then result has x -> { a }. +** +** NOTE: t2 is "only". +*/ + +environmentTable environmentTable_levelUnionSeq (/*@returned@*/ environmentTable t1, + /*@only@*/ environmentTable t2, int level) +{ + if (environmentTable_isUndefined (t2)) + { + return t1; + } + + if (environmentTable_isUndefined (t1)) + { + t1 = environmentTable_newEmpty (); + } + else + { + environmentTable_levelPrune (t1, level); + } + + environmentTable_elements (t2, key, value) + { + if (sRef_lexLevel (key) <= level) + { + int ind = environmentTable_lookupRefs (t1, key); + + sRefSet_levelPrune (value, level); + + if (ind == ATINVALID) + { + /* okay, t2 is killed */ + /*@-exposetrans@*/ /*@-dependenttrans@*/ + t1 = environmentTable_addSet (t1, key, value); + /*@=exposetrans@*/ /*@=dependenttrans@*/ + } + else + { + sRefSet_free (t1->values[ind]); + + /*@-dependenttrans@*/ /* okay, t2 is killed */ + t1->values[ind] = value; + /*@=dependenttrans@*/ + } + } + else + { + /*@-exposetrans@*/ /*@-dependenttrans@*/ + sRefSet_free (value); + /*@=exposetrans@*/ /*@=dependenttrans@*/ + } + + } end_environmentTable_elements; + + sfree (t2->keys); + sfree (t2->values); + sfree (t2); + + return t1; +} + +environmentTable +environmentTable_levelUnion (/*@returned@*/ environmentTable t1, environmentTable t2, int level) +{ + if (environmentTable_isUndefined (t1)) + { + if (environmentTable_isUndefined (t2)) + { + return t1; + } + else + { + t1 = environmentTable_newEmpty (); + } + } + else + { + environmentTable_levelPrune (t1, level); + } + + environmentTable_elements (t2, key, cvalue) + { + sRefSet value = sRefSet_newCopy (cvalue); + + if (sRef_lexLevel (key) <= level) + { + sRefSet_levelPrune (value, level); + + if (sRefSet_size (value) > 0) + { + int ind = environmentTable_lookupRefs (t1, key); + + if (ind == ATINVALID) + { + t1 = environmentTable_addSet (t1, key, value); + } + else + { + t1->values[ind] = sRefSet_union (t1->values[ind], value); + sRefSet_free (value); + } + } + else + { + sRefSet_free (value); + } + } + else + { + sRefSet_free (value); + } + } end_environmentTable_elements; + + return t1; +} + +environmentTable environmentTable_levelUnionNew (environmentTable t1, environmentTable t2, int level) +{ + environmentTable ret = environmentTable_levelUnion (environmentTable_copy (t1), t2, level); + + return ret; +} + +/*@only@*/ cstring +environmentTable_unparse (environmentTable s) +{ + cstring st = cstring_undefined; + + if (environmentTable_isUndefined (s)) return (cstring_makeLiteral ("")); + + environmentTable_elements (s, key, value) + { + st = message ("%q\t%q -> %q\n", st, sRef_unparse (key), + sRefSet_unparse (value)); + } end_environmentTable_elements; + + return st; +} + +/* +** bogus! +*/ + +void +environmentTable_fixSrefs (environmentTable s) +{ + int i; + + if (environmentTable_isUndefined (s)) return; + + for (i = 0; i < s->nelements; i++) + { + sRef old = s->keys[i]; + + if (sRef_isLocalVar (old)) + { + s->keys[i] = uentry_getSref (sRef_getUentry (old)); + } + + sRefSet_fixSrefs (s->values[i]); + } +} + +void +environmentTable_free (/*@only@*/ environmentTable s) +{ + int i; + + if (environmentTable_isUndefined (s)) return; + + for (i = 0; i < s->nelements; i++) + { + sRefSet_free (s->values[i]); + } + + sfree (s->values); + sfree (s->keys); + sfree (s); +} + +void +environmentTable_checkGlobs (environmentTable t) +{ + environmentTable_elements (t, key, value) + { + sRef root = sRef_getRootBase (key); + + if (sRef_isAliasCheckedGlobal (root)) + { + sRefSet_realElements (value, sr) + { + root = sRef_getRootBase (sr); + + if (((sRef_isAliasCheckedGlobal (root) + && !(sRef_similar (root, key))) + || sRef_isAnyParam (root)) + && !sRef_isExposed (root)) + { + if (sRef_isAliasCheckedGlobal (key)) + { + if (!(sRef_isShared (key) + && sRef_isShared (root))) + { + voptgenerror + (FLG_GLOBENVIRONMENT, + message + ("Function returns with %q variable %q environmenting %q %q", + cstring_makeLiteral (sRef_isRealGlobal (key) + ? "global" : "file static"), + sRef_unparse (key), + cstring_makeLiteral (sRef_isAnyParam (root) + ? "parameter" : "global"), + sRef_unparse (sr)), + g_currentloc); + } + } + + } + } end_sRefSet_realElements; + } + else if (sRef_isAnyParam (key) || sRef_isAnyParam (root)) + { + sRefSet_realElements (value, sr) + { + root = sRef_getRootBase (sr); + + if (sRef_isAliasCheckedGlobal (root) + && !sRef_isExposed (root) + && !sRef_isDead (key) + && !sRef_isShared (root)) + { + voptgenerror + (FLG_GLOBENVIRONMENT, + message ("Function returns with parameter %q environmenting %q %q", + sRef_unparse (key), + cstring_makeLiteral (sRef_isRealGlobal (root) + ? "global" : "file static"), + sRef_unparse (sr)), + g_currentloc); + } + } end_sRefSet_realElements; + } + else + { + ; + } + } end_environmentTable_elements; +} + + + diff --git a/src/exprData.c b/src/exprData.c new file mode 100644 index 0000000..8bcfe0d --- /dev/null +++ b/src/exprData.c @@ -0,0 +1,40 @@ +/* +** exprNode.c +*/ + +# include /* for isdigit */ +# include "lclintMacros.nf" +# include "basic.h" +# include "cgrammar.h" +# include "cgrammar_tokens.h" + +# include "exprChecks.h" +# include "aliasChecks.h" +# include "exprNodeSList.h" +# include "exprData.i" + +/*@only@*/ exprData exprData_makeLiteral (/*@only@*/ cstring s) +{ + exprData ed = (exprData) dmalloc (sizeof (*ed)); + + ed->literal = s; + return ed; +} + +/*@only@*/ exprData exprData_makeId (/*@temp@*/ uentry id) +{ + exprData ed = (exprData) dmalloc (sizeof (*ed)); + ed->id = cstring_copy (uentry_rawName (id)); + return ed; +} + +/*@only@*/ exprData exprData_makePair (/*@keep@*/ exprNode a, /*@keep@*/ exprNode b) +{ + exprData ed = (exprData) dmalloc (sizeof (*ed)); + + ed->pair = (exprPair) dmalloc (sizeof (*ed->pair)); + ed->pair->a = a; + ed->pair->b = b; + + return ed; +} diff --git a/src/rangeTable.c b/src/rangeTable.c new file mode 100644 index 0000000..2c8e407 --- /dev/null +++ b/src/rangeTable.c @@ -0,0 +1,829 @@ +/* +** LCLint - annotation-assisted static program checker +** Copyright (C) 1994-2000 University of Virginia, +** Massachusetts Institute of Technology +** +** This program is free software; you can redistribute it and/or modify it +** under the terms of the GNU General Public License as published by the +** Free Software Foundation; either version 2 of the License, or (at your +** option) any later version. +** +** This program is distributed in the hope that it will be useful, but +** WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** +** The GNU General Public License is available from http://www.gnu.org/ or +** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, +** MA 02111-1307, USA. +** +** For information on lclint: lclint-request@cs.virginia.edu +** To report a bug: lclint-bug@cs.virginia.edu +** For more information: http://lclint.cs.virginia.edu +*/ +/* +** rangeTable.c +*/ + +# include "lclintMacros.nf" +# include "basic.h" + +/*@constant int ATINVALID; @*/ +# define ATINVALID -1 + +static sRefSet + rangeTable_canRangeAux (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ; +static sRefSet + rangeTable_aliasedByLimit (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ; +static sRefSet + rangeTable_aliasedByAux (rangeTable p_s, sRef p_sr, int p_lim) /*@*/ ; + +rangeTable +rangeTable_new () +{ + return (rangeTable_undefined); +} + +static /*@only@*/ /*@notnull@*/ rangeTable +rangeTable_newEmpty (void) +{ + rangeTable s = (rangeTable) dmalloc (sizeof (*s)); + + s->nelements = 0; + s->nspace = rangeTableBASESIZE; + s->keys = (sRef *) dmalloc (sizeof (*s->keys) * rangeTableBASESIZE); + s->values = (sRefSet *) dmalloc (sizeof (*s->values) * rangeTableBASESIZE); + s->ranges = (sRefSet *) dmalloc (sizeof (*s->ranges) * rangeTableBASESIZE); + return (s); +} + +static void +rangeTable_grow (/*@notnull@*/ rangeTable s) +{ + int i; + o_sRefSet *oldvalues = s->values; + sRef *oldkeys = s->keys; + RangeAt *oldranges = s->ranges; + + s->nspace += rangeTableBASESIZE; + + s->values = (sRefSet *) dmalloc (sizeof (*s->values) + * (s->nelements + s->nspace)); + s->keys = (sRef *) dmalloc (sizeof (*s->keys) * (s->nelements + rangeTableBASESIZE)); + + s->ranges = (sRef *) dmalloc (sizeof (*s->ranges) * (s->nelements + rangeTableBASESIZE)); + + + if (s->keys == (sRef *) 0 || s->values == (sRefSet *)0 || s->ranges = (range_At*) 0 ) + { + llfatalerror (cstring_makeLiteral ("rangeTable_grow: out of memory!")); + } + + for (i = 0; i < s->nelements; i++) + { + s->values[i] = oldvalues[i]; + s->keys[i] = oldkeys[i]; + s->ranges[i] = oldranges[i]; + } + + sfree (oldvalues); + sfree (oldkeys); +} + +static int rangeTable_lookupRefs (/*@notnull@*/ rangeTable s, sRef sr) +{ + int i; + + + for (i = 0; i < rangeTable_size (s); i++) + { + if (sRef_same (sr, s->keys[i])) + { + return i; + } + } + + return ATINVALID; +} + +/* +** sr rangees al (and anything al rangees!) +*/ + +rangeTable +rangeTable_addMustRange (/*@returned@*/ rangeTable s, + /*@exposed@*/ sRef sr, + sRef al) +{ + int ind; + sRefSet ss; + + llassert (NORANGE (sr, al)); + + if (rangeTable_isUndefined (s)) + { + s = rangeTable_newEmpty (); + ind = ATINVALID; + } + else + { + ind = rangeTable_lookupRefs (s, sr); + } + + ss = rangeTable_canRange (s, al); + + + if (ind == ATINVALID) + { + if (s->nspace <= 0) { + rangeTable_grow (s); + } + + s->nspace--; + s->keys[s->nelements] = sr; + s->values[s->nelements] = sRefSet_single (al); + ind = s->nelements; + s->nelements++; + } + else + { + s->values[ind] = sRefSet_insert (s->values[ind], al); + } + + s->values[ind] = sRefSet_unionExcept (s->values[ind], ss, s->keys[ind]); + + sRefSet_free (ss); + return s; +} + +static rangeTable + rangeTable_addSet (/*@returned@*/ rangeTable s, + /*@exposed@*/ sRef key, /*@only@*/ sRefSet value) +{ + if (!sRefSet_isEmpty (value)) + { + if (rangeTable_isUndefined (s)) + { + s = rangeTable_newEmpty (); + } + else + { + if (s->nspace <= 0) + { + rangeTable_grow (s); + } + } + + s->nspace--; + s->keys[s->nelements] = key; + s->values[s->nelements] = value; + s->nelements++; + } + else + { + sRefSet_free (value); + } + + return s; +} + +/* +** When rangees are cleared: +** +** o remove all entries for sr +** o replace all rangees for things which range sr with sr's rangees +** +** Clear rangees for sr; if sr is a direct param reference, clear its rangees too. +*/ + +static void rangeTable_clearRangeesAux (/*@notnull@*/ rangeTable p_s, sRef p_sr) + /*@modifies p_s@*/ ; + +void rangeTable_clearRangees (rangeTable s, sRef sr) +{ + if (rangeTable_isUndefined (s)) + { + return; + } + else + { + sRef rb = sRef_getRootBase (sr); + + + if (!sRef_isCvar (sr) && sRef_isLocalVar (rb)) + { + int ind = rangeTable_lookupRefs (s, rb); + + if (ind != ATINVALID) + { + sRefSet al = s->values[ind]; + + + sRefSet_realElements (al, el) + { + + if (sRef_isParam (el)) + { + if (sRef_sameName (el, rb)) + { + sRef fb = sRef_fixBase (sr, el); + + rangeTable_clearRangeesAux (s, fb); + } + } + } end_sRefSet_realElements ; + } + } + + rangeTable_clearRangeesAux (s, sr); + } +} + +static +void rangeTable_clearRangeesAux (/*@notnull@*/ rangeTable s, sRef sr) +{ + int i; + + for (i = 0; i < s->nelements; i++) + { + sRef key = s->keys[i]; + + if (sRef_includedBy (key, sr)) + { + sRefSet_clear (s->values[i]); + } + else + { + (void) sRefSet_deleteBase (s->values[i], sr); + } + } +} + +/* +** returns set of all sRefs that must range sr (but are different from sr) +*/ + +static /*@only@*/ sRefSet rangeTable_rangeedByAux (rangeTable s, sRef sr, int lim) +{ + static bool hadWarning = FALSE; + sRefSet res = sRefSet_undefined; + int i; + + llassert (!sRef_isConj (sr)); + + + if (rangeTable_isUndefined (s) || lim >= RANGESEARCHLIMIT) + { + if (lim >= RANGESEARCHLIMIT && !hadWarning) + { + llquietbug + (message ("Range search limit exceeded, checking %q. " + "This either means there is a variable with at least " + "%d indirections, or there is a bug in LCLint.", + sRef_unparse (sr), + RANGESEARCHLIMIT)); + + hadWarning = TRUE; + } + + return sRefSet_undefined; + } + else + { + sRefSet abl; + + if (sRef_isPointer (sr)) + { + abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_addIndirection (abl); + } + else if (sRef_isAddress (sr)) + { + abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_removeIndirection (abl); + } + else if (sRef_isField (sr)) + { + abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim); + res = sRefSet_accessField (abl, sRef_getField (sr)); + } + else if (sRef_isArrayFetch (sr)) + { + abl = rangeTable_rangeedByLimit (s, sRef_getBase (sr), lim); + + if (sRef_isIndexKnown (sr)) + { + int idx = sRef_getIndex (sr); + + res = sRefSet_fetchKnown (abl, idx); + } + else + { + res = sRefSet_fetchUnknown (abl); + } + } + else + { + abl = sRefSet_undefined; + } + + sRefSet_free (abl); + } + + for (i = 0; i < s->nelements; i++) + { + sRef elem = s->keys[i]; + + if (!sRef_same (sr, elem)) /* was sameName */ + { + + sRefSet_realElements (s->values[i], current) + { + + if (sRef_similar (sr, current)) + { + res = sRefSet_insert (res, sRef_fixOuterRef (elem)); + /*@innerbreak@*/ break; + } + } end_sRefSet_realElements; + } + } + + return res; +} + +static /*@only@*/ sRefSet rangeTable_rangeedByLimit (rangeTable s, sRef sr, int lim) +{ + sRefSet res; + + + if (sRef_isConj (sr)) + { + res = sRefSet_unionFree (rangeTable_rangeedByLimit (s, sRef_getConjA (sr), lim), + rangeTable_rangeedByLimit (s, sRef_getConjB (sr), lim)); + } + else + { + res = rangeTable_rangeedByAux (s, sr, lim + 1); + } + + return res; +} + +/*@only@*/ sRefSet rangeTable_rangeedBy (rangeTable s, sRef sr) +{ + if (sRef_isConj (sr)) + { + return (sRefSet_unionFree (rangeTable_rangeedBy (s, sRef_getConjA (sr)), + rangeTable_rangeedBy (s, sRef_getConjB (sr)))); + } + + return (rangeTable_rangeedByAux (s, sr, 0)); +} + +/*@only@*/ sRefSet rangeTable_canRange (rangeTable s, sRef sr) +{ + sRefSet res; + + + if (sRef_isConj (sr)) + { + res = sRefSet_unionFree (rangeTable_canRange (s, sRef_getConjA (sr)), + rangeTable_canRange (s, sRef_getConjB (sr))); + } + else + { + res = rangeTable_canRangeAux (s, sr, 0); + } + + return res; +} + +/* +** need to limit the depth of rangeing searches +*/ + +static /*@only@*/ sRefSet rangeTable_canRangeLimit (rangeTable s, sRef sr, int lim) +{ + sRefSet res; + + if (sRef_isConj (sr)) + { + sRefSet a = rangeTable_canRangeLimit (s, sRef_getConjA (sr), lim); + sRefSet b = rangeTable_canRangeLimit (s, sRef_getConjB (sr), lim); + + res = sRefSet_unionFree (a, b); + } + else + { + res = rangeTable_canRangeAux (s, sr, lim + 1); + } + + return res; +} + +static /*@only@*/ sRefSet + rangeTable_canRangeAux (rangeTable s, sRef sr, int lim) +{ + static bool hadWarning = FALSE; + llassert (!sRef_isConj (sr)); + + + if (rangeTable_isUndefined (s) || lim >= RANGESEARCHLIMIT) + { + if (lim >= RANGESEARCHLIMIT && !hadWarning) + { + llquietbug + (message ("Range search limit exceeded, checking %q. " + "This either means there is a variable with at least " + "%d indirections, or there is a bug in LCLint.", + sRef_unparse (sr), + RANGESEARCHLIMIT)); + + hadWarning = TRUE; + } + + return sRefSet_undefined; + } + else + { + int ind = rangeTable_lookupRefs (s, sr); + + if (sRef_isPointer (sr) || sRef_isAddress (sr) || sRef_isField (sr) + || sRef_isArrayFetch (sr)) + { + sRef base = sRef_getBase (sr); + sRefSet tmp = rangeTable_canRangeLimit (s, base, lim); + sRefSet ret; + + if (sRef_isPointer (sr)) + { + ret = sRefSet_addIndirection (tmp); + } + else if (sRef_isAddress (sr)) + { + ret = sRefSet_removeIndirection (tmp); + } + else if (sRef_isField (sr)) + { + ret = sRefSet_accessField (tmp, sRef_getField (sr)); + } + else if (sRef_isArrayFetch (sr)) + { + if (sRef_isIndexKnown (sr)) + { + ret = sRefSet_fetchKnown (tmp, sRef_getIndex (sr)); + } + else + { + ret = sRefSet_fetchUnknown (tmp); + } + } + else + { + BADBRANCH; + } + + if (ind != ATINVALID) + { + ret = sRefSet_union (ret, s->values[ind]); + } + + sRefSet_free (tmp); + return ret; + } + + if (ind == ATINVALID) return sRefSet_undefined; + + return sRefSet_newCopy (s->values[ind]); + } +} + +rangeTable rangeTable_copy (rangeTable s) +{ + if (rangeTable_isEmpty (s)) + { + return rangeTable_undefined; + } + else + { + rangeTable t = (rangeTable) dmalloc (sizeof (*s)); + int i; + + t->nelements = s->nelements; + t->nspace = 0; + t->keys = (sRef *) dmalloc (sizeof (*s->keys) * s->nelements); + t->values = (sRefSet *) dmalloc (sizeof (*s->values) * t->nelements); + + for (i = 0; i < s->nelements; i++) + { + t->keys[i] = s->keys[i]; + t->values[i] = sRefSet_newCopy (s->values[i]); + } + + return t; + } +} + +static void +rangeTable_levelPrune (rangeTable s, int lexlevel) +{ + + + if (rangeTable_isEmpty (s)) + { + return; + } + else + { + int i; + int backcount = s->nelements - 1; + + for (i = 0; i <= backcount; i++) + { + sRef key = s->keys[i]; + + if (sRef_lexLevel (key) > lexlevel) + { + int j; + for (j = backcount; j > i; j--) + { + backcount--; + s->nelements--; + s->nspace++; + + if (sRef_lexLevel (s->keys[j]) <= lexlevel) + { + s->keys[i] = s->keys[j]; + s->values[i] = s->values[j]; + sRefSet_levelPrune (s->values[i], lexlevel); + /*@innerbreak@*/ break; + } + } + if (backcount == i) + s->nelements--; + } + else + { + sRefSet_levelPrune (s->values[i], lexlevel); + } + } + } +} + +/* +** levelUnionSeq +** +** like level union, but know that t2 was executed after t1. So if +** t1 has x -> { a, b } and t2 has x -> { a }, then result has x -> { a }. +** +** NOTE: t2 is "only". +*/ + +rangeTable rangeTable_levelUnionSeq (/*@returned@*/ rangeTable t1, + /*@only@*/ rangeTable t2, int level) +{ + if (rangeTable_isUndefined (t2)) + { + return t1; + } + + if (rangeTable_isUndefined (t1)) + { + t1 = rangeTable_newEmpty (); + } + else + { + rangeTable_levelPrune (t1, level); + } + + rangeTable_elements (t2, key, value) + { + if (sRef_lexLevel (key) <= level) + { + int ind = rangeTable_lookupRefs (t1, key); + + sRefSet_levelPrune (value, level); + + if (ind == ATINVALID) + { + /* okay, t2 is killed */ + /*@-exposetrans@*/ /*@-dependenttrans@*/ + t1 = rangeTable_addSet (t1, key, value); + /*@=exposetrans@*/ /*@=dependenttrans@*/ + } + else + { + sRefSet_free (t1->values[ind]); + + /*@-dependenttrans@*/ /* okay, t2 is killed */ + t1->values[ind] = value; + /*@=dependenttrans@*/ + } + } + else + { + /*@-exposetrans@*/ /*@-dependenttrans@*/ + sRefSet_free (value); + /*@=exposetrans@*/ /*@=dependenttrans@*/ + } + + } end_rangeTable_elements; + + sfree (t2->keys); + sfree (t2->values); + sfree (t2); + + return t1; +} + +rangeTable +rangeTable_levelUnion (/*@returned@*/ rangeTable t1, rangeTable t2, int level) +{ + if (rangeTable_isUndefined (t1)) + { + if (rangeTable_isUndefined (t2)) + { + return t1; + } + else + { + t1 = rangeTable_newEmpty (); + } + } + else + { + rangeTable_levelPrune (t1, level); + } + + rangeTable_elements (t2, key, cvalue) + { + sRefSet value = sRefSet_newCopy (cvalue); + + if (sRef_lexLevel (key) <= level) + { + sRefSet_levelPrune (value, level); + + if (sRefSet_size (value) > 0) + { + int ind = rangeTable_lookupRefs (t1, key); + + if (ind == ATINVALID) + { + t1 = rangeTable_addSet (t1, key, value); + } + else + { + t1->values[ind] = sRefSet_union (t1->values[ind], value); + sRefSet_free (value); + } + } + else + { + sRefSet_free (value); + } + } + else + { + sRefSet_free (value); + } + } end_rangeTable_elements; + + return t1; +} + +rangeTable rangeTable_levelUnionNew (rangeTable t1, rangeTable t2, int level) +{ + rangeTable ret = rangeTable_levelUnion (rangeTable_copy (t1), t2, level); + + return ret; +} + +/*@only@*/ cstring +rangeTable_unparse (rangeTable s) +{ + cstring st = cstring_undefined; + + if (rangeTable_isUndefined (s)) return (cstring_makeLiteral ("")); + + rangeTable_elements (s, key, value) + { + st = message ("%q\t%q -> %q\n", st, sRef_unparse (key), + sRefSet_unparse (value)); + } end_rangeTable_elements; + + return st; +} + +/* +** bogus! +*/ + +void +rangeTable_fixSrefs (rangeTable s) +{ + int i; + + if (rangeTable_isUndefined (s)) return; + + for (i = 0; i < s->nelements; i++) + { + sRef old = s->keys[i]; + + if (sRef_isLocalVar (old)) + { + s->keys[i] = uentry_getSref (sRef_getUentry (old)); + } + + sRefSet_fixSrefs (s->values[i]); + } +} + +void +rangeTable_free (/*@only@*/ rangeTable s) +{ + int i; + + if (rangeTable_isUndefined (s)) return; + + for (i = 0; i < s->nelements; i++) + { + sRefSet_free (s->values[i]); + } + + sfree (s->values); + sfree (s->keys); + sfree (s); +} + +void +rangeTable_checkGlobs (rangeTable t) +{ + rangeTable_elements (t, key, value) + { + sRef root = sRef_getRootBase (key); + + if (sRef_isRangeCheckedGlobal (root)) + { + sRefSet_realElements (value, sr) + { + root = sRef_getRootBase (sr); + + if (((sRef_isRangeCheckedGlobal (root) + && !(sRef_similar (root, key))) + || sRef_isAnyParam (root)) + && !sRef_isExposed (root)) + { + if (sRef_isRangeCheckedGlobal (key)) + { + if (!(sRef_isShared (key) + && sRef_isShared (root))) + { + voptgenerror + (FLG_GLOBRANGE, + message + ("Function returns with %q variable %q rangeing %q %q", + cstring_makeLiteral (sRef_isRealGlobal (key) + ? "global" : "file static"), + sRef_unparse (key), + cstring_makeLiteral (sRef_isAnyParam (root) + ? "parameter" : "global"), + sRef_unparse (sr)), + g_currentloc); + } + } + + } + } end_sRefSet_realElements; + } + else if (sRef_isAnyParam (key) || sRef_isAnyParam (root)) + { + sRefSet_realElements (value, sr) + { + root = sRef_getRootBase (sr); + + if (sRef_isRangeCheckedGlobal (root) + && !sRef_isExposed (root) + && !sRef_isDead (key) + && !sRef_isShared (root)) + { + voptgenerror + (FLG_GLOBRANGE, + message ("Function returns with parameter %q rangeing %q %q", + sRef_unparse (key), + cstring_makeLiteral (sRef_isRealGlobal (root) + ? "global" : "file static"), + sRef_unparse (sr)), + g_currentloc); + } + } end_sRefSet_realElements; + } + else + { + ; + } + } end_rangeTable_elements; +} + + + -- 2.45.2