/* ** Splint - annotation-assisted static program checker ** Copyright (C) 1994-2003 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 splint: info@splint.org ** To report a bug: splint-bug@splint.org ** For more information: http://www.splint.org */ /* ** varKinds.c */ # include "splintMacros.nf" # include "basic.h" alkind alkind_fromInt (int n) { /*@+enumint@*/ if (n < AK_UNKNOWN || n > AK_LOCAL) { llbug (message ("Alias kind out of range: %d", n)); } /*@=enumint@*/ return ((alkind)n); } nstate nstate_fromInt (int n) { /*@+enumint@*/ llassertprint (n >= NS_ERROR && n <= NS_ABSNULL, ("Bad null state: %d", n)); /*@=enumint@*/ return ((nstate)n); } sstate sstate_fromInt (int n) { /*@+enumint@*/ llassert (n >= SS_UNKNOWN && n < SS_LAST); /*@=enumint@*/ return ((sstate)n); } exkind exkind_fromInt (int n) { /*@+enumint@*/ llassert (n >= XO_UNKNOWN && n <= XO_OBSERVER); /*@=enumint@*/ return ((exkind) n); } cstring sstate_unparse (sstate s) { switch (s) { case SS_UNKNOWN: return cstring_makeLiteralTemp ("unknown"); case SS_UNUSEABLE: return cstring_makeLiteralTemp ("unuseable"); case SS_UNDEFINED: return cstring_makeLiteralTemp ("undefined"); case SS_MUNDEFINED:return cstring_makeLiteralTemp ("possibly undefined"); case SS_ALLOCATED: return cstring_makeLiteralTemp ("allocated"); case SS_PDEFINED: return cstring_makeLiteralTemp ("partially defined"); case SS_DEFINED: return cstring_makeLiteralTemp ("defined"); case SS_PARTIAL: return cstring_makeLiteralTemp ("partial"); case SS_SPECIAL: return cstring_makeLiteralTemp ("special"); case SS_DEAD: return cstring_makeLiteralTemp ("dead"); case SS_HOFFA: return cstring_makeLiteralTemp ("probably dead"); case SS_FIXED: return cstring_makeLiteralTemp ("unmodifiable"); case SS_RELDEF: return cstring_makeLiteralTemp ("reldef"); case SS_LAST: llcontbuglit ("sstate_unparse: last"); return cstring_makeLiteralTemp (""); case SS_UNDEFGLOB: return cstring_makeLiteralTemp ("undefglob"); case SS_KILLED: return cstring_makeLiteralTemp ("killed"); case SS_UNDEFKILLED: return cstring_makeLiteralTemp ("undefkilled"); } BADEXIT; } bool nstate_possiblyNull (nstate n) { /* ** note: not NS_UNKNOWN or NS_ERROR */ return ((n >= NS_CONSTNULL) && (n <= NS_ABSNULL)); } bool nstate_perhapsNull (nstate n) { /* ** note: not NS_UNKNOWN or NS_ERROR */ return ((n >= NS_RELNULL) && (n <= NS_ABSNULL)); } cstring nstate_unparse (nstate n) { switch (n) { case NS_ERROR: return cstring_makeLiteralTemp (""); case NS_UNKNOWN: return cstring_makeLiteralTemp ("implicitly non-null"); case NS_POSNULL: return cstring_makeLiteralTemp ("null"); case NS_DEFNULL: return cstring_makeLiteralTemp ("null"); case NS_NOTNULL: return cstring_makeLiteralTemp ("notnull"); case NS_MNOTNULL: return cstring_makeLiteralTemp ("notnull"); case NS_ABSNULL: return cstring_makeLiteralTemp ("null"); case NS_RELNULL: return cstring_makeLiteralTemp ("relnull"); case NS_CONSTNULL: return cstring_makeLiteralTemp ("null"); } /*@notreached@*/ llcontbuglit ("bad null state!"); /*@notreached@*/ return cstring_makeLiteralTemp ("!!! bad null state !!!"); BADEXIT; } /* ** ??? (used to do something different for guarded) */ int nstate_compare (nstate n1, nstate n2) { return (generic_compare (n1, n2)); } /* ** This occurs when we select a field with alkind inner, ** from a structure with alkind outer. It is probably ** unnecessary. */ alkind alkind_derive (alkind outer, alkind inner) { switch (outer) { case AK_ERROR: case AK_UNKNOWN: return inner; case AK_KEPT: case AK_KEEP: case AK_ONLY: case AK_IMPONLY: case AK_OWNED: case AK_IMPDEPENDENT: case AK_DEPENDENT: if (inner == AK_SHARED) return AK_SHARED; else if (outer == AK_DEPENDENT) return AK_IMPDEPENDENT; else if (outer == AK_ONLY) return AK_IMPONLY; else return outer; /* not so sure about these? */ case AK_REFCOUNTED: case AK_NEWREF: case AK_KILLREF: case AK_REFS: case AK_STACK: case AK_STATIC: return outer; case AK_TEMP: case AK_IMPTEMP: case AK_SHARED: case AK_UNIQUE: case AK_LOCAL: case AK_FRESH: case AK_RETURNED: if (alkind_isKnown (inner)) return inner; else return outer; } BADEXIT; } cstring alkind_unparse (alkind a) { switch (a) { case AK_ERROR: return cstring_makeLiteralTemp (""); case AK_UNKNOWN: return cstring_makeLiteralTemp ("unqualified"); case AK_ONLY: return cstring_makeLiteralTemp ("only"); case AK_IMPONLY: return cstring_makeLiteralTemp ("implicitly only"); case AK_OWNED: return cstring_makeLiteralTemp ("owned"); case AK_IMPDEPENDENT: return cstring_makeLiteralTemp ("implicitly dependent"); case AK_DEPENDENT: return cstring_makeLiteralTemp ("dependent"); case AK_KEEP: return cstring_makeLiteralTemp ("keep"); case AK_KEPT: return cstring_makeLiteralTemp ("kept"); case AK_IMPTEMP: return cstring_makeLiteralTemp ("implicitly temp"); case AK_TEMP: return cstring_makeLiteralTemp ("temp"); case AK_SHARED: return cstring_makeLiteralTemp ("shared"); case AK_UNIQUE: return cstring_makeLiteralTemp ("unique"); case AK_RETURNED: return cstring_makeLiteralTemp ("returned"); case AK_FRESH: return cstring_makeLiteralTemp ("fresh"); case AK_STACK: return cstring_makeLiteralTemp ("stack"); case AK_REFCOUNTED: return cstring_makeLiteralTemp ("refcounted"); case AK_REFS: return cstring_makeLiteralTemp ("refs"); case AK_KILLREF: return cstring_makeLiteralTemp ("killref"); case AK_NEWREF: return cstring_makeLiteralTemp ("newref"); case AK_LOCAL: return cstring_makeLiteralTemp ("local"); case AK_STATIC: return cstring_makeLiteralTemp ("unqualified static"); } BADEXIT; } cstring exkind_unparse (exkind a) { switch (a) { case XO_UNKNOWN: return cstring_makeLiteralTemp ("unknown"); case XO_NORMAL: return cstring_makeLiteralTemp ("unexposed"); case XO_EXPOSED: return cstring_makeLiteralTemp ("exposed"); case XO_OBSERVER: return cstring_makeLiteralTemp ("observer"); } BADEXIT; } cstring exkind_capName (exkind a) { switch (a) { case XO_UNKNOWN: return cstring_makeLiteralTemp ("Unknown"); case XO_NORMAL: return cstring_makeLiteralTemp ("Unexposed"); case XO_EXPOSED: return cstring_makeLiteralTemp ("Exposed"); case XO_OBSERVER: return cstring_makeLiteralTemp ("Observer"); } BADEXIT; } cstring exkind_unparseError (exkind a) { switch (a) { case XO_UNKNOWN: return cstring_makeLiteralTemp ("unqualified"); case XO_NORMAL: return cstring_makeLiteralTemp ("unqualifier"); case XO_EXPOSED: return cstring_makeLiteralTemp ("exposed"); case XO_OBSERVER: return cstring_makeLiteralTemp ("observer"); } BADEXIT; } cstring alkind_capName (alkind a) { switch (a) { case AK_ERROR: return cstring_makeLiteralTemp (""); case AK_UNKNOWN: return cstring_makeLiteralTemp ("Unqualified"); case AK_ONLY: return cstring_makeLiteralTemp ("Only"); case AK_IMPONLY: return cstring_makeLiteralTemp ("Implicitly only"); case AK_OWNED: return cstring_makeLiteralTemp ("Owned"); case AK_IMPDEPENDENT: return cstring_makeLiteralTemp ("Implicitly dependent"); case AK_DEPENDENT: return cstring_makeLiteralTemp ("Dependent"); case AK_KEEP: return cstring_makeLiteralTemp ("Keep"); case AK_KEPT: return cstring_makeLiteralTemp ("Kept"); case AK_IMPTEMP: return cstring_makeLiteralTemp ("Implicitly temp"); case AK_TEMP: return cstring_makeLiteralTemp ("Temp"); case AK_SHARED: return cstring_makeLiteralTemp ("Shared"); case AK_UNIQUE: return cstring_makeLiteralTemp ("Unique"); case AK_RETURNED: return cstring_makeLiteralTemp ("Returned"); case AK_FRESH: return cstring_makeLiteralTemp ("Fresh"); case AK_STACK: return cstring_makeLiteralTemp ("Stack"); case AK_REFCOUNTED: return cstring_makeLiteralTemp ("Refcounted"); case AK_REFS: return cstring_makeLiteralTemp ("Refs"); case AK_KILLREF: return cstring_makeLiteralTemp ("Killref"); case AK_NEWREF: return cstring_makeLiteralTemp ("Newref"); case AK_LOCAL: return cstring_makeLiteralTemp ("Local"); case AK_STATIC: return cstring_makeLiteralTemp ("Unqualified static"); } BADEXIT; } exkind exkind_fromQual (qual q) { if (qual_isExposed (q)) { return XO_EXPOSED; } else if (qual_isObserver (q)) { return XO_OBSERVER; } else { llcontbug (message ("exkind_fromQual: not exp qualifier: %s" , qual_unparse (q))); return XO_UNKNOWN; } } sstate sstate_fromQual (qual q) { if (qual_isOut (q)) return SS_ALLOCATED; if (qual_isIn (q)) return SS_DEFINED; else if (qual_isPartial (q)) return SS_PARTIAL; else if (qual_isRelDef (q)) return SS_RELDEF; else if (qual_isUndef (q)) return SS_UNDEFGLOB; else if (qual_isKilled (q)) return SS_KILLED; else if (qual_isSpecial (q)) return SS_SPECIAL; else { llcontbug (message ("sstate_fromQual: not alias qualifier: %s", qual_unparse (q))); return SS_UNKNOWN; } } exitkind exitkind_fromQual (qual q) { if (qual_isExits (q)) return XK_MUSTEXIT; if (qual_isMayExit (q)) return XK_MAYEXIT; if (qual_isTrueExit (q)) return XK_TRUEEXIT; if (qual_isFalseExit (q)) return XK_FALSEEXIT; if (qual_isNeverExit (q)) return XK_NEVERESCAPE; else { llcontbug (message ("exitkind_fromQual: not exit qualifier: %s", qual_unparse (q))); return XK_UNKNOWN; } } alkind alkind_fromQual (qual q) { if (qual_isOnly (q)) return AK_ONLY; if (qual_isImpOnly (q)) return AK_IMPONLY; if (qual_isKeep (q)) return AK_KEEP; if (qual_isKept (q)) return AK_KEPT; if (qual_isTemp (q)) return AK_TEMP; if (qual_isShared (q)) return AK_SHARED; if (qual_isUnique (q)) return AK_UNIQUE; if (qual_isRefCounted (q)) return AK_REFCOUNTED; if (qual_isRefs (q)) return AK_REFS; if (qual_isNewRef (q)) return AK_NEWREF; if (qual_isKillRef (q)) return AK_KILLREF; if (qual_isTempRef (q)) return AK_KILLREF; /* kludge? use kill ref for this */ if (qual_isOwned (q)) return AK_OWNED; if (qual_isDependent (q)) return AK_DEPENDENT; llcontbug (message ("alkind_fromQual: not alias qualifier: %s", qual_unparse (q))); return AK_ERROR; } static bool alkind_isMeaningless (alkind a1) { return (a1 == AK_ERROR || a1 == AK_UNKNOWN || a1 == AK_RETURNED || a1 == AK_STACK || a1 == AK_REFCOUNTED || a1 == AK_REFS || a1 == AK_KILLREF || a1 == AK_NEWREF || a1 == AK_LOCAL); } bool alkind_compatible (alkind a1, alkind a2) { if (a1 == a2) return TRUE; if (a2 == AK_ERROR) return TRUE; if (a2 == AK_UNKNOWN) { return (alkind_isMeaningless (a1) || (a1 == AK_IMPTEMP)); } switch (a1) { case AK_ERROR: return TRUE; case AK_UNKNOWN: return (alkind_isMeaningless (a2) || (a2 == AK_IMPTEMP)); case AK_IMPONLY: return (a2 == AK_KEEP || a2 == AK_FRESH || a2 == AK_ONLY); case AK_ONLY: return (a2 == AK_KEEP || a2 == AK_FRESH || a2 == AK_IMPONLY); case AK_OWNED: return FALSE; case AK_IMPDEPENDENT: return (a2 == AK_DEPENDENT); case AK_DEPENDENT: return (a2 == AK_IMPDEPENDENT); case AK_KEEP: return (a2 == AK_ONLY || a2 == AK_FRESH || a2 == AK_IMPONLY); case AK_KEPT: return FALSE; case AK_IMPTEMP: return (a2 == AK_TEMP); case AK_TEMP: return (a2 == AK_IMPTEMP); case AK_SHARED: return FALSE; case AK_UNIQUE: return (a2 == AK_TEMP); case AK_RETURNED: return (alkind_isMeaningless (a2)); case AK_FRESH: return (alkind_isOnly (a2)); case AK_STACK: return (alkind_isMeaningless (a2)); case AK_REFCOUNTED: return (alkind_isMeaningless (a2)); case AK_REFS: return (alkind_isMeaningless (a2)); case AK_KILLREF: return (alkind_isMeaningless (a2)); case AK_NEWREF: return (alkind_isMeaningless (a2)); case AK_LOCAL: return (alkind_isMeaningless (a2)); case AK_STATIC: return (alkind_isMeaningless (a2)); } BADEXIT; } bool alkind_equal (alkind a1, alkind a2) { if (a1 == a2) return TRUE; if (a2 == AK_ERROR) return TRUE; switch (a1) { case AK_ERROR: return TRUE; case AK_IMPONLY: return (a2 == AK_ONLY); case AK_ONLY: return (a2 == AK_IMPONLY); case AK_IMPDEPENDENT: return (a2 == AK_DEPENDENT); case AK_DEPENDENT: return (a2 == AK_IMPDEPENDENT); case AK_IMPTEMP: return (a2 == AK_TEMP); case AK_TEMP: return (a2 == AK_IMPTEMP); default: return FALSE; } BADEXIT; } alkind alkind_fixImplicit (alkind a) { if (a == AK_IMPTEMP) return AK_TEMP; if (a == AK_IMPONLY) return AK_IMPONLY; if (a == AK_IMPDEPENDENT) return AK_DEPENDENT; return a; } cstring exitkind_unparse (exitkind k) { switch (k) { case XK_ERROR: return (cstring_makeLiteralTemp ("")); case XK_UNKNOWN: return (cstring_makeLiteralTemp ("?")); case XK_NEVERESCAPE: return (cstring_makeLiteralTemp ("never escape")); case XK_MAYEXIT: return (cstring_makeLiteralTemp ("mayexit")); case XK_MUSTEXIT: return (cstring_makeLiteralTemp ("exits")); case XK_TRUEEXIT: return (cstring_makeLiteralTemp ("trueexit")); case XK_FALSEEXIT: return (cstring_makeLiteralTemp ("falseexit")); case XK_MUSTRETURN: return (cstring_makeLiteralTemp ("mustreturn")); case XK_MAYRETURN: return (cstring_makeLiteralTemp ("mayreturn")); case XK_MUSTRETURNEXIT: return (cstring_makeLiteralTemp ("mustreturnexit")); case XK_MAYRETURNEXIT: return (cstring_makeLiteralTemp ("mayreturnexit")); case XK_GOTO: return (cstring_makeLiteralTemp ("goto")); case XK_MAYGOTO: return (cstring_makeLiteralTemp ("maygoto")); } BADEXIT; } exitkind exitkind_makeConditional (exitkind k) { switch (k) { case XK_TRUEEXIT: case XK_FALSEEXIT: case XK_MUSTEXIT: return XK_MAYEXIT; case XK_MUSTRETURN: return XK_MAYRETURN; case XK_MUSTRETURNEXIT: return XK_MAYRETURNEXIT; case XK_GOTO: return XK_MAYGOTO; default: return k; } } exitkind exitkind_combine (exitkind k1, exitkind k2) { if (k1 == k2) { return k1; } if (k2 == XK_ERROR) { return XK_ERROR; } switch (k1) { case XK_ERROR: return XK_ERROR; case XK_UNKNOWN: case XK_NEVERESCAPE: return (exitkind_makeConditional (k2)); case XK_MUSTEXIT: switch (k2) { case XK_MUSTRETURNEXIT: case XK_MUSTRETURN: return XK_MUSTRETURNEXIT; case XK_MAYRETURNEXIT: case XK_MAYRETURN: return XK_MAYRETURNEXIT; default: return XK_MAYEXIT; } BADEXIT; case XK_MAYEXIT: case XK_TRUEEXIT: case XK_FALSEEXIT: switch (k2) { case XK_MUSTRETURNEXIT: case XK_MAYRETURNEXIT: case XK_MAYRETURN: case XK_MUSTRETURN: return XK_MAYRETURNEXIT; default: return XK_MAYEXIT; } BADEXIT; case XK_MUSTRETURN: switch (k2) { case XK_MUSTRETURNEXIT: case XK_MUSTEXIT: return XK_MUSTRETURNEXIT; case XK_MAYRETURNEXIT: case XK_TRUEEXIT: case XK_FALSEEXIT: case XK_MAYEXIT: return XK_MAYRETURNEXIT; default: return XK_MAYRETURN; } BADEXIT; case XK_MAYRETURN: if (exitkind_couldExit (k2)) { return XK_MAYRETURNEXIT; } else { return XK_MAYRETURN; } case XK_MUSTRETURNEXIT: switch (k2) { case XK_MUSTRETURN: case XK_MUSTEXIT: return XK_MUSTRETURNEXIT; default: return XK_MAYRETURNEXIT; } BADEXIT; case XK_MAYRETURNEXIT: return XK_MAYRETURNEXIT; case XK_GOTO: case XK_MAYGOTO: if (exitkind_couldExit (k2)) { return XK_MAYRETURNEXIT; } return XK_MAYGOTO; } BADEXIT; } bool exitkind_couldExit (exitkind e) { switch (e) { case XK_MAYEXIT: case XK_MUSTEXIT: case XK_TRUEEXIT: case XK_FALSEEXIT: case XK_MAYRETURNEXIT: case XK_MUSTRETURNEXIT: case XK_GOTO: case XK_MAYGOTO: return TRUE; default: return FALSE; } } static bool exitkind_couldReturn (exitkind e) /*@*/ { switch (e) { case XK_MUSTRETURN: case XK_MAYRETURN: case XK_MAYRETURNEXIT: case XK_MUSTRETURNEXIT: return TRUE; default: return FALSE; } } static bool exitkind_couldGoto (exitkind e) /*@*/ { return (e == XK_GOTO || e == XK_MAYGOTO); } bool exitkind_couldEscape (exitkind e) { return exitkind_couldReturn (e) || exitkind_couldExit (e) || exitkind_couldGoto (e); } exitkind exitkind_fromInt (int x) { /*@+enumint@*/ llassert (x >= XK_ERROR && x <= XK_LAST); /*@=enumint@*/ return (exitkind) x; }