/*
** 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
*/
# include "splintMacros.nf"
# include "basic.h"
# ifdef WIN32
/*
** Make Microsoft VC++ happy: its control checking produces too
** many spurious warnings.
*/
# pragma warning (disable:4715)
# endif
static /*@observer@*/ cstring stateAction_unparse (stateAction p_sa) /*@*/ ;
void stateInfo_free (/*@only@*/ stateInfo a)
{
if (a != NULL)
{
fileloc_free (a->loc);
sfree (a);
}
}
/*@only@*/ stateInfo stateInfo_update (/*@only@*/ stateInfo old, stateInfo newinfo)
/*
** returns an stateInfo with the same value as new. May reuse the
** storage of old. (i.e., same effect as copy, but more
** efficient.)
*/
{
if (old == NULL)
{
DPRINTF (("Update state ==> %s", stateInfo_unparse (newinfo)));
return stateInfo_copy (newinfo);
}
else if (newinfo == NULL)
{
stateInfo_free (old);
return NULL;
}
else
{
if (fileloc_equal (old->loc, newinfo->loc)
&& old->action == newinfo->action
/*@-abstractcompare@*/ && old->ref == newinfo->ref /*@=abstractcompare@*/)
{
/*
** Duplicate (change through alias most likely)
** don't add this info
*/
return old;
}
else
{
stateInfo snew = stateInfo_makeRefLoc (newinfo->ref,
newinfo->loc, newinfo->action);
llassert (snew->previous == NULL);
snew->previous = old;
DPRINTF (("Update state ==> %s", stateInfo_unparse (snew)));
return snew;
}
}
}
static /*@observer@*/ stateInfo stateInfo_sort (/*@temp@*/ stateInfo stinfo)
/* Sorts in reverse location order */
{
DPRINTF (("Sorting: %s", stateInfo_unparse (stinfo)));
if (stinfo == NULL || stinfo->previous == NULL)
{
return stinfo;
}
else
{
stateInfo snext = stateInfo_sort (stinfo->previous);
stateInfo sfirst = snext;
DPRINTF (("stinfo/sext: %s // %s", stateInfo_unparse (stinfo), stateInfo_unparse (snext)));
llassert (snext != NULL);
if (!fileloc_lessthan (stinfo->loc, snext->loc))
{
/*@i2@*/ stinfo->previous = sfirst; /* spurious? */
DPRINTF (("Sorted ==> %s", stateInfo_unparse (stinfo)));
/*@i2@*/ return stinfo; /* spurious? */
}
else
{
while (snext != NULL && fileloc_lessthan (stinfo->loc, snext->loc))
{
/*
** swap the order
*/
fileloc tloc = snext->loc;
stateAction taction = snext->action;
sRef tref = snext->ref;
DPRINTF (("in while: stinfo/sext: %s // %s", stateInfo_unparse (stinfo), stateInfo_unparse (snext)));
snext->loc = stinfo->loc;
snext->action = stinfo->action;
/*@-modobserver@*/
snext->ref = stinfo->ref; /* Doesn't actually modifie sfirst */
/*@=modobserver@*/
stinfo->loc = tloc;
stinfo->action = taction;
stinfo->ref = tref;
/*@-mustfreeonly@*/
stinfo->previous = snext->previous;
/*@=mustfreeonly@*/
snext = snext->previous;
DPRINTF (("in while: stinfo/sext: %s // %s", stateInfo_unparse (stinfo), stateInfo_unparse (snext)));
}
DPRINTF (("Sorted ==> %s", stateInfo_unparse (sfirst)));
/*@-compmempass@*/
return sfirst;
/*@=compmempass@*/
}
}
}
/*@only@*/ stateInfo
stateInfo_updateLoc (/*@only@*/ stateInfo old, stateAction action, fileloc loc)
{
if (fileloc_isUndefined (loc)) {
loc = fileloc_copy (g_currentloc);
}
if (old != NULL && fileloc_equal (old->loc, loc) && old->action == action)
{
/*
** Duplicate (change through alias most likely)
** don't add this info
*/
return old;
}
else
{
stateInfo snew = stateInfo_makeLoc (loc, action);
llassert (snew->previous == NULL);
snew->previous = old;
DPRINTF (("Update state ==> %s", stateInfo_unparse (snew)));
return snew;
}
}
/*@only@*/ stateInfo
stateInfo_updateRefLoc (/*@only@*/ stateInfo old, /*@exposed@*/ sRef ref,
stateAction action, fileloc loc)
{
if (fileloc_isUndefined (loc)) {
loc = fileloc_copy (g_currentloc);
}
if (old != NULL && fileloc_equal (old->loc, loc)
&& old->action == action
/*@-abstractcompare*/ && old->ref == ref /*@=abstractcompare@*/)
{
/*
** Duplicate (change through alias most likely)
** don't add this info
*/
return old;
}
else
{
stateInfo snew = stateInfo_makeRefLoc (ref, loc, action);
llassert (snew->previous == NULL);
snew->previous = old;
DPRINTF (("Update state ==> %s", stateInfo_unparse (snew)));
return snew;
}
}
/*@only@*/ stateInfo stateInfo_copy (stateInfo a)
{
if (a == NULL)
{
return NULL;
}
else
{
stateInfo ret = (stateInfo) dmalloc (sizeof (*ret));
ret->loc = fileloc_copy (a->loc); /*< should report bug without copy! >*/
ret->ref = a->ref;
ret->action = a->action;
ret->previous = stateInfo_copy (a->previous);
return ret;
}
}
/*@only@*/ /*@notnull@*/ stateInfo
stateInfo_currentLoc (void)
{
return stateInfo_makeLoc (g_currentloc, SA_DECLARED);
}
/*@only@*/ /*@notnull@*/ stateInfo
stateInfo_makeLoc (fileloc loc, stateAction action)
{
stateInfo ret = (stateInfo) dmalloc (sizeof (*ret));
if (fileloc_isUndefined (loc)) {
ret->loc = fileloc_copy (g_currentloc);
} else {
ret->loc = fileloc_copy (loc);
}
ret->ref = sRef_undefined;
ret->action = action;
ret->previous = stateInfo_undefined;
DPRINTF (("Make loc ==> %s", stateInfo_unparse (ret)));
return ret;
}
/*@only@*/ /*@notnull@*/ stateInfo
stateInfo_makeRefLoc (/*@exposed@*/ sRef ref, fileloc loc, stateAction action)
/*@post:isnull result->previous@*/
{
stateInfo ret = (stateInfo) dmalloc (sizeof (*ret));
if (fileloc_isUndefined (loc)) {
ret->loc = fileloc_copy (g_currentloc);
} else {
ret->loc = fileloc_copy (loc);
}
ret->ref = ref;
ret->action = action;
ret->previous = stateInfo_undefined;
return ret;
}
/*@only@*/ cstring
stateInfo_unparse (stateInfo s)
{
cstring res = cstring_makeLiteral ("");
while (stateInfo_isDefined (s)) {
res = message ("%q%q: ", res, fileloc_unparse (s->loc));
if (sRef_isValid (s->ref)) {
res = message ("%q through alias %q ", res, sRef_unparse (s->ref));
}
res = message ("%q%s; ", res, stateAction_unparse (s->action));
s = s->previous;
}
return res;
}
fileloc stateInfo_getLoc (stateInfo info)
{
if (stateInfo_isDefined (info))
{
return info->loc;
}
return fileloc_undefined;
}
stateAction stateAction_fromNState (nstate ns)
{
switch (ns)
{
case NS_ERROR:
case NS_UNKNOWN:
return SA_UNKNOWN;
case NS_NOTNULL:
case NS_MNOTNULL:
return SA_BECOMESNONNULL;
case NS_RELNULL:
case NS_CONSTNULL:
return SA_DECLARED;
case NS_POSNULL:
return SA_BECOMESPOSSIBLYNULL;
case NS_DEFNULL:
return SA_BECOMESNULL;
case NS_ABSNULL:
return SA_BECOMESPOSSIBLYNULL;
}
}
stateAction stateAction_fromExkind (exkind ex)
{
switch (ex)
{
case XO_UNKNOWN:
case XO_NORMAL:
return SA_UNKNOWN;
case XO_EXPOSED:
return SA_EXPOSED;
case XO_OBSERVER:
return SA_OBSERVER;
}
BADBRANCH;
/*@notreached@*/ return SA_UNKNOWN;
}
stateAction stateAction_fromAlkind (alkind ak)
{
switch (ak)
{
case AK_UNKNOWN:
case AK_ERROR:
return SA_UNKNOWN;
case AK_ONLY:
return SA_ONLY;
case AK_IMPONLY:
return SA_IMPONLY;
case AK_KEEP:
return SA_KEEP;
case AK_KEPT:
return SA_KEPT;
case AK_TEMP:
return SA_TEMP;
case AK_IMPTEMP:
return SA_IMPTEMP;
case AK_SHARED:
return SA_SHARED;
case AK_UNIQUE:
case AK_RETURNED:
return SA_DECLARED;
case AK_FRESH:
return SA_FRESH;
case AK_STACK:
return SA_XSTACK;
case AK_REFCOUNTED:
return SA_REFCOUNTED;
case AK_REFS:
return SA_REFS;
case AK_KILLREF:
return SA_KILLREF;
case AK_NEWREF:
return SA_NEWREF;
case AK_OWNED:
return SA_OWNED;
case AK_DEPENDENT:
return SA_DEPENDENT;
case AK_IMPDEPENDENT:
return SA_IMPDEPENDENT;
case AK_STATIC:
return SA_STATIC;
case AK_LOCAL:
return SA_LOCAL;
}
BADBRANCH;
/*@notreached@*/ return SA_UNKNOWN;
}
stateAction stateAction_fromSState (sstate ss)
{
switch (ss)
{
case SS_UNKNOWN: return SA_DECLARED;
case SS_UNUSEABLE: return SA_KILLED;
case SS_UNDEFINED: return SA_UNDEFINED;
case SS_MUNDEFINED: return SA_MUNDEFINED;
case SS_ALLOCATED: return SA_ALLOCATED;
case SS_PDEFINED: return SA_PDEFINED;
case SS_DEFINED: return SA_DEFINED;
case SS_PARTIAL: return SA_PDEFINED;
case SS_DEAD: return SA_RELEASED;
case SS_HOFFA: return SA_PKILLED;
case SS_SPECIAL: return SA_DECLARED;
case SS_RELDEF: return SA_DECLARED;
case SS_FIXED:
case SS_UNDEFGLOB:
case SS_KILLED:
case SS_UNDEFKILLED:
case SS_LAST:
llbug (message ("Unexpected sstate: %s", sstate_unparse (ss)));
/*@notreached@*/ return SA_UNKNOWN;
}
}
static /*@observer@*/ cstring stateAction_unparse (stateAction sa)
{
switch (sa)
{
case SA_UNKNOWN: return cstring_makeLiteralTemp ("changed <unknown modification>");
case SA_CHANGED: return cstring_makeLiteralTemp ("changed");
case SA_CREATED: return cstring_makeLiteralTemp ("created");
case SA_DECLARED: return cstring_makeLiteralTemp ("declared");
case SA_DEFINED: return cstring_makeLiteralTemp ("defined");
case SA_PDEFINED: return cstring_makeLiteralTemp ("partially defined");
case SA_RELEASED: return cstring_makeLiteralTemp ("released");
case SA_ALLOCATED: return cstring_makeLiteralTemp ("allocated");
case SA_KILLED: return cstring_makeLiteralTemp ("released");
case SA_PKILLED: return cstring_makeLiteralTemp ("possibly released");
case SA_MERGED: return cstring_makeLiteralTemp ("merged");
case SA_UNDEFINED: return cstring_makeLiteralTemp ("becomes undefined");
case SA_MUNDEFINED: return cstring_makeLiteralTemp ("possibly undefined");
case SA_SHARED: return cstring_makeLiteralTemp ("becomes shared");
case SA_ONLY: return cstring_makeLiteralTemp ("becomes only");
case SA_IMPONLY: return cstring_makeLiteralTemp ("becomes implicitly only");
case SA_OWNED: return cstring_makeLiteralTemp ("becomes owned");
case SA_DEPENDENT: return cstring_makeLiteralTemp ("becomes dependent");
case SA_IMPDEPENDENT: return cstring_makeLiteralTemp ("becomes implicitly dependent");
case SA_KEPT: return cstring_makeLiteralTemp ("becomes kept");
case SA_KEEP: return cstring_makeLiteralTemp ("becomes keep");
case SA_FRESH: return cstring_makeLiteralTemp ("becomes fresh");
case SA_TEMP: return cstring_makeLiteralTemp ("becomes temp");
case SA_IMPTEMP: return cstring_makeLiteralTemp ("becomes implicitly temp");
case SA_XSTACK: return cstring_makeLiteralTemp ("becomes stack-allocated storage");
case SA_STATIC: return cstring_makeLiteralTemp ("becomes static");
case SA_LOCAL: return cstring_makeLiteralTemp ("becomes local");
case SA_REFCOUNTED: return cstring_makeLiteralTemp ("becomes refcounted");
case SA_REFS: return cstring_makeLiteralTemp ("becomes refs");
case SA_NEWREF: return cstring_makeLiteralTemp ("becomes newref");
case SA_KILLREF: return cstring_makeLiteralTemp ("becomes killref");
case SA_OBSERVER: return cstring_makeLiteralTemp ("becomes observer");
case SA_EXPOSED: return cstring_makeLiteralTemp ("becomes exposed");
case SA_BECOMESNULL: return cstring_makeLiteralTemp ("becomes null");
case SA_BECOMESNONNULL: return cstring_makeLiteralTemp ("becomes non-null");
case SA_BECOMESPOSSIBLYNULL: return cstring_makeLiteralTemp ("becomes possibly null");
}
DPRINTF (("Bad state action: %d", sa));
BADBRANCH;
}
void stateInfo_display (stateInfo s, cstring sname)
{
bool showdeep = context_flagOn (FLG_SHOWDEEPHISTORY, g_currentloc);
s = stateInfo_sort (s);
while (stateInfo_isDefined (s))
{
cstring msg = message ("%s%s", sname, stateAction_unparse (s->action));
if (sRef_isValid (s->ref)) {
msg = message ("%q (through alias %q)", msg, sRef_unparse (s->ref));
}
llgenindentmsg (msg, s->loc);
if (!showdeep) {
break;
}
s = s->previous;
}
cstring_free (sname);
}
syntax highlighted by Code2HTML, v. 0.9.1