summaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
commitc0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch)
treef42add1021b9f2ac6a69ac7cf6c4499962739a45 /clang/lib/StaticAnalyzer/Checkers
parent344a3780b2e33f6ca763666c380202b18aab72a3 (diff)
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp50
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp19
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp19
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp203
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp39
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp43
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp86
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp24
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp105
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp24
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp280
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp3
46 files changed, 877 insertions, 238 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index c06604b6cffe..6154eeb3419c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -93,11 +93,10 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (!Loc.isValid())
return;
- if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
+ if (isa<FunctionDecl, ObjCMethodDecl>(D)) {
const NamedDecl *ND = cast<NamedDecl>(D);
output << *ND;
- }
- else if (isa<BlockDecl>(D)) {
+ } else if (isa<BlockDecl>(D)) {
output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index a86a410ebcbc..2c210fb6cdb9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -12,7 +12,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
@@ -20,9 +19,11 @@
#include "clang/AST/StmtObjC.h"
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/Analysis/SelectorExtras.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
@@ -533,10 +534,12 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
namespace {
class CFRetainReleaseChecker : public Checker<check::PreCall> {
mutable APIMisuse BT{this, "null passed to CF memory management function"};
- CallDescription CFRetain{"CFRetain", 1},
- CFRelease{"CFRelease", 1},
- CFMakeCollectable{"CFMakeCollectable", 1},
- CFAutorelease{"CFAutorelease", 1};
+ const CallDescriptionSet ModelledCalls = {
+ {"CFRetain", 1},
+ {"CFRelease", 1},
+ {"CFMakeCollectable", 1},
+ {"CFAutorelease", 1},
+ };
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@@ -550,8 +553,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
return;
// Check if we called CFRetain/CFRelease/CFMakeCollectable/CFAutorelease.
- if (!(Call.isCalled(CFRetain) || Call.isCalled(CFRelease) ||
- Call.isCalled(CFMakeCollectable) || Call.isCalled(CFAutorelease)))
+ if (!ModelledCalls.contains(Call))
return;
// Get the argument's value.
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 2752b37f9b3f..8416ab39e194 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -96,14 +97,7 @@ void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const {
}
bool BlockInCriticalSectionChecker::isBlockingFunction(const CallEvent &Call) const {
- if (Call.isCalled(SleepFn)
- || Call.isCalled(GetcFn)
- || Call.isCalled(FgetsFn)
- || Call.isCalled(ReadFn)
- || Call.isCalled(RecvFn)) {
- return true;
- }
- return false;
+ return matchesAny(Call, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn);
}
bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const {
@@ -113,15 +107,8 @@ bool BlockInCriticalSectionChecker::isLockFunction(const CallEvent &Call) const
return true;
}
- if (Call.isCalled(LockFn)
- || Call.isCalled(PthreadLockFn)
- || Call.isCalled(PthreadTryLockFn)
- || Call.isCalled(MtxLock)
- || Call.isCalled(MtxTimedLock)
- || Call.isCalled(MtxTryLock)) {
- return true;
- }
- return false;
+ return matchesAny(Call, LockFn, PthreadLockFn, PthreadTryLockFn, MtxLock,
+ MtxTimedLock, MtxTryLock);
}
bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) const {
@@ -132,12 +119,7 @@ bool BlockInCriticalSectionChecker::isUnlockFunction(const CallEvent &Call) cons
return true;
}
- if (Call.isCalled(UnlockFn)
- || Call.isCalled(PthreadUnlockFn)
- || Call.isCalled(MtxUnlock)) {
- return true;
- }
- return false;
+ return matchesAny(Call, UnlockFn, PthreadUnlockFn, MtxUnlock);
}
void BlockInCriticalSectionChecker::checkPostCall(const CallEvent &Call,
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 69b90be9aa7e..475cee9ce04b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
@@ -2271,11 +2272,10 @@ CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call,
if (!FD)
return nullptr;
- if (Call.isCalled(StdCopy)) {
+ if (StdCopy.matches(Call))
return &CStringChecker::evalStdCopy;
- } else if (Call.isCalled(StdCopyBackward)) {
+ if (StdCopyBackward.matches(Call))
return &CStringChecker::evalStdCopyBackward;
- }
// Pro-actively check that argument types are safe to do arithmetic upon.
// We do not want to crash if someone accidentally passes a structure
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
index 131c1345af99..4235c0c13821 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
index 175dfcef0df4..a13de306eac8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCInstMethSignature.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a CheckObjCInstMethSignature, a flow-insenstive check
+// This file defines a CheckObjCInstMethSignature, a flow-insensitive check
// that determines if an Objective-C class interface incorrectly redefines
// the method signature in a subclass.
//
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index d06c87631bfb..61ff5e59f06d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -785,9 +785,8 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
// real flow analysis.
auto FormatString =
dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
- if (FormatString &&
- FormatString->getString().find("%s") == StringRef::npos &&
- FormatString->getString().find("%[") == StringRef::npos)
+ if (FormatString && !FormatString->getString().contains("%s") &&
+ !FormatString->getString().contains("%["))
BoundsProvided = true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index fd53c04f4bbf..ce8d6c879870 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
@@ -63,11 +64,11 @@ private:
} // end anonymous namespace
bool ChrootChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
- if (Call.isCalled(Chroot)) {
+ if (Chroot.matches(Call)) {
evalChroot(Call, C);
return true;
}
- if (Call.isCalled(Chdir)) {
+ if (Chdir.matches(Call)) {
evalChdir(Call, C);
return true;
}
@@ -115,7 +116,7 @@ void ChrootChecker::evalChdir(const CallEvent &Call, CheckerContext &C) const {
void ChrootChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
// Ignore chroot and chdir.
- if (Call.isCalled(Chroot) || Call.isCalled(Chdir))
+ if (matchesAny(Call, Chroot, Chdir))
return;
// If jail state is ROOT_CHANGED, generate BugReport.
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 1a7f0d5ab74c..77a3218f55fb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -10,11 +10,12 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Driver/DriverDiagnostic.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
@@ -71,42 +72,27 @@ public:
SVal) const;
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
- {{0, "clear", 0},
- &ContainerModeling::handleClear},
- {{0, "assign", 2},
- &ContainerModeling::handleAssign},
- {{0, "push_back", 1},
- &ContainerModeling::handlePushBack},
- {{0, "emplace_back", 1},
- &ContainerModeling::handlePushBack},
- {{0, "pop_back", 0},
- &ContainerModeling::handlePopBack},
- {{0, "push_front", 1},
- &ContainerModeling::handlePushFront},
- {{0, "emplace_front", 1},
- &ContainerModeling::handlePushFront},
- {{0, "pop_front", 0},
- &ContainerModeling::handlePopFront},
+ {{"clear", 0}, &ContainerModeling::handleClear},
+ {{"assign", 2}, &ContainerModeling::handleAssign},
+ {{"push_back", 1}, &ContainerModeling::handlePushBack},
+ {{"emplace_back", 1}, &ContainerModeling::handlePushBack},
+ {{"pop_back", 0}, &ContainerModeling::handlePopBack},
+ {{"push_front", 1}, &ContainerModeling::handlePushFront},
+ {{"emplace_front", 1}, &ContainerModeling::handlePushFront},
+ {{"pop_front", 0}, &ContainerModeling::handlePopFront},
};
-
+
CallDescriptionMap<OneItParamFn> OneIterParamFunctions = {
- {{0, "insert", 2},
- &ContainerModeling::handleInsert},
- {{0, "emplace", 2},
- &ContainerModeling::handleInsert},
- {{0, "erase", 1},
- &ContainerModeling::handleErase},
- {{0, "erase_after", 1},
- &ContainerModeling::handleEraseAfter},
+ {{"insert", 2}, &ContainerModeling::handleInsert},
+ {{"emplace", 2}, &ContainerModeling::handleInsert},
+ {{"erase", 1}, &ContainerModeling::handleErase},
+ {{"erase_after", 1}, &ContainerModeling::handleEraseAfter},
};
-
+
CallDescriptionMap<TwoItParamFn> TwoIterParamFunctions = {
- {{0, "erase", 2},
- &ContainerModeling::handleErase},
- {{0, "erase_after", 2},
- &ContainerModeling::handleEraseAfter},
+ {{"erase", 2}, &ContainerModeling::handleErase},
+ {{"erase_after", 2}, &ContainerModeling::handleEraseAfter},
};
-
};
bool isBeginCall(const FunctionDecl *Func);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 4216a6883119..8da482a2aec9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -49,7 +49,8 @@ private:
bool isLossOfSign(const ImplicitCastExpr *Cast, CheckerContext &C) const;
- void reportBug(ExplodedNode *N, CheckerContext &C, const char Msg[]) const;
+ void reportBug(ExplodedNode *N, const Expr *E, CheckerContext &C,
+ const char Msg[]) const;
};
}
@@ -108,20 +109,21 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
if (!N)
return;
if (LossOfSign)
- reportBug(N, C, "Loss of sign in implicit conversion");
+ reportBug(N, Cast, C, "Loss of sign in implicit conversion");
if (LossOfPrecision)
- reportBug(N, C, "Loss of precision in implicit conversion");
+ reportBug(N, Cast, C, "Loss of precision in implicit conversion");
}
}
-void ConversionChecker::reportBug(ExplodedNode *N, CheckerContext &C,
- const char Msg[]) const {
+void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E,
+ CheckerContext &C, const char Msg[]) const {
if (!BT)
BT.reset(
new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
// Generate a report for this bug.
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
+ bugreporter::trackExpressionValue(N, E, *R);
C.emitReport(std::move(R));
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
index 6fed999ffc80..47fd57c7db9b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -40,10 +41,10 @@ class DebugContainerModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{0, "clang_analyzer_container_begin", 1},
- &DebugContainerModeling::analyzerContainerBegin},
- {{0, "clang_analyzer_container_end", 1},
- &DebugContainerModeling::analyzerContainerEnd},
+ {{"clang_analyzer_container_begin", 1},
+ &DebugContainerModeling::analyzerContainerBegin},
+ {{"clang_analyzer_container_end", 1},
+ &DebugContainerModeling::analyzerContainerEnd},
};
public:
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
index 5833eea56da8..6add9a007a87 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -41,12 +42,12 @@ class DebugIteratorModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{0, "clang_analyzer_iterator_position", 1},
- &DebugIteratorModeling::analyzerIteratorPosition},
- {{0, "clang_analyzer_iterator_container", 1},
- &DebugIteratorModeling::analyzerIteratorContainer},
- {{0, "clang_analyzer_iterator_validity", 1},
- &DebugIteratorModeling::analyzerIteratorValidity},
+ {{"clang_analyzer_iterator_position", 1},
+ &DebugIteratorModeling::analyzerIteratorPosition},
+ {{"clang_analyzer_iterator_container", 1},
+ &DebugIteratorModeling::analyzerIteratorContainer},
+ {{"clang_analyzer_iterator_validity", 1},
+ &DebugIteratorModeling::analyzerIteratorValidity},
};
public:
diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
index df88b71ff063..49486ea796c2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp
@@ -44,8 +44,8 @@ static bool DefaultMethodFilter(const ObjCMethodDecl *M) {
M->getMethodFamily() == OMF_dealloc ||
M->getMethodFamily() == OMF_copy ||
M->getMethodFamily() == OMF_mutableCopy ||
- M->getSelector().getNameForSlot(0).find("init") != StringRef::npos ||
- M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos;
+ M->getSelector().getNameForSlot(0).contains("init") ||
+ M->getSelector().getNameForSlot(0).contains("Init");
}
class DirectIvarAssignment :
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 14ba5d769969..b07f59125a82 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -384,7 +384,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
// FIXME: Instead of relying on the ParentMap, we should have the
// trigger-statement (InitListExpr in this case) available in this
// callback, ideally as part of CallEvent.
- if (dyn_cast_or_null<InitListExpr>(
+ if (isa_and_nonnull<InitListExpr>(
LCtx->getParentMap().getParent(Ctor->getOriginExpr())))
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index 0e94b915a468..e5088fb266bc 100644
--- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -94,10 +94,10 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
// Only perform enum range check on casts where such checks are valid. For
// all other cast kinds (where enum range checks are unnecessary or invalid),
- // just return immediately. TODO: The set of casts whitelisted for enum
- // range checking may be incomplete. Better to add a missing cast kind to
- // enable a missing check than to generate false negatives and have to remove
- // those later.
+ // just return immediately. TODO: The set of casts allowed for enum range
+ // checking may be incomplete. Better to add a missing cast kind to enable a
+ // missing check than to generate false negatives and have to remove those
+ // later.
switch (CE->getCastKind()) {
case CK_IntegralCast:
break;
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 42c777eb2c52..66ef781871ec 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -260,7 +260,7 @@ private:
}
bool isDestinationArgument(unsigned ArgNum) const {
- return (llvm::find(DstArgs, ArgNum) != DstArgs.end());
+ return llvm::is_contained(DstArgs, ArgNum);
}
static bool isTaintedOrPointsToTainted(const Expr *E,
@@ -435,7 +435,6 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
.Case("getch", {{}, {ReturnValueIndex}})
.Case("getchar", {{}, {ReturnValueIndex}})
.Case("getchar_unlocked", {{}, {ReturnValueIndex}})
- .Case("getenv", {{}, {ReturnValueIndex}})
.Case("gets", {{}, {0, ReturnValueIndex}})
.Case("scanf", {{}, {}, VariadicType::Dst, 1})
.Case("socket", {{},
@@ -468,6 +467,16 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
if (!Rule.isNull())
return Rule;
+
+ // `getenv` returns taint only in untrusted environments.
+ if (FData.FullName == "getenv") {
+ if (C.getAnalysisManager()
+ .getAnalyzerOptions()
+ .ShouldAssumeControlledEnvironment)
+ return {};
+ return {{}, {ReturnValueIndex}};
+ }
+
assert(FData.FDecl);
// Check if it's one of the memory setting/copying functions.
@@ -505,7 +514,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
if (OneOf("snprintf"))
return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 3};
if (OneOf("sprintf"))
- return {{}, {0, ReturnValueIndex}, VariadicType::Src, 2};
+ return {{1}, {0, ReturnValueIndex}, VariadicType::Src, 2};
if (OneOf("strcpy", "stpcpy", "strcat"))
return {{1}, {0, ReturnValueIndex}};
if (OneOf("bcopy"))
@@ -780,7 +789,7 @@ bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
// variable named stdin with the proper type.
if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
D = D->getCanonicalDecl();
- if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC()) {
+ if (D->getName().contains("stdin") && D->isExternC()) {
const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr());
if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
C.getASTContext().getFILEType().getCanonicalType())
@@ -807,7 +816,7 @@ static bool getPrintfFormatArgumentNum(const CallEvent &Call,
}
// Or if a function is named setproctitle (this is a heuristic).
- if (C.getCalleeName(FDecl).find("setproctitle") != StringRef::npos) {
+ if (C.getCalleeName(FDecl).contains("setproctitle")) {
ArgNum = 0;
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index bcae73378028..6f9867b9607d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -13,11 +13,12 @@
//===----------------------------------------------------------------------===//
#include "AllocationState.h"
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "InterCheckerAPI.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -125,19 +126,15 @@ bool InnerPointerChecker::isInvalidatingMemberFunction(
return true;
return false;
}
- return (isa<CXXDestructorCall>(Call) || Call.isCalled(AppendFn) ||
- Call.isCalled(AssignFn) || Call.isCalled(ClearFn) ||
- Call.isCalled(EraseFn) || Call.isCalled(InsertFn) ||
- Call.isCalled(PopBackFn) || Call.isCalled(PushBackFn) ||
- Call.isCalled(ReplaceFn) || Call.isCalled(ReserveFn) ||
- Call.isCalled(ResizeFn) || Call.isCalled(ShrinkToFitFn) ||
- Call.isCalled(SwapFn));
+ return isa<CXXDestructorCall>(Call) ||
+ matchesAny(Call, AppendFn, AssignFn, ClearFn, EraseFn, InsertFn,
+ PopBackFn, PushBackFn, ReplaceFn, ReserveFn, ResizeFn,
+ ShrinkToFitFn, SwapFn);
}
bool InnerPointerChecker::isInnerPointerAccessFunction(
const CallEvent &Call) const {
- return (Call.isCalled(CStrFn) || Call.isCalled(DataFn) ||
- Call.isCalled(DataMemberFn));
+ return matchesAny(Call, CStrFn, DataFn, DataMemberFn);
}
void InnerPointerChecker::markPtrSymbolsReleased(const CallEvent &Call,
@@ -184,7 +181,7 @@ void InnerPointerChecker::checkFunctionArguments(const CallEvent &Call,
// std::addressof function accepts a non-const reference as an argument,
// but doesn't modify it.
- if (Call.isCalled(AddressofFn))
+ if (AddressofFn.matches(Call))
continue;
markPtrSymbolsReleased(Call, State, ArgRegion, C);
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
index ab5e6a1c9991..235c9010412a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp
@@ -64,10 +64,11 @@
// making an assumption e.g. `S1 + n == S2 + m` we store `S1 - S2 == m - n` as
// a constraint which we later retrieve when doing an actual comparison.
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
index a47484497771..c682449921ac 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -14,10 +14,10 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-
#include "Iterator.h"
using namespace clang;
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index 28d3e058fee2..b57c5dc6de56 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -949,7 +949,7 @@ void NonLocalizedStringChecker::checkPostCall(const CallEvent &Call,
const IdentifierInfo *Identifier = Call.getCalleeIdentifier();
SVal sv = Call.getReturnValue();
- if (isAnnotatedAsReturningLocalized(D) || LSF.count(Identifier) != 0) {
+ if (isAnnotatedAsReturningLocalized(D) || LSF.contains(Identifier)) {
setLocalizedState(sv, C);
} else if (isNSStringType(RT, C.getASTContext()) &&
!hasLocalizedState(sv, C)) {
@@ -1339,7 +1339,10 @@ bool PluralMisuseChecker::MethodCrawler::EndVisitIfStmt(IfStmt *I) {
}
bool PluralMisuseChecker::MethodCrawler::VisitIfStmt(const IfStmt *I) {
- const Expr *Condition = I->getCond()->IgnoreParenImpCasts();
+ const Expr *Condition = I->getCond();
+ if (!Condition)
+ return true;
+ Condition = Condition->IgnoreParenImpCasts();
if (isCheckingPlurality(Condition)) {
MatchingStatements.push_back(I);
InMatchingStatement = true;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index b72d72580c28..5bf96acc0462 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -27,6 +27,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -180,7 +181,7 @@ static bool isInMIGCall(CheckerContext &C) {
}
void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
- if (Call.isCalled(OsRefRetain)) {
+ if (OsRefRetain.matches(Call)) {
// If the code is doing reference counting over the parameter,
// it opens up an opportunity for safely calling a destructor function.
// TODO: We should still check for over-releases.
@@ -198,7 +199,7 @@ void MIGChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const {
auto I = llvm::find_if(Deallocators,
[&](const std::pair<CallDescription, unsigned> &Item) {
- return Call.isCalled(Item.first);
+ return Item.first.matches(Call);
});
if (I == Deallocators.end())
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index a157ee2da5df..635eb00e4ca9 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -160,7 +160,7 @@ static bool isEnclosingFunctionParam(const Expr *E) {
E = E->IgnoreParenCasts();
if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
const ValueDecl *VD = DRE->getDecl();
- if (isa<ImplicitParamDecl>(VD) || isa<ParmVarDecl>(VD))
+ if (isa<ImplicitParamDecl, ParmVarDecl>(VD))
return true;
}
return false;
@@ -199,8 +199,7 @@ unsigned MacOSKeychainAPIChecker::getTrackedFunctionIndex(StringRef Name,
static bool isBadDeallocationArgument(const MemRegion *Arg) {
if (!Arg)
return false;
- return isa<AllocaRegion>(Arg) || isa<BlockDataRegion>(Arg) ||
- isa<TypedRegion>(Arg);
+ return isa<AllocaRegion, BlockDataRegion, TypedRegion>(Arg);
}
/// Given the address expression, retrieve the value it's pointing to. Assume
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index a6470da09c45..10ed6149528c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -48,9 +48,13 @@
#include "InterCheckerAPI.h"
#include "clang/AST/Attr.h"
#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -60,20 +64,26 @@
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/StoreRef.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include <climits>
#include <functional>
#include <utility>
@@ -298,6 +308,8 @@ public:
/// which might free a pointer are annotated.
DefaultBool ShouldIncludeOwnershipAnnotatedFunctions;
+ DefaultBool ShouldRegisterNoOwnershipChangeVisitor;
+
/// Many checkers are essentially built into this one, so enabling them will
/// make MallocChecker perform additional modeling and reporting.
enum CheckKind {
@@ -722,11 +734,169 @@ private:
bool isArgZERO_SIZE_PTR(ProgramStateRef State, CheckerContext &C,
SVal ArgVal) const;
};
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// Definition of NoOwnershipChangeVisitor.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class NoOwnershipChangeVisitor final : public NoStateChangeFuncVisitor {
+ SymbolRef Sym;
+ using OwnerSet = llvm::SmallPtrSet<const MemRegion *, 8>;
+
+ // Collect which entities point to the allocated memory, and could be
+ // responsible for deallocating it.
+ class OwnershipBindingsHandler : public StoreManager::BindingsHandler {
+ SymbolRef Sym;
+ OwnerSet &Owners;
+
+ public:
+ OwnershipBindingsHandler(SymbolRef Sym, OwnerSet &Owners)
+ : Sym(Sym), Owners(Owners) {}
+
+ bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *Region,
+ SVal Val) override {
+ if (Val.getAsSymbol() == Sym)
+ Owners.insert(Region);
+ return true;
+ }
+
+ LLVM_DUMP_METHOD void dump() const { dumpToStream(llvm::errs()); }
+ LLVM_DUMP_METHOD void dumpToStream(llvm::raw_ostream &out) const {
+ out << "Owners: {\n";
+ for (const MemRegion *Owner : Owners) {
+ out << " ";
+ Owner->dumpToStream(out);
+ out << ",\n";
+ }
+ out << "}\n";
+ }
+ };
+
+protected:
+ OwnerSet getOwnersAtNode(const ExplodedNode *N) {
+ OwnerSet Ret;
+
+ ProgramStateRef State = N->getState();
+ OwnershipBindingsHandler Handler{Sym, Ret};
+ State->getStateManager().getStoreManager().iterBindings(State->getStore(),
+ Handler);
+ return Ret;
+ }
+
+ LLVM_DUMP_METHOD static std::string
+ getFunctionName(const ExplodedNode *CallEnterN) {
+ if (const CallExpr *CE = llvm::dyn_cast_or_null<CallExpr>(
+ CallEnterN->getLocationAs<CallEnter>()->getCallExpr()))
+ if (const FunctionDecl *FD = CE->getDirectCallee())
+ return FD->getQualifiedNameAsString();
+ return "";
+ }
+
+ bool doesFnIntendToHandleOwnership(const Decl *Callee, ASTContext &ACtx) {
+ using namespace clang::ast_matchers;
+ const FunctionDecl *FD = dyn_cast<FunctionDecl>(Callee);
+ if (!FD)
+ return false;
+ // TODO: Operator delete is hardly the only deallocator -- Can we reuse
+ // isFreeingCall() or something thats already here?
+ auto Deallocations = match(
+ stmt(hasDescendant(cxxDeleteExpr().bind("delete"))
+ ), *FD->getBody(), ACtx);
+ // TODO: Ownership my change with an attempt to store the allocated memory.
+ return !Deallocations.empty();
+ }
+
+ virtual bool
+ wasModifiedInFunction(const ExplodedNode *CallEnterN,
+ const ExplodedNode *CallExitEndN) override {
+ if (!doesFnIntendToHandleOwnership(
+ CallExitEndN->getFirstPred()->getLocationContext()->getDecl(),
+ CallExitEndN->getState()->getAnalysisManager().getASTContext()))
+ return true;
+
+ if (CallEnterN->getState()->get<RegionState>(Sym) !=
+ CallExitEndN->getState()->get<RegionState>(Sym))
+ return true;
+
+ OwnerSet CurrOwners = getOwnersAtNode(CallEnterN);
+ OwnerSet ExitOwners = getOwnersAtNode(CallExitEndN);
+
+ // Owners in the current set may be purged from the analyzer later on.
+ // If a variable is dead (is not referenced directly or indirectly after
+ // some point), it will be removed from the Store before the end of its
+ // actual lifetime.
+ // This means that that if the ownership status didn't change, CurrOwners
+ // must be a superset of, but not necessarily equal to ExitOwners.
+ return !llvm::set_is_subset(ExitOwners, CurrOwners);
+ }
+
+ static PathDiagnosticPieceRef emitNote(const ExplodedNode *N) {
+ PathDiagnosticLocation L = PathDiagnosticLocation::create(
+ N->getLocation(),
+ N->getState()->getStateManager().getContext().getSourceManager());
+ return std::make_shared<PathDiagnosticEventPiece>(
+ L, "Returning without deallocating memory or storing the pointer for "
+ "later deallocation");
+ }
+
+ virtual PathDiagnosticPieceRef
+ maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
+ const ObjCMethodCall &Call,
+ const ExplodedNode *N) override {
+ // TODO: Implement.
+ return nullptr;
+ }
+
+ virtual PathDiagnosticPieceRef
+ maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
+ const CXXConstructorCall &Call,
+ const ExplodedNode *N) override {
+ // TODO: Implement.
+ return nullptr;
+ }
+
+ virtual PathDiagnosticPieceRef
+ maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
+ const ExplodedNode *N) override {
+ // TODO: Factor the logic of "what constitutes as an entity being passed
+ // into a function call" out by reusing the code in
+ // NoStoreFuncVisitor::maybeEmitNoteForParameters, maybe by incorporating
+ // the printing technology in UninitializedObject's FieldChainInfo.
+ ArrayRef<ParmVarDecl *> Parameters = Call.parameters();
+ for (unsigned I = 0; I < Call.getNumArgs() && I < Parameters.size(); ++I) {
+ SVal V = Call.getArgSVal(I);
+ if (V.getAsSymbol() == Sym)
+ return emitNote(N);
+ }
+ return nullptr;
+ }
+
+public:
+ NoOwnershipChangeVisitor(SymbolRef Sym)
+ : NoStateChangeFuncVisitor(bugreporter::TrackingKind::Thorough),
+ Sym(Sym) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int Tag = 0;
+ ID.AddPointer(&Tag);
+ ID.AddPointer(Sym);
+ }
+
+ void *getTag() const {
+ static int Tag = 0;
+ return static_cast<void *>(&Tag);
+ }
+};
+
+} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Definition of MallocBugVisitor.
//===----------------------------------------------------------------------===//
+namespace {
/// The bug visitor which allows us to print extra diagnostics along the
/// BugReport path. For example, showing the allocation site of the leaked
/// region.
@@ -767,7 +937,7 @@ public:
/// Did not track -> allocated. Other state (released) -> allocated.
static inline bool isAllocated(const RefState *RSCurr, const RefState *RSPrev,
const Stmt *Stmt) {
- return (Stmt && (isa<CallExpr>(Stmt) || isa<CXXNewExpr>(Stmt)) &&
+ return (isa_and_nonnull<CallExpr, CXXNewExpr>(Stmt) &&
(RSCurr &&
(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
(!RSPrev ||
@@ -780,8 +950,7 @@ public:
const Stmt *Stmt) {
bool IsReleased =
(RSCurr && RSCurr->isReleased()) && (!RSPrev || !RSPrev->isReleased());
- assert(!IsReleased ||
- (Stmt && (isa<CallExpr>(Stmt) || isa<CXXDeleteExpr>(Stmt))) ||
+ assert(!IsReleased || (isa_and_nonnull<CallExpr, CXXDeleteExpr>(Stmt)) ||
(!Stmt && RSCurr->getAllocationFamily() == AF_InnerBuffer));
return IsReleased;
}
@@ -789,11 +958,10 @@ public:
/// Did not track -> relinquished. Other state (allocated) -> relinquished.
static inline bool isRelinquished(const RefState *RSCurr,
const RefState *RSPrev, const Stmt *Stmt) {
- return (Stmt &&
- (isa<CallExpr>(Stmt) || isa<ObjCMessageExpr>(Stmt) ||
- isa<ObjCPropertyRefExpr>(Stmt)) &&
- (RSCurr && RSCurr->isRelinquished()) &&
- (!RSPrev || !RSPrev->isRelinquished()));
+ return (
+ isa_and_nonnull<CallExpr, ObjCMessageExpr, ObjCPropertyRefExpr>(Stmt) &&
+ (RSCurr && RSCurr->isRelinquished()) &&
+ (!RSPrev || !RSPrev->isRelinquished()));
}
/// If the expression is not a call, and the state change is
@@ -803,7 +971,7 @@ public:
static inline bool hasReallocFailed(const RefState *RSCurr,
const RefState *RSPrev,
const Stmt *Stmt) {
- return ((!Stmt || !isa<CallExpr>(Stmt)) &&
+ return ((!isa_and_nonnull<CallExpr>(Stmt)) &&
(RSCurr &&
(RSCurr->isAllocated() || RSCurr->isAllocatedOfSizeZero())) &&
(RSPrev &&
@@ -851,7 +1019,6 @@ private:
}
};
};
-
} // end anonymous namespace
// A map from the freed symbol to the symbol representing the return value of
@@ -1753,7 +1920,7 @@ ProgramStateRef MallocChecker::FreeMemAux(
// Parameters, locals, statics, globals, and memory returned by
// __builtin_alloca() shouldn't be freed.
- if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
+ if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
// FIXME: at the time this code was written, malloc() regions were
// represented by conjured symbols, which are all in UnknownSpaceRegion.
// This means that there isn't actually anything from HeapSpaceRegion
@@ -2303,7 +2470,8 @@ void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
categories::MemoryError));
auto R = std::make_unique<PathSensitiveBugReport>(
- *BT_UseZerroAllocated[*CheckKind], "Use of zero-allocated memory", N);
+ *BT_UseZerroAllocated[*CheckKind],
+ "Use of memory allocated with size zero", N);
R->addRange(Range);
if (Sym) {
@@ -2579,6 +2747,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
AllocNode->getLocationContext()->getDecl());
R->markInteresting(Sym);
R->addVisitor<MallocBugVisitor>(Sym, true);
+ if (ShouldRegisterNoOwnershipChangeVisitor)
+ R->addVisitor<NoOwnershipChangeVisitor>(Sym);
C.emitReport(std::move(R));
}
@@ -2733,7 +2903,7 @@ void MallocChecker::checkEscapeOnReturn(const ReturnStmt *S,
// the callee could still free the memory.
// TODO: This logic should be a part of generic symbol escape callback.
if (const MemRegion *MR = RetVal.getAsRegion())
- if (isa<FieldRegion>(MR) || isa<ElementRegion>(MR))
+ if (isa<FieldRegion, ElementRegion>(MR))
if (const SymbolicRegion *BMR =
dyn_cast<SymbolicRegion>(MR->getBaseRegion()))
Sym = BMR->getSymbol();
@@ -2916,7 +3086,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// TODO: If we want to be more optimistic here, we'll need to make sure that
// regions escape to C++ containers. They seem to do that even now, but for
// mysterious reasons.
- if (!(isa<SimpleFunctionCall>(Call) || isa<ObjCMethodCall>(Call)))
+ if (!isa<SimpleFunctionCall, ObjCMethodCall>(Call))
return true;
// Check Objective-C messages by selector name.
@@ -3024,7 +3194,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
const Expr *ArgE = Call->getArgExpr(0)->IgnoreParenCasts();
if (const DeclRefExpr *ArgDRE = dyn_cast<DeclRefExpr>(ArgE))
if (const VarDecl *D = dyn_cast<VarDecl>(ArgDRE->getDecl()))
- if (D->getCanonicalDecl()->getName().find("std") != StringRef::npos)
+ if (D->getCanonicalDecl()->getName().contains("std"))
return true;
}
}
@@ -3395,6 +3565,9 @@ void ento::registerDynamicMemoryModeling(CheckerManager &mgr) {
auto *checker = mgr.registerChecker<MallocChecker>();
checker->ShouldIncludeOwnershipAnnotatedFunctions =
mgr.getAnalyzerOptions().getCheckerBooleanOption(checker, "Optimistic");
+ checker->ShouldRegisterNoOwnershipChangeVisitor =
+ mgr.getAnalyzerOptions().getCheckerBooleanOption(
+ checker, "AddNoOwnershipChangeNotes");
}
bool ento::shouldRegisterDynamicMemoryModeling(const CheckerManager &mgr) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index e31630f63b5a..a6e8fcd425d5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -32,12 +32,14 @@ using llvm::APSInt;
namespace {
struct MallocOverflowCheck {
+ const CallExpr *call;
const BinaryOperator *mulop;
const Expr *variable;
APSInt maxVal;
- MallocOverflowCheck(const BinaryOperator *m, const Expr *v, APSInt val)
- : mulop(m), variable(v), maxVal(std::move(val)) {}
+ MallocOverflowCheck(const CallExpr *call, const BinaryOperator *m,
+ const Expr *v, APSInt val)
+ : call(call), mulop(m), variable(v), maxVal(std::move(val)) {}
};
class MallocOverflowSecurityChecker : public Checker<check::ASTCodeBody> {
@@ -46,8 +48,8 @@ public:
BugReporter &BR) const;
void CheckMallocArgument(
- SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
- const Expr *TheArgument, ASTContext &Context) const;
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const CallExpr *TheCall, ASTContext &Context) const;
void OutputPossibleOverflows(
SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
@@ -62,16 +64,15 @@ static inline bool EvaluatesToZero(APSInt &Val, BinaryOperatorKind op) {
}
void MallocOverflowSecurityChecker::CheckMallocArgument(
- SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
- const Expr *TheArgument,
- ASTContext &Context) const {
+ SmallVectorImpl<MallocOverflowCheck> &PossibleMallocOverflows,
+ const CallExpr *TheCall, ASTContext &Context) const {
/* Look for a linear combination with a single variable, and at least
one multiplication.
Reject anything that applies to the variable: an explicit cast,
conditional expression, an operation that could reduce the range
of the result, or anything too complicated :-). */
- const Expr *e = TheArgument;
+ const Expr *e = TheCall->getArg(0);
const BinaryOperator * mulop = nullptr;
APSInt maxVal;
@@ -101,8 +102,7 @@ void MallocOverflowSecurityChecker::CheckMallocArgument(
e = rhs;
} else
return;
- }
- else if (isa<DeclRefExpr>(e) || isa<MemberExpr>(e))
+ } else if (isa<DeclRefExpr, MemberExpr>(e))
break;
else
return;
@@ -115,9 +115,8 @@ void MallocOverflowSecurityChecker::CheckMallocArgument(
// the data so when the body of the function is completely available
// we can check for comparisons.
- // TODO: Could push this into the innermost scope where 'e' is
- // defined, rather than the whole function.
- PossibleMallocOverflows.push_back(MallocOverflowCheck(mulop, e, maxVal));
+ PossibleMallocOverflows.push_back(
+ MallocOverflowCheck(TheCall, mulop, e, maxVal));
}
namespace {
@@ -153,17 +152,19 @@ private:
return getDecl(CheckDR) == getDecl(DR) && Pred(Check);
return false;
};
- toScanFor.erase(std::remove_if(toScanFor.begin(), toScanFor.end(), P),
- toScanFor.end());
+ llvm::erase_if(toScanFor, P);
}
void CheckExpr(const Expr *E_p) {
- auto PredTrue = [](const MallocOverflowCheck &) { return true; };
const Expr *E = E_p->IgnoreParenImpCasts();
+ const auto PrecedesMalloc = [E, this](const MallocOverflowCheck &c) {
+ return Context.getSourceManager().isBeforeInTranslationUnit(
+ E->getExprLoc(), c.call->getExprLoc());
+ };
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
- Erase<DeclRefExpr>(DR, PredTrue);
+ Erase<DeclRefExpr>(DR, PrecedesMalloc);
else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
- Erase<MemberExpr>(ME, PredTrue);
+ Erase<MemberExpr>(ME, PrecedesMalloc);
}
}
@@ -322,7 +323,7 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) {
if (TheCall->getNumArgs() == 1)
- CheckMallocArgument(PossibleMallocOverflows, TheCall->getArg(0),
+ CheckMallocArgument(PossibleMallocOverflows, TheCall,
mgr.getASTContext());
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 5d63d6efd234..517a5d78271b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -46,7 +47,7 @@ int MmapWriteExecChecker::ProtRead = 0x01;
void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- if (Call.isCalled(MmapFn) || Call.isCalled(MprotectFn)) {
+ if (matchesAny(Call, MmapFn, MprotectFn)) {
SVal ProtVal = Call.getArgSVal(2);
Optional<nonloc::ConcreteInt> ProtLoc = ProtVal.getAs<nonloc::ConcreteInt>();
int64_t Prot = ProtLoc->getValue().getSExtValue();
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index cbe938982000..4a232c6f4b3f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -553,8 +553,8 @@ MoveChecker::classifyObject(const MemRegion *MR,
// For the purposes of this checker, we classify move-safe STL types
// as not-"STL" types, because that's how the checker treats them.
MR = unwrapRValueReferenceIndirection(MR);
- bool IsLocal =
- MR && isa<VarRegion>(MR) && isa<StackSpaceRegion>(MR->getMemorySpace());
+ bool IsLocal = isa_and_nonnull<VarRegion>(MR) &&
+ isa<StackSpaceRegion>(MR->getMemorySpace());
if (!RD || !RD->getDeclContext()->isStdNamespace())
return { IsLocal, SK_NonStd };
@@ -712,12 +712,9 @@ ProgramStateRef MoveChecker::checkRegionChanges(
// directly, but not all of them end up being invalidated.
// But when they do, they appear in the InvalidatedRegions array as well.
for (const auto *Region : RequestedRegions) {
- if (ThisRegion != Region) {
- if (llvm::find(InvalidatedRegions, Region) !=
- std::end(InvalidatedRegions)) {
- State = removeFromState(State, Region);
- }
- }
+ if (ThisRegion != Region &&
+ llvm::is_contained(InvalidatedRegions, Region))
+ State = removeFromState(State, Region);
}
} else {
// For invalidations that aren't caused by calls, assume nothing. In
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 90c5583d8969..dcca8be55e33 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This file defines a CheckNSError, a flow-insenstive check
+// This file defines a CheckNSError, a flow-insensitive check
// that determines if an Objective-C class interface correctly returns
// a non-void return type.
//
diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index ee71b55a39e6..f4e9a67438e7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -681,9 +682,7 @@ ProgramStateRef PthreadLockChecker::checkRegionChanges(
// We assume that system library function wouldn't touch the mutex unless
// it takes the mutex explicitly as an argument.
// FIXME: This is a bit quadratic.
- if (IsLibraryFunction &&
- std::find(ExplicitRegions.begin(), ExplicitRegions.end(), R) ==
- ExplicitRegions.end())
+ if (IsLibraryFunction && !llvm::is_contained(ExplicitRegions, R))
continue;
State = State->remove<LockMap>(R);
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index 3f3267ff9391..0bde088d0e85 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -290,7 +290,7 @@ void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
ProgramStateRef State = C.getState();
SymbolRef Sym = State->getSVal(*IVarLoc).getAsSymbol();
- if (!Sym || !dyn_cast_or_null<ObjCIvarRegion>(Sym->getOriginRegion()))
+ if (!Sym || !isa_and_nonnull<ObjCIvarRegion>(Sym->getOriginRegion()))
return;
// Accessing an ivar directly is unusual. If we've done that, be more
@@ -1188,14 +1188,14 @@ ProgramStateRef RetainCountChecker::checkRegionChanges(
if (!invalidated)
return state;
- llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols;
+ llvm::SmallPtrSet<SymbolRef, 8> AllowedSymbols;
for (const MemRegion *I : ExplicitRegions)
if (const SymbolicRegion *SR = I->StripCasts()->getAs<SymbolicRegion>())
- WhitelistedSymbols.insert(SR->getSymbol());
+ AllowedSymbols.insert(SR->getSymbol());
for (SymbolRef sym : *invalidated) {
- if (WhitelistedSymbols.count(sym))
+ if (AllowedSymbols.count(sym))
continue;
// Remove any existing reference-count binding.
state = removeRefBinding(state, sym);
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 64ac6bc4c06b..41ef45d317cd 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -73,11 +73,8 @@ RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT)
static bool isNumericLiteralExpression(const Expr *E) {
// FIXME: This set of cases was copied from SemaExprObjC.
- return isa<IntegerLiteral>(E) ||
- isa<CharacterLiteral>(E) ||
- isa<FloatingLiteral>(E) ||
- isa<ObjCBoolLiteralExpr>(E) ||
- isa<CXXBoolLiteralExpr>(E);
+ return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral,
+ ObjCBoolLiteralExpr, CXXBoolLiteralExpr>(E);
}
/// If type represents a pointer to CXXRecordDecl,
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index 885750218b9e..c4dc06d4a077 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -79,16 +80,44 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
"Returned pointer value points outside the original object "
"(potential buffer overflow)"));
- // FIXME: It would be nice to eventually make this diagnostic more clear,
- // e.g., by referencing the original declaration or by saying *why* this
- // reference is outside the range.
-
// Generate a report for this bug.
- auto report =
+ auto Report =
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+ Report->addRange(RetE->getSourceRange());
+
+ const auto ConcreteElementCount = ElementCount.getAs<nonloc::ConcreteInt>();
+ const auto ConcreteIdx = Idx.getAs<nonloc::ConcreteInt>();
+
+ const auto *DeclR = ER->getSuperRegion()->getAs<DeclRegion>();
+
+ if (DeclR)
+ Report->addNote("Original object declared here",
+ {DeclR->getDecl(), C.getSourceManager()});
+
+ if (ConcreteElementCount) {
+ SmallString<128> SBuf;
+ llvm::raw_svector_ostream OS(SBuf);
+ OS << "Original object ";
+ if (DeclR) {
+ OS << "'";
+ DeclR->getDecl()->printName(OS);
+ OS << "' ";
+ }
+ OS << "is an array of " << ConcreteElementCount->getValue() << " '";
+ ER->getValueType().print(OS,
+ PrintingPolicy(C.getASTContext().getLangOpts()));
+ OS << "' objects";
+ if (ConcreteIdx) {
+ OS << ", returned pointer points at index " << ConcreteIdx->getValue();
+ }
+
+ Report->addNote(SBuf,
+ {RetE, C.getSourceManager(), C.getLocationContext()});
+ }
+
+ bugreporter::trackExpressionValue(N, RetE, *Report);
- report->addRange(RetE->getSourceRange());
- C.emitReport(std::move(report));
+ C.emitReport(std::move(Report));
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
index 14ecede17083..cd502241ef61 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/Optional.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
index 933e0146ff59..ea72ebe3ed57 100644
--- a/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/STLAlgorithmModeling.cpp
@@ -12,6 +12,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 8d380ed1b93d..1de5d7285f65 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include <utility>
@@ -119,7 +120,7 @@ void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
if (!Call.isGlobalCFunction())
return;
- if (!Call.isCalled(OpenFn))
+ if (!OpenFn.matches(Call))
return;
// Get the symbolic value corresponding to the file handle.
@@ -138,7 +139,7 @@ void SimpleStreamChecker::checkPreCall(const CallEvent &Call,
if (!Call.isGlobalCFunction())
return;
- if (!Call.isCalled(CloseFn))
+ if (!CloseFn.matches(Call))
return;
// Get the symbolic value corresponding to the file handle.
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 09e885e8133f..c789a8dbcca1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -23,6 +23,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h"
@@ -102,12 +103,8 @@ static bool hasStdClassWithName(const CXXRecordDecl *RD,
ArrayRef<llvm::StringLiteral> Names) {
if (!RD || !RD->getDeclContext()->isStdNamespace())
return false;
- if (RD->getDeclName().isIdentifier()) {
- StringRef Name = RD->getName();
- return llvm::any_of(Names, [&Name](StringRef GivenName) -> bool {
- return Name == GivenName;
- });
- }
+ if (RD->getDeclName().isIdentifier())
+ return llvm::is_contained(Names, RD->getName());
return false;
}
@@ -289,7 +286,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
if (ModelSmartPtrDereference && isStdOstreamOperatorCall(Call))
return handleOstreamOperator(Call, C);
- if (Call.isCalled(StdSwapCall)) {
+ if (StdSwapCall.matches(Call)) {
// Check the first arg, if it is of std::unique_ptr type.
assert(Call.getNumArgs() == 2 && "std::swap should have two arguments");
const Expr *FirstArg = Call.getArgExpr(0);
@@ -298,8 +295,7 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
return handleSwap(State, Call.getArgSVal(0), Call.getArgSVal(1), C);
}
- if (Call.isCalled(StdMakeUniqueCall) ||
- Call.isCalled(StdMakeUniqueForOverwriteCall)) {
+ if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
if (!ModelSmartPtrDereference)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index b5c9356322fc..d5e86e86424d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -11,9 +11,9 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
@@ -303,21 +303,53 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
class CallBack : public StoreManager::BindingsHandler {
private:
CheckerContext &Ctx;
- const StackFrameContext *CurSFC;
+ const StackFrameContext *PoppedFrame;
+
+ /// Look for stack variables referring to popped stack variables.
+ /// Returns true only if it found some dangling stack variables
+ /// referred by an other stack variable from different stack frame.
+ bool checkForDanglingStackVariable(const MemRegion *Referrer,
+ const MemRegion *Referred) {
+ const auto *ReferrerMemSpace =
+ Referrer->getMemorySpace()->getAs<StackSpaceRegion>();
+ const auto *ReferredMemSpace =
+ Referred->getMemorySpace()->getAs<StackSpaceRegion>();
+
+ if (!ReferrerMemSpace || !ReferredMemSpace)
+ return false;
+
+ const auto *ReferrerFrame = ReferrerMemSpace->getStackFrame();
+ const auto *ReferredFrame = ReferredMemSpace->getStackFrame();
+
+ if (ReferrerMemSpace && ReferredMemSpace) {
+ if (ReferredFrame == PoppedFrame &&
+ ReferrerFrame->isParentOf(PoppedFrame)) {
+ V.emplace_back(Referrer, Referred);
+ return true;
+ }
+ }
+ return false;
+ }
public:
SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V;
- CallBack(CheckerContext &CC) : Ctx(CC), CurSFC(CC.getStackFrame()) {}
+ CallBack(CheckerContext &CC) : Ctx(CC), PoppedFrame(CC.getStackFrame()) {}
bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region,
SVal Val) override {
+ const MemRegion *VR = Val.getAsRegion();
+ if (!VR)
+ return true;
+ if (checkForDanglingStackVariable(Region, VR))
+ return true;
+
+ // Check the globals for the same.
if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace()))
return true;
- const MemRegion *VR = Val.getAsRegion();
- if (VR && isa<StackSpaceRegion>(VR->getMemorySpace()) &&
- !isArcManagedBlock(VR, Ctx) && !isNotInCurrentFrame(VR, Ctx))
+ if (VR && VR->hasStackStorage() && !isArcManagedBlock(VR, Ctx) &&
+ !isNotInCurrentFrame(VR, Ctx))
V.emplace_back(Region, VR);
return true;
}
@@ -344,19 +376,41 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
"invalid after returning from the function");
for (const auto &P : Cb.V) {
+ const MemRegion *Referrer = P.first;
+ const MemRegion *Referred = P.second;
+
// Generate a report for this bug.
+ const StringRef CommonSuffix =
+ "upon returning to the caller. This will be a dangling reference";
SmallString<128> Buf;
llvm::raw_svector_ostream Out(Buf);
- SourceRange Range = genName(Out, P.second, Ctx.getASTContext());
- Out << " is still referred to by the ";
- if (isa<StaticGlobalSpaceRegion>(P.first->getMemorySpace()))
- Out << "static";
- else
- Out << "global";
- Out << " variable '";
- const VarRegion *VR = cast<VarRegion>(P.first->getBaseRegion());
- Out << *VR->getDecl()
- << "' upon returning to the caller. This will be a dangling reference";
+ const SourceRange Range = genName(Out, Referred, Ctx.getASTContext());
+
+ if (isa<CXXTempObjectRegion>(Referrer)) {
+ Out << " is still referred to by a temporary object on the stack "
+ << CommonSuffix;
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
+ Ctx.emitReport(std::move(Report));
+ return;
+ }
+
+ const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
+ if (isa<StaticGlobalSpaceRegion>(Space))
+ return "static";
+ if (isa<GlobalsSpaceRegion>(Space))
+ return "global";
+ assert(isa<StackSpaceRegion>(Space));
+ return "stack";
+ }(Referrer->getMemorySpace());
+
+ // This cast supposed to succeed.
+ const VarRegion *ReferrerVar = cast<VarRegion>(Referrer->getBaseRegion());
+ const std::string ReferrerVarName =
+ ReferrerVar->getDecl()->getDeclName().getAsString();
+
+ Out << " is still referred to by the " << ReferrerMemorySpace
+ << " variable '" << ReferrerVarName << "' " << CommonSuffix;
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
if (Range.isValid())
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index e758b465af1b..e8b963a535d8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -568,6 +568,7 @@ public:
bool DisplayLoadedSummaries = false;
bool ModelPOSIX = false;
+ bool ShouldAssumeControlledEnvironment = false;
private:
Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
@@ -1433,6 +1434,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
RetType{Ssize_tTy}),
GetLineSummary);
+ {
+ Summary GetenvSummary = Summary(NoEvalCall)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .Case({NotNull(Ret)});
+ // In untrusted environments the envvar might not exist.
+ if (!ShouldAssumeControlledEnvironment)
+ GetenvSummary.Case({NotNull(Ret)->negate()});
+
+ // char *getenv(const char *name);
+ addToFunctionSummaryMap(
+ "getenv", Signature(ArgTypes{ConstCharPtrTy}, RetType{CharPtrTy}),
+ std::move(GetenvSummary));
+ }
+
if (ModelPOSIX) {
// long a64l(const char *str64);
@@ -2645,11 +2660,12 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
void ento::registerStdCLibraryFunctionsChecker(CheckerManager &mgr) {
auto *Checker = mgr.registerChecker<StdLibraryFunctionsChecker>();
+ const AnalyzerOptions &Opts = mgr.getAnalyzerOptions();
Checker->DisplayLoadedSummaries =
- mgr.getAnalyzerOptions().getCheckerBooleanOption(
- Checker, "DisplayLoadedSummaries");
- Checker->ModelPOSIX =
- mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker, "ModelPOSIX");
+ Opts.getCheckerBooleanOption(Checker, "DisplayLoadedSummaries");
+ Checker->ModelPOSIX = Opts.getCheckerBooleanOption(Checker, "ModelPOSIX");
+ Checker->ShouldAssumeControlledEnvironment =
+ Opts.ShouldAssumeControlledEnvironment;
}
bool ento::shouldRegisterStdCLibraryFunctionsChecker(
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index dd65f8c035aa..26218b8e0454 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
@@ -1118,4 +1119,4 @@ void ento::registerStreamTesterChecker(CheckerManager &Mgr) {
bool ento::shouldRegisterStreamTesterChecker(const CheckerManager &Mgr) {
return true;
-} \ No newline at end of file
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp
new file mode 100644
index 000000000000..0d745f5d8d6f
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/StringChecker.cpp
@@ -0,0 +1,105 @@
+//=== StringChecker.cpp -------------------------------------------*- C++ -*--//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the modeling of the std::basic_string type.
+// This involves checking preconditions of the operations and applying the
+// effects of the operations, e.g. their post-conditions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class StringChecker : public Checker<check::PreCall> {
+ BugType BT_Null{this, "Dereference of null pointer", categories::LogicError};
+ mutable const FunctionDecl *StringConstCharPtrCtor = nullptr;
+ mutable CanQualType SizeTypeTy;
+ const CallDescription TwoParamStdStringCtor = {
+ {"std", "basic_string", "basic_string"}, 2, 2};
+
+ bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const;
+
+public:
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+};
+
+bool StringChecker::isCharToStringCtor(const CallEvent &Call,
+ const ASTContext &ACtx) const {
+ if (!TwoParamStdStringCtor.matches(Call))
+ return false;
+ const auto *FD = dyn_cast<FunctionDecl>(Call.getDecl());
+ assert(FD);
+
+ // See if we already cached it.
+ if (StringConstCharPtrCtor && StringConstCharPtrCtor == FD)
+ return true;
+
+ // Verify that the parameters have the expected types:
+ // - arg 1: `const CharT *`
+ // - arg 2: some allocator - which is definately not `size_t`.
+ const QualType Arg1Ty = Call.getArgExpr(0)->getType().getCanonicalType();
+ const QualType Arg2Ty = Call.getArgExpr(1)->getType().getCanonicalType();
+
+ if (!Arg1Ty->isPointerType())
+ return false;
+
+ // It makes sure that we don't select the `string(const char* p, size_t len)`
+ // overload accidentally.
+ if (Arg2Ty.getCanonicalType() == ACtx.getSizeType())
+ return false;
+
+ StringConstCharPtrCtor = FD; // Cache the decl of the right overload.
+ return true;
+}
+
+void StringChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (!isCharToStringCtor(Call, C.getASTContext()))
+ return;
+ const auto Param = Call.getArgSVal(0).getAs<Loc>();
+ if (!Param.hasValue())
+ return;
+
+ // We managed to constrain the parameter to non-null.
+ ProgramStateRef NotNull, Null;
+ std::tie(NotNull, Null) = C.getState()->assume(*Param);
+
+ if (NotNull) {
+ const auto Callback = [Param](PathSensitiveBugReport &BR) -> std::string {
+ return BR.isInteresting(*Param) ? "Assuming the pointer is not null."
+ : "";
+ };
+
+ // Emit note only if this operation constrained the pointer to be null.
+ C.addTransition(NotNull, Null ? C.getNoteTag(Callback) : nullptr);
+ return;
+ }
+
+ // We found a path on which the parameter is NULL.
+ if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
+ auto R = std::make_unique<PathSensitiveBugReport>(
+ BT_Null, "The parameter must not be null", N);
+ bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
+ C.emitReport(std::move(R));
+ }
+}
+
+} // end anonymous namespace
+
+void ento::registerStringChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<StringChecker>();
+}
+
+bool ento::shouldRegisterStringChecker(const CheckerManager &) { return true; }
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index 381334de068e..2244cdb96d4f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -110,7 +110,7 @@ void UnixAPIMisuseChecker::checkPreStmt(const CallExpr *CE,
// Don't treat functions in namespaces with the same name a Unix function
// as a call to the Unix function.
const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
- if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
+ if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
return;
StringRef FName = C.getCalleeName(FD);
@@ -466,7 +466,7 @@ void UnixAPIPortabilityChecker::checkPreStmt(const CallExpr *CE,
// Don't treat functions in namespaces with the same name a Unix function
// as a call to the Unix function.
const DeclContext *NamespaceCtx = FD->getEnclosingNamespaceContext();
- if (NamespaceCtx && isa<NamespaceDecl>(NamespaceCtx))
+ if (isa_and_nonnull<NamespaceDecl>(NamespaceCtx))
return;
StringRef FName = C.getCalleeName(FD);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index dde5912b6d6e..60da4fca12e6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@@ -126,15 +127,15 @@ void ValistChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
return;
- if (Call.isCalled(VaStart))
+ if (VaStart.matches(Call))
checkVAListStartCall(Call, C, false);
- else if (Call.isCalled(VaCopy))
+ else if (VaCopy.matches(Call))
checkVAListStartCall(Call, C, true);
- else if (Call.isCalled(VaEnd))
+ else if (VaEnd.matches(Call))
checkVAListEndCall(Call, C);
else {
for (auto FuncInfo : VAListAccepters) {
- if (!Call.isCalled(FuncInfo.Func))
+ if (!FuncInfo.Func.matches(Call))
continue;
bool Symbolic;
const MemRegion *VAList =
diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
index 8f147026ae19..04e6603b4cbe 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
@@ -9,7 +9,7 @@
// This file defines vfork checker which checks for dangerous uses of vfork.
// Vforked process shares memory (including stack) with parent so it's
// range of actions is significantly limited: can't write variables,
-// can't call functions not in whitelist, etc. For more details, see
+// can't call functions not in the allowed list, etc. For more details, see
// http://man7.org/linux/man-pages/man2/vfork.2.html
//
// This checker checks for prohibited constructs in vforked process.
@@ -44,13 +44,14 @@ namespace {
class VforkChecker : public Checker<check::PreCall, check::PostCall,
check::Bind, check::PreStmt<ReturnStmt>> {
mutable std::unique_ptr<BuiltinBug> BT;
- mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkWhitelist;
+ mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkAllowlist;
mutable const IdentifierInfo *II_vfork;
static bool isChildProcess(const ProgramStateRef State);
bool isVforkCall(const Decl *D, CheckerContext &C) const;
- bool isCallWhitelisted(const IdentifierInfo *II, CheckerContext &C) const;
+ bool isCallExplicitelyAllowed(const IdentifierInfo *II,
+ CheckerContext &C) const;
void reportBug(const char *What, CheckerContext &C,
const char *Details = nullptr) const;
@@ -93,9 +94,9 @@ bool VforkChecker::isVforkCall(const Decl *D, CheckerContext &C) const {
}
// Returns true iff ok to call function after successful vfork.
-bool VforkChecker::isCallWhitelisted(const IdentifierInfo *II,
- CheckerContext &C) const {
- if (VforkWhitelist.empty()) {
+bool VforkChecker::isCallExplicitelyAllowed(const IdentifierInfo *II,
+ CheckerContext &C) const {
+ if (VforkAllowlist.empty()) {
// According to manpage.
const char *ids[] = {
"_Exit",
@@ -112,10 +113,10 @@ bool VforkChecker::isCallWhitelisted(const IdentifierInfo *II,
ASTContext &AC = C.getASTContext();
for (const char **id = ids; *id; ++id)
- VforkWhitelist.insert(&AC.Idents.get(*id));
+ VforkAllowlist.insert(&AC.Idents.get(*id));
}
- return VforkWhitelist.count(II);
+ return VforkAllowlist.count(II);
}
void VforkChecker::reportBug(const char *What, CheckerContext &C,
@@ -179,12 +180,13 @@ void VforkChecker::checkPostCall(const CallEvent &Call,
C.addTransition(ChildState);
}
-// Prohibit calls to non-whitelist functions in child process.
+// Prohibit calls to functions in child process which are not explicitly
+// allowed.
void VforkChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- if (isChildProcess(State)
- && !isCallWhitelisted(Call.getCalleeIdentifier(), C))
+ if (isChildProcess(State) &&
+ !isCallExplicitelyAllowed(Call.getCalleeIdentifier(), C))
reportBug("This function call", C);
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
index ed4577755457..ec6a7144fa45 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.h
@@ -29,7 +29,7 @@ class Expr;
/// values).
///
/// For more context see Static Analyzer checkers documentation - specifically
-/// webkit.UncountedCallArgsChecker checker. Whitelist of transformations:
+/// webkit.UncountedCallArgsChecker checker. Allowed list of transformations:
/// - constructors of ref-counted types (including factory methods)
/// - getters of ref-counted types
/// - member overloaded operators
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index d70bd9489d2c..e6d0948f71bb 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -68,8 +68,7 @@ public:
if (auto *F = CE->getDirectCallee()) {
// Skip the first argument for overloaded member operators (e. g. lambda
// or std::function call operator).
- unsigned ArgIdx =
- isa<CXXOperatorCallExpr>(CE) && dyn_cast_or_null<CXXMethodDecl>(F);
+ unsigned ArgIdx = isa<CXXOperatorCallExpr>(CE) && isa_and_nonnull<CXXMethodDecl>(F);
for (auto P = F->param_begin();
// FIXME: Also check variadic function parameters.
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
new file mode 100644
index 000000000000..d7d573cd2d3b
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -0,0 +1,280 @@
+//== InvalidPtrChecker.cpp ------------------------------------- -*- C++ -*--=//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines InvalidPtrChecker which finds usages of possibly
+// invalidated pointer.
+// CERT SEI Rules ENV31-C and ENV34-C
+// For more information see:
+// https://wiki.sei.cmu.edu/confluence/x/8tYxBQ
+// https://wiki.sei.cmu.edu/confluence/x/5NUxBQ
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+class InvalidPtrChecker
+ : public Checker<check::Location, check::BeginFunction, check::PostCall> {
+private:
+ BugType BT{this, "Use of invalidated pointer", categories::MemoryError};
+
+ void EnvpInvalidatingCall(const CallEvent &Call, CheckerContext &C) const;
+
+ using HandlerFn = void (InvalidPtrChecker::*)(const CallEvent &Call,
+ CheckerContext &C) const;
+
+ // SEI CERT ENV31-C
+ const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
+ {{"setenv", 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{"unsetenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{"putenv", 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{"_putenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ {{"_wputenv_s", 2}, &InvalidPtrChecker::EnvpInvalidatingCall},
+ };
+
+ void postPreviousReturnInvalidatingCall(const CallEvent &Call,
+ CheckerContext &C) const;
+
+ // SEI CERT ENV34-C
+ const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
+ {{"getenv", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{"setlocale", 2},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{"strerror", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{"localeconv", 0},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{"asctime", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ };
+
+public:
+ // Obtain the environment pointer from 'main()' (if present).
+ void checkBeginFunction(CheckerContext &C) const;
+
+ // Handle functions in EnvpInvalidatingFunctions, that invalidate environment
+ // pointer from 'main()'
+ // Handle functions in PreviousCallInvalidatingFunctions.
+ // Also, check if invalidated region is passed to a
+ // conservatively evaluated function call as an argument.
+ void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
+
+ // Check if invalidated region is being dereferenced.
+ void checkLocation(SVal l, bool isLoad, const Stmt *S,
+ CheckerContext &C) const;
+};
+
+} // namespace
+
+// Set of memory regions that were invalidated
+REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *)
+
+// Stores the region of the environment pointer of 'main' (if present).
+// Note: This pointer has type 'const MemRegion *', however the trait is only
+// specialized to 'const void*' and 'void*'
+REGISTER_TRAIT_WITH_PROGRAMSTATE(EnvPtrRegion, const void *)
+
+// Stores key-value pairs, where key is function declaration and value is
+// pointer to memory region returned by previous call of this function
+REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *,
+ const MemRegion *)
+
+void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ StringRef FunctionName = Call.getCalleeIdentifier()->getName();
+ ProgramStateRef State = C.getState();
+ const auto *Reg = State->get<EnvPtrRegion>();
+ if (!Reg)
+ return;
+ const auto *SymbolicEnvPtrRegion =
+ reinterpret_cast<const MemRegion *>(const_cast<const void *>(Reg));
+
+ State = State->add<InvalidMemoryRegions>(SymbolicEnvPtrRegion);
+
+ const NoteTag *Note =
+ C.getNoteTag([SymbolicEnvPtrRegion, FunctionName](
+ PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
+ if (!BR.isInteresting(SymbolicEnvPtrRegion))
+ return;
+ Out << '\'' << FunctionName
+ << "' call may invalidate the environment parameter of 'main'";
+ });
+
+ C.addTransition(State, Note);
+}
+
+void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
+ const CallEvent &Call, CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ const NoteTag *Note = nullptr;
+ const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
+ // Invalidate the region of the previously returned pointer - if there was
+ // one.
+ if (const MemRegion *const *Reg = State->get<PreviousCallResultMap>(FD)) {
+ const MemRegion *PrevReg = *Reg;
+ State = State->add<InvalidMemoryRegions>(PrevReg);
+ Note = C.getNoteTag([PrevReg, FD](PathSensitiveBugReport &BR,
+ llvm::raw_ostream &Out) {
+ if (!BR.isInteresting(PrevReg))
+ return;
+ Out << '\'';
+ FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
+ Out << "' call may invalidate the the result of the previous " << '\'';
+ FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
+ Out << '\'';
+ });
+ }
+
+ const LocationContext *LCtx = C.getLocationContext();
+ const auto *CE = cast<CallExpr>(Call.getOriginExpr());
+
+ // Function call will return a pointer to the new symbolic region.
+ DefinedOrUnknownSVal RetVal = C.getSValBuilder().conjureSymbolVal(
+ CE, LCtx, CE->getType(), C.blockCount());
+ State = State->BindExpr(CE, LCtx, RetVal);
+
+ // Remember to this region.
+ const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.getAsRegion());
+ const MemRegion *MR =
+ const_cast<MemRegion *>(SymRegOfRetVal->getBaseRegion());
+ State = State->set<PreviousCallResultMap>(FD, MR);
+
+ ExplodedNode *Node = C.addTransition(State, Note);
+ const NoteTag *PreviousCallNote =
+ C.getNoteTag([MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
+ if (!BR.isInteresting(MR))
+ return;
+ Out << '\'' << "'previous function call was here" << '\'';
+ });
+
+ C.addTransition(State, Node, PreviousCallNote);
+}
+
+// TODO: This seems really ugly. Simplify this.
+static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State,
+ const MemRegion *Reg) {
+ while (Reg) {
+ if (State->contains<InvalidMemoryRegions>(Reg))
+ return Reg;
+ const auto *SymBase = Reg->getSymbolicBase();
+ if (!SymBase)
+ break;
+ const auto *SRV = dyn_cast<SymbolRegionValue>(SymBase->getSymbol());
+ if (!SRV)
+ break;
+ Reg = SRV->getRegion();
+ if (const auto *VarReg = dyn_cast<VarRegion>(SRV->getRegion()))
+ Reg = VarReg;
+ }
+ return nullptr;
+}
+
+// Handle functions in EnvpInvalidatingFunctions, that invalidate environment
+// pointer from 'main()' Also, check if invalidated region is passed to a
+// function call as an argument.
+void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ // Check if function invalidates 'envp' argument of 'main'
+ if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call))
+ (this->**Handler)(Call, C);
+
+ // Check if function invalidates the result of previous call
+ if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call))
+ (this->**Handler)(Call, C);
+
+ // Check if one of the arguments of the function call is invalidated
+
+ // If call was inlined, don't report invalidated argument
+ if (C.wasInlined)
+ return;
+
+ ProgramStateRef State = C.getState();
+
+ for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) {
+
+ if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(
+ Call.getArgSVal(I).getAsRegion())) {
+ if (const MemRegion *InvalidatedSymbolicBase =
+ findInvalidatedSymbolicBase(State, SR)) {
+ ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
+ if (!ErrorNode)
+ return;
+
+ SmallString<256> Msg;
+ llvm::raw_svector_ostream Out(Msg);
+ Out << "use of invalidated pointer '";
+ Call.getArgExpr(I)->printPretty(Out, /*Helper=*/nullptr,
+ C.getASTContext().getPrintingPolicy());
+ Out << "' in a function call";
+
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(BT, Out.str(), ErrorNode);
+ Report->markInteresting(InvalidatedSymbolicBase);
+ Report->addRange(Call.getArgSourceRange(I));
+ C.emitReport(std::move(Report));
+ }
+ }
+ }
+}
+
+// Obtain the environment pointer from 'main()', if present.
+void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const {
+ if (!C.inTopFrame())
+ return;
+
+ const auto *FD = dyn_cast<FunctionDecl>(C.getLocationContext()->getDecl());
+ if (!FD || FD->param_size() != 3 || !FD->isMain())
+ return;
+
+ ProgramStateRef State = C.getState();
+ const MemRegion *EnvpReg =
+ State->getRegion(FD->parameters()[2], C.getLocationContext());
+
+ // Save the memory region pointed by the environment pointer parameter of
+ // 'main'.
+ State = State->set<EnvPtrRegion>(
+ reinterpret_cast<void *>(const_cast<MemRegion *>(EnvpReg)));
+ C.addTransition(State);
+}
+
+// Check if invalidated region is being dereferenced.
+void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+
+ // Ignore memory operations involving 'non-invalidated' locations.
+ const MemRegion *InvalidatedSymbolicBase =
+ findInvalidatedSymbolicBase(State, Loc.getAsRegion());
+ if (!InvalidatedSymbolicBase)
+ return;
+
+ ExplodedNode *ErrorNode = C.generateNonFatalErrorNode();
+ if (!ErrorNode)
+ return;
+
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ BT, "dereferencing an invalid pointer", ErrorNode);
+ Report->markInteresting(InvalidatedSymbolicBase);
+ C.emitReport(std::move(Report));
+}
+
+void ento::registerInvalidPtrChecker(CheckerManager &Mgr) {
+ Mgr.registerChecker<InvalidPtrChecker>();
+}
+
+bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) {
+ return true;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
index 1c67bbd77ec8..ed3bdafad084 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
@@ -38,7 +39,7 @@ public:
void PutenvWithAutoChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- if (!Call.isCalled(Putenv))
+ if (!Putenv.matches(Call))
return;
SVal ArgV = Call.getArgSVal(0);