aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
authorFangyi Zhou <me@fangyi.io>2025-04-25 09:39:45 +0100
committerGitHub <noreply@github.com>2025-04-25 10:39:45 +0200
commitec936b3186e3512a9297c5a12b58d627ef1a1b32 (patch)
tree0c59bbf6f6df0ef42a7407408c51c40f8fc6f1c5 /clang/lib/StaticAnalyzer/Checkers
parentc4d44ecb98896d1b0919ce064eefa8cae286f55d (diff)
downloadllvm-ec936b3186e3512a9297c5a12b58d627ef1a1b32.zip
llvm-ec936b3186e3512a9297c5a12b58d627ef1a1b32.tar.gz
llvm-ec936b3186e3512a9297c5a12b58d627ef1a1b32.tar.bz2
[Clang][analyzer] Replace Stmt* with ConstCFGElementRef in SymbolConjured (#128251)
This PR changes the `Stmt *` field in `SymbolConjured` with `CFGBlock::ConstCFGElementRef`. The motivation is that, when conjuring a symbol, there might not always be a statement available, causing information to be lost for conjured symbols, whereas the CFGElementRef can always be provided at the callsite. Following the idea, this PR changes callsites of functions to create conjured symbols, and replaces them with appropriate `CFGElementRef`s. Closes #57270
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp107
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp55
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Iterator.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Iterator.h3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp93
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp26
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp43
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp2
15 files changed, 211 insertions, 183 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 39dcaf0..49ca39f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -273,28 +273,29 @@ public:
/// Invalidate the destination buffer determined by characters copied.
static ProgramStateRef
invalidateDestinationBufferBySize(CheckerContext &C, ProgramStateRef S,
- const Expr *BufE, SVal BufV, SVal SizeV,
- QualType SizeTy);
+ const Expr *BufE, ConstCFGElementRef Elem,
+ SVal BufV, SVal SizeV, QualType SizeTy);
/// Operation never overflows, do not invalidate the super region.
static ProgramStateRef invalidateDestinationBufferNeverOverflows(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
+ CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV);
/// We do not know whether the operation can overflow (e.g. size is unknown),
/// invalidate the super region and escape related pointers.
static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
+ CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV);
/// Invalidate the source buffer for escaping pointers.
static ProgramStateRef invalidateSourceBuffer(CheckerContext &C,
ProgramStateRef S,
- const Expr *BufE, SVal BufV);
+ ConstCFGElementRef Elem,
+ SVal BufV);
/// @param InvalidationTraitOperations Determine how to invlidate the
/// MemRegion by setting the invalidation traits. Return true to cause pointer
/// escape, or false otherwise.
static ProgramStateRef invalidateBufferAux(
- CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V,
+ CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V,
llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
const MemRegion *)>
InvalidationTraitOperations);
@@ -302,8 +303,8 @@ public:
static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
const MemRegion *MR);
- static bool memsetAux(const Expr *DstBuffer, SVal CharE,
- const Expr *Size, CheckerContext &C,
+ static bool memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem,
+ SVal CharE, const Expr *Size, CheckerContext &C,
ProgramStateRef &State);
// Re-usable checks
@@ -1211,8 +1212,8 @@ bool CStringChecker::isFirstBufInBound(CheckerContext &C, ProgramStateRef State,
}
ProgramStateRef CStringChecker::invalidateDestinationBufferBySize(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV,
- SVal SizeV, QualType SizeTy) {
+ CheckerContext &C, ProgramStateRef S, const Expr *BufE,
+ ConstCFGElementRef Elem, SVal BufV, SVal SizeV, QualType SizeTy) {
auto InvalidationTraitOperations =
[&C, S, BufTy = BufE->getType(), BufV, SizeV,
SizeTy](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
@@ -1227,22 +1228,22 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferBySize(
return false;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations);
}
ProgramStateRef
CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
+ CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) {
auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
const MemRegion *R) {
return isa<FieldRegion>(R);
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
- CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
+ CheckerContext &C, ProgramStateRef S, ConstCFGElementRef Elem, SVal BufV) {
auto InvalidationTraitOperations =
[](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
if (MemRegion::FieldRegionKind == R->getKind())
@@ -1252,12 +1253,12 @@ ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
return false;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C,
ProgramStateRef S,
- const Expr *BufE,
+ ConstCFGElementRef Elem,
SVal BufV) {
auto InvalidationTraitOperations =
[](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
@@ -1269,11 +1270,11 @@ ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C,
return true;
};
- return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
+ return invalidateBufferAux(C, S, Elem, BufV, InvalidationTraitOperations);
}
ProgramStateRef CStringChecker::invalidateBufferAux(
- CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V,
+ CheckerContext &C, ProgramStateRef State, ConstCFGElementRef Elem, SVal V,
llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
const MemRegion *)>
InvalidationTraitOperations) {
@@ -1299,7 +1300,7 @@ ProgramStateRef CStringChecker::invalidateBufferAux(
RegionAndSymbolInvalidationTraits ITraits;
bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
- return State->invalidateRegions(R, E, C.blockCount(), LCtx,
+ return State->invalidateRegions(R, Elem, C.blockCount(), LCtx,
CausesPointerEscape, nullptr, nullptr,
&ITraits);
}
@@ -1349,9 +1350,9 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
}
}
-bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
- const Expr *Size, CheckerContext &C,
- ProgramStateRef &State) {
+bool CStringChecker::memsetAux(const Expr *DstBuffer, ConstCFGElementRef Elem,
+ SVal CharVal, const Expr *Size,
+ CheckerContext &C, ProgramStateRef &State) {
SVal MemVal = C.getSVal(DstBuffer);
SVal SizeVal = C.getSVal(Size);
const MemRegion *MR = MemVal.getAsRegion();
@@ -1404,8 +1405,8 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
} else {
// If the destination buffer's extent is not equal to the value of
// third argument, just invalidate buffer.
- State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal,
- SizeVal, Size->getType());
+ State = invalidateDestinationBufferBySize(
+ C, State, DstBuffer, Elem, MemVal, SizeVal, Size->getType());
}
if (StateNullChar && !StateNonNullChar) {
@@ -1430,7 +1431,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
} else {
// If the offset is not zero and char value is not concrete, we can do
// nothing but invalidate the buffer.
- State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal,
+ State = invalidateDestinationBufferBySize(C, State, DstBuffer, Elem, MemVal,
SizeVal, Size->getType());
}
return true;
@@ -1515,7 +1516,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx,
+ C.blockCount());
// The byte after the last byte copied is the return value.
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
@@ -1532,12 +1534,12 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
// This would probably remove any existing bindings past the end of the
// copied region, but that's still an improvement over blank invalidation.
state = invalidateDestinationBufferBySize(
- C, state, Dest.Expression, C.getSVal(Dest.Expression), sizeVal,
- Size.Expression->getType());
+ C, state, Dest.Expression, Call.getCFGElementRef(),
+ C.getSVal(Dest.Expression), sizeVal, Size.Expression->getType());
// Invalidate the source (const-invalidation without const-pointer-escaping
// the address of the top-level region).
- state = invalidateSourceBuffer(C, state, Source.Expression,
+ state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(),
C.getSVal(Source.Expression));
C.addTransition(state);
@@ -1665,8 +1667,8 @@ 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(
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
@@ -1770,7 +1772,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// 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());
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
@@ -1794,7 +1796,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C,
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(
- nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
}
}
@@ -2235,13 +2237,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
// can use LazyCompoundVals to copy the source values into the destination.
// This would probably remove any existing bindings past the end of the
// string, but that's still an improvement over blank invalidation.
- state = invalidateDestinationBufferBySize(C, state, Dst.Expression,
- *dstRegVal, amountCopied,
- C.getASTContext().getSizeType());
+ state = invalidateDestinationBufferBySize(
+ C, state, Dst.Expression, Call.getCFGElementRef(), *dstRegVal,
+ amountCopied, C.getASTContext().getSizeType());
// Invalidate the source (const-invalidation without const-pointer-escaping
// the address of the top-level region).
- state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal);
+ state = invalidateSourceBuffer(C, state, Call.getCFGElementRef(), srcVal);
// Set the C string length of the destination, if we know it.
if (IsBounded && (appendK == ConcatFnKind::none)) {
@@ -2261,8 +2263,8 @@ 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(
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
}
}
// Set the return value.
@@ -2361,8 +2363,8 @@ 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(
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
@@ -2463,20 +2465,20 @@ void CStringChecker::evalStrsep(CheckerContext &C,
// character to NUL.
// As the replacement never overflows, do not invalidate its super region.
State = invalidateDestinationBufferNeverOverflows(
- C, State, SearchStrPtr.Expression, Result);
+ C, State, Call.getCFGElementRef(), Result);
// 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(),
+ SVB.conjureSymbolVal(getTag(), Call.getCFGElementRef(),
LCtx, CharPtrTy, C.blockCount()),
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(
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
}
// Set the return value, and finish.
@@ -2514,13 +2516,13 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SVal DstVal = State->getSVal(Dst, LCtx);
// FIXME: As we do not know how many items are copied, we also invalidate the
// super region containing the target location.
- State =
- invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal);
+ State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
+ C, State, Call.getCFGElementRef(), DstVal);
SValBuilder &SVB = C.getSValBuilder();
- SVal ResultVal =
- SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
+ SVal ResultVal = SVB.conjureSymbolVal(
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
C.addTransition(State);
@@ -2569,8 +2571,8 @@ void CStringChecker::evalMemset(CheckerContext &C,
// According to the values of the arguments, bind the value of the second
// argument to the destination buffer and set string length, or just
// invalidate the destination buffer.
- if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression),
- Size.Expression, C, State))
+ if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(),
+ C.getSVal(CharE.Expression), Size.Expression, C, State))
return;
State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
@@ -2614,7 +2616,8 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const {
if (!State)
return;
- if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State))
+ if (!memsetAux(Buffer.Expression, Call.getCFGElementRef(), Zero,
+ Size.Expression, C, State))
return;
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index d850344..3cc49e4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -33,11 +33,11 @@ namespace {
class ContainerModeling
: public Checker<check::PostCall, check::LiveSymbols, check::DeadSymbols> {
- void handleBegin(CheckerContext &C, const Expr *CE, SVal RetVal,
+ void handleBegin(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal,
SVal Cont) const;
- void handleEnd(CheckerContext &C, const Expr *CE, SVal RetVal,
+ void handleEnd(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal,
SVal Cont) const;
- void handleAssignment(CheckerContext &C, SVal Cont, const Expr *CE = nullptr,
+ void handleAssignment(CheckerContext &C, SVal Cont, ConstCFGElementRef Elem,
SVal OldCont = UndefinedVal()) const;
void handleAssign(CheckerContext &C, SVal Cont, const Expr *ContE) const;
void handleClear(CheckerContext &C, SVal Cont, const Expr *ContE) const;
@@ -108,11 +108,12 @@ bool backModifiable(ProgramStateRef State, const MemRegion *Reg);
SymbolRef getContainerBegin(ProgramStateRef State, const MemRegion *Cont);
SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont);
ProgramStateRef createContainerBegin(ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
- QualType T, const LocationContext *LCtx,
+ const MemRegion *Cont,
+ ConstCFGElementRef Elem, QualType T,
+ const LocationContext *LCtx,
unsigned BlockCount);
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
- const Expr *E, QualType T,
+ ConstCFGElementRef Elem, QualType T,
const LocationContext *LCtx,
unsigned BlockCount);
ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont,
@@ -163,12 +164,12 @@ void ContainerModeling::checkPostCall(const CallEvent &Call,
return;
if (cast<CXXMethodDecl>(Func)->isMoveAssignmentOperator()) {
- handleAssignment(C, InstCall->getCXXThisVal(), Call.getOriginExpr(),
- Call.getArgSVal(0));
+ handleAssignment(C, InstCall->getCXXThisVal(), Call.getCFGElementRef(),
+ Call.getArgSVal(0));
return;
}
- handleAssignment(C, InstCall->getCXXThisVal());
+ handleAssignment(C, InstCall->getCXXThisVal(), C.getCFGElementRef());
return;
}
} else {
@@ -198,13 +199,13 @@ void ContainerModeling::checkPostCall(const CallEvent &Call,
return;
if (isBeginCall(Func)) {
- handleBegin(C, OrigExpr, Call.getReturnValue(),
+ handleBegin(C, Call.getCFGElementRef(), Call.getReturnValue(),
InstCall->getCXXThisVal());
return;
}
if (isEndCall(Func)) {
- handleEnd(C, OrigExpr, Call.getReturnValue(),
+ handleEnd(C, Call.getCFGElementRef(), Call.getReturnValue(),
InstCall->getCXXThisVal());
return;
}
@@ -250,8 +251,8 @@ void ContainerModeling::checkDeadSymbols(SymbolReaper &SR,
C.addTransition(State);
}
-void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
- SVal RetVal, SVal Cont) const {
+void ContainerModeling::handleBegin(CheckerContext &C, ConstCFGElementRef Elem,
+ SVal RetVal, SVal Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -263,7 +264,7 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto BeginSym = getContainerBegin(State, ContReg);
if (!BeginSym) {
- State = createContainerBegin(State, ContReg, CE, C.getASTContext().LongTy,
+ State = createContainerBegin(State, ContReg, Elem, C.getASTContext().LongTy,
C.getLocationContext(), C.blockCount());
BeginSym = getContainerBegin(State, ContReg);
}
@@ -272,8 +273,8 @@ void ContainerModeling::handleBegin(CheckerContext &C, const Expr *CE,
C.addTransition(State);
}
-void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
- SVal RetVal, SVal Cont) const {
+void ContainerModeling::handleEnd(CheckerContext &C, ConstCFGElementRef Elem,
+ SVal RetVal, SVal Cont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -285,7 +286,7 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
auto State = C.getState();
auto EndSym = getContainerEnd(State, ContReg);
if (!EndSym) {
- State = createContainerEnd(State, ContReg, CE, C.getASTContext().LongTy,
+ State = createContainerEnd(State, ContReg, Elem, C.getASTContext().LongTy,
C.getLocationContext(), C.blockCount());
EndSym = getContainerEnd(State, ContReg);
}
@@ -295,7 +296,8 @@ void ContainerModeling::handleEnd(CheckerContext &C, const Expr *CE,
}
void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
- const Expr *CE, SVal OldCont) const {
+ ConstCFGElementRef Elem,
+ SVal OldCont) const {
const auto *ContReg = Cont.getAsRegion();
if (!ContReg)
return;
@@ -329,7 +331,7 @@ void ContainerModeling::handleAssignment(CheckerContext &C, SVal Cont,
auto &SVB = C.getSValBuilder();
// Then generate and assign a new "end" symbol for the new container.
auto NewEndSym =
- SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ SymMgr.conjureSymbol(Elem, C.getLocationContext(),
C.getASTContext().LongTy, C.blockCount());
State = assumeNoOverflow(State, NewEndSym, 4);
if (CData) {
@@ -848,8 +850,9 @@ SymbolRef getContainerEnd(ProgramStateRef State, const MemRegion *Cont) {
}
ProgramStateRef createContainerBegin(ProgramStateRef State,
- const MemRegion *Cont, const Expr *E,
- QualType T, const LocationContext *LCtx,
+ const MemRegion *Cont,
+ ConstCFGElementRef Elem, QualType T,
+ const LocationContext *LCtx,
unsigned BlockCount) {
// Only create if it does not exist
const auto *CDataPtr = getContainerData(State, Cont);
@@ -857,8 +860,8 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
return State;
auto &SymMgr = State->getSymbolManager();
- const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
- "begin");
+ const SymbolConjured *Sym =
+ SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "begin");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
@@ -871,7 +874,7 @@ ProgramStateRef createContainerBegin(ProgramStateRef State,
}
ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
- const Expr *E, QualType T,
+ ConstCFGElementRef Elem, QualType T,
const LocationContext *LCtx,
unsigned BlockCount) {
// Only create if it does not exist
@@ -880,8 +883,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont,
return State;
auto &SymMgr = State->getSymbolManager();
- const SymbolConjured *Sym = SymMgr.conjureSymbol(E, LCtx, T, BlockCount,
- "end");
+ const SymbolConjured *Sym =
+ SymMgr.conjureSymbol(Elem, LCtx, T, BlockCount, "end");
State = assumeNoOverflow(State, Sym, 4);
if (CDataPtr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index 6ffc05f..abfc5d2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -124,7 +124,7 @@ void ErrnoModeling::checkBeginFunction(CheckerContext &C) const {
// of the data member `ErrnoDecl` of the singleton `ErrnoModeling` checker
// object.
const SymbolConjured *Sym = SVB.conjureSymbol(
- nullptr, C.getLocationContext(),
+ C.getCFGElementRef(), C.getLocationContext(),
ACtx.getLValueReferenceType(ACtx.IntTy), C.blockCount(), &ErrnoDecl);
// The symbolic region is untyped, create a typed sub-region in it.
@@ -256,11 +256,11 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
CheckerContext &C,
- const Expr *InvalE) {
+ ConstCFGElementRef Elem) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return State;
- State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
+ State = State->invalidateRegions(ErrnoR, Elem, C.blockCount(),
C.getLocationContext(), false);
if (!State)
return nullptr;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
index 95da8a2..e414353 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
@@ -96,9 +96,10 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
/// Set errno state for the common case when a standard function indicates
/// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and
/// invalidates the errno region (clear of previous value).
-/// \arg \c InvalE Expression that causes invalidation of \c errno.
+/// \arg \c Elem CFG Element that causes invalidation of \c errno.
ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
- CheckerContext &C, const Expr *InvalE);
+ CheckerContext &C,
+ ConstCFGElementRef Elem);
} // namespace errno_modeling
} // namespace ento
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
index 6076a6b..be70819 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
@@ -131,7 +131,8 @@ 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());
+ /*symbolTag=*/nullptr, Call.getCFGElementRef(), C.getLocationContext(),
+ C.blockCount());
StateFailure = StateFailure->assume(ErrnoVal, true);
assert(StateFailure && "Failed to assume on an initial value.");
StateFailure =
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
index ba561dd..e9825b7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp
@@ -207,14 +207,15 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
}
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
- const MemRegion *Cont, const Stmt *S,
+ const MemRegion *Cont,
+ ConstCFGElementRef Elem,
const LocationContext *LCtx,
unsigned blockCount) {
auto &StateMgr = State->getStateManager();
auto &SymMgr = StateMgr.getSymbolManager();
auto &ACtx = StateMgr.getContext();
- auto Sym = SymMgr.conjureSymbol(S, LCtx, ACtx.LongTy, blockCount);
+ auto *Sym = SymMgr.conjureSymbol(Elem, LCtx, ACtx.LongTy, blockCount);
State = assumeNoOverflow(State, Sym, 4);
return setIteratorPosition(State, Val,
IteratorPosition::getPosition(Cont, Sym));
diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
index 46de8ea..0a26db0 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Iterator.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h
@@ -165,7 +165,8 @@ const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val);
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
const IteratorPosition &Pos);
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
- const MemRegion *Cont, const Stmt *S,
+ const MemRegion *Cont,
+ ConstCFGElementRef Elem,
const LocationContext *LCtx,
unsigned blockCount);
ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter,
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index d4ce73b..6139585 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -90,8 +90,9 @@ class IteratorModeling
check::PostStmt<MaterializeTemporaryExpr>,
check::Bind, check::LiveSymbols, check::DeadSymbols> {
- using AdvanceFn = void (IteratorModeling::*)(CheckerContext &, const Expr *,
- SVal, SVal, SVal) const;
+ using AdvanceFn = void (IteratorModeling::*)(CheckerContext &,
+ ConstCFGElementRef, SVal, SVal,
+ SVal) const;
void handleOverloadedOperator(CheckerContext &C, const CallEvent &Call,
OverloadedOperatorKind Op) const;
@@ -99,8 +100,9 @@ class IteratorModeling
const Expr *OrigExpr,
const AdvanceFn *Handler) const;
- void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
- SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
+ void handleComparison(CheckerContext &C, const Expr *CE,
+ ConstCFGElementRef Elem, SVal RetVal, SVal LVal,
+ SVal RVal, OverloadedOperatorKind Op) const;
void processComparison(CheckerContext &C, ProgramStateRef State,
SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
OverloadedOperatorKind Op) const;
@@ -108,19 +110,20 @@ class IteratorModeling
bool Postfix) const;
void handleDecrement(CheckerContext &C, SVal RetVal, SVal Iter,
bool Postfix) const;
- void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
+ void handleRandomIncrOrDecr(CheckerContext &C, ConstCFGElementRef Elem,
OverloadedOperatorKind Op, SVal RetVal,
SVal Iterator, SVal Amount) const;
void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
- OverloadedOperatorKind OK, SVal Offset) const;
- void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
- SVal Amount) const;
- void handlePrev(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
- SVal Amount) const;
- void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
- SVal Amount) const;
- void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal,
- const MemRegion *Cont) const;
+ ConstCFGElementRef Elem, OverloadedOperatorKind OK,
+ SVal Offset) const;
+ void handleAdvance(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal,
+ SVal Iter, SVal Amount) const;
+ void handlePrev(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal,
+ SVal Iter, SVal Amount) const;
+ void handleNext(CheckerContext &C, ConstCFGElementRef Elem, SVal RetVal,
+ SVal Iter, SVal Amount) const;
+ void assignToContainer(CheckerContext &C, ConstCFGElementRef Elem,
+ SVal RetVal, const MemRegion *Cont) const;
bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
const char *Sep) const override;
@@ -224,7 +227,7 @@ void IteratorModeling::checkPostCall(const CallEvent &Call,
C.getASTContext()).getTypePtr() ==
Call.getResultType().getDesugaredType(C.getASTContext()).getTypePtr()) {
if (const auto *Pos = getIteratorPosition(State, Call.getArgSVal(i))) {
- assignToContainer(C, OrigExpr, Call.getReturnValue(),
+ assignToContainer(C, Call.getCFGElementRef(), Call.getReturnValue(),
Pos->getContainer());
return;
}
@@ -255,7 +258,7 @@ void IteratorModeling::checkPostStmt(const UnaryOperator *UO,
return;
auto &SVB = C.getSValBuilder();
- handlePtrIncrOrDecr(C, UO->getSubExpr(),
+ handlePtrIncrOrDecr(C, UO->getSubExpr(), C.getCFGElementRef(),
isIncrementOperator(OK) ? OO_Plus : OO_Minus,
SVB.makeArrayIndex(1));
}
@@ -271,7 +274,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
if (isSimpleComparisonOperator(BO->getOpcode())) {
SVal Result = State->getSVal(BO, C.getLocationContext());
- handleComparison(C, BO, Result, LVal, RVal,
+ handleComparison(C, BO, C.getCFGElementRef(), Result, LVal, RVal,
BinaryOperator::getOverloadedOperator(OK));
} else if (isRandomIncrOrDecrOperator(OK)) {
// In case of operator+ the iterator can be either on the LHS (eg.: it + 1),
@@ -284,8 +287,8 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
if (!AmountExpr->getType()->isIntegralOrEnumerationType())
return;
SVal AmountVal = IsIterOnLHS ? RVal : LVal;
- handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK),
- AmountVal);
+ handlePtrIncrOrDecr(C, IterExpr, C.getCFGElementRef(),
+ BinaryOperator::getOverloadedOperator(OK), AmountVal);
}
}
@@ -351,27 +354,29 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
OverloadedOperatorKind Op) const {
if (isSimpleComparisonOperator(Op)) {
const auto *OrigExpr = Call.getOriginExpr();
+ const auto Elem = Call.getCFGElementRef();
if (!OrigExpr)
return;
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
- handleComparison(C, OrigExpr, Call.getReturnValue(),
+ handleComparison(C, OrigExpr, Elem, Call.getReturnValue(),
InstCall->getCXXThisVal(), Call.getArgSVal(0), Op);
return;
}
- handleComparison(C, OrigExpr, Call.getReturnValue(), Call.getArgSVal(0),
- Call.getArgSVal(1), Op);
+ handleComparison(C, OrigExpr, Elem, Call.getReturnValue(),
+ Call.getArgSVal(0), Call.getArgSVal(1), Op);
return;
} else if (isRandomIncrOrDecrOperator(Op)) {
const auto *OrigExpr = Call.getOriginExpr();
+ const auto Elem = Call.getCFGElementRef();
if (!OrigExpr)
return;
if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) {
if (Call.getNumArgs() >= 1 &&
Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) {
- handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
+ handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(),
InstCall->getCXXThisVal(), Call.getArgSVal(0));
return;
}
@@ -391,8 +396,8 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
SVal Iterator = IsIterFirst ? FirstArg : SecondArg;
SVal Amount = IsIterFirst ? SecondArg : FirstArg;
- handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
- Iterator, Amount);
+ handleRandomIncrOrDecr(C, Elem, Op, Call.getReturnValue(), Iterator,
+ Amount);
return;
}
}
@@ -425,7 +430,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
const Expr *OrigExpr,
const AdvanceFn *Handler) const {
if (!C.wasInlined) {
- (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
+ (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(),
Call.getArgSVal(0), Call.getArgSVal(1));
return;
}
@@ -436,7 +441,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
if (IdInfo) {
if (IdInfo->getName() == "advance") {
if (noChangeInAdvance(C, Call.getArgSVal(0), OrigExpr)) {
- (this->**Handler)(C, OrigExpr, Call.getReturnValue(),
+ (this->**Handler)(C, Call.getCFGElementRef(), Call.getReturnValue(),
Call.getArgSVal(0), Call.getArgSVal(1));
}
}
@@ -444,7 +449,8 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
}
void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
- SVal RetVal, SVal LVal, SVal RVal,
+ ConstCFGElementRef Elem, SVal RetVal,
+ SVal LVal, SVal RVal,
OverloadedOperatorKind Op) const {
// Record the operands and the operator of the comparison for the next
// evalAssume, if the result is a symbolic expression. If it is a concrete
@@ -467,7 +473,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
SymbolRef Sym;
if (!LPos || !RPos) {
auto &SymMgr = C.getSymbolManager();
- Sym = SymMgr.conjureSymbol(CE, C.getLocationContext(),
+ Sym = SymMgr.conjureSymbol(Elem, C.getLocationContext(),
C.getASTContext().LongTy, C.blockCount());
State = assumeNoOverflow(State, Sym, 4);
}
@@ -494,7 +500,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
auto &SymMgr = C.getSymbolManager();
auto *LCtx = C.getLocationContext();
RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol(
- CE, LCtx, C.getASTContext().BoolTy, C.blockCount()));
+ Elem, LCtx, C.getASTContext().BoolTy, C.blockCount()));
State = State->BindExpr(CE, LCtx, RetVal);
}
@@ -583,7 +589,8 @@ void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal,
C.addTransition(State);
}
-void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
+void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C,
+ ConstCFGElementRef Elem,
OverloadedOperatorKind Op,
SVal RetVal, SVal Iterator,
SVal Amount) const {
@@ -617,12 +624,13 @@ void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
State = setIteratorPosition(State, TgtVal, *NewPos);
C.addTransition(State);
} else {
- assignToContainer(C, CE, TgtVal, Pos->getContainer());
+ assignToContainer(C, Elem, TgtVal, Pos->getContainer());
}
}
void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
const Expr *Iterator,
+ ConstCFGElementRef Elem,
OverloadedOperatorKind OK,
SVal Offset) const {
if (!isa<DefinedSVal>(Offset))
@@ -661,34 +669,35 @@ void IteratorModeling::handlePtrIncrOrDecr(CheckerContext &C,
ProgramStateRef NewState = setIteratorPosition(State, NewVal, *NewPos);
C.addTransition(NewState);
} else {
- assignToContainer(C, Iterator, NewVal, OldPos->getContainer());
+ assignToContainer(C, Elem, NewVal, OldPos->getContainer());
}
}
-void IteratorModeling::handleAdvance(CheckerContext &C, const Expr *CE,
+void IteratorModeling::handleAdvance(CheckerContext &C, ConstCFGElementRef Elem,
SVal RetVal, SVal Iter,
SVal Amount) const {
- handleRandomIncrOrDecr(C, CE, OO_PlusEqual, RetVal, Iter, Amount);
+ handleRandomIncrOrDecr(C, Elem, OO_PlusEqual, RetVal, Iter, Amount);
}
-void IteratorModeling::handlePrev(CheckerContext &C, const Expr *CE,
+void IteratorModeling::handlePrev(CheckerContext &C, ConstCFGElementRef Elem,
SVal RetVal, SVal Iter, SVal Amount) const {
- handleRandomIncrOrDecr(C, CE, OO_Minus, RetVal, Iter, Amount);
+ handleRandomIncrOrDecr(C, Elem, OO_Minus, RetVal, Iter, Amount);
}
-void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
+void IteratorModeling::handleNext(CheckerContext &C, ConstCFGElementRef Elem,
SVal RetVal, SVal Iter, SVal Amount) const {
- handleRandomIncrOrDecr(C, CE, OO_Plus, RetVal, Iter, Amount);
+ handleRandomIncrOrDecr(C, Elem, OO_Plus, RetVal, Iter, Amount);
}
-void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
- SVal RetVal,
+void IteratorModeling::assignToContainer(CheckerContext &C,
+ ConstCFGElementRef Elem, SVal RetVal,
const MemRegion *Cont) const {
Cont = Cont->getMostDerivedObjectRegion();
auto State = C.getState();
const auto *LCtx = C.getLocationContext();
- State = createIteratorPosition(State, RetVal, Cont, CE, LCtx, C.blockCount());
+ State =
+ createIteratorPosition(State, RetVal, Cont, Elem, LCtx, C.blockCount());
C.addTransition(State);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 1c4293c..e970a89 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1833,8 +1833,10 @@ ProgramStateRef MallocChecker::MallocBindRetVal(CheckerContext &C,
unsigned Count = C.blockCount();
SValBuilder &SVB = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal = isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
- : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count);
+ DefinedSVal RetVal =
+ isAlloca ? SVB.getAllocaRegionVal(CE, LCtx, Count)
+ : SVB.getConjuredHeapSymbolVal(Call.getCFGElementRef(), LCtx,
+ CE->getType(), Count);
return State->BindExpr(CE, C.getLocationContext(), RetVal);
}
@@ -2304,7 +2306,7 @@ MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
// Assume that after memory is freed, it contains unknown values. This
// conforts languages standards, since reading from freed memory is considered
// UB and may result in arbitrary value.
- State = State->invalidateRegions({location}, Call.getOriginExpr(),
+ State = State->invalidateRegions({location}, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index cc1ced7..03a6b60 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -932,7 +932,8 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
(hasTrustedImplementationAnnotation && !ResultTy.isNull())) {
SValBuilder &SVB = C.getSValBuilder();
RetVal =
- SVB.conjureSymbolVal(nullptr, CE, LCtx, ResultTy, C.blockCount());
+ SVB.conjureSymbolVal(/*symbolTag=*/nullptr, Call.getCFGElementRef(),
+ LCtx, ResultTy, C.blockCount());
}
// Bind the value.
diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
index e037719..8e19963 100644
--- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -25,12 +25,12 @@ using namespace iterator;
namespace {
class STLAlgorithmModeling : public Checker<eval::Call> {
- bool evalFind(CheckerContext &C, const CallExpr *CE) const;
+ bool evalFind(CheckerContext &C, const CallEvent &Call) const;
- void Find(CheckerContext &C, const CallExpr *CE, unsigned paramNum) const;
+ void Find(CheckerContext &C, const CallEvent &Call, unsigned paramNum) const;
using FnCheck = bool (STLAlgorithmModeling::*)(CheckerContext &,
- const CallExpr *) const;
+ const CallEvent &Call) const;
const CallDescriptionMap<FnCheck> Callbacks = {
{{CDM::SimpleFunc, {"std", "find"}, 3}, &STLAlgorithmModeling::evalFind},
@@ -97,11 +97,12 @@ bool STLAlgorithmModeling::evalCall(const CallEvent &Call,
if (!Handler)
return false;
- return (this->**Handler)(C, CE);
+ return (this->**Handler)(C, Call);
}
bool STLAlgorithmModeling::evalFind(CheckerContext &C,
- const CallExpr *CE) const {
+ const CallEvent &Call) const {
+ const auto *CE = dyn_cast<CallExpr>(Call.getOriginExpr());
// std::find()-like functions either take their primary range in the first
// two parameters, or if the first parameter is "execution policy" then in
// the second and third. This means that the second parameter must always be
@@ -112,27 +113,29 @@ bool STLAlgorithmModeling::evalFind(CheckerContext &C,
// If no "execution policy" parameter is used then the first argument is the
// beginning of the range.
if (isIteratorType(CE->getArg(0)->getType())) {
- Find(C, CE, 0);
+ Find(C, Call, 0);
return true;
}
// If "execution policy" parameter is used then the second argument is the
// beginning of the range.
if (isIteratorType(CE->getArg(2)->getType())) {
- Find(C, CE, 1);
+ Find(C, Call, 1);
return true;
}
return false;
}
-void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
+void STLAlgorithmModeling::Find(CheckerContext &C, const CallEvent &Call,
unsigned paramNum) const {
+ const auto *CE = dyn_cast<CallExpr>(Call.getOriginExpr());
+ const auto &Elem = Call.getCFGElementRef();
auto State = C.getState();
auto &SVB = C.getSValBuilder();
const auto *LCtx = C.getLocationContext();
- SVal RetVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
+ SVal RetVal = SVB.conjureSymbolVal(nullptr, Elem, LCtx, C.blockCount());
SVal Param = State->getSVal(CE->getArg(paramNum), LCtx);
auto StateFound = State->BindExpr(CE, LCtx, RetVal);
@@ -144,7 +147,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
const auto *Pos = getIteratorPosition(State, Param);
if (Pos) {
StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
- CE, LCtx, C.blockCount());
+ Elem, LCtx, C.blockCount());
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
assert(NewPos && "Failed to create new iterator position.");
@@ -166,7 +169,7 @@ void STLAlgorithmModeling::Find(CheckerContext &C, const CallExpr *CE,
Pos = getIteratorPosition(State, Param);
if (Pos) {
StateFound = createIteratorPosition(StateFound, RetVal, Pos->getContainer(),
- CE, LCtx, C.blockCount());
+ Elem, LCtx, C.blockCount());
const auto *NewPos = getIteratorPosition(StateFound, RetVal);
assert(NewPos && "Failed to create new iterator position.");
@@ -199,4 +202,3 @@ void ento::registerSTLAlgorithmModeling(CheckerManager &Mgr) {
bool ento::shouldRegisterSTLAlgorithmModeling(const CheckerManager &mgr) {
return true;
}
-
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 321388a..9b0ce15 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -78,10 +78,9 @@ private:
bool handleOstreamOperator(const CallEvent &Call, CheckerContext &C) const;
bool handleSwap(ProgramStateRef State, SVal First, SVal Second,
CheckerContext &C) const;
- std::pair<SVal, ProgramStateRef>
- retrieveOrConjureInnerPtrVal(ProgramStateRef State,
- const MemRegion *ThisRegion, const Expr *E,
- QualType Type, CheckerContext &C) const;
+ std::pair<SVal, ProgramStateRef> retrieveOrConjureInnerPtrVal(
+ ProgramStateRef State, const MemRegion *ThisRegion,
+ ConstCFGElementRef Elem, QualType Type, CheckerContext &C) const;
using SmartPtrMethodHandlerFn =
void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
@@ -306,7 +305,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return false;
const auto PtrVal = C.getSValBuilder().getConjuredHeapSymbolVal(
- Call.getOriginExpr(), C.getLocationContext(),
+ Call.getCFGElementRef(), C.getLocationContext(),
getPointerTypeFromTemplateArg(Call, C), C.blockCount());
const MemRegion *ThisRegion = ThisRegionOpt->getAsRegion();
@@ -437,12 +436,12 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
}
std::pair<SVal, ProgramStateRef> SmartPtrModeling::retrieveOrConjureInnerPtrVal(
- ProgramStateRef State, const MemRegion *ThisRegion, const Expr *E,
+ ProgramStateRef State, const MemRegion *ThisRegion, ConstCFGElementRef Elem,
QualType Type, CheckerContext &C) const {
const auto *Ptr = State->get<TrackedRegionMap>(ThisRegion);
if (Ptr)
return {*Ptr, State};
- auto Val = C.getSValBuilder().conjureSymbolVal(E, C.getLocationContext(),
+ auto Val = C.getSValBuilder().conjureSymbolVal(Elem, C.getLocationContext(),
Type, C.blockCount());
State = State->set<TrackedRegionMap>(ThisRegion, Val);
return {Val, State};
@@ -469,6 +468,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
// https://en.cppreference.com/w/cpp/memory/unique_ptr/operator_cmp.
auto makeSValFor = [&C, this](ProgramStateRef State, const Expr *E,
+ ConstCFGElementRef Elem,
SVal S) -> std::pair<SVal, ProgramStateRef> {
if (S.isZeroConstant()) {
return {S, State};
@@ -477,7 +477,7 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
assert(Reg &&
"this pointer of std::unique_ptr should be obtainable as MemRegion");
QualType Type = getInnerPointerType(C, E->getType()->getAsCXXRecordDecl());
- return retrieveOrConjureInnerPtrVal(State, Reg, E, Type, C);
+ return retrieveOrConjureInnerPtrVal(State, Reg, Elem, Type, C);
};
SVal First = Call.getArgSVal(0);
@@ -491,8 +491,10 @@ bool SmartPtrModeling::handleComparisionOp(const CallEvent &Call,
ProgramStateRef State = C.getState();
SVal FirstPtrVal, SecondPtrVal;
- std::tie(FirstPtrVal, State) = makeSValFor(State, FirstExpr, First);
- std::tie(SecondPtrVal, State) = makeSValFor(State, SecondExpr, Second);
+ std::tie(FirstPtrVal, State) =
+ makeSValFor(State, FirstExpr, Call.getCFGElementRef(), First);
+ std::tie(SecondPtrVal, State) =
+ makeSValFor(State, SecondExpr, Call.getCFGElementRef(), Second);
BinaryOperatorKind BOK =
operationKindFromOverloadedOperator(OOK, true).GetBinaryOpUnsafe();
auto RetVal = Bldr.evalBinOp(State, BOK, FirstPtrVal, SecondPtrVal,
@@ -530,7 +532,7 @@ bool SmartPtrModeling::handleOstreamOperator(const CallEvent &Call,
if (!StreamThisRegion)
return false;
State =
- State->invalidateRegions({StreamThisRegion}, Call.getOriginExpr(),
+ State->invalidateRegions({StreamThisRegion}, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(), false);
State =
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), StreamVal);
@@ -722,7 +724,7 @@ void SmartPtrModeling::handleGet(const CallEvent &Call,
SVal InnerPointerVal;
std::tie(InnerPointerVal, State) = retrieveOrConjureInnerPtrVal(
- State, ThisRegion, Call.getOriginExpr(), Call.getResultType(), C);
+ State, ThisRegion, Call.getCFGElementRef(), Call.getResultType(), C);
State = State->BindExpr(Call.getOriginExpr(), C.getLocationContext(),
InnerPointerVal);
// TODO: Add NoteTag, for how the raw pointer got using 'get' method.
@@ -853,7 +855,7 @@ void SmartPtrModeling::handleBoolConversion(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
InnerPointerVal = C.getSValBuilder().conjureSymbolVal(
- CallExpr, LC, InnerPointerType, C.blockCount());
+ Call.getCFGElementRef(), LC, InnerPointerType, C.blockCount());
State = State->set<TrackedRegionMap>(ThisRegion, InnerPointerVal);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 9c0b79a..3628a14 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -585,7 +585,7 @@ class StdLibraryFunctionsChecker
CheckerContext &C) const override {
SValBuilder &SVB = C.getSValBuilder();
NonLoc ErrnoSVal =
- SVB.conjureSymbolVal(&Tag, Call.getOriginExpr(),
+ SVB.conjureSymbolVal(&Tag, Call.getCFGElementRef(),
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
@@ -621,7 +621,7 @@ class StdLibraryFunctionsChecker
const Summary &Summary,
CheckerContext &C) const override {
return errno_modeling::setErrnoStdMustBeChecked(State, C,
- Call.getOriginExpr());
+ Call.getCFGElementRef());
}
const std::string describe(CheckerContext &C) const override {
@@ -1482,7 +1482,8 @@ bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
const LocationContext *LC = C.getLocationContext();
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
SVal V = C.getSValBuilder().conjureSymbolVal(
- CE, LC, CE->getType().getCanonicalType(), C.blockCount());
+ Call.getCFGElementRef(), LC, CE->getType().getCanonicalType(),
+ C.blockCount());
State = State->BindExpr(CE, LC, V);
C.addTransition(State);
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 80969ce..6481b76 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -224,18 +224,16 @@ SVal getStreamArg(const FnDescription *Desc, const CallEvent &Call) {
}
/// Create a conjured symbol return value for a call expression.
-DefinedSVal makeRetVal(CheckerContext &C, const CallExpr *CE) {
- assert(CE && "Expecting a call expression.");
-
- const LocationContext *LCtx = C.getLocationContext();
+DefinedSVal makeRetVal(CheckerContext &C, ConstCFGElementRef Elem) {
return C.getSValBuilder()
- .conjureSymbolVal(nullptr, CE, LCtx, C.blockCount())
+ .conjureSymbolVal(/*symbolTag=*/nullptr, Elem, C.getLocationContext(),
+ C.blockCount())
.castAs<DefinedSVal>();
}
ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C,
- const CallExpr *CE) {
- DefinedSVal RetVal = makeRetVal(C, CE);
+ const CallExpr *CE, ConstCFGElementRef Elem) {
+ DefinedSVal RetVal = makeRetVal(C, Elem);
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
State = State->assume(RetVal, true);
assert(State && "Assumption on new value should not fail.");
@@ -645,6 +643,7 @@ struct StreamOperationEvaluator {
SymbolRef StreamSym = nullptr;
const StreamState *SS = nullptr;
const CallExpr *CE = nullptr;
+ std::optional<ConstCFGElementRef> Elem;
StreamErrorState NewES;
StreamOperationEvaluator(CheckerContext &C)
@@ -664,6 +663,7 @@ struct StreamOperationEvaluator {
CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
if (!CE)
return false;
+ Elem = Call.getCFGElementRef();
assertStreamStateOpened(SS);
@@ -683,7 +683,7 @@ struct StreamOperationEvaluator {
}
ProgramStateRef makeAndBindRetVal(ProgramStateRef State, CheckerContext &C) {
- NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, Elem.value()).castAs<NonLoc>();
return State->BindExpr(CE, C.getLocationContext(), RetVal);
}
@@ -716,7 +716,7 @@ struct StreamOperationEvaluator {
ConstraintManager::ProgramStatePair
makeRetValAndAssumeDual(ProgramStateRef State, CheckerContext &C) {
- DefinedSVal RetVal = makeRetVal(C, CE);
+ DefinedSVal RetVal = makeRetVal(C, Elem.value());
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
return C.getConstraintManager().assumeDual(State, RetVal);
}
@@ -858,7 +858,7 @@ escapeByStartIndexAndCount(ProgramStateRef State, const CallEvent &Call,
ITraits.setTrait(Element, DoNotInvalidateSuperRegion);
}
return State->invalidateRegions(
- EscapingVals, Call.getOriginExpr(), BlockCount, LCtx,
+ EscapingVals, Call.getCFGElementRef(), BlockCount, LCtx,
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr, &Call, &ITraits);
}
@@ -868,7 +868,7 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C,
ArrayRef<unsigned int> EscapingArgs) {
auto GetArgSVal = [&Call](int Idx) { return Call.getArgSVal(Idx); };
auto EscapingVals = to_vector(map_range(EscapingArgs, GetArgSVal));
- State = State->invalidateRegions(EscapingVals, Call.getOriginExpr(),
+ State = State->invalidateRegions(EscapingVals, Call.getCFGElementRef(),
C.blockCount(), C.getLocationContext(),
/*CausesPointerEscape=*/false,
/*InvalidatedSymbols=*/nullptr);
@@ -931,7 +931,7 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call,
if (!CE)
return;
- DefinedSVal RetVal = makeRetVal(C, CE);
+ DefinedSVal RetVal = makeRetVal(C, Call.getCFGElementRef());
SymbolRef RetSym = RetVal.getAsSymbol();
assert(RetSym && "RetVal must be a symbol here.");
@@ -1200,7 +1200,7 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
if (!IsFread && !PedanticMode)
return;
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
StateFailed = E.assumeBinOpNN(StateFailed, BO_LT, RetVal, *NMembVal);
@@ -1235,7 +1235,7 @@ void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call,
State = escapeArgs(State, C, Call, {0});
if (SingleChar) {
// Generate a transition for the success state of `fgetc`.
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateNotFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
// The returned 'unsigned char' of `fgetc` is converted to 'int',
@@ -1300,7 +1300,7 @@ void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateNotFailed);
} else {
// Generate a transition for the success state of `fputs`.
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateNotFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
StateNotFailed =
@@ -1334,7 +1334,7 @@ void StreamChecker::evalFprintf(const FnDescription *Desc,
if (!E.Init(Desc, Call, C, State))
return;
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
State = State->BindExpr(E.CE, C.getLocationContext(), RetVal);
auto Cond =
E.SVB
@@ -1379,7 +1379,7 @@ void StreamChecker::evalFscanf(const FnDescription *Desc, const CallEvent &Call,
// case, and no error flags are set on the stream. This is probably not
// accurate, and the POSIX documentation does not tell more.
if (!E.isStreamEof()) {
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateNotFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
StateNotFailed =
@@ -1460,7 +1460,7 @@ void StreamChecker::evalGetdelim(const FnDescription *Desc,
State = escapeArgs(State, C, Call, {0, 1});
// Add transition for the successful state.
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateNotFailed = E.bindReturnValue(State, C, RetVal);
StateNotFailed =
E.assumeBinOpNN(StateNotFailed, BO_GE, RetVal, E.getZeroVal(Call));
@@ -1601,7 +1601,7 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
if (!E.Init(Desc, Call, C, State))
return;
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
ProgramStateRef StateNotFailed =
State->BindExpr(E.CE, C.getLocationContext(), RetVal);
StateNotFailed =
@@ -1735,7 +1735,8 @@ void StreamChecker::evalFeofFerror(const FnDescription *Desc,
// Execution path with error of ErrorKind.
// Function returns true.
// From now on it is the only one error state.
- ProgramStateRef TrueState = bindAndAssumeTrue(State, C, E.CE);
+ ProgramStateRef TrueState =
+ bindAndAssumeTrue(State, C, E.CE, E.Elem.value());
C.addTransition(E.setStreamState(
TrueState, StreamState::getOpened(Desc, ErrorKind,
E.SS->FilePositionIndeterminate &&
@@ -1769,7 +1770,7 @@ void StreamChecker::evalFileno(const FnDescription *Desc, const CallEvent &Call,
if (!E.Init(Desc, Call, C, State))
return;
- NonLoc RetVal = makeRetVal(C, E.CE).castAs<NonLoc>();
+ NonLoc RetVal = makeRetVal(C, E.Elem.value()).castAs<NonLoc>();
State = State->BindExpr(E.CE, C.getLocationContext(), RetVal);
State = E.assumeBinOpNN(State, BO_GE, RetVal, E.getZeroVal(Call));
if (!State)
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index fefe846..044f9ba 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -207,7 +207,7 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
// Function call will return a pointer to the new symbolic region.
DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
- CE, LCtx, CE->getType(), C.blockCount());
+ Call.getCFGElementRef(), LCtx, CE->getType(), C.blockCount());
State = State->BindExpr(CE, LCtx, RetVal);
const auto *SymRegOfRetVal =