How to access SVal of SubExpr with LocationContext

Hi,

I was wondering if there is a way to get SVal of a SubExpr with
the LocationContext at a function call.

Here is what I mean:

A function fun is declared and called like this:

Type arg; //1.
fun(Type* par){…} //2.
fun(&arg); //3.

If I wanted to detect if arg was uninitialized when the function fun is called (line 3.), I would use:

const CallEvent Call;
CheckerContext C;
Expr* argExp = Call.getArgExpr(0);
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
SVal LV = state->getSVal(argExp, LCtx);
bool FirstArgIsUndef = LV.isUndef();

FirstArgIsUndef will be false, because the address of arg does exist.

But now I want to detect if that which arg/par is pointing at is uninitialized, how would I do that?.

I started experimenting with this in CallAndMessageChecker::checkPreCall:

const Expr* argExp = Call.getArgExpr(i);
const Expr* argExpPure = argExp->IgnoreImpCasts();

if(const UnaryOperator* unOp = dyn_cast(argExpPure))
{
UnaryOperator::Opcode opc = unOp->getOpcode();
if(opc == UO_AddrOf)// ‘&’ operator
{
Expr* referencedInputArg = unOp->getSubExpr(); // in a dump() I see that this is really the argument arg (not par)
SVal refVal = state->getSVal(referencedInputArg, LCtx);
bool unknownRefVal = refVal.isUnknown();
bool validRefVal = refVal.isValid();
bool undefRefVal = refVal.isUndef();
}
}

it turns out that it will set refVal to isUnknown() instead of isUndef(). The context LCtx seems to forget that the SubExpr (that is here
arg) is uninitialized. I put this code in the CallAndMessageChecker::checkPreCall, perhaps this is the wrong place? or do I need to use the LCtx in another way so that it remembers the SVal of SubExpr too?.

/Per


Per Viberg Senior Engineer
Evidente ES East AB Warfvinges väg 34 SE-112 51 Stockholm Sweden

Phone: +46 (0)8 402 79 00
Mobile: +46 (0)70 912 42 52
E-mail: Per.Viberg@evidente.se

www.evidente.se

This e-mail, which might contain confidential information, is addressed to the above stated person/company. If you are not the correct addressee, employee or in any other way the person concerned, please notify the sender immediately. At the same time, please delete this e-mail and destroy any prints. Thank You.

Hi, Per. Yeah, what you’re trying to do isn’t directly supported. The structure that maps from statements (Stmt*) to values (SVal) is called the Environment, and it very deliberately only holds values necessary to compute the next expression. For example, in the expression “(x + y) + z”, the value for the subexpression “x + y” is live when trying to evaluate the whole thing, as is “z”, but “x” and “y” have already been consumed and so have been taken out of the map to save memory.

What you should actually do here is load the value stored in ‘par’. That will look something like this:

SVal ArgVal = Call.getArgSVal(0); // “par”
const MemRegion *MR = ArgVal.getAsRegion();
if (!MR)
return;
SVal DerefVal = State->getSVal(MR); // “*par”

And now you can check if DerefVal is uninitialized. (Another advantage of this code is that it’s also correct for a reference argument.)

By the way, this is a good idea for a check. Thanks for working on it!
Jordan

Hi Jordan,

thanks for the quick reply!, it helped a lot.

while on the topic,

this:

const MemRegion *MR = ArgVal.getAsRegion();

is basically casting the SVal ArgVal as a MemRegion (which I assume is something like a pointer in C), so you can access the symbol that it points to (using getSVal) ?.

Am I roughly correct?

cheers!
/Per


Per Viberg Senior Engineer
Evidente ES East AB Warfvinges väg 34 SE-112 51 Stockholm Sweden

Phone: +46 (0)8 402 79 00
Mobile: +46 (0)70 912 42 52
E-mail: Per.Viberg@evidente.se

www.evidente.se

This e-mail, which might contain confidential information, is addressed to the above stated person/company. If you are not the correct addressee, employee or in any other way the person concerned, please notify the sender immediately. At the same time, please delete this e-mail and destroy any prints. Thank You.

You’ve got the idea correct. Here’s how I would explain it:

An SVal represents any sort of value, something that can be “the value of an expression” or “the value currently stored in a variable”. A MemRegion represents, well, a region of memory. So a loc::MemRegionVal is a value that represents (the address of) a region in memory, and when you use getAsRegion(), you’re saying “I want to see if this value refers to a region of memory, and if so, which region.”

(I’ve tried to avoid saying “the value of a region”, since then it’s unclear whether you mean its address or its contents.)

A lot more of this is described (verbosely) in the “Representing Values” section of the Checker Developer Manual on the analyzer site, and in the first half of the “Building a Checker in 24 Hours” talk linked at the top of the same page.

Hope that helps clear things up!
Jordan