summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp80
1 files changed, 55 insertions, 25 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index ca4be178c85..a1a540c4b96 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -162,6 +162,7 @@ class MallocChecker : public Checker<check::DeadSymbols,
check::PreCall,
check::PostStmt<CallExpr>,
check::PostStmt<CXXNewExpr>,
+ check::NewAllocator,
check::PreStmt<CXXDeleteExpr>,
check::PostStmt<BlockExpr>,
check::PostObjCMessage,
@@ -207,6 +208,8 @@ public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const;
+ void checkNewAllocator(const CXXNewExpr *NE, SVal Target,
+ CheckerContext &C) const;
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const;
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
@@ -281,10 +284,18 @@ private:
bool isStandardNewDelete(const FunctionDecl *FD, ASTContext &C) const;
///@}
+ /// \brief Process C++ operator new()'s allocation, which is the part of C++
+ /// new-expression that goes before the constructor.
+ void processNewAllocation(const CXXNewExpr *NE, CheckerContext &C,
+ SVal Target) const;
+
/// \brief Perform a zero-allocation check.
+ /// The optional \p RetVal parameter specifies the newly allocated pointer
+ /// value; if unspecified, the value of expression \p E is used.
ProgramStateRef ProcessZeroAllocation(CheckerContext &C, const Expr *E,
const unsigned AllocationSizeArg,
- ProgramStateRef State) const;
+ ProgramStateRef State,
+ Optional<SVal> RetVal = None) const;
ProgramStateRef MallocMemReturnsAttr(CheckerContext &C,
const CallExpr *CE,
@@ -300,7 +311,7 @@ private:
AllocationFamily Family = AF_Malloc);
static ProgramStateRef addExtentSize(CheckerContext &C, const CXXNewExpr *NE,
- ProgramStateRef State);
+ 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).
@@ -309,9 +320,12 @@ private:
const ProgramStateRef &State) const;
/// Update the RefState to reflect the new memory allocation.
+ /// The optional \p RetVal parameter specifies the newly allocated pointer
+ /// value; if unspecified, the value of expression \p E is used.
static ProgramStateRef
MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
- AllocationFamily Family = AF_Malloc);
+ AllocationFamily Family = AF_Malloc,
+ Optional<SVal> RetVal = None);
ProgramStateRef FreeMemAttr(CheckerContext &C, const CallExpr *CE,
const OwnershipAttr* Att,
@@ -949,13 +963,15 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const {
}
// Performs a 0-sized allocations check.
-ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
- const Expr *E,
- const unsigned AllocationSizeArg,
- ProgramStateRef State) const {
+ProgramStateRef MallocChecker::ProcessZeroAllocation(
+ CheckerContext &C, const Expr *E, const unsigned AllocationSizeArg,
+ ProgramStateRef State, Optional<SVal> RetVal) const {
if (!State)
return nullptr;
+ if (!RetVal)
+ RetVal = C.getSVal(E);
+
const Expr *Arg = nullptr;
if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
@@ -987,8 +1003,7 @@ ProgramStateRef MallocChecker::ProcessZeroAllocation(CheckerContext &C,
State->assume(SvalBuilder.evalEQ(State, *DefArgVal, Zero));
if (TrueState && !FalseState) {
- SVal retVal = C.getSVal(E);
- SymbolRef Sym = retVal.getAsLocSymbol();
+ SymbolRef Sym = RetVal->getAsLocSymbol();
if (!Sym)
return State;
@@ -1049,9 +1064,9 @@ static bool treatUnusedNewEscaped(const CXXNewExpr *NE) {
return false;
}
-void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
- CheckerContext &C) const {
-
+void MallocChecker::processNewAllocation(const CXXNewExpr *NE,
+ CheckerContext &C,
+ SVal Target) const {
if (NE->getNumPlacementArgs())
for (CXXNewExpr::const_arg_iterator I = NE->placement_arg_begin(),
E = NE->placement_arg_end(); I != E; ++I)
@@ -1071,37 +1086,48 @@ void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
// MallocUpdateRefState() instead of MallocMemAux() which breakes the
// existing binding.
State = MallocUpdateRefState(C, NE, State, NE->isArray() ? AF_CXXNewArray
- : AF_CXXNew);
- State = addExtentSize(C, NE, State);
- State = ProcessZeroAllocation(C, NE, 0, State);
+ : AF_CXXNew, Target);
+ State = addExtentSize(C, NE, State, Target);
+ State = ProcessZeroAllocation(C, NE, 0, State, Target);
C.addTransition(State);
}
+void MallocChecker::checkPostStmt(const CXXNewExpr *NE,
+ CheckerContext &C) const {
+ if (!C.getAnalysisManager().getAnalyzerOptions().mayInlineCXXAllocator())
+ processNewAllocation(NE, C, C.getSVal(NE));
+}
+
+void MallocChecker::checkNewAllocator(const CXXNewExpr *NE, SVal Target,
+ CheckerContext &C) const {
+ if (!C.wasInlined)
+ processNewAllocation(NE, C, Target);
+}
+
// 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) {
+ ProgramStateRef State,
+ SVal Target) {
if (!State)
return nullptr;
SValBuilder &svalBuilder = C.getSValBuilder();
SVal ElementCount;
- const LocationContext *LCtx = C.getLocationContext();
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 = (State->getSVal(NE, LCtx))
- .getAsRegion()
+ Region = Target.getAsRegion()
->getAs<SubRegion>()
- ->getSuperRegion()
+ ->StripCasts()
->getAs<SubRegion>();
} else {
ElementCount = svalBuilder.makeIntVal(1, true);
- Region = (State->getSVal(NE, LCtx)).getAsRegion()->getAs<SubRegion>();
+ Region = Target.getAsRegion()->getAs<SubRegion>();
}
assert(Region);
@@ -1261,18 +1287,22 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
ProgramStateRef MallocChecker::MallocUpdateRefState(CheckerContext &C,
const Expr *E,
ProgramStateRef State,
- AllocationFamily Family) {
+ AllocationFamily Family,
+ Optional<SVal> RetVal) {
if (!State)
return nullptr;
// Get the return value.
- SVal retVal = C.getSVal(E);
+ if (!RetVal)
+ RetVal = C.getSVal(E);
// We expect the malloc functions to return a pointer.
- if (!retVal.getAs<Loc>())
+ if (!RetVal->getAs<Loc>())
return nullptr;
- SymbolRef Sym = retVal.getAsLocSymbol();
+ SymbolRef Sym = RetVal->getAsLocSymbol();
+ // This is a return value of a function that was not inlined, such as malloc()
+ // or new(). We've checked that in the caller. Therefore, it must be a symbol.
assert(Sym);
// Set the symbol's state to Allocated.
OpenPOWER on IntegriCloud