Skip to content

[clang][analyzer][NFC] Add a helper for conjuring symbols at call events #137182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ class Stmt;

namespace ento {

class CallEvent;
class ConditionTruthVal;
class ProgramStateManager;
class StoreRef;

class SValBuilder {
virtual void anchor();

Expand Down Expand Up @@ -209,6 +209,12 @@ class SValBuilder {
const LocationContext *LCtx,
QualType type,
unsigned visitCount);
DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call, QualType type,
unsigned visitCount,
const void *symbolTag = nullptr);
DefinedOrUnknownSVal conjureSymbolVal(const CallEvent &call,
unsigned visitCount,
const void *symbolTag = nullptr);

/// Conjure a symbol representing heap allocated memory region.
///
Expand Down
32 changes: 11 additions & 21 deletions clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,8 +1514,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// If we don't know how much we copied, we can at least
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
lastElement = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());

// The byte after the last byte copied is the return value.
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
Expand Down Expand Up @@ -1665,8 +1664,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
SVal CmpV = Builder.conjureSymbolVal(Call, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
Expand Down Expand Up @@ -1769,8 +1767,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// no guarantee the full string length will actually be returned.
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();

if (strLengthNL) {
Expand All @@ -1793,8 +1790,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
result = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
}
}

Expand Down Expand Up @@ -2261,8 +2257,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (ReturnEnd && Result.isUnknown()) {
Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
Result = svalBuilder.conjureSymbolVal(Call, C.blockCount());
}
}
// Set the return value.
Expand Down Expand Up @@ -2361,8 +2356,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
const StringLiteral *RightStrLiteral =
getCStringLiteral(C, state, Right.Expression, RightVal);
bool canComputeResult = false;
SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
LCtx, C.blockCount());
SVal resultVal = svalBuilder.conjureSymbolVal(Call, C.blockCount());

if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
Expand Down Expand Up @@ -2467,16 +2461,13 @@ void CStringChecker::evalStrsep(CheckerContext &C,

// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
State =
State->bindLoc(*SearchStrLoc,
SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(),
LCtx, CharPtrTy, C.blockCount()),
LCtx);
State = State->bindLoc(*SearchStrLoc,
SVB.conjureSymbolVal(Call, C.blockCount(), getTag()),
LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
Result = SVB.conjureSymbolVal(Call, C.blockCount());
}

// Set the return value, and finish.
Expand Down Expand Up @@ -2519,8 +2510,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,

SValBuilder &SVB = C.getSValBuilder();

SVal ResultVal =
SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
SVal ResultVal = SVB.conjureSymbolVal(Call, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);

C.addTransition(State);
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ void ErrnoTesterChecker::evalSetErrnoIfErrorRange(CheckerContext &C,

ProgramStateRef StateFailure = State->BindExpr(
Call.getOriginExpr(), C.getLocationContext(), SVB.makeIntVal(1, true));
DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(
nullptr, Call.getOriginExpr(), C.getLocationContext(), C.blockCount());
DefinedOrUnknownSVal ErrnoVal = SVB.conjureSymbolVal(Call, C.blockCount());
StateFailure = StateFailure->assume(ErrnoVal, true);
assert(StateFailure && "Failed to assume on an initial value.");
StateFailure =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -931,8 +931,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
if (RetVal.isUnknown() ||
(hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
SValBuilder &SVB = C.getSValBuilder();
RetVal =
SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
RetVal = SVB.conjureSymbolVal(Call, C.blockCount());
}

// Bind the value.
Expand Down
3 changes: 1 addition & 2 deletions clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -851,9 +851,8 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
if (InnerPointerType.isNull())
return;

const LocationContext *LC = C.getLocationContext();
InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
CallExpr, LC, InnerPointerType, C.blockCount());
Call, InnerPointerType, C.blockCount());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example, this inner pointer type is sometimes different from the call result type.

State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
}

Expand Down
11 changes: 4 additions & 7 deletions clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -584,11 +584,9 @@ class StdLibraryFunctionsChecker
const Summary &Summary,
CheckerContext &C) const override {
SValBuilder &SVB = C.getSValBuilder();
NonLoc ErrnoSVal =
SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
NonLoc ErrnoSVal = SVB.conjureSymbolVal(Call, C.getASTContext().IntTy,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This int type is different from the call result type at times too.

C.blockCount(), &Tag)
.castAs<NonLoc>();
return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
}
};
Expand Down Expand Up @@ -1481,8 +1479,7 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
ProgramStateRef State = C.getState();
const LocationContext *LC = C.getLocationContext();
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
SVal V = C.getSValBuilder().conjureSymbolVal(
CE, LC, CE->getType().getCanonicalType(), C.blockCount());
SVal V = C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
State = State->BindExpr(CE, LC, V);

C.addTransition(State);
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,8 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
const auto *CE = cast<CallExpr>(Call.getOriginExpr());

// Function call will return a pointer to the new symbolic region.
DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
CE, LCtx, CE->getType(), C.blockCount());
DefinedOrUnknownSVal RetVal =
C.getSValBuilder().conjureSymbolVal(Call, C.blockCount());
State = State->BindExpr(CE, LCtx, RetVal);

const auto *SymRegOfRetVal =
Expand Down
25 changes: 15 additions & 10 deletions clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/BasicValueFactory.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
Expand Down Expand Up @@ -192,18 +193,22 @@ DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt,
const LocationContext *LCtx,
QualType type,
unsigned visitCount) {
if (type->isNullPtrType())
return makeZeroVal(type);

if (!SymbolManager::canSymbolicate(type))
return UnknownVal();

SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount);
return conjureSymbolVal(/*symbolTag=*/nullptr, stmt, LCtx, type, visitCount);
}

if (Loc::isLocType(type))
return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym));
DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const CallEvent &call,
unsigned visitCount,
const void *symbolTag) {
return conjureSymbolVal(symbolTag, call.getOriginExpr(),
call.getLocationContext(), visitCount);
}

return nonloc::SymbolVal(sym);
DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const CallEvent &call,
QualType type,
unsigned visitCount,
const void *symbolTag) {
return conjureSymbolVal(symbolTag, call.getOriginExpr(),
call.getLocationContext(), type, visitCount);
}

DefinedSVal SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
Expand Down
Loading