Charusso updated this revision to Diff 254051.
Charusso added a comment.
- Remove the last gymnastic.
- Rebase.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D69726/new/
https://reviews.llvm.org/D69726
Files:
clang/docs/analyzer/developer-docs/DebugChecks.rst
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
clang/lib/StaticAnalyzer/Core/MemRegion.cpp
clang/test/Analysis/explain-svals.cpp
clang/test/Analysis/expr-inspection.cpp
clang/test/Analysis/memory-model.cpp
Index: clang/test/Analysis/memory-model.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/memory-model.cpp
@@ -0,0 +1,114 @@
+// RUN: %clang_analyze_cc1 \
+// RUN: -analyzer-checker=core,unix,cplusplus,debug.ExprInspection \
+// RUN: -triple x86_64-unknown-linux-gnu \
+// RUN: -verify %s
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+typedef __SIZE_TYPE__ size_t;
+void *malloc(size_t);
+void *alloca(size_t);
+void *realloc(void *ptr, size_t size);
+void *calloc(size_t number, size_t size);
+void free(void *);
+
+struct S { int f; };
+
+void clang_analyzer_dump(int);
+void clang_analyzer_dump(const void *);
+void clang_analyzer_dumpExtent(int);
+void clang_analyzer_dumpExtent(const void *);
+void clang_analyzer_dumpElementCount(int);
+void clang_analyzer_dumpElementCount(const void *);
+
+void var_simple_ref() {
+ int a = 13;
+ clang_analyzer_dump(&a); // expected-warning {{a}}
+ clang_analyzer_dumpExtent(&a); // expected-warning {{4 S64b}}
+ clang_analyzer_dumpElementCount(&a); // expected-warning {{1 S64b}}
+}
+
+void var_simple_ptr(int *a) {
+ clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$0<int * a>}}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{extent_$1{SymRegion{reg_$0<int * a>}}}}
+ clang_analyzer_dumpElementCount(a); // expected-warning-re {{{{^\(extent_\$1\{SymRegion\{reg_\$0<int \* a>\}\}\) / 4$}}}}
+}
+
+void var_array() {
+ int a[] = {1, 2, 3};
+ clang_analyzer_dump(a); // expected-warning {{Element{a,0 S64b,int}}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{12 S64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{3 S64b}}
+}
+
+void string() {
+ clang_analyzer_dump("foo"); // expected-warning {{Element{"foo",0 S64b,char}}}
+ clang_analyzer_dumpExtent("foo"); // expected-warning {{4 S64b}}
+ clang_analyzer_dumpElementCount("foo"); // expected-warning {{4 S64b}}
+}
+
+void struct_simple_ptr(S *a) {
+ clang_analyzer_dump(a); // expected-warning {{SymRegion{reg_$0<struct S * a>}}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{extent_$1{SymRegion{reg_$0<struct S * a>}}}}
+ clang_analyzer_dumpElementCount(a); // expected-warning-re {{{{^\(extent_\$1\{SymRegion\{reg_\$0<struct S \* a>\}\}\) / 4$}}}}
+}
+
+void field_ref(S a) {
+ clang_analyzer_dump(&a.f); // expected-warning {{a.f}}
+ clang_analyzer_dumpExtent(&a.f); // expected-warning {{4 S64b}}
+ clang_analyzer_dumpElementCount(&a.f); // expected-warning {{1 S64b}}
+}
+
+void field_ptr(S *a) {
+ clang_analyzer_dump(&a->f); // expected-warning {{SymRegion{reg_$0<struct S * a>}.f}}
+ clang_analyzer_dumpExtent(&a->f); // expected-warning {{4 S64b}}
+ clang_analyzer_dumpElementCount(&a->f); // expected-warning {{1 S64b}}
+}
+
+void symbolic_array() {
+ int *a = new int[3];
+ clang_analyzer_dump(a); // expected-warning {{Element{HeapSymRegion{conj}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{12 S64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{3 S64b}}
+ delete[] a;
+}
+
+void symbolic_placement_new() {
+ char *buf = new char[sizeof(int) * 3];
+ int *a = new (buf) int(13);
+ clang_analyzer_dump(a); // expected-warning {{Element{HeapSymRegion{conj}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{12 S64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{3 S64b}}
+ delete[] buf;
+}
+
+void symbolic_malloc() {
+ int *a = (int *)malloc(12);
+ clang_analyzer_dump(a); // expected-warning {{Element{HeapSymRegion{conj}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{12 U64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{3 S64b}}
+ free(a);
+}
+
+void symbolic_alloca() {
+ int *a = (int *)alloca(12);
+ clang_analyzer_dump(a); // expected-warning {{Element{HeapSymRegion{conj}}
+ clang_analyzer_dumpExtent(a); // expected-warning {{12 U64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{3 S64b}}
+}
+
+void symbolic_complex() {
+ int *a = (int *)malloc(4);
+ clang_analyzer_dumpExtent(a); // expected-warning {{4 U64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{1 S64b}}
+
+ int *b = (int *)realloc(a, sizeof(int) * 2);
+ clang_analyzer_dumpExtent(b); // expected-warning {{8 U64b}}
+ clang_analyzer_dumpElementCount(b); // expected-warning {{2 S64b}}
+ free(b);
+
+ int *c = (int *)calloc(3, 4);
+ clang_analyzer_dumpExtent(c); // expected-warning {{12 U64b}}
+ clang_analyzer_dumpElementCount(c); // expected-warning {{3 S64b}}
+ free(c);
+}
Index: clang/test/Analysis/expr-inspection.cpp
===================================================================
--- clang/test/Analysis/expr-inspection.cpp
+++ clang/test/Analysis/expr-inspection.cpp
@@ -12,7 +12,7 @@
void foo(int x, unsigned y) {
clang_analyzer_denote(); // expected-warning{{clang_analyzer_denote() requires a symbol and a string literal}}
- clang_analyzer_express(); // expected-warning{{clang_analyzer_express() requires a symbol}}
+ clang_analyzer_express(); // expected-warning{{Missing argument}}
clang_analyzer_denote(x); // expected-warning{{clang_analyzer_denote() requires a symbol and a string literal}}
clang_analyzer_express(x); // expected-warning{{Unable to express}}
Index: clang/test/Analysis/explain-svals.cpp
===================================================================
--- clang/test/Analysis/explain-svals.cpp
+++ clang/test/Analysis/explain-svals.cpp
@@ -49,7 +49,7 @@
int *x = new int[ext];
clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}}
// Sic! What gets computed is the extent of the element-region.
- clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^signed 32-bit integer '4'$}}}}
+ clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}}
delete[] x;
}
Index: clang/lib/StaticAnalyzer/Core/MemRegion.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/MemRegion.cpp
+++ clang/lib/StaticAnalyzer/Core/MemRegion.cpp
@@ -28,6 +28,7 @@
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
@@ -667,13 +668,6 @@
// MemRegionManager methods.
//===----------------------------------------------------------------------===//
-static DefinedOrUnknownSVal getTypeSize(QualType Ty, ASTContext &Ctx,
- SValBuilder &SVB) {
- CharUnits Size = Ctx.getTypeSizeInChars(Ty);
- QualType SizeTy = SVB.getArrayIndexType();
- return SVB.makeIntVal(Size.getQuantity(), SizeTy);
-}
-
DefinedOrUnknownSVal MemRegionManager::getStaticSize(const MemRegion *MR,
SValBuilder &SVB) const {
const auto *SR = cast<SubRegion>(MR);
@@ -703,7 +697,7 @@
if (Ty->isIncompleteType())
return UnknownVal();
- return getTypeSize(Ty, Ctx, SVB);
+ return getElementSize(Ty, SVB);
}
case MemRegion::FieldRegionKind: {
// Force callers to deal with bitfields explicitly.
@@ -711,7 +705,7 @@
return UnknownVal();
QualType Ty = cast<TypedValueRegion>(SR)->getDesugaredValueType(Ctx);
- DefinedOrUnknownSVal Size = getTypeSize(Ty, Ctx, SVB);
+ DefinedOrUnknownSVal Size = getElementSize(Ty, SVB);
// A zero-length array at the end of a struct often stands for dynamically
// allocated extra memory.
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -10,15 +10,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/AST/Decl.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "PrettyStackTraceLocationContext.h"
#include "clang/AST/CXXInheritance.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/ConstructionContext.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/SaveAndRestore.h"
@@ -690,16 +691,15 @@
// See if we need to conjure a heap pointer instead of
// a regular unknown pointer.
- bool IsHeapPointer = false;
- if (const auto *CNE = dyn_cast<CXXNewExpr>(E))
- if (CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
- // FIXME: Delegate this to evalCall in MallocChecker?
- IsHeapPointer = true;
- }
+ const auto *CNE = dyn_cast<CXXNewExpr>(E);
+ if (CNE && CNE->getOperatorNew()->isReplaceableGlobalAllocationFunction()) {
+ R = svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count);
- R = IsHeapPointer ? svalBuilder.getConjuredHeapSymbolVal(E, LCtx, Count)
- : svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy,
- Count);
+ // FIXME: Delegate this to evalCall in MallocChecker?
+ State = setDynamicSize(State, R.getAsRegion(), CNE, LCtx, svalBuilder);
+ } else {
+ R = svalBuilder.conjureSymbolVal(nullptr, E, LCtx, ResultTy, Count);
+ }
}
return State->BindExpr(E, LCtx, R);
}
Index: clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -10,15 +10,16 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/ConstructionContext.h"
#include "clang/AST/DeclCXX.h"
-#include "clang/AST/StmtCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/Analysis/ConstructionContext.h"
#include "clang/Basic/PrettyStackTrace.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
using namespace clang;
using namespace ento;
@@ -790,11 +791,14 @@
// heap. We realize this is an approximation that might not correctly model
// a custom global allocator.
if (symVal.isUnknown()) {
- if (IsStandardGlobalOpNewFunction)
+ if (IsStandardGlobalOpNewFunction) {
symVal = svalBuilder.getConjuredHeapSymbolVal(CNE, LCtx, blockCount);
- else
+ State =
+ setDynamicSize(State, symVal.getAsRegion(), CNE, LCtx, svalBuilder);
+ } else {
symVal = svalBuilder.conjureSymbolVal(nullptr, CNE, LCtx, CNE->getType(),
blockCount);
+ }
}
CallEventManager &CEMgr = getStateManager().getCallEventManager();
Index: clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
+++ clang/lib/StaticAnalyzer/Core/DynamicSize.cpp
@@ -19,30 +19,86 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
+REGISTER_MAP_WITH_PROGRAMSTATE(DynamicSizeMap, const clang::ento::MemRegion *,
+ clang::ento::DefinedOrUnknownSVal)
+
namespace clang {
namespace ento {
+/// Helper to bypass the top-level ElementRegion of \p MR.
+static const MemRegion *getSuperRegion(const MemRegion *MR) {
+ assert(MR);
+ if (const auto *ER = MR->getAs<ElementRegion>())
+ MR = ER->getSuperRegion();
+ return MR;
+}
+
DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR,
SValBuilder &SVB) {
+ MR = getSuperRegion(MR);
+
+ if (const DefinedOrUnknownSVal *Size = State->get<DynamicSizeMap>(MR))
+ return *Size;
+
return MR->getMemRegionManager().getStaticSize(MR, SVB);
}
+DefinedOrUnknownSVal getElementSize(QualType Ty, SValBuilder &SVB) {
+ return SVB.makeIntVal(SVB.getContext().getTypeSizeInChars(Ty).getQuantity(),
+ SVB.getArrayIndexType());
+}
+
+static DefinedOrUnknownSVal getSize(ProgramStateRef State, SVal ElementCount,
+ QualType Ty, SValBuilder &SVB) {
+ DefinedOrUnknownSVal ElementSize = getElementSize(Ty, SVB);
+
+ return SVB
+ .evalBinOp(State, BO_Mul, ElementCount, ElementSize,
+ SVB.getArrayIndexType())
+ .castAs<DefinedOrUnknownSVal>();
+}
+
DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
const MemRegion *MR,
- SValBuilder &SVB,
- QualType ElementTy) {
- MemRegionManager &MemMgr = MR->getMemRegionManager();
- ASTContext &Ctx = MemMgr.getContext();
+ SValBuilder &SVB, QualType Ty) {
+ MR = getSuperRegion(MR);
DefinedOrUnknownSVal Size = getDynamicSize(State, MR, SVB);
- SVal ElementSizeV = SVB.makeIntVal(
- Ctx.getTypeSizeInChars(ElementTy).getQuantity(), SVB.getArrayIndexType());
+ SVal ElementSize = getElementSize(Ty, SVB);
SVal DivisionV =
- SVB.evalBinOp(State, BO_Div, Size, ElementSizeV, SVB.getArrayIndexType());
+ SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType());
return DivisionV.castAs<DefinedOrUnknownSVal>();
}
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+ DefinedOrUnknownSVal Size, SValBuilder &SVB) {
+ if (Size.isUnknown())
+ return State;
+
+ /* FIXME: Make this work.
+ if (const auto CI = Size.getAs<nonloc::ConcreteInt>())
+ assert(CI->getValue().isUnsigned());*/
+
+ MR = getSuperRegion(MR);
+ return State->set<DynamicSizeMap>(MR, Size);
+}
+
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+ const CXXNewExpr *NE,
+ const LocationContext *LCtx, SValBuilder &SVB) {
+ SVal ElementCount;
+ if (const Expr *SizeExpr = NE->getArraySize().getValueOr(nullptr)) {
+ ElementCount = State->getSVal(SizeExpr, LCtx);
+ } else {
+ ElementCount = SVB.makeIntVal(1, /*IsUnsigned=*/true);
+ }
+
+ return setDynamicSize(
+ State, MR, getSize(State, ElementCount, NE->getAllocatedType(), SVB),
+ SVB);
+}
+
} // namespace ento
} // namespace clang
Index: clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -94,6 +94,9 @@
return;
// FIXME: Handle multi-dimensional VLAs.
+ if (VLA->getElementType()->getAsArrayTypeUnsafe())
+ return;
+
const Expr *SE = VLA->getSizeExpr();
ProgramStateRef state = C.getState();
SVal sizeV = C.getSVal(SE);
@@ -166,18 +169,10 @@
SVal ArraySizeVal = svalBuilder.evalBinOpNN(
state, BO_Mul, ArrayLength, EleSizeVal.castAs<NonLoc>(), SizeTy);
- // Finally, assume that the array's size matches the given size.
- const LocationContext *LC = C.getLocationContext();
- DefinedOrUnknownSVal DynSize =
- getDynamicSize(state, state->getRegion(VD, LC), svalBuilder);
-
- DefinedOrUnknownSVal ArraySize = ArraySizeVal.castAs<DefinedOrUnknownSVal>();
- DefinedOrUnknownSVal sizeIsKnown =
- svalBuilder.evalEQ(state, DynSize, ArraySize);
- state = state->assume(sizeIsKnown, true);
-
- // Assume should not fail at this point.
- assert(state);
+ // Finally, set the size.
+ state =
+ setDynamicSize(state, state->getRegion(VD, C.getLocationContext()),
+ ArraySizeVal.castAs<DefinedOrUnknownSVal>(), svalBuilder);
// Remember our assumptions!
C.addTransition(state);
Index: clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -503,9 +503,6 @@
ProgramStateRef State,
AllocationFamily Family);
- static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE,
- ProgramStateRef State, SVal Target);
-
// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
llvm::Optional<ProgramStateRef>
@@ -1344,7 +1341,8 @@
// MallocUpdateRefState() instead of MallocMemAux() which breaks the
// existing binding.
State = MallocUpdateRefState(C, NE, State, Family, Target);
- State = addExtentSize(C, NE, State, Target);
+ State = setDynamicSize(State, Target.getAsRegion(), NE,
+ C.getLocationContext(), C.getSValBuilder());
State = ProcessZeroAllocCheck(C, NE, 0, State, Target);
C.addTransition(State);
}
@@ -1366,52 +1364,6 @@
}
}
-// Sets the extent value of the MemRegion allocated by
-// new expression NE to its size in Bytes.
-//
-ProgramStateRef MallocChecker::addExtentSize(CheckerContext &C,
- const CXXNewExpr *NE,
- ProgramStateRef State,
- SVal Target) {
- if (!State)
- return nullptr;
- SValBuilder &svalBuilder = C.getSValBuilder();
- SVal ElementCount;
- const SubRegion *Region;
- if (NE->isArray()) {
- const Expr *SizeExpr = *NE->getArraySize();
- ElementCount = C.getSVal(SizeExpr);
- // Store the extent size for the (symbolic)region
- // containing the elements.
- Region = Target.getAsRegion()
- ->castAs<SubRegion>()
- ->StripCasts()
- ->castAs<SubRegion>();
- } else {
- ElementCount = svalBuilder.makeIntVal(1, true);
- Region = Target.getAsRegion()->castAs<SubRegion>();
- }
-
- // Set the region's extent equal to the Size in Bytes.
- QualType ElementType = NE->getAllocatedType();
- ASTContext &AstContext = C.getASTContext();
- CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType);
-
- if (ElementCount.getAs<NonLoc>()) {
- DefinedOrUnknownSVal DynSize = getDynamicSize(State, Region, svalBuilder);
-
- // size in Bytes = ElementCount*TypeSize
- SVal SizeInBytes = svalBuilder.evalBinOpNN(
- State, BO_Mul, ElementCount.castAs<NonLoc>(),
- svalBuilder.makeArrayIndex(TypeSize.getQuantity()),
- svalBuilder.getArrayIndexType());
- DefinedOrUnknownSVal DynSizeMatchesSize = svalBuilder.evalEQ(
- State, DynSize, SizeInBytes.castAs<DefinedOrUnknownSVal>());
- State = State->assume(DynSizeMatchesSize, true);
- }
- return State;
-}
-
void MallocChecker::checkPreStmt(const CXXDeleteExpr *DE,
CheckerContext &C) const {
@@ -1531,21 +1483,9 @@
// Fill the region with the initialization value.
State = State->bindDefaultInitial(RetVal, Init, LCtx);
- // Set the region's extent equal to the Size parameter.
- const SymbolicRegion *R =
- dyn_cast_or_null<SymbolicRegion>(RetVal.getAsRegion());
- if (!R)
- return nullptr;
- if (Optional<DefinedOrUnknownSVal> DefinedSize =
- Size.getAs<DefinedOrUnknownSVal>()) {
- DefinedOrUnknownSVal DynSize = getDynamicSize(State, R, svalBuilder);
-
- DefinedOrUnknownSVal DynSizeMatchesSize =
- svalBuilder.evalEQ(State, DynSize, *DefinedSize);
-
- State = State->assume(DynSizeMatchesSize, true);
- assert(State);
- }
+ // Set the region's size.
+ State = setDynamicSize(State, RetVal.getAsRegion(),
+ Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
return MallocUpdateRefState(C, CE, State, Family);
}
Index: clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -22,8 +22,8 @@
using namespace ento;
namespace {
-class ExprInspectionChecker : public Checker<eval::Call, check::DeadSymbols,
- check::EndAnalysis> {
+class ExprInspectionChecker
+ : public Checker<eval::Call, check::DeadSymbols, check::EndAnalysis> {
mutable std::unique_ptr<BugType> BT;
// These stats are per-analysis, not per-branch, hence they shouldn't
@@ -44,6 +44,8 @@
void analyzerExplain(const CallExpr *CE, CheckerContext &C) const;
void analyzerPrintState(const CallExpr *CE, CheckerContext &C) const;
void analyzerGetExtent(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerDumpExtent(const CallExpr *CE, CheckerContext &C) const;
+ void analyzerDumpElementCount(const CallExpr *CE, CheckerContext &C) const;
void analyzerHashDump(const CallExpr *CE, CheckerContext &C) const;
void analyzerDenote(const CallExpr *CE, CheckerContext &C) const;
void analyzerExpress(const CallExpr *CE, CheckerContext &C) const;
@@ -59,13 +61,16 @@
ExplodedNode *N,
Optional<SVal> ExprVal = None) const;
+ const Expr *getArgExpr(const CallExpr *CE, CheckerContext &C) const;
+ const MemRegion *getArgRegion(const CallExpr *CE, CheckerContext &C) const;
+
public:
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
void checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng) const;
};
-}
+} // namespace
REGISTER_SET_WITH_PROGRAMSTATE(MarkedSymbols, SymbolRef)
REGISTER_MAP_WITH_PROGRAMSTATE(DenotedSymbols, SymbolRef, const StringLiteral *)
@@ -90,6 +95,10 @@
&ExprInspectionChecker::analyzerWarnOnDeadSymbol)
.StartsWith("clang_analyzer_explain",
&ExprInspectionChecker::analyzerExplain)
+ .Case("clang_analyzer_dumpExtent",
+ &ExprInspectionChecker::analyzerDumpExtent)
+ .Case("clang_analyzer_dumpElementCount",
+ &ExprInspectionChecker::analyzerDumpElementCount)
.StartsWith("clang_analyzer_dump",
&ExprInspectionChecker::analyzerDump)
.Case("clang_analyzer_getExtent",
@@ -131,7 +140,7 @@
ProgramStateRef StTrue, StFalse;
std::tie(StTrue, StFalse) =
- State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
+ State->assume(AssertionVal.castAs<DefinedOrUnknownSVal>());
if (StTrue) {
if (StFalse)
@@ -172,6 +181,30 @@
return N;
}
+const Expr *ExprInspectionChecker::getArgExpr(const CallExpr *CE,
+ CheckerContext &C) const {
+ if (CE->getNumArgs() == 0) {
+ reportBug("Missing argument", C);
+ return nullptr;
+ }
+ return CE->getArg(0);
+}
+
+const MemRegion *ExprInspectionChecker::getArgRegion(const CallExpr *CE,
+ CheckerContext &C) const {
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
+ return nullptr;
+
+ const MemRegion *MR = C.getSVal(Arg).getAsRegion();
+ if (!MR) {
+ reportBug("Cannot obtain the region", C);
+ return nullptr;
+ }
+
+ return MR;
+}
+
void ExprInspectionChecker::analyzerEval(const CallExpr *CE,
CheckerContext &C) const {
const LocationContext *LC = C.getPredecessor()->getLocationContext();
@@ -215,24 +248,22 @@
void ExprInspectionChecker::analyzerExplain(const CallExpr *CE,
CheckerContext &C) const {
- if (CE->getNumArgs() == 0) {
- reportBug("Missing argument for explaining", C);
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
- }
- SVal V = C.getSVal(CE->getArg(0));
+ SVal V = C.getSVal(Arg);
SValExplainer Ex(C.getASTContext());
reportBug(Ex.Visit(V), C);
}
void ExprInspectionChecker::analyzerDump(const CallExpr *CE,
CheckerContext &C) const {
- if (CE->getNumArgs() == 0) {
- reportBug("Missing argument for dumping", C);
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
- }
- SVal V = C.getSVal(CE->getArg(0));
+ SVal V = C.getSVal(Arg);
llvm::SmallString<32> Str;
llvm::raw_svector_ostream OS(Str);
@@ -242,16 +273,9 @@
void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
CheckerContext &C) const {
- if (CE->getNumArgs() == 0) {
- reportBug("Missing region for obtaining extent", C);
+ const MemRegion *MR = getArgRegion(CE, C);
+ if (!MR)
return;
- }
-
- auto MR = dyn_cast_or_null<SubRegion>(C.getSVal(CE->getArg(0)).getAsRegion());
- if (!MR) {
- reportBug("Obtaining extent of a non-region", C);
- return;
- }
ProgramStateRef State = C.getState();
DefinedOrUnknownSVal Size = getDynamicSize(State, MR, C.getSValBuilder());
@@ -260,6 +284,43 @@
C.addTransition(State);
}
+void ExprInspectionChecker::analyzerDumpExtent(const CallExpr *CE,
+ CheckerContext &C) const {
+ const MemRegion *MR = getArgRegion(CE, C);
+ if (!MR)
+ return;
+
+ DefinedOrUnknownSVal Size =
+ getDynamicSize(C.getState(), MR, C.getSValBuilder());
+
+ SmallString<128> Msg;
+ llvm::raw_svector_ostream Out(Msg);
+ Out << Size;
+ reportBug(Out.str(), C);
+}
+
+void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE,
+ CheckerContext &C) const {
+ const MemRegion *MR = getArgRegion(CE, C);
+ if (!MR)
+ return;
+
+ const auto *TVR = MR->getAs<TypedValueRegion>();
+
+ QualType Ty = TVR ? TVR->getValueType()
+ : CE->getArg(0)->IgnoreParenImpCasts()->getType();
+ if (Ty->isPointerType())
+ Ty = Ty->getPointeeType();
+
+ DefinedOrUnknownSVal ElementCount =
+ getDynamicElementCount(C.getState(), MR, C.getSValBuilder(), Ty);
+
+ SmallString<128> Msg;
+ llvm::raw_svector_ostream Out(Msg);
+ Out << ElementCount;
+ reportBug(Out.str(), C);
+}
+
void ExprInspectionChecker::analyzerPrintState(const CallExpr *CE,
CheckerContext &C) const {
C.getState()->dump();
@@ -267,9 +328,11 @@
void ExprInspectionChecker::analyzerWarnOnDeadSymbol(const CallExpr *CE,
CheckerContext &C) const {
- if (CE->getNumArgs() == 0)
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
- SVal Val = C.getSVal(CE->getArg(0));
+
+ SVal Val = C.getSVal(Arg);
SymbolRef Sym = Val.getAsSymbol();
if (!Sym)
return;
@@ -306,7 +369,7 @@
void ExprInspectionChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &BR,
ExprEngine &Eng) const {
- for (auto Item: ReachedStats) {
+ for (auto Item : ReachedStats) {
unsigned NumTimesReached = Item.second.NumTimesReached;
ExplodedNode *N = Item.second.ExampleNode;
@@ -373,9 +436,7 @@
return None;
}
- Optional<std::string> VisitSymExpr(const SymExpr *S) {
- return lookup(S);
- }
+ Optional<std::string> VisitSymExpr(const SymExpr *S) { return lookup(S); }
Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
if (Optional<std::string> Str = lookup(S))
@@ -394,7 +455,8 @@
if (Optional<std::string> Str1 = Visit(S->getLHS()))
if (Optional<std::string> Str2 = Visit(S->getRHS()))
return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) +
- " " + *Str2).str();
+ " " + *Str2)
+ .str();
return None;
}
@@ -410,10 +472,9 @@
void ExprInspectionChecker::analyzerExpress(const CallExpr *CE,
CheckerContext &C) const {
- if (CE->getNumArgs() == 0) {
- reportBug("clang_analyzer_express() requires a symbol", C);
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
- }
SVal ArgVal = C.getSVal(CE->getArg(0));
SymbolRef Sym = ArgVal.getAsSymbol();
Index: clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -90,12 +90,8 @@
if (Size.isUndef())
return true; // Return true to model purity.
- SValBuilder& svalBuilder = C.getSValBuilder();
- DefinedOrUnknownSVal DynSize = getDynamicSize(state, R, svalBuilder);
- DefinedOrUnknownSVal DynSizeMatchesSizeArg =
- svalBuilder.evalEQ(state, DynSize, Size.castAs<DefinedOrUnknownSVal>());
- state = state->assume(DynSizeMatchesSizeArg, true);
- assert(state && "The region should not have any previous constraints");
+ state = setDynamicSize(state, R, Size.castAs<DefinedOrUnknownSVal>(),
+ C.getSValBuilder());
C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
return true;
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h
@@ -22,15 +22,26 @@
namespace clang {
namespace ento {
-/// Get the stored dynamic size for the region \p MR.
+/// \returns The stored dynamic size for the region \p MR.
DefinedOrUnknownSVal getDynamicSize(ProgramStateRef State, const MemRegion *MR,
SValBuilder &SVB);
-/// Get the stored element count of the region \p MR.
+/// \returns The element size of the type \p Ty.
+DefinedOrUnknownSVal getElementSize(QualType Ty, SValBuilder &SVB);
+
+/// \returns The stored element count of the region \p MR.
DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
const MemRegion *MR,
- SValBuilder &SVB,
- QualType ElementTy);
+ SValBuilder &SVB, QualType Ty);
+
+/// Set the dynamic size \p Size of the region \p MR.
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+ DefinedOrUnknownSVal Size, SValBuilder &SVB);
+
+/// Set the dynamic size of a CXXNewExpr \p NE by its region \p MR.
+ProgramStateRef setDynamicSize(ProgramStateRef State, const MemRegion *MR,
+ const CXXNewExpr *NE,
+ const LocationContext *LCtx, SValBuilder &SVB);
} // namespace ento
} // namespace clang
Index: clang/docs/analyzer/developer-docs/DebugChecks.rst
===================================================================
--- clang/docs/analyzer/developer-docs/DebugChecks.rst
+++ clang/docs/analyzer/developer-docs/DebugChecks.rst
@@ -297,6 +297,19 @@
return n;
}
+- ``clang_analyzer_dumpExtent(a single argument of any type)``
+- ``clang_analyzer_dumpElementCount(a single argument of any type)``
+
+ Dumps out the extent and the element count of the argument.
+
+ Example usage::
+
+ void array() {
+ int a[] = {1, 3};
+ clang_analyzer_dumpExtent(a); // expected-warning {{8 S64b}}
+ clang_analyzer_dumpElementCount(a); // expected-warning {{2 S64b}}
+ }
+
Statistics
==========
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits