aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Checkers
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Checkers')
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp46
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp211
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp28
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp35
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp11
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp76
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h62
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp315
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp270
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp38
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp12
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp8
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp136
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp76
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp38
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp14
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp16
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp635
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp241
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Taint.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp2
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp80
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp17
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp6
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp7
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp41
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp9
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp49
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h21
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp4
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp13
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/Yaml.h11
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp2
72 files changed, 1794 insertions, 1067 deletions
diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
index 6154eeb3419c..45783729e142 100644
--- a/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/AnalyzerStatsChecker.cpp
@@ -19,6 +19,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -59,7 +60,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (D != P.getLocationContext()->getDecl())
continue;
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB);
}
@@ -123,7 +124,7 @@ void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G,
if (Exit->empty())
continue;
const CFGElement &CE = Exit->front();
- if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
SmallString<128> bufI;
llvm::raw_svector_ostream outputI(bufI);
outputI << "(" << NameOfRootFunction << ")" <<
diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 5be5bcde4d6e..986b0add93df 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -23,6 +23,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -84,7 +85,7 @@ static SVal computeExtentBegin(SValBuilder &svalBuilder,
static std::pair<NonLoc, nonloc::ConcreteInt>
getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent,
SValBuilder &svalBuilder) {
- Optional<nonloc::SymbolVal> SymVal = offset.getAs<nonloc::SymbolVal>();
+ std::optional<nonloc::SymbolVal> SymVal = offset.getAs<nonloc::SymbolVal>();
if (SymVal && SymVal->isExpression()) {
if (const SymIntExpr *SIE = dyn_cast<SymIntExpr>(SymVal->getSymbol())) {
llvm::APSInt constant =
@@ -143,7 +144,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal extentBegin = computeExtentBegin(svalBuilder, rawOffset.getRegion());
- if (Optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> NV = extentBegin.getAs<NonLoc>()) {
if (auto ConcreteNV = NV->getAs<nonloc::ConcreteInt>()) {
std::pair<NonLoc, nonloc::ConcreteInt> simplifiedOffsets =
getSimplifiedOffsets(rawOffset.getByteOffset(), *ConcreteNV,
@@ -155,7 +156,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
SVal lowerBound = svalBuilder.evalBinOpNN(state, BO_LT, rawOffsetVal, *NV,
svalBuilder.getConditionType());
- Optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
+ std::optional<NonLoc> lowerBoundToCheck = lowerBound.getAs<NonLoc>();
if (!lowerBoundToCheck)
return;
@@ -194,7 +195,7 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
Size.castAs<NonLoc>(),
svalBuilder.getConditionType());
- Optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
+ std::optional<NonLoc> upperboundToCheck = upperbound.getAs<NonLoc>();
if (!upperboundToCheck)
break;
diff --git a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index ca76e2d83381..44166aaf5b85 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -33,6 +33,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -369,7 +370,7 @@ enum CFNumberType {
kCFNumberCGFloatType = 16
};
-static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
+static std::optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
if (i < kCFNumberCharType)
@@ -390,7 +391,7 @@ static Optional<uint64_t> GetCFNumberSize(ASTContext &Ctx, uint64_t i) {
case kCFNumberCGFloatType:
// FIXME: We need a way to map from names to Type*.
default:
- return None;
+ return std::nullopt;
}
return Ctx.getTypeSize(T);
@@ -442,12 +443,13 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
// FIXME: We really should allow ranges of valid theType values, and
// bifurcate the state appropriately.
- Optional<nonloc::ConcreteInt> V = dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
+ std::optional<nonloc::ConcreteInt> V =
+ dyn_cast<nonloc::ConcreteInt>(TheTypeVal);
if (!V)
return;
uint64_t NumberKind = V->getValue().getLimitedValue();
- Optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
+ std::optional<uint64_t> OptCFNumberSize = GetCFNumberSize(Ctx, NumberKind);
// FIXME: In some cases we can emit an error.
if (!OptCFNumberSize)
@@ -462,7 +464,7 @@ void CFNumberChecker::checkPreStmt(const CallExpr *CE,
// FIXME: Eventually we should handle arbitrary locations. We can do this
// by having an enhanced memory model that does low-level typing.
- Optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
+ std::optional<loc::MemRegionVal> LV = TheValueExpr.getAs<loc::MemRegionVal>();
if (!LV)
return;
@@ -531,10 +533,10 @@ namespace {
class CFRetainReleaseChecker : public Checker<check::PreCall> {
mutable APIMisuse BT{this, "null passed to CF memory management function"};
const CallDescriptionSet ModelledCalls = {
- {"CFRetain", 1},
- {"CFRelease", 1},
- {"CFMakeCollectable", 1},
- {"CFAutorelease", 1},
+ {{"CFRetain"}, 1},
+ {{"CFRelease"}, 1},
+ {{"CFMakeCollectable"}, 1},
+ {{"CFAutorelease"}, 1},
};
public:
@@ -554,7 +556,7 @@ void CFRetainReleaseChecker::checkPreCall(const CallEvent &Call,
// Get the argument's value.
SVal ArgVal = Call.getArgSVal(0);
- Optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DefArgVal = ArgVal.getAs<DefinedSVal>();
if (!DefArgVal)
return;
@@ -742,7 +744,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
return;
// Verify that all arguments have Objective-C types.
- Optional<ExplodedNode*> errorNode;
+ std::optional<ExplodedNode *> errorNode;
for (unsigned I = variadicArgsBegin; I != variadicArgsEnd; ++I) {
QualType ArgTy = msg.getArgExpr(I)->getType();
@@ -769,7 +771,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (!errorNode)
errorNode = C.generateNonFatalErrorNode();
- if (!errorNode.value())
+ if (!*errorNode)
continue;
SmallString<128> sbuf;
@@ -786,8 +788,8 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
ArgTy.print(os, C.getLangOpts());
os << "'";
- auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(),
- errorNode.value());
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT, os.str(), *errorNode);
R->addRange(msg.getArgSourceRange(I));
C.emitReport(std::move(R));
}
@@ -857,7 +859,8 @@ static ProgramStateRef checkCollectionNonNil(CheckerContext &C,
return nullptr;
SVal CollectionVal = C.getSVal(FCS->getCollection());
- Optional<DefinedSVal> KnownCollection = CollectionVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> KnownCollection =
+ CollectionVal.getAs<DefinedSVal>();
if (!KnownCollection)
return State;
@@ -889,7 +892,7 @@ static ProgramStateRef checkElementNonNil(CheckerContext &C,
const Stmt *Element = FCS->getElement();
// FIXME: Copied from ExprEngineObjC.
- Optional<Loc> ElementLoc;
+ std::optional<Loc> ElementLoc;
if (const DeclStmt *DS = dyn_cast<DeclStmt>(Element)) {
const VarDecl *ElemDecl = cast<VarDecl>(DS->getSingleDecl());
assert(ElemDecl->getInit() == nullptr);
@@ -928,8 +931,8 @@ assumeCollectionNonEmpty(CheckerContext &C, ProgramStateRef State,
nonloc::SymbolVal(*CountS),
SvalBuilder.makeIntVal(0, (*CountS)->getType()),
SvalBuilder.getConditionType());
- Optional<DefinedSVal> CountGreaterThanZero =
- CountGreaterThanZeroVal.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> CountGreaterThanZero =
+ CountGreaterThanZeroVal.getAs<DefinedSVal>();
if (!CountGreaterThanZero) {
// The SValBuilder cannot construct a valid SVal for this condition.
// This means we cannot properly reason about it.
@@ -957,7 +960,7 @@ static bool alreadyExecutedAtLeastOneLoopIteration(const ExplodedNode *N,
return false;
ProgramPoint P = N->getLocation();
- if (Optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
+ if (std::optional<BlockEdge> BE = P.getAs<BlockEdge>()) {
return BE->getSrc()->getLoopTarget() == FCS;
}
@@ -1092,7 +1095,7 @@ ObjCLoopChecker::checkPointerEscape(ProgramStateRef State,
PointerEscapeKind Kind) const {
SymbolRef ImmutableReceiver = getMethodReceiverIfKnownImmutable(Call);
- // Remove the invalidated symbols form the collection count map.
+ // Remove the invalidated symbols from the collection count map.
for (InvalidatedSymbols::const_iterator I = Escaped.begin(),
E = Escaped.end();
I != E; ++I) {
@@ -1174,7 +1177,8 @@ ObjCNonNilReturnValueChecker::assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
CheckerContext &C) const {
SVal Val = C.getSVal(NonNullExpr);
- if (Optional<DefinedOrUnknownSVal> DV = Val.getAs<DefinedOrUnknownSVal>())
+ if (std::optional<DefinedOrUnknownSVal> DV =
+ Val.getAs<DefinedOrUnknownSVal>())
return State->assume(*DV, true);
return State;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
index 8416ab39e194..76f091562cd5 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BlockInCriticalSectionChecker.cpp
@@ -64,19 +64,15 @@ public:
REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
- : IILockGuard(nullptr), IIUniqueLock(nullptr),
- LockFn("lock"), UnlockFn("unlock"), SleepFn("sleep"), GetcFn("getc"),
- FgetsFn("fgets"), ReadFn("read"), RecvFn("recv"),
- PthreadLockFn("pthread_mutex_lock"),
- PthreadTryLockFn("pthread_mutex_trylock"),
- PthreadUnlockFn("pthread_mutex_unlock"),
- MtxLock("mtx_lock"),
- MtxTimedLock("mtx_timedlock"),
- MtxTryLock("mtx_trylock"),
- MtxUnlock("mtx_unlock"),
- ClassLockGuard("lock_guard"),
- ClassUniqueLock("unique_lock"),
- IdentifierInfoInitialized(false) {
+ : IILockGuard(nullptr), IIUniqueLock(nullptr), LockFn({"lock"}),
+ UnlockFn({"unlock"}), SleepFn({"sleep"}), GetcFn({"getc"}),
+ FgetsFn({"fgets"}), ReadFn({"read"}), RecvFn({"recv"}),
+ PthreadLockFn({"pthread_mutex_lock"}),
+ PthreadTryLockFn({"pthread_mutex_trylock"}),
+ PthreadUnlockFn({"pthread_mutex_unlock"}), MtxLock({"mtx_lock"}),
+ MtxTimedLock({"mtx_timedlock"}), MtxTryLock({"mtx_trylock"}),
+ MtxUnlock({"mtx_unlock"}), ClassLockGuard("lock_guard"),
+ ClassUniqueLock("unique_lock"), IdentifierInfoInitialized(false) {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
diff --git a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index dad25d6f853b..2d20e394681d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -74,7 +75,7 @@ void BoolAssignmentChecker::checkBind(SVal loc, SVal val, const Stmt *S,
// Get the value of the right-hand side. We only care about values
// that are defined (UnknownVals and UndefinedVals are handled by other
// checkers).
- Optional<NonLoc> NV = val.getAs<NonLoc>();
+ std::optional<NonLoc> NV = val.getAs<NonLoc>();
if (!NV)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 9a6c013bcf66..12b948a65261 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -27,6 +27,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <functional>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -75,6 +76,16 @@ static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
}
enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
+
+enum class CharKind { Regular = 0, Wide };
+constexpr CharKind CK_Regular = CharKind::Regular;
+constexpr CharKind CK_Wide = CharKind::Wide;
+
+static QualType getCharPtrType(ASTContext &Ctx, CharKind CK) {
+ return Ctx.getPointerType(CK == CharKind::Regular ? Ctx.CharTy
+ : Ctx.WideCharTy);
+}
+
class CStringChecker : public Checker< eval::Call,
check::PreStmt<DeclStmt>,
check::LiveSymbols,
@@ -124,35 +135,46 @@ public:
const CallExpr *)>;
CallDescriptionMap<FnCheck> Callbacks = {
- {{CDF_MaybeBuiltin, "memcpy", 3},
- std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, false)},
- {{CDF_MaybeBuiltin, "wmemcpy", 3},
- std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, true)},
- {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy},
- {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp},
- {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove},
- {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset},
- {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset},
- {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy},
- {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy},
- {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy},
- {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy},
- {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat},
- {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat},
- {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat},
- {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength},
- {{CDF_MaybeBuiltin, "wcslen", 1}, &CStringChecker::evalstrLength},
- {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength},
- {{CDF_MaybeBuiltin, "wcsnlen", 2}, &CStringChecker::evalstrnLength},
- {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp},
- {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp},
- {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp},
- {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp},
- {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep},
- {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy},
- {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp},
- {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero},
- {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero},
+ {{CDF_MaybeBuiltin, {"memcpy"}, 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemcpy"}, 3},
+ std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"mempcpy"}, 3},
+ std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
+ {{CDF_None, {"wmempcpy"}, 3},
+ std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memmove"}, 3},
+ std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"wmemmove"}, 3},
+ std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
+ {{CDF_MaybeBuiltin, {"memset"}, 3}, &CStringChecker::evalMemset},
+ {{CDF_MaybeBuiltin, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
+ {{CDF_MaybeBuiltin, {"strcpy"}, 2}, &CStringChecker::evalStrcpy},
+ {{CDF_MaybeBuiltin, {"strncpy"}, 3}, &CStringChecker::evalStrncpy},
+ {{CDF_MaybeBuiltin, {"stpcpy"}, 2}, &CStringChecker::evalStpcpy},
+ {{CDF_MaybeBuiltin, {"strlcpy"}, 3}, &CStringChecker::evalStrlcpy},
+ {{CDF_MaybeBuiltin, {"strcat"}, 2}, &CStringChecker::evalStrcat},
+ {{CDF_MaybeBuiltin, {"strncat"}, 3}, &CStringChecker::evalStrncat},
+ {{CDF_MaybeBuiltin, {"strlcat"}, 3}, &CStringChecker::evalStrlcat},
+ {{CDF_MaybeBuiltin, {"strlen"}, 1}, &CStringChecker::evalstrLength},
+ {{CDF_MaybeBuiltin, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
+ {{CDF_MaybeBuiltin, {"strnlen"}, 2}, &CStringChecker::evalstrnLength},
+ {{CDF_MaybeBuiltin, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
+ {{CDF_MaybeBuiltin, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
+ {{CDF_MaybeBuiltin, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
+ {{CDF_MaybeBuiltin, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
+ {{CDF_MaybeBuiltin, {"strncasecmp"}, 3},
+ &CStringChecker::evalStrncasecmp},
+ {{CDF_MaybeBuiltin, {"strsep"}, 2}, &CStringChecker::evalStrsep},
+ {{CDF_MaybeBuiltin, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
+ {{CDF_MaybeBuiltin, {"bcmp"}, 3},
+ std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
+ {{CDF_MaybeBuiltin, {"bzero"}, 2}, &CStringChecker::evalBzero},
+ {{CDF_MaybeBuiltin, {"explicit_bzero"}, 2}, &CStringChecker::evalBzero},
};
// These require a bit of special handling.
@@ -160,16 +182,16 @@ public:
StdCopyBackward{{"std", "copy_backward"}, 3};
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
- void evalMemcpy(CheckerContext &C, const CallExpr *CE, bool IsWide) const;
- void evalMempcpy(CheckerContext &C, const CallExpr *CE) const;
- void evalMemmove(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
+ void evalMempcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
+ void evalMemmove(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest, SourceArgExpr Source,
- bool Restricted, bool IsMempcpy, bool IsWide) const;
+ bool Restricted, bool IsMempcpy, CharKind CK) const;
- void evalMemcmp(CheckerContext &C, const CallExpr *CE) const;
+ void evalMemcmp(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
@@ -248,14 +270,16 @@ public:
AnyArgExpr Arg, SVal l) const;
ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
- AccessKind Access, bool IsWide = false) const;
+ AccessKind Access,
+ CharKind CK = CharKind::Regular) const;
ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
AccessKind Access,
- bool IsWide = false) const;
+ CharKind CK = CharKind::Regular) const;
ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
- AnyArgExpr Second, bool IsWide = false) const;
+ AnyArgExpr Second,
+ CharKind CK = CharKind::Regular) const;
void emitOverlapBug(CheckerContext &C,
ProgramStateRef state,
const Stmt *First,
@@ -295,7 +319,7 @@ REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
std::pair<ProgramStateRef , ProgramStateRef >
CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V,
QualType Ty) {
- Optional<DefinedSVal> val = V.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> val = V.getAs<DefinedSVal>();
if (!val)
return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
@@ -339,7 +363,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef state,
AnyArgExpr Buffer, SVal Element,
AccessKind Access,
- bool IsWide) const {
+ CharKind CK) const {
// If a previous check has failed, propagate the failure.
if (!state)
@@ -360,7 +384,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
// Get the index of the accessed element.
NonLoc Idx = ER->getIndex();
- if (!IsWide) {
+ if (CK == CharKind::Regular) {
if (ER->getValueType() != Ctx.CharTy)
return state;
} else {
@@ -417,7 +441,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
ProgramStateRef
CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
AnyArgExpr Buffer, SizeArgExpr Size,
- AccessKind Access, bool IsWide) const {
+ AccessKind Access, CharKind CK) const {
// If a previous check has failed, propagate the failure.
if (!State)
return nullptr;
@@ -426,7 +450,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
ASTContext &Ctx = svalBuilder.getContext();
QualType SizeTy = Size.Expression->getType();
- QualType PtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
+ QualType PtrTy = getCharPtrType(Ctx, CK);
// Check that the first buffer is non-null.
SVal BufVal = C.getSVal(Buffer.Expression);
@@ -442,7 +466,7 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
SVal LengthVal = C.getSVal(Size.Expression);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return State;
@@ -456,11 +480,11 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
// Check that the first buffer is sufficiently long.
SVal BufStart =
svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
- if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
+ if (std::optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
SVal BufEnd =
svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
- State = CheckLocation(C, State, Buffer, BufEnd, Access, IsWide);
+ State = CheckLocation(C, State, Buffer, BufEnd, Access, CK);
// If the buffer isn't large enough, abort.
if (!State)
@@ -475,7 +499,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
ProgramStateRef state,
SizeArgExpr Size, AnyArgExpr First,
AnyArgExpr Second,
- bool IsWide) const {
+ CharKind CK) const {
if (!Filter.CheckCStringBufferOverlap)
return state;
@@ -499,11 +523,11 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
SVal firstVal = state->getSVal(First.Expression, LCtx);
SVal secondVal = state->getSVal(Second.Expression, LCtx);
- Optional<Loc> firstLoc = firstVal.getAs<Loc>();
+ std::optional<Loc> firstLoc = firstVal.getAs<Loc>();
if (!firstLoc)
return state;
- Optional<Loc> secondLoc = secondVal.getAs<Loc>();
+ std::optional<Loc> secondLoc = secondVal.getAs<Loc>();
if (!secondLoc)
return state;
@@ -526,7 +550,7 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
QualType cmpTy = svalBuilder.getConditionType();
SVal reverse =
svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
- Optional<DefinedOrUnknownSVal> reverseTest =
+ std::optional<DefinedOrUnknownSVal> reverseTest =
reverse.getAs<DefinedOrUnknownSVal>();
if (!reverseTest)
return state;
@@ -547,31 +571,31 @@ ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
// Get the length, and make sure it too is known.
SVal LengthVal = state->getSVal(Size.Expression, LCtx);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return state;
// Convert the first buffer's start address to char*.
// Bail out if the cast fails.
ASTContext &Ctx = svalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(IsWide ? Ctx.WideCharTy : Ctx.CharTy);
+ QualType CharPtrTy = getCharPtrType(Ctx, CK);
SVal FirstStart =
svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
- Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
+ std::optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
if (!FirstStartLoc)
return state;
// Compute the end of the first buffer. Bail out if THAT fails.
SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc,
*Length, CharPtrTy);
- Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
+ std::optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
if (!FirstEndLoc)
return state;
// Is the end of the first buffer past the start of the second buffer?
SVal Overlap =
svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
- Optional<DefinedOrUnknownSVal> OverlapTest =
+ std::optional<DefinedOrUnknownSVal> OverlapTest =
Overlap.getAs<DefinedOrUnknownSVal>();
if (!OverlapTest)
return state;
@@ -736,7 +760,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
left = right;
}
- if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
QualType cmpTy = svalBuilder.getConditionType();
// If left > max - right, we have an overflow.
SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
@@ -822,7 +846,7 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
C.blockCount());
if (!hypothetical) {
- if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
// In case of unbounded calls strlen etc bound the range to SIZE_MAX/4
BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
@@ -848,7 +872,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
// If we can't get a region, see if it's something we /know/ isn't a
// C string. In the context of locations, the only time we can issue such
// a warning is for labels.
- if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
+ if (std::optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
if (Filter.CheckCStringNotNullTerm) {
SmallString<120> buf;
llvm::raw_svector_ostream os(buf);
@@ -953,7 +977,7 @@ bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
SVal BufVal = state->getSVal(FirstBuf, LCtx);
SVal LengthVal = state->getSVal(Size, LCtx);
- Optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
+ std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
if (!Length)
return true; // cf top comment.
@@ -966,7 +990,7 @@ bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
// Check that the first buffer is sufficiently long.
SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
- Optional<Loc> BufLoc = BufStart.getAs<Loc>();
+ std::optional<Loc> BufLoc = BufStart.getAs<Loc>();
if (!BufLoc)
return true; // cf top comment.
@@ -1004,14 +1028,14 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C,
const Expr *E, SVal V,
bool IsSourceBuffer,
const Expr *Size) {
- Optional<Loc> L = V.getAs<Loc>();
+ std::optional<Loc> L = V.getAs<Loc>();
if (!L)
return state;
// FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
// some assumptions about the value that CFRefCount can't. Even so, it should
// probably be refactored.
- if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
const MemRegion *R = MR->getRegion()->StripCasts();
// Are we dealing with an ElementRegion? If so, we should be invalidating
@@ -1111,7 +1135,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
RegionOffset Offset = MR->getAsOffset();
const MemRegion *BR = Offset.getRegion();
- Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
+ std::optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
if (!SizeNL)
return false;
@@ -1190,7 +1214,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest,
SourceArgExpr Source, bool Restricted,
- bool IsMempcpy, bool IsWide) const {
+ bool IsMempcpy, CharKind CK) const {
CurrentFunctionDescription = "memory copy function";
// See if the size argument is zero.
@@ -1233,11 +1257,11 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
return;
// Ensure the accesses are valid and that the buffers do not overlap.
- state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, IsWide);
- state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, IsWide);
+ state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, CK);
+ state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, CK);
if (Restricted)
- state = CheckOverlap(C, state, Size, Dest, Source, IsWide);
+ state = CheckOverlap(C, state, Size, Dest, Source, CK);
if (!state)
return;
@@ -1248,7 +1272,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
// Get the byte after the last byte copied.
SValBuilder &SvalBuilder = C.getSValBuilder();
ASTContext &Ctx = SvalBuilder.getContext();
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
+ QualType CharPtrTy = getCharPtrType(Ctx, CK);
SVal DestRegCharVal =
SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
SVal lastElement = C.getSValBuilder().evalBinOp(
@@ -1288,7 +1312,7 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
- bool IsWide) const {
+ CharKind CK) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1299,11 +1323,11 @@ void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = false;
- evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy,
- IsWide);
+ evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
}
-void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is a pointer to the byte following the last written byte.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1313,10 +1337,11 @@ void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = true;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CK);
}
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {CE->getArg(0), 0};
@@ -1326,7 +1351,7 @@ void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CK);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
@@ -1338,10 +1363,11 @@ void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
- false);
+ CharKind::Regular);
}
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
+void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
+ CharKind CK) const {
// int memcmp(const void *s1, const void *s2, size_t n);
CurrentFunctionDescription = "memory comparison function";
@@ -1401,8 +1427,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const {
// If the two arguments might be different buffers, we have to check
// the size of both of them.
assert(NotSameBuffer);
- State = CheckBufferAccess(C, State, Right, Size, AccessKind::read);
- State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
+ State = CheckBufferAccess(C, State, Right, Size, AccessKind::read, CK);
+ State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
@@ -1481,8 +1507,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
const Expr *maxlenExpr = CE->getArg(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
- Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
- Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
+ std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ std::optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
if (strLengthNL && maxlenValNL) {
ProgramStateRef stateStringTooLong, stateStringNotTooLong;
@@ -1630,11 +1656,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// Get the string length of the source.
SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal);
- Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
+ std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
// Get the string length of the destination buffer.
SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal);
- Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
+ std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
// If the source isn't a valid C string, give up.
if (strLength.isUndef())
@@ -1672,7 +1698,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
lenVal =
svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
- Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
+ std::optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
// If we know both values, we might be able to figure out how much
// we're copying.
@@ -1714,7 +1740,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
freeSpace =
svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
svalBuilder.makeIntVal(1, sizeTy), sizeTy);
- Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
+ std::optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
// While unlikely, it is possible that the subtraction is
// too complex to compute, let's check whether it succeeded.
@@ -1839,7 +1865,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
*dstStrLengthNL, sizeTy);
}
- Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
+ std::optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
// If we know both string lengths, we might know the final string length.
if (amountCopiedNL && dstStrLengthNL) {
@@ -1860,7 +1886,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
finalStrLength = getCStringLength(C, state, CE, DstVal, true);
assert(!finalStrLength.isUndef());
- if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> finalStrLengthNL =
+ finalStrLength.getAs<NonLoc>()) {
if (amountCopiedNL && appendK == ConcatFnKind::none) {
// we overwrite dst string with the src
// finalStrLength >= srcStrLength
@@ -1911,13 +1938,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the destination is a MemRegion, try to check for a buffer overflow and
// record the new string length.
- if (Optional<loc::MemRegionVal> dstRegVal =
- DstVal.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> dstRegVal =
+ DstVal.getAs<loc::MemRegionVal>()) {
QualType ptrTy = Dst.Expression->getType();
// If we have an exact value on a bounded copy, use that to check for
// overflows, rather than our estimate about how much is actually copied.
- if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
SVal maxLastElement =
svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
@@ -1927,7 +1954,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
}
// Then, if the final length is known...
- if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
+ if (std::optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
*knownStrLength, ptrTy);
@@ -2119,7 +2146,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType());
// Constrain strcmp's result range based on the result of StringRef's
// comparison methods.
- BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT;
+ BinaryOperatorKind op = (compareRes > 0) ? BO_GT : BO_LT;
SVal compareWithZero =
svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
svalBuilder.getConditionType());
@@ -2165,7 +2192,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
SValBuilder &SVB = C.getSValBuilder();
SVal Result;
- if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
+ if (std::optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
// Get the current value of the search string pointer, as a char*.
Result = State->getSVal(*SearchStrLoc, CharPtrTy);
diff --git a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
index 45f9a82a9d0a..f02d20d45678 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
@@ -24,7 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
-#include "llvm/ADT/Optional.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -472,7 +472,7 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
const CastCheck &Check = Lookup->first;
CallKind Kind = Lookup->second;
- Optional<DefinedOrUnknownSVal> DV;
+ std::optional<DefinedOrUnknownSVal> DV;
switch (Kind) {
case CallKind::Function: {
diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index 2d2ddcdf3890..3fcf6f435a43 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -45,6 +45,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -282,7 +283,7 @@ void ObjCDeallocChecker::checkBeginFunction(
continue;
SVal LVal = State->getLValue(PropImpl->getPropertyIvarDecl(), SelfVal);
- Optional<Loc> LValLoc = LVal.getAs<Loc>();
+ std::optional<Loc> LValLoc = LVal.getAs<Loc>();
if (!LValLoc)
continue;
@@ -953,7 +954,7 @@ ObjCDeallocChecker::getValueReleasedByNillingOut(const ObjCMethodCall &M,
ProgramStateRef State = C.getState();
SVal LVal = State->getLValue(PropIvarDecl, ReceiverVal);
- Optional<Loc> LValLoc = LVal.getAs<Loc>();
+ std::optional<Loc> LValLoc = LVal.getAs<Loc>();
if (!LValLoc)
return nullptr;
@@ -1004,7 +1005,7 @@ bool ObjCDeallocChecker::instanceDeallocIsOnStack(const CheckerContext &C,
return false;
}
-/// Returns true if the ID is a class in which which is known to have
+/// Returns true if the ID is a class in which is known to have
/// a separate teardown lifecycle. In this case, -dealloc warnings
/// about missing releases should be suppressed.
bool ObjCDeallocChecker::classHasSeparateTeardown(
diff --git a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index ce8d6c879870..9ace1583eb53 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -43,7 +43,7 @@ class ChrootChecker : public Checker<eval::Call, check::PreCall> {
// This bug refers to possibly break out of a chroot() jail.
mutable std::unique_ptr<BuiltinBug> BT_BreakJail;
- const CallDescription Chroot{"chroot", 1}, Chdir{"chdir", 1};
+ const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
public:
ChrootChecker() {}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
index 77a3218f55fb..67962f75f9bf 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ContainerModeling.cpp
@@ -72,26 +72,26 @@ public:
SVal) const;
CallDescriptionMap<NoItParamFn> NoIterParamFunctions = {
- {{"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},
+ {{{"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 = {
- {{"insert", 2}, &ContainerModeling::handleInsert},
- {{"emplace", 2}, &ContainerModeling::handleInsert},
- {{"erase", 1}, &ContainerModeling::handleErase},
- {{"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 = {
- {{"erase", 2}, &ContainerModeling::handleErase},
- {{"erase_after", 2}, &ContainerModeling::handleEraseAfter},
+ {{{"erase"}, 2}, &ContainerModeling::handleErase},
+ {{{"erase_after"}, 2}, &ContainerModeling::handleEraseAfter},
};
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 2102f9233bc1..01b662064d7b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -38,17 +38,17 @@ public:
llvm::DenseSet<const VarDecl *> &S;
bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
- SaveAndRestore<bool> inFinally(inEH, true);
+ SaveAndRestore inFinally(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
}
bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
- SaveAndRestore<bool> inCatch(inEH, true);
+ SaveAndRestore inCatch(inEH, true);
return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
}
bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
- SaveAndRestore<bool> inCatch(inEH, true);
+ SaveAndRestore inCatch(inEH, true);
return TraverseStmt(S->getHandlerBlock());
}
@@ -103,8 +103,8 @@ void ReachableCode::computeReachableBlocks() {
static const Expr *
LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
while (Ex) {
- const BinaryOperator *BO =
- dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
+ Ex = Ex->IgnoreParenCasts();
+ const BinaryOperator *BO = dyn_cast<BinaryOperator>(Ex);
if (!BO)
break;
BinaryOperatorKind Op = BO->getOpcode();
@@ -240,7 +240,7 @@ public:
case DeadIncrement:
BugType = "Dead increment";
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case Standard:
if (!BugType) BugType = "Dead assignment";
os << "Value stored to '" << *V << "' is never read";
@@ -331,8 +331,7 @@ public:
// Special case: check for assigning null to a pointer.
// This is a common form of defensive programming.
const Expr *RHS =
- LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
- RHS = RHS->IgnoreParenCasts();
+ LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
QualType T = VD->getType();
if (T.isVolatileQualified())
@@ -415,8 +414,7 @@ public:
if (isConstant(E))
return;
- if (const DeclRefExpr *DRE =
- dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+ if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
// Special case: check for initialization from constant
// variables.
@@ -438,7 +436,7 @@ public:
PathDiagnosticLocation Loc =
PathDiagnosticLocation::create(V, BR.getSourceManager());
- Report(V, DeadInit, Loc, E->getSourceRange());
+ Report(V, DeadInit, Loc, V->getInit()->getSourceRange());
}
}
}
@@ -450,8 +448,9 @@ private:
bool isConstant(const InitListExpr *Candidate) const {
// We consider init list to be constant if each member of the list can be
// interpreted as constant.
- return llvm::all_of(Candidate->inits(),
- [this](const Expr *Init) { return isConstant(Init); });
+ return llvm::all_of(Candidate->inits(), [this](const Expr *Init) {
+ return isConstant(Init->IgnoreParenCasts());
+ });
}
/// Return true if the given expression can be interpreted as constant
@@ -461,7 +460,7 @@ private:
return true;
// We should also allow defensive initialization of structs, i.e. { 0 }
- if (const auto *ILE = dyn_cast<InitListExpr>(E->IgnoreParenCasts())) {
+ if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
return isConstant(ILE);
}
@@ -504,7 +503,7 @@ public:
// Treat local variables captured by reference in C++ lambdas as escaped.
void findLambdaReferenceCaptures(const LambdaExpr *LE) {
const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
- llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+ llvm::DenseMap<const ValueDecl *, FieldDecl *> CaptureFields;
FieldDecl *ThisCaptureField;
LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
@@ -512,14 +511,14 @@ public:
if (!C.capturesVariable())
continue;
- VarDecl *VD = C.getCapturedVar();
+ ValueDecl *VD = C.getCapturedVar();
const FieldDecl *FD = CaptureFields[VD];
- if (!FD)
+ if (!FD || !isa<VarDecl>(VD))
continue;
// If the capture field is a reference type, it is capture-by-reference.
if (FD->getType()->isReferenceType())
- Escaped.insert(VD);
+ Escaped.insert(cast<VarDecl>(VD));
}
}
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
index 47fd57c7db9b..832bb78c4803 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugContainerModeling.cpp
@@ -41,9 +41,9 @@ class DebugContainerModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{"clang_analyzer_container_begin", 1},
+ {{{"clang_analyzer_container_begin"}, 1},
&DebugContainerModeling::analyzerContainerBegin},
- {{"clang_analyzer_container_end", 1},
+ {{{"clang_analyzer_container_end"}, 1},
&DebugContainerModeling::analyzerContainerEnd},
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
index 6add9a007a87..d05298b42c55 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp
@@ -42,11 +42,11 @@ class DebugIteratorModeling
CheckerContext &) const;
CallDescriptionMap<FnCheck> Callbacks = {
- {{"clang_analyzer_iterator_position", 1},
+ {{{"clang_analyzer_iterator_position"}, 1},
&DebugIteratorModeling::analyzerIteratorPosition},
- {{"clang_analyzer_iterator_container", 1},
+ {{{"clang_analyzer_iterator_container"}, 1},
&DebugIteratorModeling::analyzerIteratorContainer},
- {{"clang_analyzer_iterator_validity", 1},
+ {{{"clang_analyzer_iterator_validity"}, 1},
&DebugIteratorModeling::analyzerIteratorValidity},
};
diff --git a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
index bfd1d4c162ec..cc01e97d3fa2 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -67,7 +68,7 @@ void DivZeroChecker::checkPreStmt(const BinaryOperator *B,
return;
SVal Denom = C.getSVal(B->getRHS());
- Optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DV = Denom.getAs<DefinedSVal>();
// Divide-by-undefined handled in the generic checking for uses of
// undefined values.
diff --git a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index aaf8cca32b60..6f26842e62c7 100644
--- a/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -31,6 +31,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -846,7 +847,7 @@ void DynamicTypePropagation::checkPreObjCMessage(const ObjCMethodCall &M,
return;
}
- Optional<ArrayRef<QualType>> TypeArgs =
+ std::optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
// This case might happen when there is an unspecialized override of a
// specialized method.
@@ -979,7 +980,7 @@ void DynamicTypePropagation::checkPostObjCMessage(const ObjCMethodCall &M,
if (!Method)
return;
- Optional<ArrayRef<QualType>> TypeArgs =
+ std::optional<ArrayRef<QualType>> TypeArgs =
(*TrackedType)->getObjCSubstitutions(Method->getDeclContext());
if (!TypeArgs)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index e5088fb266bc..1077ceb6288e 100644
--- a/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -108,7 +109,7 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
}
// Get the value of the expression to cast.
- const llvm::Optional<DefinedOrUnknownSVal> ValueToCast =
+ const std::optional<DefinedOrUnknownSVal> ValueToCast =
C.getSVal(CE->getSubExpr()).getAs<DefinedOrUnknownSVal>();
// If the value cannot be reasoned about (not even a DefinedOrUnknownSVal),
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
index d8c3d7a4a6a6..265185e64107 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoChecker.cpp
@@ -22,6 +22,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -132,7 +133,7 @@ void ErrnoChecker::generateErrnoNotCheckedBug(
void ErrnoChecker::checkLocation(SVal Loc, bool IsLoad, const Stmt *S,
CheckerContext &C) const {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
if (!ErrnoLoc)
return;
@@ -206,7 +207,7 @@ void ErrnoChecker::checkPreCall(const CallEvent &Call,
C.getSourceManager().isInSystemHeader(CallF->getLocation()) &&
!isErrno(CallF)) {
if (getErrnoState(C.getState()) == MustBeChecked) {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(C.getState());
assert(ErrnoLoc && "ErrnoLoc should exist if an errno state is set.");
generateErrnoNotCheckedBug(C, setErrnoStateIrrelevant(C.getState()),
ErrnoLoc->getAsRegion(), &Call);
@@ -219,7 +220,7 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
ArrayRef<const MemRegion *> ExplicitRegions,
ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx,
const CallEvent *Call) const {
- Optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
+ std::optional<ento::Loc> ErrnoLoc = getErrnoLoc(State);
if (!ErrnoLoc)
return State;
const MemRegion *ErrnoRegion = ErrnoLoc->getAsRegion();
@@ -227,12 +228,12 @@ ProgramStateRef ErrnoChecker::checkRegionChanges(
// If 'errno' is invalidated we can not know if it is checked or written into,
// allow read and write without bug reports.
if (llvm::is_contained(Regions, ErrnoRegion))
- return setErrnoStateIrrelevant(State);
+ return clearErrnoState(State);
// Always reset errno state when the system memory space is invalidated.
// The ErrnoRegion is not always found in the list in this case.
if (llvm::is_contained(Regions, ErrnoRegion->getMemorySpace()))
- return setErrnoStateIrrelevant(State);
+ return clearErrnoState(State);
return State;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index 618f7e97f6e8..51f39c606d5c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -28,6 +28,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/STLExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -57,11 +58,11 @@ public:
private:
// FIXME: Names from `ErrnoLocationFuncNames` are used to build this set.
- CallDescriptionSet ErrnoLocationCalls{{"__errno_location", 0, 0},
- {"___errno", 0, 0},
- {"__errno", 0, 0},
- {"_errno", 0, 0},
- {"__error", 0, 0}};
+ CallDescriptionSet ErrnoLocationCalls{{{"__errno_location"}, 0, 0},
+ {{"___errno"}, 0, 0},
+ {{"__errno"}, 0, 0},
+ {{"_errno"}, 0, 0},
+ {{"__error"}, 0, 0}};
};
} // namespace
@@ -207,7 +208,7 @@ namespace clang {
namespace ento {
namespace errno_modeling {
-Optional<SVal> getErrnoValue(ProgramStateRef State) {
+std::optional<SVal> getErrnoValue(ProgramStateRef State) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return {};
@@ -239,19 +240,23 @@ ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
return State->set<ErrnoState>(EState);
}
-Optional<Loc> getErrnoLoc(ProgramStateRef State) {
+std::optional<Loc> getErrnoLoc(ProgramStateRef State) {
const MemRegion *ErrnoR = State->get<ErrnoRegion>();
if (!ErrnoR)
return {};
return loc::MemRegionVal{ErrnoR};
}
+ErrnoCheckState getErrnoState(ProgramStateRef State) {
+ return State->get<ErrnoState>();
+}
+
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState) {
return State->set<ErrnoState>(EState);
}
-ErrnoCheckState getErrnoState(ProgramStateRef State) {
- return State->get<ErrnoState>();
+ProgramStateRef clearErrnoState(ProgramStateRef State) {
+ return setErrnoState(State, Irrelevant);
}
bool isErrno(const Decl *D) {
@@ -264,6 +269,12 @@ bool isErrno(const Decl *D) {
return false;
}
+const char *describeErrnoCheckState(ErrnoCheckState CS) {
+ assert(CS == errno_modeling::MustNotBeChecked &&
+ "Errno description not applicable.");
+ return "may be undefined after the call and should not be used";
+}
+
const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
return C.getNoteTag([Message](PathSensitiveBugReport &BR) -> std::string {
const MemRegion *ErrnoR = BR.getErrorNode()->getState()->get<ErrnoRegion>();
@@ -275,6 +286,53 @@ const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message) {
});
}
+ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State,
+ CheckerContext &C) {
+ return setErrnoState(State, MustNotBeChecked);
+}
+
+ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
+ NonLoc ErrnoSym) {
+ SValBuilder &SVB = C.getSValBuilder();
+ NonLoc ZeroVal = SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
+ DefinedOrUnknownSVal Cond =
+ SVB.evalBinOp(State, BO_NE, ErrnoSym, ZeroVal, SVB.getConditionType())
+ .castAs<DefinedOrUnknownSVal>();
+ State = State->assume(Cond, true);
+ if (!State)
+ return nullptr;
+ return setErrnoValue(State, C.getLocationContext(), ErrnoSym, Irrelevant);
+}
+
+ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
+ CheckerContext &C,
+ const Expr *InvalE) {
+ const MemRegion *ErrnoR = State->get<ErrnoRegion>();
+ if (!ErrnoR)
+ return State;
+ State = State->invalidateRegions(ErrnoR, InvalE, C.blockCount(),
+ C.getLocationContext(), false);
+ if (!State)
+ return nullptr;
+ return setErrnoState(State, MustBeChecked);
+}
+
+const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
+ return getErrnoNoteTag(
+ C, (Twine("Assuming that function '") + Twine(Fn) +
+ Twine("' is successful, in this case the value 'errno' ") +
+ Twine(describeErrnoCheckState(MustNotBeChecked)))
+ .str());
+}
+
+const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
+ llvm::StringRef Fn) {
+ return getErrnoNoteTag(
+ C, (Twine("Function '") + Twine(Fn) +
+ Twine("' indicates failure only by setting of 'errno'"))
+ .str());
+}
+
} // namespace errno_modeling
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
index 3757e25e1afe..2ca3979944e3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
@@ -16,35 +16,43 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include <optional>
namespace clang {
namespace ento {
namespace errno_modeling {
+/// Describe how reads and writes of \c errno are handled by the checker.
enum ErrnoCheckState : unsigned {
/// We do not know anything about 'errno'.
+ /// Read and write is always allowed.
Irrelevant = 0,
/// Value of 'errno' should be checked to find out if a previous function call
/// has failed.
+ /// When this state is set \c errno must be read by the program before a next
+ /// standard function call or other overwrite of \c errno follows, otherwise
+ /// a bug report is emitted.
MustBeChecked = 1,
/// Value of 'errno' is not allowed to be read, it can contain an unspecified
/// value.
+ /// When this state is set \c errno is not allowed to be read by the program
+ /// until it is overwritten or invalidated.
MustNotBeChecked = 2
};
/// Returns the value of 'errno', if 'errno' was found in the AST.
-llvm::Optional<SVal> getErrnoValue(ProgramStateRef State);
+std::optional<SVal> getErrnoValue(ProgramStateRef State);
/// Returns the errno check state, \c Errno_Irrelevant if 'errno' was not found
/// (this is not the only case for that value).
ErrnoCheckState getErrnoState(ProgramStateRef State);
/// Returns the location that points to the \c MemoryRegion where the 'errno'
-/// value is stored. Returns \c None if 'errno' was not found. Otherwise it
-/// always returns a valid memory region in the system global memory space.
-llvm::Optional<Loc> getErrnoLoc(ProgramStateRef State);
+/// value is stored. Returns \c std::nullopt if 'errno' was not found. Otherwise
+/// it always returns a valid memory region in the system global memory space.
+std::optional<Loc> getErrnoLoc(ProgramStateRef State);
/// Set value of 'errno' to any SVal, if possible.
/// The errno check state is set always when the 'errno' value is set.
@@ -60,6 +68,9 @@ ProgramStateRef setErrnoValue(ProgramStateRef State, CheckerContext &C,
/// Set the errno check state, do not modify the errno value.
ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState);
+/// Clear state of errno (make it irrelevant).
+ProgramStateRef clearErrnoState(ProgramStateRef State);
+
/// Determine if a `Decl` node related to 'errno'.
/// This is true if the declaration is the errno variable or a function
/// that returns a pointer to the 'errno' value (usually the 'errno' macro is
@@ -67,10 +78,53 @@ ProgramStateRef setErrnoState(ProgramStateRef State, ErrnoCheckState EState);
/// declaration.
bool isErrno(const Decl *D);
+/// Produce a textual description about how \c errno is allowed to be used
+/// (in a \c ErrnoCheckState).
+/// The returned string is insertable into a longer warning message in the form
+/// "the value 'errno' <...>".
+/// Currently only the \c errno_modeling::MustNotBeChecked state is supported,
+/// others are not used by the clients.
+const char *describeErrnoCheckState(ErrnoCheckState CS);
+
/// Create a NoteTag that displays the message if the 'errno' memory region is
/// marked as interesting, and resets the interestingness.
const NoteTag *getErrnoNoteTag(CheckerContext &C, const std::string &Message);
+/// Set errno state for the common case when a standard function is successful.
+/// Set \c ErrnoCheckState to \c MustNotBeChecked (the \c errno value is not
+/// affected). At the state transition a note tag created by
+/// \c getNoteTagForStdSuccess can be used.
+ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C);
+
+/// Set errno state for the common case when a standard function fails.
+/// Set \c errno value to be not equal to zero and \c ErrnoCheckState to
+/// \c Irrelevant . The irrelevant errno state ensures that no related bug
+/// report is emitted later and no note tag is needed.
+/// \arg \c ErrnoSym Value to be used for \c errno and constrained to be
+/// non-zero.
+ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
+ NonLoc ErrnoSym);
+
+/// Set errno state for the common case when a standard function indicates
+/// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and
+/// invalidates the errno region (clear of previous value).
+/// At the state transition a note tag created by
+/// \c getNoteTagForStdMustBeChecked can be used.
+/// \arg \c InvalE Expression that causes invalidation of \c errno.
+ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
+ CheckerContext &C, const Expr *InvalE);
+
+/// Generate the note tag that can be applied at the state generated by
+/// \c setErrnoForStdSuccess .
+/// \arg \c Fn Name of the (standard) function that is modeled.
+const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn);
+
+/// Generate the note tag that can be applied at the state generated by
+/// \c setErrnoStdMustBeChecked .
+/// \arg \c Fn Name of the (standard) function that is modeled.
+const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
+ llvm::StringRef Fn);
+
} // namespace errno_modeling
} // namespace ento
} // namespace clang
diff --git a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
index 924407ebe2d1..c46ebee0c94f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ErrnoTesterChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,13 +70,13 @@ private:
using EvalFn = std::function<void(CheckerContext &, const CallEvent &)>;
const CallDescriptionMap<EvalFn> TestCalls{
- {{"ErrnoTesterChecker_setErrno", 1}, &ErrnoTesterChecker::evalSetErrno},
- {{"ErrnoTesterChecker_getErrno", 0}, &ErrnoTesterChecker::evalGetErrno},
- {{"ErrnoTesterChecker_setErrnoIfError", 0},
+ {{{"ErrnoTesterChecker_setErrno"}, 1}, &ErrnoTesterChecker::evalSetErrno},
+ {{{"ErrnoTesterChecker_getErrno"}, 0}, &ErrnoTesterChecker::evalGetErrno},
+ {{{"ErrnoTesterChecker_setErrnoIfError"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfError},
- {{"ErrnoTesterChecker_setErrnoIfErrorRange", 0},
+ {{{"ErrnoTesterChecker_setErrnoIfErrorRange"}, 0},
&ErrnoTesterChecker::evalSetErrnoIfErrorRange},
- {{"ErrnoTesterChecker_setErrnoCheckState", 0},
+ {{{"ErrnoTesterChecker_setErrnoCheckState"}, 0},
&ErrnoTesterChecker::evalSetErrnoCheckState}};
};
@@ -91,7 +92,7 @@ void ErrnoTesterChecker::evalGetErrno(CheckerContext &C,
const CallEvent &Call) {
ProgramStateRef State = C.getState();
- Optional<SVal> ErrnoVal = getErrnoValue(State);
+ std::optional<SVal> ErrnoVal = getErrnoValue(State);
assert(ErrnoVal && "Errno value should be available.");
State =
State->BindExpr(Call.getOriginExpr(), C.getLocationContext(), *ErrnoVal);
diff --git a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index ec1b0a70d7d3..355e9c2238a4 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ScopedPrinter.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -58,9 +59,9 @@ class ExprInspectionChecker
// Optional parameter `ExprVal` for expression value to be marked interesting.
ExplodedNode *reportBug(llvm::StringRef Msg, CheckerContext &C,
- Optional<SVal> ExprVal = None) const;
+ std::optional<SVal> ExprVal = std::nullopt) const;
ExplodedNode *reportBug(llvm::StringRef Msg, BugReporter &BR, ExplodedNode *N,
- Optional<SVal> ExprVal = None) const;
+ std::optional<SVal> ExprVal = std::nullopt) const;
template <typename T> void printAndReport(CheckerContext &C, T What) const;
const Expr *getArgExpr(const CallExpr *CE, CheckerContext &C) const;
@@ -115,7 +116,8 @@ bool ExprInspectionChecker::evalCall(const CallEvent &Call,
.Case("clang_analyzer_hashDump",
&ExprInspectionChecker::analyzerHashDump)
.Case("clang_analyzer_denote", &ExprInspectionChecker::analyzerDenote)
- .Case("clang_analyzer_express",
+ .Case("clang_analyzer_express", // This also marks the argument as
+ // interesting.
&ExprInspectionChecker::analyzerExpress)
.StartsWith("clang_analyzer_isTainted",
&ExprInspectionChecker::analyzerIsTainted)
@@ -160,17 +162,18 @@ static const char *getArgumentValueString(const CallExpr *CE,
}
}
-ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
- CheckerContext &C,
- Optional<SVal> ExprVal) const {
+ExplodedNode *
+ExprInspectionChecker::reportBug(llvm::StringRef Msg, CheckerContext &C,
+ std::optional<SVal> ExprVal) const {
ExplodedNode *N = C.generateNonFatalErrorNode();
reportBug(Msg, C.getBugReporter(), N, ExprVal);
return N;
}
-ExplodedNode *ExprInspectionChecker::reportBug(llvm::StringRef Msg,
- BugReporter &BR, ExplodedNode *N,
- Optional<SVal> ExprVal) const {
+ExplodedNode *
+ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR,
+ ExplodedNode *N,
+ std::optional<SVal> ExprVal) const {
if (!N)
return nullptr;
@@ -354,8 +357,7 @@ void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE,
if (const auto *TVR = MR->getAs<TypedValueRegion>()) {
ElementTy = TVR->getValueType();
} else {
- ElementTy =
- MR->castAs<SymbolicRegion>()->getSymbol()->getType()->getPointeeType();
+ ElementTy = MR->castAs<SymbolicRegion>()->getPointeeStaticType();
}
assert(!ElementTy->isPointerType());
@@ -466,58 +468,60 @@ void ExprInspectionChecker::analyzerDenote(const CallExpr *CE,
namespace {
class SymbolExpressor
- : public SymExprVisitor<SymbolExpressor, Optional<std::string>> {
+ : public SymExprVisitor<SymbolExpressor, std::optional<std::string>> {
ProgramStateRef State;
public:
SymbolExpressor(ProgramStateRef State) : State(State) {}
- Optional<std::string> lookup(const SymExpr *S) {
+ std::optional<std::string> lookup(const SymExpr *S) {
if (const StringLiteral *const *SLPtr = State->get<DenotedSymbols>(S)) {
const StringLiteral *SL = *SLPtr;
return std::string(SL->getBytes());
}
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymExpr(const SymExpr *S) { return lookup(S); }
+ std::optional<std::string> VisitSymExpr(const SymExpr *S) {
+ return lookup(S);
+ }
- Optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymIntExpr(const SymIntExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getLHS()))
+ if (std::optional<std::string> Str = Visit(S->getLHS()))
return (*Str + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) + " " +
std::to_string(S->getRHS().getLimitedValue()) +
(S->getRHS().isUnsigned() ? "U" : ""))
.str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymSymExpr(const SymSymExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str1 = Visit(S->getLHS()))
- if (Optional<std::string> Str2 = Visit(S->getRHS()))
+ if (std::optional<std::string> Str1 = Visit(S->getLHS()))
+ if (std::optional<std::string> Str2 = Visit(S->getRHS()))
return (*Str1 + " " + BinaryOperator::getOpcodeStr(S->getOpcode()) +
" " + *Str2)
.str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitUnarySymExpr(const UnarySymExpr *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitUnarySymExpr(const UnarySymExpr *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getOperand()))
+ if (std::optional<std::string> Str = Visit(S->getOperand()))
return (UnaryOperator::getOpcodeStr(S->getOpcode()) + *Str).str();
- return None;
+ return std::nullopt;
}
- Optional<std::string> VisitSymbolCast(const SymbolCast *S) {
- if (Optional<std::string> Str = lookup(S))
+ std::optional<std::string> VisitSymbolCast(const SymbolCast *S) {
+ if (std::optional<std::string> Str = lookup(S))
return Str;
- if (Optional<std::string> Str = Visit(S->getOperand()))
+ if (std::optional<std::string> Str = Visit(S->getOperand()))
return (Twine("(") + S->getType().getAsString() + ")" + *Str).str();
- return None;
+ return std::nullopt;
}
};
} // namespace
@@ -531,14 +535,14 @@ void ExprInspectionChecker::analyzerExpress(const CallExpr *CE,
SVal ArgVal = C.getSVal(CE->getArg(0));
SymbolRef Sym = ArgVal.getAsSymbol();
if (!Sym) {
- reportBug("Not a symbol", C);
+ reportBug("Not a symbol", C, ArgVal);
return;
}
SymbolExpressor V(C.getState());
auto Str = V.Visit(Sym);
if (!Str) {
- reportBug("Unable to express", C);
+ reportBug("Unable to express", C, ArgVal);
return;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
index eb3b89ee6c5c..65ff1be8ec05 100644
--- a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
@@ -101,6 +101,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -300,7 +301,7 @@ getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) {
}
} else {
assert(PtrToHandleLevel == 1);
- if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
+ if (std::optional<Loc> ArgLoc = Arg.getAs<Loc>()) {
SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol();
if (Sym) {
return {Sym};
diff --git a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
index dbfdff4d2a3b..43d2eeeb4b27 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -258,7 +259,7 @@ SVal GTestChecker::getAssertionResultSuccessFieldValue(
if (!SuccessField)
return UnknownVal();
- Optional<Loc> FieldLoc =
+ std::optional<Loc> FieldLoc =
State->getLValue(SuccessField, Instance).getAs<Loc>();
if (!FieldLoc)
return UnknownVal();
diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index f0a114801dda..f6e2f59d5697 100644
--- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -30,6 +30,7 @@
#include <limits>
#include <memory>
+#include <optional>
#include <utility>
#define DEBUG_TYPE "taint-checker"
@@ -124,16 +125,17 @@ SVal getPointeeOf(const CheckerContext &C, Loc LValue) {
}
/// Given a pointer/reference argument, return the value it refers to.
-Optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) {
+std::optional<SVal> getPointeeOf(const CheckerContext &C, SVal Arg) {
if (auto LValue = Arg.getAs<Loc>())
return getPointeeOf(C, *LValue);
- return None;
+ return std::nullopt;
}
/// Given a pointer, return the SVal of its pointee or if it is tainted,
/// otherwise return the pointer's SVal if tainted.
/// Also considers stdin as a taint source.
-Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) {
+std::optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C,
+ SVal Arg) {
const ProgramStateRef State = C.getState();
if (auto Pointee = getPointeeOf(C, Arg))
@@ -147,7 +149,7 @@ Optional<SVal> getTaintedPointeeOrPointer(const CheckerContext &C, SVal Arg) {
if (isStdin(Arg, C.getASTContext()))
return Arg;
- return None;
+ return std::nullopt;
}
bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State,
@@ -161,7 +163,8 @@ bool isTaintedOrPointsToTainted(const Expr *E, const ProgramStateRef &State,
class ArgSet {
public:
ArgSet() = default;
- ArgSet(ArgVecTy &&DiscreteArgs, Optional<ArgIdxTy> VariadicIndex = None)
+ ArgSet(ArgVecTy &&DiscreteArgs,
+ std::optional<ArgIdxTy> VariadicIndex = std::nullopt)
: DiscreteArgs(std::move(DiscreteArgs)),
VariadicIndex(std::move(VariadicIndex)) {}
@@ -176,7 +179,7 @@ public:
private:
ArgVecTy DiscreteArgs;
- Optional<ArgIdxTy> VariadicIndex;
+ std::optional<ArgIdxTy> VariadicIndex;
};
/// A struct used to specify taint propagation rules for a function.
@@ -197,12 +200,12 @@ class GenericTaintRule {
ArgSet PropDstArgs;
/// A message that explains why the call is sensitive to taint.
- Optional<StringRef> SinkMsg;
+ std::optional<StringRef> SinkMsg;
GenericTaintRule() = default;
GenericTaintRule(ArgSet &&Sink, ArgSet &&Filter, ArgSet &&Src, ArgSet &&Dst,
- Optional<StringRef> SinkMsg = None)
+ std::optional<StringRef> SinkMsg = std::nullopt)
: SinkArgs(std::move(Sink)), FilterArgs(std::move(Filter)),
PropSrcArgs(std::move(Src)), PropDstArgs(std::move(Dst)),
SinkMsg(SinkMsg) {}
@@ -211,7 +214,7 @@ public:
/// Make a rule that reports a warning if taint reaches any of \p FilterArgs
/// arguments.
static GenericTaintRule Sink(ArgSet &&SinkArgs,
- Optional<StringRef> Msg = None) {
+ std::optional<StringRef> Msg = std::nullopt) {
return {std::move(SinkArgs), {}, {}, {}, Msg};
}
@@ -232,9 +235,9 @@ public:
}
/// Make a rule that taints all PropDstArgs if any of PropSrcArgs is tainted.
- static GenericTaintRule SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs,
- ArgSet &&DstArgs,
- Optional<StringRef> Msg = None) {
+ static GenericTaintRule
+ SinkProp(ArgSet &&SinkArgs, ArgSet &&SrcArgs, ArgSet &&DstArgs,
+ std::optional<StringRef> Msg = std::nullopt) {
return {
std::move(SinkArgs), {}, std::move(SrcArgs), std::move(DstArgs), Msg};
}
@@ -302,7 +305,7 @@ struct GenericTaintRuleParser {
TaintConfiguration &&Config) const;
private:
- using NamePartsTy = llvm::SmallVector<SmallString<32>, 2>;
+ using NamePartsTy = llvm::SmallVector<StringRef, 2>;
/// Validate part of the configuration, which contains a list of argument
/// indexes.
@@ -359,8 +362,8 @@ private:
// TODO: Remove separation to simplify matching logic once CallDescriptions
// are more expressive.
- mutable Optional<RuleLookupTy> StaticTaintRules;
- mutable Optional<RuleLookupTy> DynamicTaintRules;
+ mutable std::optional<RuleLookupTy> StaticTaintRules;
+ mutable std::optional<RuleLookupTy> DynamicTaintRules;
};
} // end of anonymous namespace
@@ -442,10 +445,8 @@ GenericTaintRuleParser::parseNameParts(const Config &C) {
if (!C.Scope.empty()) {
// If the Scope argument contains multiple "::" parts, those are considered
// namespace identifiers.
- llvm::SmallVector<StringRef, 2> NSParts;
- StringRef{C.Scope}.split(NSParts, "::", /*MaxSplit*/ -1,
+ StringRef{C.Scope}.split(NameParts, "::", /*MaxSplit*/ -1,
/*KeepEmpty*/ false);
- NameParts.append(NSParts.begin(), NSParts.end());
}
NameParts.emplace_back(C.Name);
return NameParts;
@@ -456,10 +457,7 @@ void GenericTaintRuleParser::consumeRulesFromConfig(const Config &C,
GenericTaintRule &&Rule,
RulesContTy &Rules) {
NamePartsTy NameParts = parseNameParts(C);
- llvm::SmallVector<const char *, 2> CallDescParts{NameParts.size()};
- llvm::transform(NameParts, CallDescParts.begin(),
- [](SmallString<32> &S) { return S.c_str(); });
- Rules.emplace_back(CallDescription(CallDescParts), std::move(Rule));
+ Rules.emplace_back(CallDescription(NameParts), std::move(Rule));
}
void GenericTaintRuleParser::parseConfig(const std::string &Option,
@@ -485,10 +483,12 @@ void GenericTaintRuleParser::parseConfig(const std::string &Option,
validateArgVector(Option, P.DstArgs);
bool IsSrcVariadic = P.VarType == TaintConfiguration::VariadicType::Src;
bool IsDstVariadic = P.VarType == TaintConfiguration::VariadicType::Dst;
- Optional<ArgIdxTy> JustVarIndex = P.VarIndex;
+ std::optional<ArgIdxTy> JustVarIndex = P.VarIndex;
- ArgSet SrcDesc(std::move(P.SrcArgs), IsSrcVariadic ? JustVarIndex : None);
- ArgSet DstDesc(std::move(P.DstArgs), IsDstVariadic ? JustVarIndex : None);
+ ArgSet SrcDesc(std::move(P.SrcArgs),
+ IsSrcVariadic ? JustVarIndex : std::nullopt);
+ ArgSet DstDesc(std::move(P.DstArgs),
+ IsDstVariadic ? JustVarIndex : std::nullopt);
consumeRulesFromConfig(
P, GenericTaintRule::Prop(std::move(SrcDesc), std::move(DstDesc)), Rules);
@@ -527,128 +527,128 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
RulesConstructionTy GlobalCRules{
// Sources
- {{"fdopen"}, TR::Source({{ReturnValueIndex}})},
- {{"fopen"}, TR::Source({{ReturnValueIndex}})},
- {{"freopen"}, TR::Source({{ReturnValueIndex}})},
- {{"getch"}, TR::Source({{ReturnValueIndex}})},
- {{"getchar"}, TR::Source({{ReturnValueIndex}})},
- {{"getchar_unlocked"}, TR::Source({{ReturnValueIndex}})},
- {{"gets"}, TR::Source({{0}, ReturnValueIndex})},
- {{"gets_s"}, TR::Source({{0}, ReturnValueIndex})},
- {{"scanf"}, TR::Source({{}, 1})},
- {{"scanf_s"}, TR::Source({{}, {1}})},
- {{"wgetch"}, TR::Source({{}, ReturnValueIndex})},
+ {{{"fdopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"fopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"freopen"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getch"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getchar"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getchar_unlocked"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"gets"}}, TR::Source({{0}, ReturnValueIndex})},
+ {{{"gets_s"}}, TR::Source({{0}, ReturnValueIndex})},
+ {{{"scanf"}}, TR::Source({{}, 1})},
+ {{{"scanf_s"}}, TR::Source({{}, {1}})},
+ {{{"wgetch"}}, TR::Source({{}, ReturnValueIndex})},
// Sometimes the line between taint sources and propagators is blurry.
// _IO_getc is choosen to be a source, but could also be a propagator.
// This way it is simpler, as modeling it as a propagator would require
// to model the possible sources of _IO_FILE * values, which the _IO_getc
// function takes as parameters.
- {{"_IO_getc"}, TR::Source({{ReturnValueIndex}})},
- {{"getcwd"}, TR::Source({{0, ReturnValueIndex}})},
- {{"getwd"}, TR::Source({{0, ReturnValueIndex}})},
- {{"readlink"}, TR::Source({{1, ReturnValueIndex}})},
- {{"readlinkat"}, TR::Source({{2, ReturnValueIndex}})},
- {{"get_current_dir_name"}, TR::Source({{ReturnValueIndex}})},
- {{"gethostname"}, TR::Source({{0}})},
- {{"getnameinfo"}, TR::Source({{2, 4}})},
- {{"getseuserbyname"}, TR::Source({{1, 2}})},
- {{"getgroups"}, TR::Source({{1, ReturnValueIndex}})},
- {{"getlogin"}, TR::Source({{ReturnValueIndex}})},
- {{"getlogin_r"}, TR::Source({{0}})},
+ {{{"_IO_getc"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getcwd"}}, TR::Source({{0, ReturnValueIndex}})},
+ {{{"getwd"}}, TR::Source({{0, ReturnValueIndex}})},
+ {{{"readlink"}}, TR::Source({{1, ReturnValueIndex}})},
+ {{{"readlinkat"}}, TR::Source({{2, ReturnValueIndex}})},
+ {{{"get_current_dir_name"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"gethostname"}}, TR::Source({{0}})},
+ {{{"getnameinfo"}}, TR::Source({{2, 4}})},
+ {{{"getseuserbyname"}}, TR::Source({{1, 2}})},
+ {{{"getgroups"}}, TR::Source({{1, ReturnValueIndex}})},
+ {{{"getlogin"}}, TR::Source({{ReturnValueIndex}})},
+ {{{"getlogin_r"}}, TR::Source({{0}})},
// Props
- {{"atoi"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"atol"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"atoll"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgetc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgetln"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fgets"}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
- {{"fscanf"}, TR::Prop({{0}}, {{}, 2})},
- {{"fscanf_s"}, TR::Prop({{0}}, {{}, {2}})},
- {{"sscanf"}, TR::Prop({{0}}, {{}, 2})},
-
- {{"getc"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"getc_unlocked"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"getdelim"}, TR::Prop({{3}}, {{0}})},
- {{"getline"}, TR::Prop({{2}}, {{0}})},
- {{"getw"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"pread"}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
- {{"read"}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
- {{"strchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"tolower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"toupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fread"}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
- {{"recv"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"recvfrom"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"ttyname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"ttyname_r"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"basename"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"dirname"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"fnmatch"}, TR::Prop({{1}}, {{ReturnValueIndex}})},
- {{"memchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"memrchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"rawmemchr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
-
- {{"mbtowc"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"wctomb"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"wcwidth"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
-
- {{"memcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"memcpy"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{"memmove"}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"atoi"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"atol"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"atoll"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgetc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgetln"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fgets"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
+ {{{"fscanf"}}, TR::Prop({{0}}, {{}, 2})},
+ {{{"fscanf_s"}}, TR::Prop({{0}}, {{}, {2}})},
+ {{{"sscanf"}}, TR::Prop({{0}}, {{}, 2})},
+
+ {{{"getc"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"getc_unlocked"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"getdelim"}}, TR::Prop({{3}}, {{0}})},
+ {{{"getline"}}, TR::Prop({{2}}, {{0}})},
+ {{{"getw"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"pread"}}, TR::Prop({{0, 1, 2, 3}}, {{1, ReturnValueIndex}})},
+ {{{"read"}}, TR::Prop({{0, 2}}, {{1, ReturnValueIndex}})},
+ {{{"strchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"tolower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"toupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fread"}}, TR::Prop({{3}}, {{0, ReturnValueIndex}})},
+ {{{"recv"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"recvfrom"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"ttyname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"ttyname_r"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"basename"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"dirname"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"fnmatch"}}, TR::Prop({{1}}, {{ReturnValueIndex}})},
+ {{{"memchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"memrchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"rawmemchr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+
+ {{{"mbtowc"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"wctomb"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"wcwidth"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+
+ {{{"memcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"memcpy"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{{"memmove"}}, TR::Prop({{1}}, {{0, ReturnValueIndex}})},
// If memmem was called with a tainted needle and the search was
// successful, that would mean that the value pointed by the return value
// has the same content as the needle. If we choose to go by the policy of
// content equivalence implies taintedness equivalence, that would mean
// haystack should be considered a propagation source argument.
- {{"memmem"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"memmem"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// The comment for memmem above also applies to strstr.
- {{"strstr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strcasestr"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strstr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strcasestr"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strchrnul"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strchrnul"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"index"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"rindex"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"index"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"rindex"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// FIXME: In case of arrays, only the first element of the array gets
// tainted.
- {{"qsort"}, TR::Prop({{0}}, {{0}})},
- {{"qsort_r"}, TR::Prop({{0}}, {{0}})},
-
- {{"strcmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strcasecmp"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strncmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
- {{"strncasecmp"}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
- {{"strspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strcspn"}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
- {{"strpbrk"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strndup"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strndupa"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strnlen"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"strtol"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoll"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoul"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
- {{"strtoull"}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
-
- {{"isalnum"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isalpha"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isascii"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isblank"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"iscntrl"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isgraph"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"islower"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isprint"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"ispunct"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isspace"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isupper"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{"isxdigit"}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"qsort"}}, TR::Prop({{0}}, {{0}})},
+ {{{"qsort_r"}}, TR::Prop({{0}}, {{0}})},
+
+ {{{"strcmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strcasecmp"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strncmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
+ {{{"strncasecmp"}}, TR::Prop({{0, 1, 2}}, {{ReturnValueIndex}})},
+ {{{"strspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strcspn"}}, TR::Prop({{0, 1}}, {{ReturnValueIndex}})},
+ {{{"strpbrk"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strndup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strndupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strnlen"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"strtol"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoll"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoul"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+ {{{"strtoull"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
+
+ {{{"isalnum"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isalpha"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isascii"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isblank"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"iscntrl"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isgraph"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"islower"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isprint"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"ispunct"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isspace"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isupper"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{{"isxdigit"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrncat)}},
TR::Prop({{1, 2}}, {{0, ReturnValueIndex}})},
@@ -656,37 +656,40 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
TR::Prop({{1, 2}}, {{0}})},
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrlcat)}},
TR::Prop({{1, 2}}, {{0}})},
- {{CDF_MaybeBuiltin, {"snprintf"}},
+ {{CDF_MaybeBuiltin, {{"snprintf"}}},
TR::Prop({{1}, 3}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"sprintf"}},
+ {{CDF_MaybeBuiltin, {{"sprintf"}}},
TR::Prop({{1}, 2}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strcpy"}},
+ {{CDF_MaybeBuiltin, {{"strcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"stpcpy"}},
+ {{CDF_MaybeBuiltin, {{"stpcpy"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strcat"}},
+ {{CDF_MaybeBuiltin, {{"strcat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"strdupa"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
- {{CDF_MaybeBuiltin, {"wcsdup"}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"strdupa"}}},
+ TR::Prop({{0}}, {{ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"wcsdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
// Sinks
- {{"system"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"popen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execl"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execle"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execlp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execvp"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execvP"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"execve"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{"dlopen"}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
- {{CDF_MaybeBuiltin, {"malloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"calloc"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"alloca"}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"memccpy"}}, TR::Sink({{3}}, MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"realloc"}}, TR::Sink({{1}}, MsgTaintedBufferSize)},
- {{{"setproctitle"}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
- {{{"setproctitle_fast"}},
+ {{{"system"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"popen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execl"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execle"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execlp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execvp"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execvP"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"execve"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
+ {{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"alloca"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"memccpy"}}},
+ TR::Sink({{3}}, MsgTaintedBufferSize)},
+ {{CDF_MaybeBuiltin, {{"realloc"}}},
+ TR::Sink({{1}}, MsgTaintedBufferSize)},
+ {{{{"setproctitle"}}}, TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
+ {{{{"setproctitle_fast"}}},
TR::Sink({{0}, 1}, MsgUncontrolledFormatString)},
// SinkProps
@@ -702,7 +705,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{CDF_MaybeBuiltin, {BI.getName(Builtin::BIstrndup)}},
TR::SinkProp({{1}}, {{0, 1}}, {{ReturnValueIndex}},
MsgTaintedBufferSize)},
- {{CDF_MaybeBuiltin, {"bcopy"}},
+ {{CDF_MaybeBuiltin, {{"bcopy"}}},
TR::SinkProp({{2}}, {{0, 2}}, {{1}}, MsgTaintedBufferSize)}};
// `getenv` returns taint only in untrusted environments.
@@ -710,7 +713,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
// void setproctitle_init(int argc, char *argv[], char *envp[])
GlobalCRules.push_back(
{{{"setproctitle_init"}}, TR::Sink({{1, 2}}, MsgCustomSink)});
- GlobalCRules.push_back({{"getenv"}, TR::Source({{ReturnValueIndex}})});
+ GlobalCRules.push_back({{{"getenv"}}, TR::Source({{ReturnValueIndex}})});
}
StaticTaintRules.emplace(std::make_move_iterator(GlobalCRules.begin()),
@@ -723,7 +726,7 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
std::string Option{"Config"};
StringRef ConfigFile =
Mgr->getAnalyzerOptions().getCheckerStringOption(this, Option);
- llvm::Optional<TaintConfiguration> Config =
+ std::optional<TaintConfiguration> Config =
getConfiguration<TaintConfiguration>(*Mgr, this, Option, ConfigFile);
if (!Config) {
// We don't have external taint config, no parsing required.
@@ -899,7 +902,7 @@ bool GenericTaintRule::UntrustedEnv(CheckerContext &C) {
bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
CheckerContext &C) const {
assert(E);
- Optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))};
+ std::optional<SVal> TaintedSVal{getTaintedPointeeOrPointer(C, C.getSVal(E))};
if (!TaintedSVal)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index ce334b18386e..b3f2d7f4d268 100644
--- a/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -379,8 +379,7 @@ visit(const ObjCImplementationDecl *ImplD) const {
IvarToPropMapTy IvarToPopertyMap;
ObjCInterfaceDecl::PropertyMap PropMap;
- ObjCInterfaceDecl::PropertyDeclOrder PropOrder;
- InterfaceD->collectPropertiesToImplement(PropMap, PropOrder);
+ InterfaceD->collectPropertiesToImplement(PropMap);
for (ObjCInterfaceDecl::PropertyMap::iterator
I = PropMap.begin(), E = PropMap.end(); I != E; ++I) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index 9870746cbe0c..bca10ec96cea 100644
--- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -29,6 +29,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/Support/Unicode.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -1004,7 +1005,7 @@ NonLocalizedStringBRVisitor::VisitNode(const ExplodedNode *Succ,
if (Satisfied)
return nullptr;
- Optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>();
+ std::optional<StmtPoint> Point = Succ->getLocation().getAs<StmtPoint>();
if (!Point)
return nullptr;
@@ -1141,7 +1142,7 @@ void EmptyLocalizationContextChecker::MethodCrawler::VisitObjCMessageExpr(
SE = Mgr.getSourceManager().getSLocEntry(SLInfo.first);
}
- llvm::Optional<llvm::MemoryBufferRef> BF =
+ std::optional<llvm::MemoryBufferRef> BF =
Mgr.getSourceManager().getBufferOrNone(SLInfo.first, SL);
if (!BF)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
index 139bc0e99d78..153a0a51e980 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp
@@ -30,6 +30,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -86,7 +87,7 @@ class MIGChecker : public Checker<check::PostCall, check::PreStmt<ReturnStmt>,
#undef CALL
};
- CallDescription OsRefRetain{"os_ref_retain", 1};
+ CallDescription OsRefRetain{{"os_ref_retain"}, 1};
void checkReturnAux(const ReturnStmt *RS, CheckerContext &C) const;
@@ -157,7 +158,7 @@ static bool isInMIGCall(CheckerContext &C) {
const Decl *D = SFC->getDecl();
- if (Optional<AnyCall> AC = AnyCall::forDecl(D)) {
+ if (std::optional<AnyCall> AC = AnyCall::forDecl(D)) {
// Even though there's a Sema warning when the return type of an annotated
// function is not a kern_return_t, this warning isn't an error, so we need
// an extra check here.
diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
index 635eb00e4ca9..c1b85ace3e2d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp
@@ -21,6 +21,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -209,7 +210,7 @@ static SymbolRef getAsPointeeSymbol(const Expr *Expr,
ProgramStateRef State = C.getState();
SVal ArgV = C.getSVal(Expr);
- if (Optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> X = ArgV.getAs<loc::MemRegionVal>()) {
StoreManager& SM = C.getStoreManager();
SymbolRef sym = SM.getBinding(State->getStore(), *X).getAsLocSymbol();
if (sym)
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index adedc9c30fad..f05cd9227b65 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -86,6 +86,7 @@
#include "llvm/Support/raw_ostream.h"
#include <climits>
#include <functional>
+#include <optional>
#include <utility>
using namespace clang;
@@ -220,10 +221,10 @@ static bool isReleased(SymbolRef Sym, CheckerContext &C);
/// Update the RefState to reflect the new memory allocation.
/// The optional \p RetVal parameter specifies the newly allocated pointer
/// value; if unspecified, the value of expression \p E is used.
-static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
- ProgramStateRef State,
- AllocationFamily Family,
- Optional<SVal> RetVal = None);
+static ProgramStateRef
+MallocUpdateRefState(CheckerContext &C, const Expr *E, ProgramStateRef State,
+ AllocationFamily Family,
+ std::optional<SVal> RetVal = std::nullopt);
//===----------------------------------------------------------------------===//
// The modeling of memory reallocation.
@@ -391,10 +392,10 @@ private:
const CallEvent &Call, CheckerContext &C)>;
const CallDescriptionMap<CheckFn> FreeingMemFnMap{
- {{"free", 1}, &MallocChecker::checkFree},
- {{"if_freenameindex", 1}, &MallocChecker::checkIfFreeNameIndex},
- {{"kfree", 1}, &MallocChecker::checkFree},
- {{"g_free", 1}, &MallocChecker::checkFree},
+ {{{"free"}, 1}, &MallocChecker::checkFree},
+ {{{"if_freenameindex"}, 1}, &MallocChecker::checkIfFreeNameIndex},
+ {{{"kfree"}, 1}, &MallocChecker::checkFree},
+ {{{"g_free"}, 1}, &MallocChecker::checkFree},
};
bool isFreeingCall(const CallEvent &Call) const;
@@ -403,61 +404,60 @@ private:
friend class NoOwnershipChangeVisitor;
CallDescriptionMap<CheckFn> AllocatingMemFnMap{
- {{"alloca", 1}, &MallocChecker::checkAlloca},
- {{"_alloca", 1}, &MallocChecker::checkAlloca},
- {{"malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"malloc", 3}, &MallocChecker::checkKernelMalloc},
- {{"calloc", 2}, &MallocChecker::checkCalloc},
- {{"valloc", 1}, &MallocChecker::checkBasicAlloc},
- {{CDF_MaybeBuiltin, "strndup", 2}, &MallocChecker::checkStrdup},
- {{CDF_MaybeBuiltin, "strdup", 1}, &MallocChecker::checkStrdup},
- {{"_strdup", 1}, &MallocChecker::checkStrdup},
- {{"kmalloc", 2}, &MallocChecker::checkKernelMalloc},
- {{"if_nameindex", 1}, &MallocChecker::checkIfNameIndex},
- {{CDF_MaybeBuiltin, "wcsdup", 1}, &MallocChecker::checkStrdup},
- {{CDF_MaybeBuiltin, "_wcsdup", 1}, &MallocChecker::checkStrdup},
- {{"g_malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"g_malloc0", 1}, &MallocChecker::checkGMalloc0},
- {{"g_try_malloc", 1}, &MallocChecker::checkBasicAlloc},
- {{"g_try_malloc0", 1}, &MallocChecker::checkGMalloc0},
- {{"g_memdup", 2}, &MallocChecker::checkGMemdup},
- {{"g_malloc_n", 2}, &MallocChecker::checkGMallocN},
- {{"g_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
- {{"g_try_malloc_n", 2}, &MallocChecker::checkGMallocN},
- {{"g_try_malloc0_n", 2}, &MallocChecker::checkGMallocN0},
+ {{{"alloca"}, 1}, &MallocChecker::checkAlloca},
+ {{{"_alloca"}, 1}, &MallocChecker::checkAlloca},
+ {{{"malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"malloc"}, 3}, &MallocChecker::checkKernelMalloc},
+ {{{"calloc"}, 2}, &MallocChecker::checkCalloc},
+ {{{"valloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{CDF_MaybeBuiltin, {"strndup"}, 2}, &MallocChecker::checkStrdup},
+ {{CDF_MaybeBuiltin, {"strdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"_strdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"kmalloc"}, 2}, &MallocChecker::checkKernelMalloc},
+ {{{"if_nameindex"}, 1}, &MallocChecker::checkIfNameIndex},
+ {{CDF_MaybeBuiltin, {"wcsdup"}, 1}, &MallocChecker::checkStrdup},
+ {{CDF_MaybeBuiltin, {"_wcsdup"}, 1}, &MallocChecker::checkStrdup},
+ {{{"g_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"g_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
+ {{{"g_try_malloc"}, 1}, &MallocChecker::checkBasicAlloc},
+ {{{"g_try_malloc0"}, 1}, &MallocChecker::checkGMalloc0},
+ {{{"g_memdup"}, 2}, &MallocChecker::checkGMemdup},
+ {{{"g_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
+ {{{"g_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
+ {{{"g_try_malloc_n"}, 2}, &MallocChecker::checkGMallocN},
+ {{{"g_try_malloc0_n"}, 2}, &MallocChecker::checkGMallocN0},
};
CallDescriptionMap<CheckFn> ReallocatingMemFnMap{
- {{"realloc", 2},
+ {{{"realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"reallocf", 2},
+ {{{"reallocf"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, true)},
- {{"g_realloc", 2},
+ {{{"g_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"g_try_realloc", 2},
+ {{{"g_try_realloc"}, 2},
std::bind(&MallocChecker::checkRealloc, _1, _2, _3, false)},
- {{"g_realloc_n", 3}, &MallocChecker::checkReallocN},
- {{"g_try_realloc_n", 3}, &MallocChecker::checkReallocN},
+ {{{"g_realloc_n"}, 3}, &MallocChecker::checkReallocN},
+ {{{"g_try_realloc_n"}, 3}, &MallocChecker::checkReallocN},
};
bool isMemCall(const CallEvent &Call) const;
// TODO: Remove mutable by moving the initializtaion to the registry function.
- mutable Optional<uint64_t> KernelZeroFlagVal;
+ mutable std::optional<uint64_t> KernelZeroFlagVal;
- using KernelZeroSizePtrValueTy = Optional<int>;
+ using KernelZeroSizePtrValueTy = std::optional<int>;
/// Store the value of macro called `ZERO_SIZE_PTR`.
/// The value is initialized at first use, before first use the outer
/// Optional is empty, afterwards it contains another Optional that indicates
/// if the macro value could be determined, and if yes the value itself.
- mutable Optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
+ mutable std::optional<KernelZeroSizePtrValueTy> KernelZeroSizePtrValue;
/// Process C++ operator new()'s allocation, which is the part of C++
/// new-expression that goes before the constructor.
- LLVM_NODISCARD
- ProgramStateRef processNewAllocation(const CXXAllocatorCall &Call,
- CheckerContext &C,
- AllocationFamily Family) const;
+ [[nodiscard]] ProgramStateRef
+ processNewAllocation(const CXXAllocatorCall &Call, CheckerContext &C,
+ AllocationFamily Family) const;
/// Perform a zero-allocation check.
///
@@ -467,11 +467,10 @@ private:
/// 0.
/// \param [in] RetVal Specifies the newly allocated pointer value;
/// if unspecified, the value of expression \p E is used.
- LLVM_NODISCARD
- static ProgramStateRef ProcessZeroAllocCheck(const CallEvent &Call,
- const unsigned IndexOfSizeArg,
- ProgramStateRef State,
- Optional<SVal> RetVal = None);
+ [[nodiscard]] static ProgramStateRef
+ ProcessZeroAllocCheck(const CallEvent &Call, const unsigned IndexOfSizeArg,
+ ProgramStateRef State,
+ std::optional<SVal> RetVal = std::nullopt);
/// Model functions with the ownership_returns attribute.
///
@@ -489,10 +488,9 @@ private:
/// \param [in] Att The ownership_returns attribute.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- ProgramStateRef MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
- const OwnershipAttr *Att,
- ProgramStateRef State) const;
+ [[nodiscard]] ProgramStateRef
+ MallocMemReturnsAttr(CheckerContext &C, const CallEvent &Call,
+ const OwnershipAttr *Att, ProgramStateRef State) const;
/// Models memory allocation.
///
@@ -503,11 +501,9 @@ private:
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef MallocMemAux(CheckerContext &C, const CallEvent &Call,
- const Expr *SizeEx, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family);
+ [[nodiscard]] static ProgramStateRef
+ MallocMemAux(CheckerContext &C, const CallEvent &Call, const Expr *SizeEx,
+ SVal Init, ProgramStateRef State, AllocationFamily Family);
/// Models memory allocation.
///
@@ -518,16 +514,13 @@ private:
/// malloc leaves it undefined.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef MallocMemAux(CheckerContext &C, const CallEvent &Call,
- SVal Size, SVal Init,
- ProgramStateRef State,
- AllocationFamily Family);
+ [[nodiscard]] static ProgramStateRef
+ MallocMemAux(CheckerContext &C, const CallEvent &Call, SVal Size, SVal Init,
+ ProgramStateRef State, AllocationFamily Family);
// Check if this malloc() for special flags. At present that means M_ZERO or
// __GFP_ZERO (in which case, treat it like calloc).
- LLVM_NODISCARD
- llvm::Optional<ProgramStateRef>
+ [[nodiscard]] std::optional<ProgramStateRef>
performKernelMalloc(const CallEvent &Call, CheckerContext &C,
const ProgramStateRef &State) const;
@@ -548,10 +541,10 @@ private:
/// \param [in] Att The ownership_takes or ownership_holds attribute.
/// \param [in] State The \c ProgramState right before allocation.
/// \returns The ProgramState right after deallocation.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAttr(CheckerContext &C, const CallEvent &Call,
- const OwnershipAttr *Att,
- ProgramStateRef State) const;
+ [[nodiscard]] ProgramStateRef FreeMemAttr(CheckerContext &C,
+ const CallEvent &Call,
+ const OwnershipAttr *Att,
+ ProgramStateRef State) const;
/// Models memory deallocation.
///
@@ -572,12 +565,10 @@ private:
/// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
/// we're modeling returns with Null on failure.
/// \returns The ProgramState right after deallocation.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAux(CheckerContext &C, const CallEvent &Call,
- ProgramStateRef State, unsigned Num, bool Hold,
- bool &IsKnownToBeAllocated,
- AllocationFamily Family,
- bool ReturnsNullOnFailure = false) const;
+ [[nodiscard]] ProgramStateRef
+ FreeMemAux(CheckerContext &C, const CallEvent &Call, ProgramStateRef State,
+ unsigned Num, bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
/// Models memory deallocation.
///
@@ -598,12 +589,10 @@ private:
/// \param [in] ReturnsNullOnFailure Whether the memory deallocation function
/// we're modeling returns with Null on failure.
/// \returns The ProgramState right after deallocation.
- LLVM_NODISCARD
- ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *ArgExpr,
- const CallEvent &Call, ProgramStateRef State,
- bool Hold, bool &IsKnownToBeAllocated,
- AllocationFamily Family,
- bool ReturnsNullOnFailure = false) const;
+ [[nodiscard]] ProgramStateRef
+ FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const CallEvent &Call,
+ ProgramStateRef State, bool Hold, bool &IsKnownToBeAllocated,
+ AllocationFamily Family, bool ReturnsNullOnFailure = false) const;
// TODO: Needs some refactoring, as all other deallocation modeling
// functions are suffering from out parameters and messy code due to how
@@ -618,29 +607,27 @@ private:
/// \param [in] SuffixWithN Whether the reallocation function we're modeling
/// has an '_n' suffix, such as g_realloc_n.
/// \returns The ProgramState right after reallocation.
- LLVM_NODISCARD
- ProgramStateRef ReallocMemAux(CheckerContext &C, const CallEvent &Call,
- bool ShouldFreeOnFail, ProgramStateRef State,
- AllocationFamily Family,
- bool SuffixWithN = false) const;
+ [[nodiscard]] ProgramStateRef
+ ReallocMemAux(CheckerContext &C, const CallEvent &Call, bool ShouldFreeOnFail,
+ ProgramStateRef State, AllocationFamily Family,
+ bool SuffixWithN = false) const;
/// Evaluates the buffer size that needs to be allocated.
///
/// \param [in] Blocks The amount of blocks that needs to be allocated.
/// \param [in] BlockBytes The size of a block.
/// \returns The symbolic value of \p Blocks * \p BlockBytes.
- LLVM_NODISCARD
- static SVal evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
- const Expr *BlockBytes);
+ [[nodiscard]] static SVal evalMulForBufferSize(CheckerContext &C,
+ const Expr *Blocks,
+ const Expr *BlockBytes);
/// Models zero initialized array allocation.
///
/// \param [in] Call The expression that reallocated memory
/// \param [in] State The \c ProgramState right before reallocation.
/// \returns The ProgramState right after allocation.
- LLVM_NODISCARD
- static ProgramStateRef CallocMem(CheckerContext &C, const CallEvent &Call,
- ProgramStateRef State);
+ [[nodiscard]] static ProgramStateRef
+ CallocMem(CheckerContext &C, const CallEvent &Call, ProgramStateRef State);
/// See if deallocation happens in a suspicious context. If so, escape the
/// pointers that otherwise would have been deallocated and return true.
@@ -673,12 +660,11 @@ private:
SymbolRef &EscapingSymbol) const;
/// Implementation of the checkPointerEscape callbacks.
- LLVM_NODISCARD
- ProgramStateRef checkPointerEscapeAux(ProgramStateRef State,
- const InvalidatedSymbols &Escaped,
- const CallEvent *Call,
- PointerEscapeKind Kind,
- bool IsConstPointerEscape) const;
+ [[nodiscard]] ProgramStateRef
+ checkPointerEscapeAux(ProgramStateRef State,
+ const InvalidatedSymbols &Escaped,
+ const CallEvent *Call, PointerEscapeKind Kind,
+ bool IsConstPointerEscape) const;
// Implementation of the checkPreStmt and checkEndFunction callbacks.
void checkEscapeOnReturn(const ReturnStmt *S, CheckerContext &C) const;
@@ -687,11 +673,11 @@ private:
/// Tells if a given family/call/symbol is tracked by the current checker.
/// Sets CheckKind to the kind of the checker responsible for this
/// family/call/symbol.
- Optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
- bool IsALeakCheck = false) const;
+ std::optional<CheckKind> getCheckIfTracked(AllocationFamily Family,
+ bool IsALeakCheck = false) const;
- Optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
- bool IsALeakCheck = false) const;
+ std::optional<CheckKind> getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
+ bool IsALeakCheck = false) const;
///@}
static bool SummarizeValue(raw_ostream &os, SVal V);
static bool SummarizeRegion(raw_ostream &os, const MemRegion *MR);
@@ -870,7 +856,7 @@ protected:
// 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
+ // This means 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);
}
@@ -1132,7 +1118,7 @@ bool MallocChecker::isMemCall(const CallEvent &Call) const {
return Func && Func->hasAttr<OwnershipAttr>();
}
-llvm::Optional<ProgramStateRef>
+std::optional<ProgramStateRef>
MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
const ProgramStateRef &State) const {
// 3-argument malloc(), as commonly used in {Free,Net,Open}BSD Kernels:
@@ -1170,33 +1156,32 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
// Fall back to normal malloc behavior on platforms where we don't
// know M_ZERO.
- return None;
+ return std::nullopt;
}
// We treat the last argument as the flags argument, and callers fall-back to
// normal malloc on a None return. This works for the FreeBSD kernel malloc
// as well as Linux kmalloc.
if (Call.getNumArgs() < 2)
- return None;
+ return std::nullopt;
const Expr *FlagsEx = Call.getArgExpr(Call.getNumArgs() - 1);
const SVal V = C.getSVal(FlagsEx);
if (!isa<NonLoc>(V)) {
// The case where 'V' can be a location can only be due to a bad header,
// so in this case bail out.
- return None;
+ return std::nullopt;
}
NonLoc Flags = V.castAs<NonLoc>();
- NonLoc ZeroFlag =
- C.getSValBuilder()
- .makeIntVal(KernelZeroFlagVal.value(), FlagsEx->getType())
- .castAs<NonLoc>();
+ NonLoc ZeroFlag = C.getSValBuilder()
+ .makeIntVal(*KernelZeroFlagVal, FlagsEx->getType())
+ .castAs<NonLoc>();
SVal MaskedFlagsUC = C.getSValBuilder().evalBinOpNN(State, BO_And,
Flags, ZeroFlag,
FlagsEx->getType());
if (MaskedFlagsUC.isUnknownOrUndef())
- return None;
+ return std::nullopt;
DefinedSVal MaskedFlags = MaskedFlagsUC.castAs<DefinedSVal>();
// Check if maskedFlags is non-zero.
@@ -1210,7 +1195,7 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
AF_Malloc);
}
- return None;
+ return std::nullopt;
}
SVal MallocChecker::evalMulForBufferSize(CheckerContext &C, const Expr *Blocks,
@@ -1236,10 +1221,10 @@ void MallocChecker::checkBasicAlloc(const CallEvent &Call,
void MallocChecker::checkKernelMalloc(const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
- llvm::Optional<ProgramStateRef> MaybeState =
+ std::optional<ProgramStateRef> MaybeState =
performKernelMalloc(Call, C, State);
if (MaybeState)
- State = MaybeState.value();
+ State = *MaybeState;
else
State = MallocMemAux(C, Call, Call.getArgExpr(0), UndefinedVal(), State,
AF_Malloc);
@@ -1506,7 +1491,7 @@ void MallocChecker::checkPostCall(const CallEvent &Call,
// Performs a 0-sized allocations check.
ProgramStateRef MallocChecker::ProcessZeroAllocCheck(
const CallEvent &Call, const unsigned IndexOfSizeArg, ProgramStateRef State,
- Optional<SVal> RetVal) {
+ std::optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -1658,7 +1643,7 @@ static bool isKnownDeallocObjCMethodName(const ObjCMethodCall &Call) {
FirstSlot == "initWithCharactersNoCopy";
}
-static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
+static std::optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
Selector S = Call.getSelector();
// FIXME: We should not rely on fully-constrained symbols being folded.
@@ -1666,7 +1651,7 @@ static Optional<bool> getFreeWhenDoneArg(const ObjCMethodCall &Call) {
if (S.getNameForSlot(i).equals("freeWhenDone"))
return !Call.getArgSVal(i).isZeroConstant();
- return None;
+ return std::nullopt;
}
void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
@@ -1677,7 +1662,7 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call,
if (!isKnownDeallocObjCMethodName(Call))
return;
- if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
+ if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(Call))
if (!*FreeWhenDone)
return;
@@ -1749,6 +1734,10 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// Fill the region with the initialization value.
State = State->bindDefaultInitial(RetVal, Init, LCtx);
+ // If Size is somehow undefined at this point, this line prevents a crash.
+ if (Size.isUndef())
+ Size = UnknownVal();
+
// Set the region's extent.
State = setDynamicExtent(State, RetVal.getAsRegion(),
Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
@@ -1759,7 +1748,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
static ProgramStateRef MallocUpdateRefState(CheckerContext &C, const Expr *E,
ProgramStateRef State,
AllocationFamily Family,
- Optional<SVal> RetVal) {
+ std::optional<SVal> RetVal) {
if (!State)
return nullptr;
@@ -2074,7 +2063,7 @@ ProgramStateRef MallocChecker::FreeMemAux(
RefState::getReleased(Family, ParentExpr));
}
-Optional<MallocChecker::CheckKind>
+std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(AllocationFamily Family,
bool IsALeakCheck) const {
switch (Family) {
@@ -2083,7 +2072,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
case AF_IfNameIndex: {
if (ChecksEnabled[CK_MallocChecker])
return CK_MallocChecker;
- return None;
+ return std::nullopt;
}
case AF_CXXNew:
case AF_CXXNewArray: {
@@ -2095,12 +2084,12 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
if (ChecksEnabled[CK_NewDeleteChecker])
return CK_NewDeleteChecker;
}
- return None;
+ return std::nullopt;
}
case AF_InnerBuffer: {
if (ChecksEnabled[CK_InnerPointerChecker])
return CK_InnerPointerChecker;
- return None;
+ return std::nullopt;
}
case AF_None: {
llvm_unreachable("no family");
@@ -2109,7 +2098,7 @@ MallocChecker::getCheckIfTracked(AllocationFamily Family,
llvm_unreachable("unhandled family");
}
-Optional<MallocChecker::CheckKind>
+std::optional<MallocChecker::CheckKind>
MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
bool IsALeakCheck) const {
if (C.getState()->contains<ReallocSizeZeroSymbols>(Sym))
@@ -2121,11 +2110,13 @@ MallocChecker::getCheckIfTracked(CheckerContext &C, SymbolRef Sym,
}
bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) {
- if (Optional<nonloc::ConcreteInt> IntVal = V.getAs<nonloc::ConcreteInt>())
+ if (std::optional<nonloc::ConcreteInt> IntVal =
+ V.getAs<nonloc::ConcreteInt>())
os << "an integer (" << IntVal->getValue() << ")";
- else if (Optional<loc::ConcreteInt> ConstAddr = V.getAs<loc::ConcreteInt>())
+ else if (std::optional<loc::ConcreteInt> ConstAddr =
+ V.getAs<loc::ConcreteInt>())
os << "a constant address (" << ConstAddr->getValue() << ")";
- else if (Optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
+ else if (std::optional<loc::GotoLabel> Label = V.getAs<loc::GotoLabel>())
os << "the address of the label '" << Label->getLabel()->getName() << "'";
else
return false;
@@ -2217,7 +2208,7 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2258,7 +2249,7 @@ void MallocChecker::HandleNonHeapDealloc(CheckerContext &C, SVal ArgVal,
void MallocChecker::HandleFreeAlloca(CheckerContext &C, SVal ArgVal,
SourceRange Range) const {
- Optional<MallocChecker::CheckKind> CheckKind;
+ std::optional<MallocChecker::CheckKind> CheckKind;
if (ChecksEnabled[CK_MallocChecker])
CheckKind = CK_MallocChecker;
@@ -2350,7 +2341,7 @@ void MallocChecker::HandleOffsetFree(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2407,7 +2398,7 @@ void MallocChecker::HandleUseAfterFree(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2446,7 +2437,7 @@ void MallocChecker::HandleDoubleFree(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2476,7 +2467,7 @@ void MallocChecker::HandleDoubleDelete(CheckerContext &C, SymbolRef Sym) const {
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2503,7 +2494,7 @@ void MallocChecker::HandleUseZeroAlloc(CheckerContext &C, SourceRange Range,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(C, Sym);
if (!CheckKind)
return;
@@ -2536,7 +2527,7 @@ void MallocChecker::HandleFunctionPtrFree(CheckerContext &C, SVal ArgVal,
return;
}
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
if (!CheckKind)
return;
@@ -2747,8 +2738,8 @@ void MallocChecker::HandleLeak(SymbolRef Sym, ExplodedNode *N,
if (Family == AF_Alloca)
return;
- Optional<MallocChecker::CheckKind>
- CheckKind = getCheckIfTracked(Family, true);
+ std::optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(Family, true);
if (!CheckKind)
return;
@@ -3151,7 +3142,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// about, we can't be sure that the object will use free() to deallocate the
// memory, so we can't model it explicitly. The best we can do is use it to
// decide whether the pointer escapes.
- if (Optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
+ if (std::optional<bool> FreeWhenDone = getFreeWhenDoneArg(*Msg))
return *FreeWhenDone;
// If the first selector piece ends with "NoCopy", and there is no
@@ -3570,7 +3561,8 @@ void MallocChecker::printState(raw_ostream &Out, ProgramStateRef State,
for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
const RefState *RefS = State->get<RegionState>(I.getKey());
AllocationFamily Family = RefS->getAllocationFamily();
- Optional<MallocChecker::CheckKind> CheckKind = getCheckIfTracked(Family);
+ std::optional<MallocChecker::CheckKind> CheckKind =
+ getCheckIfTracked(Family);
if (!CheckKind)
CheckKind = getCheckIfTracked(Family, true);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
index a6e8fcd425d5..5266df2ae6a6 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MallocOverflowSecurityChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -308,26 +309,27 @@ void MallocOverflowSecurityChecker::checkASTCodeBody(const Decl *D,
CFGBlock *block = *it;
for (CFGBlock::iterator bi = block->begin(), be = block->end();
bi != be; ++bi) {
- if (Optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
- if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
- // Get the callee.
- const FunctionDecl *FD = TheCall->getDirectCallee();
-
- if (!FD)
- continue;
-
- // Get the name of the callee. If it's a builtin, strip off the prefix.
- IdentifierInfo *FnInfo = FD->getIdentifier();
- if (!FnInfo)
- continue;
-
- if (FnInfo->isStr ("malloc") || FnInfo->isStr ("_MALLOC")) {
- if (TheCall->getNumArgs() == 1)
- CheckMallocArgument(PossibleMallocOverflows, TheCall,
- mgr.getASTContext());
+ if (std::optional<CFGStmt> CS = bi->getAs<CFGStmt>()) {
+ if (const CallExpr *TheCall = dyn_cast<CallExpr>(CS->getStmt())) {
+ // Get the callee.
+ const FunctionDecl *FD = TheCall->getDirectCallee();
+
+ if (!FD)
+ continue;
+
+ // Get the name of the callee. If it's a builtin, strip off the
+ // prefix.
+ IdentifierInfo *FnInfo = FD->getIdentifier();
+ if (!FnInfo)
+ continue;
+
+ if (FnInfo->isStr("malloc") || FnInfo->isStr("_MALLOC")) {
+ if (TheCall->getNumArgs() == 1)
+ CheckMallocArgument(PossibleMallocOverflows, TheCall,
+ mgr.getASTContext());
+ }
}
}
- }
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
index 1960873599f7..2020dc7cc791 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp
@@ -176,8 +176,10 @@ void MismatchedIteratorChecker::checkPreCall(const CallEvent &Call,
const auto *Param = Func->getParamDecl(J);
const auto *ParamType =
Param->getType()->getAs<SubstTemplateTypeParmType>();
- if (!ParamType ||
- ParamType->getReplacedParameter()->getDecl() != TPDecl)
+ if (!ParamType)
+ continue;
+ const TemplateTypeParmDecl *D = ParamType->getReplacedParameter();
+ if (D != TPDecl)
continue;
if (LHS.isUndef()) {
LHS = Call.getArgSVal(J);
diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 1906ca5c8f55..0b3d635a50a3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -33,7 +33,7 @@ class MmapWriteExecChecker : public Checker<check::PreCall> {
static int ProtRead;
mutable std::unique_ptr<BugType> BT;
public:
- MmapWriteExecChecker() : MmapFn("mmap", 6), MprotectFn("mprotect", 3) {}
+ MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {}
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
int ProtExecOv;
int ProtReadOv;
diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
index e78c130a9c22..c8ddf3b2c14f 100644
--- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp
@@ -309,7 +309,7 @@ MoveChecker::MovedBugVisitor::VisitNode(const ExplodedNode *N,
// If it's not a dereference, we don't care if it was reset to null
// or that it is even a smart pointer.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_NonStd:
case SK_Safe:
OS << "Object";
@@ -587,7 +587,7 @@ void MoveChecker::explainObject(llvm::raw_ostream &OS, const MemRegion *MR,
break;
// We only care about the type if it's a dereference.
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case SK_Unsafe:
OS << " of type '" << RD->getQualifiedNameAsString() << "'";
break;
@@ -618,10 +618,6 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
if (!IC)
return;
- // Calling a destructor on a moved object is fine.
- if (isa<CXXDestructorCall>(IC))
- return;
-
const MemRegion *ThisRegion = IC->getCXXThisVal().getAsRegion();
if (!ThisRegion)
return;
@@ -631,6 +627,10 @@ void MoveChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const {
if (!MethodDecl)
return;
+ // Calling a destructor on a moved object is fine.
+ if (isa<CXXDestructorDecl>(MethodDecl))
+ return;
+
// We want to investigate the whole object, not only sub-object of a parent
// class in which the encountered method defined.
ThisRegion = ThisRegion->getMostDerivedObjectRegion();
diff --git a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index fea35d03cb81..59741dde1eea 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -118,7 +119,7 @@ void CFErrorFunctionChecker::checkASTDecl(const FunctionDecl *D,
II = &D->getASTContext().Idents.get("CFErrorRef");
bool hasCFError = false;
- for (auto I : D->parameters()) {
+ for (auto *I : D->parameters()) {
if (IsCFError(I->getType(), II)) {
hasCFError = true;
break;
@@ -197,7 +198,7 @@ static void setFlag(ProgramStateRef state, SVal val, CheckerContext &C) {
static QualType parameterTypeFromSVal(SVal val, CheckerContext &C) {
const StackFrameContext * SFC = C.getStackFrame();
- if (Optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
+ if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>()) {
const MemRegion* R = X->getRegion();
if (const VarRegion *VR = R->getAs<VarRegion>())
if (const StackArgumentsSpaceRegion *
diff --git a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
index af208e867318..17c3cb4e9e04 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp
@@ -44,9 +44,11 @@ void NoReturnFunctionChecker::checkPostCall(const CallEvent &CE,
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CE.getDecl()))
BuildSinks = FD->hasAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn();
- const Expr *Callee = CE.getOriginExpr();
- if (!BuildSinks && Callee)
- BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
+ if (const CallExpr *CExpr = dyn_cast_or_null<CallExpr>(CE.getOriginExpr());
+ CExpr && !BuildSinks) {
+ if (const Expr *C = CExpr->getCallee())
+ BuildSinks = getFunctionExtInfo(C->getType()).getNoReturn();
+ }
if (!BuildSinks && CE.isGlobalCFunction()) {
if (const IdentifierInfo *II = CE.getCalleeIdentifier()) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index fb6afd0fdabc..fd47e19cb786 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -136,10 +136,10 @@ void NonNullParamChecker::checkPreCall(const CallEvent &Call,
if (!DV)
continue;
- assert(!HasRefTypeParam || isa<Loc>(DV.value()));
+ assert(!HasRefTypeParam || isa<Loc>(*DV));
// Process the case when the argument is not a location.
- if (ExpectedToBeNonNull && !isa<Loc>(DV.value())) {
+ if (ExpectedToBeNonNull && !isa<Loc>(*DV)) {
// If the argument is a union type, we want to handle a potential
// transparent_union GCC extension.
if (!ArgE)
diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
index c5437b16c688..72c6a869d225 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp
@@ -26,6 +26,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -77,7 +78,8 @@ void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
if (isGlobalConstString(location)) {
SVal V = State->getSVal(location.castAs<Loc>());
- Optional<DefinedOrUnknownSVal> Constr = V.getAs<DefinedOrUnknownSVal>();
+ std::optional<DefinedOrUnknownSVal> Constr =
+ V.getAs<DefinedOrUnknownSVal>();
if (Constr) {
@@ -91,7 +93,7 @@ void NonnullGlobalConstantsChecker::checkLocation(SVal location, bool isLoad,
/// \param V loaded lvalue.
/// \return whether @c val is a string-like const global.
bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
- Optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
+ std::optional<loc::MemRegionVal> RegionVal = V.getAs<loc::MemRegionVal>();
if (!RegionVal)
return false;
auto *Region = dyn_cast<VarRegion>(RegionVal->getAsRegion());
@@ -109,17 +111,20 @@ bool NonnullGlobalConstantsChecker::isGlobalConstString(SVal V) const {
// Look through the typedefs.
while (const Type *T = Ty.getTypePtr()) {
- if (const auto *TT = dyn_cast<TypedefType>(T)) {
+ if (const auto *AT = dyn_cast<AttributedType>(T)) {
+ if (AT->getAttrKind() == attr::TypeNonNull)
+ return true;
+ Ty = AT->getModifiedType();
+ } else if (const auto *ET = dyn_cast<ElaboratedType>(T)) {
+ const auto *TT = dyn_cast<TypedefType>(ET->getNamedType());
+ if (!TT)
+ return false;
Ty = TT->getDecl()->getUnderlyingType();
// It is sufficient for any intermediate typedef
// to be classified const.
HasConst = HasConst || Ty.isConstQualified();
if (isNonnullType(Ty) && HasConst)
return true;
- } else if (const auto *AT = dyn_cast<AttributedType>(T)) {
- if (AT->getAttrKind() == attr::TypeNonNull)
- return true;
- Ty = AT->getModifiedType();
} else {
return false;
}
@@ -136,7 +141,7 @@ bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const {
if (auto *T = dyn_cast<ObjCObjectPointerType>(Ty)) {
return T->getInterfaceDecl() &&
T->getInterfaceDecl()->getIdentifier() == NSStringII;
- } else if (auto *T = dyn_cast<TypedefType>(Ty)) {
+ } else if (auto *T = Ty->getAs<TypedefType>()) {
IdentifierInfo* II = T->getDecl()->getIdentifier();
return II == CFStringRefII || II == CFBooleanRefII || II == CFNullRefII;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 1d8835f6b474..da8529f4ea81 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -80,7 +80,7 @@ enum class ErrorKind : int {
class NullabilityChecker
: public Checker<check::Bind, check::PreCall, check::PreStmt<ReturnStmt>,
check::PostCall, check::PostStmt<ExplicitCastExpr>,
- check::PostObjCMessage, check::DeadSymbols,
+ check::PostObjCMessage, check::DeadSymbols, eval::Assume,
check::Location, check::Event<ImplicitNullDerefEvent>> {
public:
@@ -102,6 +102,8 @@ public:
void checkEvent(ImplicitNullDerefEvent Event) const;
void checkLocation(SVal Location, bool IsLoad, const Stmt *S,
CheckerContext &C) const;
+ ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
const char *Sep) const override;
@@ -129,7 +131,7 @@ public:
// When set to false no nullability information will be tracked in
// NullabilityMap. It is possible to catch errors like passing a null pointer
// to a callee that expects nonnull argument without the information that is
- // stroed in the NullabilityMap. This is an optimization.
+ // stored in the NullabilityMap. This is an optimization.
bool NeedTracking = false;
private:
@@ -230,10 +232,41 @@ bool operator==(NullabilityState Lhs, NullabilityState Rhs) {
Lhs.getNullabilitySource() == Rhs.getNullabilitySource();
}
+// For the purpose of tracking historical property accesses, the key for lookup
+// is an object pointer (could be an instance or a class) paired with the unique
+// identifier for the property being invoked on that object.
+using ObjectPropPair = std::pair<const MemRegion *, const IdentifierInfo *>;
+
+// Metadata associated with the return value from a recorded property access.
+struct ConstrainedPropertyVal {
+ // This will reference the conjured return SVal for some call
+ // of the form [object property]
+ DefinedOrUnknownSVal Value;
+
+ // If the SVal has been determined to be nonnull, that is recorded here
+ bool isConstrainedNonnull;
+
+ ConstrainedPropertyVal(DefinedOrUnknownSVal SV)
+ : Value(SV), isConstrainedNonnull(false) {}
+
+ void Profile(llvm::FoldingSetNodeID &ID) const {
+ Value.Profile(ID);
+ ID.AddInteger(isConstrainedNonnull ? 1 : 0);
+ }
+};
+
+bool operator==(const ConstrainedPropertyVal &Lhs,
+ const ConstrainedPropertyVal &Rhs) {
+ return Lhs.Value == Rhs.Value &&
+ Lhs.isConstrainedNonnull == Rhs.isConstrainedNonnull;
+}
+
} // end anonymous namespace
REGISTER_MAP_WITH_PROGRAMSTATE(NullabilityMap, const MemRegion *,
NullabilityState)
+REGISTER_MAP_WITH_PROGRAMSTATE(PropertyAccessesMap, ObjectPropPair,
+ ConstrainedPropertyVal)
// We say "the nullability type invariant is violated" when a location with a
// non-null type contains NULL or a function with a non-null return type returns
@@ -285,8 +318,11 @@ NullabilityChecker::getTrackRegion(SVal Val, bool CheckSuperRegion) const {
const MemRegion *Region = RegionSVal->getRegion();
if (CheckSuperRegion) {
- if (auto FieldReg = Region->getAs<FieldRegion>())
+ if (const SubRegion *FieldReg = Region->getAs<FieldRegion>()) {
+ if (const auto *ER = dyn_cast<ElementRegion>(FieldReg->getSuperRegion()))
+ FieldReg = ER;
return dyn_cast<SymbolicRegion>(FieldReg->getSuperRegion());
+ }
if (auto ElementReg = Region->getAs<ElementRegion>())
return dyn_cast<SymbolicRegion>(ElementReg->getSuperRegion());
}
@@ -464,6 +500,19 @@ void NullabilityChecker::checkDeadSymbols(SymbolReaper &SR,
State = State->remove<NullabilityMap>(I->first);
}
}
+
+ // When an object goes out of scope, we can free the history associated
+ // with any property accesses on that object
+ PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
+ for (PropertyAccessesMapTy::iterator I = PropertyAccesses.begin(),
+ E = PropertyAccesses.end();
+ I != E; ++I) {
+ const MemRegion *ReceiverRegion = I->first.first;
+ if (!SR.isLiveRegion(ReceiverRegion)) {
+ State = State->remove<PropertyAccessesMap>(I->first);
+ }
+ }
+
// When one of the nonnull arguments are constrained to be null, nullability
// preconditions are violated. It is not enough to check this only when we
// actually report an error, because at that time interesting symbols might be
@@ -851,6 +900,32 @@ static Nullability getReceiverNullability(const ObjCMethodCall &M,
return Nullability::Unspecified;
}
+// The return value of a property access is typically a temporary value which
+// will not be tracked in a persistent manner by the analyzer. We use
+// evalAssume() in order to immediately record constraints on those temporaries
+// at the time they are imposed (e.g. by a nil-check conditional).
+ProgramStateRef NullabilityChecker::evalAssume(ProgramStateRef State, SVal Cond,
+ bool Assumption) const {
+ PropertyAccessesMapTy PropertyAccesses = State->get<PropertyAccessesMap>();
+ for (PropertyAccessesMapTy::iterator I = PropertyAccesses.begin(),
+ E = PropertyAccesses.end();
+ I != E; ++I) {
+ if (!I->second.isConstrainedNonnull) {
+ ConditionTruthVal IsNonNull = State->isNonNull(I->second.Value);
+ if (IsNonNull.isConstrainedTrue()) {
+ ConstrainedPropertyVal Replacement = I->second;
+ Replacement.isConstrainedNonnull = true;
+ State = State->set<PropertyAccessesMap>(I->first, Replacement);
+ } else if (IsNonNull.isConstrainedFalse()) {
+ // Space optimization: no point in tracking constrained-null cases
+ State = State->remove<PropertyAccessesMap>(I->first);
+ }
+ }
+ }
+
+ return State;
+}
+
/// Calculate the nullability of the result of a message expr based on the
/// nullability of the receiver, the nullability of the return value, and the
/// constraints.
@@ -907,7 +982,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// this class of methods reduced the emitted diagnostics by about 30% on
// some projects (and all of that was false positives).
if (Name.contains("String")) {
- for (auto Param : M.parameters()) {
+ for (auto *Param : M.parameters()) {
if (Param->getName() == "encoding") {
State = State->set<NullabilityMap>(ReturnRegion,
Nullability::Contradicted);
@@ -947,12 +1022,53 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// No tracked information. Use static type information for return value.
Nullability RetNullability = getNullabilityAnnotation(RetType);
- // Properties might be computed. For this reason the static analyzer creates a
- // new symbol each time an unknown property is read. To avoid false pozitives
- // do not treat unknown properties as nullable, even when they explicitly
- // marked nullable.
- if (M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined)
- RetNullability = Nullability::Nonnull;
+ // Properties might be computed, which means the property value could
+ // theoretically change between calls even in commonly-observed cases like
+ // this:
+ //
+ // if (foo.prop) { // ok, it's nonnull here...
+ // [bar doStuffWithNonnullVal:foo.prop]; // ...but what about
+ // here?
+ // }
+ //
+ // If the property is nullable-annotated, a naive analysis would lead to many
+ // false positives despite the presence of probably-correct nil-checks. To
+ // reduce the false positive rate, we maintain a history of the most recently
+ // observed property value. For each property access, if the prior value has
+ // been constrained to be not nil then we will conservatively assume that the
+ // next access can be inferred as nonnull.
+ if (RetNullability != Nullability::Nonnull &&
+ M.getMessageKind() == OCM_PropertyAccess && !C.wasInlined) {
+ bool LookupResolved = false;
+ if (const MemRegion *ReceiverRegion = getTrackRegion(M.getReceiverSVal())) {
+ if (IdentifierInfo *Ident = M.getSelector().getIdentifierInfoForSlot(0)) {
+ LookupResolved = true;
+ ObjectPropPair Key = std::make_pair(ReceiverRegion, Ident);
+ const ConstrainedPropertyVal *PrevPropVal =
+ State->get<PropertyAccessesMap>(Key);
+ if (PrevPropVal && PrevPropVal->isConstrainedNonnull) {
+ RetNullability = Nullability::Nonnull;
+ } else {
+ // If a previous property access was constrained as nonnull, we hold
+ // on to that constraint (effectively inferring that all subsequent
+ // accesses on that code path can be inferred as nonnull). If the
+ // previous property access was *not* constrained as nonnull, then
+ // let's throw it away in favor of keeping the SVal associated with
+ // this more recent access.
+ if (auto ReturnSVal =
+ M.getReturnValue().getAs<DefinedOrUnknownSVal>()) {
+ State = State->set<PropertyAccessesMap>(
+ Key, ConstrainedPropertyVal(*ReturnSVal));
+ }
+ }
+ }
+ }
+
+ if (!LookupResolved) {
+ // Fallback: err on the side of suppressing the false positive.
+ RetNullability = Nullability::Nonnull;
+ }
+ }
Nullability ComputedNullab = getMostNullable(RetNullability, SelfNullability);
if (ComputedNullab == Nullability::Nullable) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
index 3e9fc696f8e6..f217520d8f4a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/NumberObjectConversionChecker.cpp
@@ -196,12 +196,10 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
AnalysisManager &AM,
BugReporter &BR) const {
// Currently this matches CoreFoundation opaque pointer typedefs.
- auto CSuspiciousNumberObjectExprM =
- expr(ignoringParenImpCasts(
- expr(hasType(
- typedefType(hasDeclaration(anyOf(
- typedefDecl(hasName("CFNumberRef")),
- typedefDecl(hasName("CFBooleanRef")))))))
+ auto CSuspiciousNumberObjectExprM = expr(ignoringParenImpCasts(
+ expr(hasType(elaboratedType(namesType(typedefType(
+ hasDeclaration(anyOf(typedefDecl(hasName("CFNumberRef")),
+ typedefDecl(hasName("CFBooleanRef")))))))))
.bind("c_object")));
// Currently this matches XNU kernel number-object pointers.
@@ -240,8 +238,9 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
// The .bind here is in order to compose the error message more accurately.
auto ObjCSuspiciousScalarBooleanTypeM =
- qualType(typedefType(hasDeclaration(
- typedefDecl(hasName("BOOL"))))).bind("objc_bool_type");
+ qualType(elaboratedType(namesType(
+ typedefType(hasDeclaration(typedefDecl(hasName("BOOL")))))))
+ .bind("objc_bool_type");
// The .bind here is in order to compose the error message more accurately.
auto SuspiciousScalarBooleanTypeM =
@@ -253,9 +252,9 @@ void NumberObjectConversionChecker::checkASTCodeBody(const Decl *D,
// for storing pointers.
auto SuspiciousScalarNumberTypeM =
qualType(hasCanonicalType(isInteger()),
- unless(typedefType(hasDeclaration(
- typedefDecl(matchesName("^::u?intptr_t$"))))))
- .bind("int_type");
+ unless(elaboratedType(namesType(typedefType(hasDeclaration(
+ typedefDecl(matchesName("^::u?intptr_t$"))))))))
+ .bind("int_type");
auto SuspiciousScalarTypeM =
qualType(anyOf(SuspiciousScalarBooleanTypeM,
diff --git a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
index 6688278a7a33..2b008d1c775a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp
@@ -72,7 +72,7 @@ class WalkAST : public StmtVisitor<WalkAST> {
public:
WalkAST(BugReporter &br, const CheckerBase *checker, AnalysisDeclContext *ac)
: BR(br), Checker(checker), AC(ac), ASTC(AC->getASTContext()),
- PtrWidth(ASTC.getTargetInfo().getPointerWidth(0)) {}
+ PtrWidth(ASTC.getTargetInfo().getPointerWidth(LangAS::Default)) {}
// Statement visitor methods.
void VisitChildren(Stmt *S);
diff --git a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
index e877dd119ff6..929bd6bc3eb3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp
@@ -87,7 +87,7 @@ private:
CheckerKind CheckKind) const;
CallDescriptionMap<FnCheck> PThreadCallbacks = {
// Init.
- {{"pthread_mutex_init", 2}, &PthreadLockChecker::InitAnyLock},
+ {{{"pthread_mutex_init"}, 2}, &PthreadLockChecker::InitAnyLock},
// TODO: pthread_rwlock_init(2 arguments).
// TODO: lck_mtx_init(3 arguments).
// TODO: lck_mtx_alloc_init(2 arguments) => returns the mutex.
@@ -95,74 +95,74 @@ private:
// TODO: lck_rw_alloc_init(2 arguments) => returns the mutex.
// Acquire.
- {{"pthread_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"pthread_rwlock_rdlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"pthread_rwlock_wrlock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"lck_mtx_lock", 1}, &PthreadLockChecker::AcquireXNULock},
- {{"lck_rw_lock_exclusive", 1}, &PthreadLockChecker::AcquireXNULock},
- {{"lck_rw_lock_shared", 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"pthread_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"pthread_rwlock_rdlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"pthread_rwlock_wrlock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"lck_mtx_lock"}, 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"lck_rw_lock_exclusive"}, 1}, &PthreadLockChecker::AcquireXNULock},
+ {{{"lck_rw_lock_shared"}, 1}, &PthreadLockChecker::AcquireXNULock},
// Try.
- {{"pthread_mutex_trylock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"pthread_rwlock_tryrdlock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"pthread_rwlock_trywrlock", 1}, &PthreadLockChecker::TryPthreadLock},
- {{"lck_mtx_try_lock", 1}, &PthreadLockChecker::TryXNULock},
- {{"lck_rw_try_lock_exclusive", 1}, &PthreadLockChecker::TryXNULock},
- {{"lck_rw_try_lock_shared", 1}, &PthreadLockChecker::TryXNULock},
+ {{{"pthread_mutex_trylock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"pthread_rwlock_tryrdlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"pthread_rwlock_trywrlock"}, 1}, &PthreadLockChecker::TryPthreadLock},
+ {{{"lck_mtx_try_lock"}, 1}, &PthreadLockChecker::TryXNULock},
+ {{{"lck_rw_try_lock_exclusive"}, 1}, &PthreadLockChecker::TryXNULock},
+ {{{"lck_rw_try_lock_shared"}, 1}, &PthreadLockChecker::TryXNULock},
// Release.
- {{"pthread_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"pthread_rwlock_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_unlock_exclusive", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_unlock_shared", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"lck_rw_done", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"pthread_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"pthread_rwlock_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_unlock_exclusive"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_unlock_shared"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"lck_rw_done"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
// Destroy.
- {{"pthread_mutex_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
- {{"lck_mtx_destroy", 2}, &PthreadLockChecker::DestroyXNULock},
+ {{{"pthread_mutex_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
+ {{{"lck_mtx_destroy"}, 2}, &PthreadLockChecker::DestroyXNULock},
// TODO: pthread_rwlock_destroy(1 argument).
// TODO: lck_rw_destroy(2 arguments).
};
CallDescriptionMap<FnCheck> FuchsiaCallbacks = {
// Init.
- {{"spin_lock_init", 1}, &PthreadLockChecker::InitAnyLock},
+ {{{"spin_lock_init"}, 1}, &PthreadLockChecker::InitAnyLock},
// Acquire.
- {{"spin_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"spin_lock_save", 3}, &PthreadLockChecker::AcquirePthreadLock},
- {{"sync_mutex_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
- {{"sync_mutex_lock_with_waiter", 1},
+ {{{"spin_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"spin_lock_save"}, 3}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"sync_mutex_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"sync_mutex_lock_with_waiter"}, 1},
&PthreadLockChecker::AcquirePthreadLock},
// Try.
- {{"spin_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
- {{"sync_mutex_trylock", 1}, &PthreadLockChecker::TryFuchsiaLock},
- {{"sync_mutex_timedlock", 2}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"spin_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"sync_mutex_trylock"}, 1}, &PthreadLockChecker::TryFuchsiaLock},
+ {{{"sync_mutex_timedlock"}, 2}, &PthreadLockChecker::TryFuchsiaLock},
// Release.
- {{"spin_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
- {{"spin_unlock_restore", 3}, &PthreadLockChecker::ReleaseAnyLock},
- {{"sync_mutex_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"spin_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"spin_unlock_restore"}, 3}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"sync_mutex_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
};
CallDescriptionMap<FnCheck> C11Callbacks = {
// Init.
- {{"mtx_init", 2}, &PthreadLockChecker::InitAnyLock},
+ {{{"mtx_init"}, 2}, &PthreadLockChecker::InitAnyLock},
// Acquire.
- {{"mtx_lock", 1}, &PthreadLockChecker::AcquirePthreadLock},
+ {{{"mtx_lock"}, 1}, &PthreadLockChecker::AcquirePthreadLock},
// Try.
- {{"mtx_trylock", 1}, &PthreadLockChecker::TryC11Lock},
- {{"mtx_timedlock", 2}, &PthreadLockChecker::TryC11Lock},
+ {{{"mtx_trylock"}, 1}, &PthreadLockChecker::TryC11Lock},
+ {{{"mtx_timedlock"}, 2}, &PthreadLockChecker::TryC11Lock},
// Release.
- {{"mtx_unlock", 1}, &PthreadLockChecker::ReleaseAnyLock},
+ {{{"mtx_unlock"}, 1}, &PthreadLockChecker::ReleaseAnyLock},
// Destroy
- {{"mtx_destroy", 1}, &PthreadLockChecker::DestroyPthreadLock},
+ {{{"mtx_destroy"}, 1}, &PthreadLockChecker::DestroyPthreadLock},
};
ProgramStateRef resolvePossiblyDestroyedMutex(ProgramStateRef state,
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
index bee7c468812c..01c71d91d1a1 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.cpp
@@ -14,6 +14,7 @@
#include "RetainCountChecker.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -284,7 +285,7 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex,
void RetainCountChecker::checkPostStmt(const ObjCIvarRefExpr *IRE,
CheckerContext &C) const {
- Optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
+ std::optional<Loc> IVarLoc = C.getSVal(IRE).getAs<Loc>();
if (!IVarLoc)
return;
@@ -412,15 +413,15 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) {
return RetTy;
}
-static Optional<RefVal> refValFromRetEffect(RetEffect RE,
- QualType ResultTy) {
+static std::optional<RefVal> refValFromRetEffect(RetEffect RE,
+ QualType ResultTy) {
if (RE.isOwned()) {
return RefVal::makeOwned(RE.getObjKind(), ResultTy);
} else if (RE.notOwned()) {
return RefVal::makeNotOwned(RE.getObjKind(), ResultTy);
}
- return None;
+ return std::nullopt;
}
static bool isPointerToObject(QualType QT) {
@@ -692,7 +693,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ,
assert(Ex);
ResultTy = GetReturnType(Ex, C.getASTContext());
}
- if (Optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
+ if (std::optional<RefVal> updatedRefVal = refValFromRetEffect(RE, ResultTy))
state = setRefBinding(state, Sym, *updatedRefVal);
}
@@ -767,7 +768,7 @@ ProgramStateRef RetainCountChecker::updateSymbol(ProgramStateRef state,
break;
}
- LLVM_FALLTHROUGH;
+ [[fallthrough]];
case DoNothing:
return state;
@@ -907,7 +908,7 @@ bool RetainCountChecker::evalCall(const CallEvent &Call,
const LocationContext *LCtx = C.getLocationContext();
using BehaviorSummary = RetainSummaryManager::BehaviorSummary;
- Optional<BehaviorSummary> BSmr =
+ std::optional<BehaviorSummary> BSmr =
SmrMgr.canEval(CE, FD, hasTrustedImplementationAnnotation);
// See if it's one of the specific functions we know how to eval.
@@ -1336,7 +1337,7 @@ void RetainCountChecker::checkBeginFunction(CheckerContext &Ctx) const {
RetainSummaryManager &SmrMgr = getSummaryManager(Ctx);
const LocationContext *LCtx = Ctx.getLocationContext();
const Decl *D = LCtx->getDecl();
- Optional<AnyCall> C = AnyCall::forDecl(D);
+ std::optional<AnyCall> C = AnyCall::forDecl(D);
if (!C || SmrMgr.isTrustedReferenceCountImplementation(D))
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 5109ae668686..e11e509f159d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -15,6 +15,7 @@
#include "RetainCountChecker.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -165,13 +166,12 @@ static bool shouldGenerateNote(llvm::raw_string_ostream &os,
/// Finds argument index of the out paramter in the call @c S
/// corresponding to the symbol @c Sym.
-/// If none found, returns None.
-static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
- const LocationContext *LCtx,
- SymbolRef &Sym,
- Optional<CallEventRef<>> CE) {
+/// If none found, returns std::nullopt.
+static std::optional<unsigned>
+findArgIdxOfSymbol(ProgramStateRef CurrSt, const LocationContext *LCtx,
+ SymbolRef &Sym, std::optional<CallEventRef<>> CE) {
if (!CE)
- return None;
+ return std::nullopt;
for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
@@ -179,25 +179,25 @@ static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym)
return Idx;
- return None;
+ return std::nullopt;
}
-static Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
+static std::optional<std::string> findMetaClassAlloc(const Expr *Callee) {
if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
if (ME->getMemberDecl()->getNameAsString() != "alloc")
- return None;
+ return std::nullopt;
const Expr *This = ME->getBase()->IgnoreParenImpCasts();
if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
const ValueDecl *VD = DRE->getDecl();
if (VD->getNameAsString() != "metaClass")
- return None;
+ return std::nullopt;
if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
return RD->getNameAsString();
}
}
- return None;
+ return std::nullopt;
}
static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
@@ -250,7 +250,7 @@ static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
}
}
- Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
+ std::optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
// If index is not found, we assume that the symbol was returned.
@@ -602,16 +602,17 @@ RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC,
return std::move(P);
}
-static Optional<std::string> describeRegion(const MemRegion *MR) {
+static std::optional<std::string> describeRegion(const MemRegion *MR) {
if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
return std::string(VR->getDecl()->getName());
// Once we support more storage locations for bindings,
// this would need to be improved.
- return None;
+ return std::nullopt;
}
using Bindings = llvm::SmallVector<std::pair<const MemRegion *, SVal>, 4>;
+namespace {
class VarBindingsCollector : public StoreManager::BindingsHandler {
SymbolRef Sym;
Bindings &Result;
@@ -632,6 +633,7 @@ public:
return true;
}
};
+} // namespace
Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager,
const ExplodedNode *Node, SymbolRef Sym) {
@@ -728,7 +730,7 @@ static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
const LocationContext *InterestingMethodContext = nullptr;
if (InitMethodContext) {
const ProgramPoint AllocPP = AllocationNode->getLocation();
- if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
+ if (std::optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
if (ME->getMethodFamily() == OMF_alloc)
InterestingMethodContext = InitMethodContext;
@@ -771,7 +773,7 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
os << "Object leaked: ";
- Optional<std::string> RegionDescription = describeRegion(LastBinding);
+ std::optional<std::string> RegionDescription = describeRegion(LastBinding);
if (RegionDescription) {
os << "object allocated and stored into '" << *RegionDescription << '\'';
} else {
@@ -917,7 +919,7 @@ void RefLeakReport::createDescription(CheckerContext &Ctx) {
llvm::raw_string_ostream os(Description);
os << "Potential leak of an object";
- Optional<std::string> RegionDescription =
+ std::optional<std::string> RegionDescription =
describeRegion(AllocBindingToReport);
if (RegionDescription) {
os << " stored into '" << *RegionDescription << '\'';
@@ -969,7 +971,7 @@ void RefLeakReport::findBindingToReport(CheckerContext &Ctx,
// Let's pick one of them at random (if there is something to pick from).
AllocBindingToReport = AllVarBindings[0].first;
- // Because 'AllocBindingToReport' is not the the same as
+ // Because 'AllocBindingToReport' is not the same as
// 'AllocFirstBinding', we need to explain how the leaking object
// got from one to another.
//
diff --git a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
index cf97439a468d..c3112ebe4e79 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ReturnValueChecker.cpp
@@ -17,8 +17,8 @@
#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"
#include "llvm/ADT/SmallVector.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -70,11 +70,11 @@ static std::string getName(const CallEvent &Call) {
// The predefinitions ('CDM') could break due to the ever growing code base.
// Check for the expected invariants and see whether they apply.
-static Optional<bool> isInvariantBreak(bool ExpectedValue, SVal ReturnV,
- CheckerContext &C) {
+static std::optional<bool> isInvariantBreak(bool ExpectedValue, SVal ReturnV,
+ CheckerContext &C) {
auto ReturnDV = ReturnV.getAs<DefinedOrUnknownSVal>();
if (!ReturnDV)
- return None;
+ return std::nullopt;
if (ExpectedValue)
return C.getState()->isNull(*ReturnDV).isConstrainedTrue();
@@ -90,7 +90,8 @@ void ReturnValueChecker::checkPostCall(const CallEvent &Call,
SVal ReturnV = Call.getReturnValue();
bool ExpectedValue = *RawExpectedValue;
- Optional<bool> IsInvariantBreak = isInvariantBreak(ExpectedValue, ReturnV, C);
+ std::optional<bool> IsInvariantBreak =
+ isInvariantBreak(ExpectedValue, ReturnV, C);
if (!IsInvariantBreak)
return;
@@ -137,7 +138,8 @@ void ReturnValueChecker::checkEndFunction(const ReturnStmt *RS,
SVal ReturnV = State->getSVal(RS->getRetValue(), C.getLocationContext());
bool ExpectedValue = *RawExpectedValue;
- Optional<bool> IsInvariantBreak = isInvariantBreak(ExpectedValue, ReturnV, C);
+ std::optional<bool> IsInvariantBreak =
+ isInvariantBreak(ExpectedValue, ReturnV, C);
if (!IsInvariantBreak)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 8c87a548fd91..9251c895614c 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
@@ -90,7 +90,7 @@ public:
REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
SimpleStreamChecker::SimpleStreamChecker()
- : OpenFn("fopen"), CloseFn("fclose", 1) {
+ : OpenFn({"fopen"}), CloseFn({"fclose"}, 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
diff --git a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index 92eef20d2daa..5689a63f8dd8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -33,6 +33,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
+#include <optional>
#include <string>
using namespace clang;
@@ -85,10 +86,10 @@ private:
using SmartPtrMethodHandlerFn =
void (SmartPtrModeling::*)(const CallEvent &Call, CheckerContext &) const;
CallDescriptionMap<SmartPtrMethodHandlerFn> SmartPtrMethodHandlers{
- {{"reset"}, &SmartPtrModeling::handleReset},
- {{"release"}, &SmartPtrModeling::handleRelease},
- {{"swap", 1}, &SmartPtrModeling::handleSwapMethod},
- {{"get"}, &SmartPtrModeling::handleGet}};
+ {{{"reset"}}, &SmartPtrModeling::handleReset},
+ {{{"release"}}, &SmartPtrModeling::handleRelease},
+ {{{"swap"}, 1}, &SmartPtrModeling::handleSwapMethod},
+ {{{"get"}}, &SmartPtrModeling::handleGet}};
const CallDescription StdSwapCall{{"std", "swap"}, 2};
const CallDescription StdMakeUniqueCall{{"std", "make_unique"}};
const CallDescription StdMakeUniqueForOverwriteCall{
@@ -298,8 +299,9 @@ bool SmartPtrModeling::evalCall(const CallEvent &Call,
if (matchesAny(Call, StdMakeUniqueCall, StdMakeUniqueForOverwriteCall)) {
if (!ModelSmartPtrDereference)
return false;
-
- const Optional<SVal> ThisRegionOpt = Call.getReturnValueUnderConstruction();
+
+ const std::optional<SVal> ThisRegionOpt =
+ Call.getReturnValueUnderConstruction();
if (!ThisRegionOpt)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index e6cea0fbff8c..c4b7411e9401 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -61,7 +61,6 @@ private:
ASTContext &Ctx);
static SmallVector<const MemRegion *, 4>
getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
- static bool isArcManagedBlock(const MemRegion *R, CheckerContext &C);
static bool isNotInCurrentFrame(const MemRegion *R, CheckerContext &C);
};
} // namespace
@@ -110,13 +109,6 @@ SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
return range;
}
-bool StackAddrEscapeChecker::isArcManagedBlock(const MemRegion *R,
- CheckerContext &C) {
- assert(R && "MemRegion should not be null");
- return C.getASTContext().getLangOpts().ObjCAutoRefCount &&
- isa<BlockDataRegion>(R);
-}
-
bool StackAddrEscapeChecker::isNotInCurrentFrame(const MemRegion *R,
CheckerContext &C) {
const StackSpaceRegion *S = cast<StackSpaceRegion>(R->getMemorySpace());
@@ -214,7 +206,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
void StackAddrEscapeChecker::checkReturnedBlockCaptures(
const BlockDataRegion &B, CheckerContext &C) const {
for (const MemRegion *Region : getCapturedStackRegions(B, C)) {
- if (isArcManagedBlock(Region, C) || isNotInCurrentFrame(Region, C))
+ if (isNotInCurrentFrame(Region, C))
continue;
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
@@ -267,8 +259,7 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
checkReturnedBlockCaptures(*B, C);
- if (!isa<StackSpaceRegion>(R->getMemorySpace()) ||
- isNotInCurrentFrame(R, C) || isArcManagedBlock(R, C))
+ if (!isa<StackSpaceRegion>(R->getMemorySpace()) || isNotInCurrentFrame(R, C))
return;
// Returning a record by value is fine. (In this case, the returned
@@ -348,8 +339,7 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
// Check the globals for the same.
if (!isa<GlobalsSpaceRegion>(Region->getMemorySpace()))
return true;
- if (VR && VR->hasStackStorage() && !isArcManagedBlock(VR, Ctx) &&
- !isNotInCurrentFrame(VR, Ctx))
+ if (VR && VR->hasStackStorage() && !isNotInCurrentFrame(VR, Ctx))
V.emplace_back(Region, VR);
return true;
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index 5897e5096461..49b3db560843 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -52,24 +52,12 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include <optional>
#include <string>
using namespace clang;
using namespace clang::ento;
-/// Produce a textual description of the state of \c errno (this describes the
-/// way how it is allowed to be used).
-/// The returned string is insertable into a longer warning message (in the form
-/// "the value 'errno' <...>").
-/// Currently only the \c errno_modeling::MustNotBeChecked state is supported.
-/// But later other kind of errno state may be needed if functions with special
-/// handling of \c errno are added.
-static const char *describeErrnoCheckState(errno_modeling::ErrnoCheckState CS) {
- assert(CS == errno_modeling::MustNotBeChecked &&
- "Errno description not applicable.");
- return "may be undefined after the call and should not be used";
-}
-
namespace {
class StdLibraryFunctionsChecker
: public Checker<check::PreCall, check::PostCall, eval::Call> {
@@ -147,9 +135,18 @@ class StdLibraryFunctionsChecker
virtual StringRef getName() const = 0;
+ // Represents that in which context do we require a description of the
+ // constraint.
+ enum class DescriptionKind {
+ // The constraint is violated.
+ Violation,
+ // We assume that the constraint is satisfied.
+ Assumption
+ };
+
// Give a description that explains the constraint to the user. Used when
// the bug is reported.
- virtual std::string describe(ProgramStateRef State,
+ virtual std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const {
// There are some descendant classes that are not used as argument
// constraints, e.g. ComparisonConstraint. In that case we can safely
@@ -187,7 +184,7 @@ class StdLibraryFunctionsChecker
RangeConstraint(ArgNo ArgN, RangeKind Kind, const IntRangeVector &Ranges)
: ValueConstraint(ArgN), Kind(Kind), Ranges(Ranges) {}
- std::string describe(ProgramStateRef State,
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
const IntRangeVector &getRanges() const { return Ranges; }
@@ -257,7 +254,9 @@ class StdLibraryFunctionsChecker
bool CannotBeNull = true;
public:
- std::string describe(ProgramStateRef State,
+ NotNullConstraint(ArgNo ArgN, bool CannotBeNull = true)
+ : ValueConstraint(ArgN), CannotBeNull(CannotBeNull) {}
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
StringRef getName() const override { return "NonNull"; }
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -300,13 +299,13 @@ class StdLibraryFunctionsChecker
// // Here, ptr is the buffer, and its minimum size is `size * nmemb`.
class BufferSizeConstraint : public ValueConstraint {
// The concrete value which is the minimum size for the buffer.
- llvm::Optional<llvm::APSInt> ConcreteSize;
+ std::optional<llvm::APSInt> ConcreteSize;
// The argument which holds the size of the buffer.
- llvm::Optional<ArgNo> SizeArgN;
+ std::optional<ArgNo> SizeArgN;
// The argument which is a multiplier to size. This is set in case of
// `fread` like functions where the size is computed as a multiplication of
// two arguments.
- llvm::Optional<ArgNo> SizeMultiplierArgN;
+ std::optional<ArgNo> SizeMultiplierArgN;
// The operator we use in apply. This is negated in negate().
BinaryOperator::Opcode Op = BO_LE;
@@ -329,7 +328,7 @@ class StdLibraryFunctionsChecker
return Result;
}
- std::string describe(ProgramStateRef State,
+ std::string describe(DescriptionKind DK, ProgramStateRef State,
const Summary &Summary) const override;
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -392,45 +391,67 @@ class StdLibraryFunctionsChecker
using ConstraintSet = std::vector<ValueConstraintPtr>;
/// Define how a function affects the system variable 'errno'.
- /// This works together with the ErrnoModeling and ErrnoChecker classes.
+ /// This works together with the \c ErrnoModeling and \c ErrnoChecker classes.
+ /// Currently 3 use cases exist: success, failure, irrelevant.
+ /// In the future the failure case can be customized to set \c errno to a
+ /// more specific constraint (for example > 0), or new case can be added
+ /// for functions which require check of \c errno in both success and failure
+ /// case.
class ErrnoConstraintBase {
public:
/// Apply specific state changes related to the errno variable.
virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const = 0;
- /// Get a description about what is applied to 'errno' and how is it allowed
- /// to be used. If ErrnoChecker generates a bug then this message is
- /// displayed as a note at the function call.
- /// It may return empty string if no note tag is to be added.
- virtual std::string describe(StringRef FunctionName) const { return ""; }
+ /// Get a NoteTag about the changes made to 'errno' and the possible bug.
+ /// It may return \c nullptr (if no bug report from \c ErrnoChecker is
+ /// expected).
+ virtual const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const {
+ return nullptr;
+ }
virtual ~ErrnoConstraintBase() {}
protected:
- /// Many of the descendant classes use this value.
- const errno_modeling::ErrnoCheckState CheckState;
-
- ErrnoConstraintBase(errno_modeling::ErrnoCheckState CS) : CheckState(CS) {}
+ ErrnoConstraintBase() = default;
/// This is used for conjure symbol for errno to differentiate from the
/// original call expression (same expression is used for the errno symbol).
static int Tag;
};
- /// Set value of 'errno' to be related to 0 in a specified way, with a
- /// specified "errno check state". For example with \c BO_GT 'errno' is
- /// constrained to be greater than 0. Use this for failure cases of functions.
- class ZeroRelatedErrnoConstraint : public ErrnoConstraintBase {
- BinaryOperatorKind Op;
+ /// Reset errno constraints to irrelevant.
+ /// This is applicable to functions that may change 'errno' and are not
+ /// modeled elsewhere.
+ class ResetErrnoConstraint : public ErrnoConstraintBase {
+ public:
+ ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
+ const Summary &Summary,
+ CheckerContext &C) const override {
+ return errno_modeling::setErrnoState(State, errno_modeling::Irrelevant);
+ }
+ };
+ /// Do not change errno constraints.
+ /// This is applicable to functions that are modeled in another checker
+ /// and the already set errno constraints should not be changed in the
+ /// post-call event.
+ class NoErrnoConstraint : public ErrnoConstraintBase {
public:
- ZeroRelatedErrnoConstraint(clang::BinaryOperatorKind OpK,
- errno_modeling::ErrnoCheckState CS)
- : ErrnoConstraintBase(CS), Op(OpK) {
- assert(BinaryOperator::isComparisonOp(OpK));
+ ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
+ const Summary &Summary,
+ CheckerContext &C) const override {
+ return State;
}
+ };
+ /// Set errno constraint at failure cases of standard functions.
+ /// Failure case: 'errno' becomes not equal to 0 and may or may not be checked
+ /// by the program. \c ErrnoChecker does not emit a bug report after such a
+ /// function call.
+ class FailureErrnoConstraint : public ErrnoConstraintBase {
+ public:
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
@@ -440,62 +461,40 @@ class StdLibraryFunctionsChecker
C.getLocationContext(), C.getASTContext().IntTy,
C.blockCount())
.castAs<NonLoc>();
- NonLoc ZeroVal =
- SVB.makeZeroVal(C.getASTContext().IntTy).castAs<NonLoc>();
- DefinedOrUnknownSVal Cond =
- SVB.evalBinOp(State, Op, ErrnoSVal, ZeroVal, SVB.getConditionType())
- .castAs<DefinedOrUnknownSVal>();
- State = State->assume(Cond, true);
- if (!State)
- return State;
- return errno_modeling::setErrnoValue(State, C.getLocationContext(),
- ErrnoSVal, CheckState);
- }
-
- std::string describe(StringRef FunctionName) const override {
- if (CheckState == errno_modeling::Irrelevant)
- return "";
- return (Twine("Assuming that function '") + FunctionName.str() +
- "' fails, in this case the value 'errno' becomes " +
- BinaryOperator::getOpcodeStr(Op).str() + " 0 and " +
- describeErrnoCheckState(CheckState))
- .str();
+ return errno_modeling::setErrnoForStdFailure(State, C, ErrnoSVal);
}
};
- /// Applies the constraints to 'errno' for a common case when a standard
- /// function is successful. The value of 'errno' after the call is not
- /// specified by the standard (it may change or not). The \c ErrnoChecker can
- /// generate a bug if 'errno' is read afterwards.
+ /// Set errno constraint at success cases of standard functions.
+ /// Success case: 'errno' is not allowed to be used.
+ /// \c ErrnoChecker can emit bug report after such a function call if errno
+ /// is used.
class SuccessErrnoConstraint : public ErrnoConstraintBase {
public:
- SuccessErrnoConstraint()
- : ErrnoConstraintBase(errno_modeling::MustNotBeChecked) {}
-
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
- return errno_modeling::setErrnoState(State, CheckState);
+ return errno_modeling::setErrnoForStdSuccess(State, C);
}
- std::string describe(StringRef FunctionName) const override {
- return (Twine("Assuming that function '") + FunctionName.str() +
- "' is successful, in this case the value 'errno' " +
- describeErrnoCheckState(CheckState))
- .str();
+ const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const override {
+ return errno_modeling::getNoteTagForStdSuccess(C, FunctionName);
}
};
- /// Set errno constraints if use of 'errno' is completely irrelevant to the
- /// modeled function or modeling is not possible.
- class NoErrnoConstraint : public ErrnoConstraintBase {
+ class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
public:
- NoErrnoConstraint() : ErrnoConstraintBase(errno_modeling::Irrelevant) {}
-
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const override {
- return errno_modeling::setErrnoState(State, CheckState);
+ return errno_modeling::setErrnoStdMustBeChecked(State, C,
+ Call.getOriginExpr());
+ }
+
+ const NoteTag *describe(CheckerContext &C,
+ StringRef FunctionName) const override {
+ return errno_modeling::getNoteTagForStdMustBeChecked(C, FunctionName);
}
};
@@ -542,8 +541,8 @@ class StdLibraryFunctionsChecker
StringRef getNote() const { return Note; }
};
- using ArgTypes = std::vector<Optional<QualType>>;
- using RetType = Optional<QualType>;
+ using ArgTypes = std::vector<std::optional<QualType>>;
+ using RetType = std::optional<QualType>;
// A placeholder type, we use it whenever we do not care about the concrete
// type in a Signature.
@@ -565,7 +564,7 @@ class StdLibraryFunctionsChecker
// Construct a signature from optional types. If any of the optional types
// are not set then the signature will be invalid.
Signature(ArgTypes ArgTys, RetType RetTy) {
- for (Optional<QualType> Arg : ArgTys) {
+ for (std::optional<QualType> Arg : ArgTys) {
if (!Arg) {
Invalid = true;
return;
@@ -718,10 +717,10 @@ public:
bool ShouldAssumeControlledEnvironment = false;
private:
- Optional<Summary> findFunctionSummary(const FunctionDecl *FD,
- CheckerContext &C) const;
- Optional<Summary> findFunctionSummary(const CallEvent &Call,
- CheckerContext &C) const;
+ std::optional<Summary> findFunctionSummary(const FunctionDecl *FD,
+ CheckerContext &C) const;
+ std::optional<Summary> findFunctionSummary(const CallEvent &Call,
+ CheckerContext &C) const;
void initFunctionSummaries(CheckerContext &C) const;
@@ -746,9 +745,12 @@ private:
// Highlight the range of the argument that was violated.
R->addRange(Call.getArgSourceRange(VC->getArgNo()));
- // Describe the argument constraint in a note.
- R->addNote(VC->describe(C.getState(), Summary), R->getLocation(),
- Call.getArgSourceRange(VC->getArgNo()));
+ // Describe the argument constraint violation in a note.
+ std::string Descr = VC->describe(
+ ValueConstraint::DescriptionKind::Violation, C.getState(), Summary);
+ // Capitalize the first letter b/c we want a full sentence.
+ Descr[0] = toupper(Descr[0]);
+ R->addNote(Descr, R->getLocation(), Call.getArgSourceRange(VC->getArgNo()));
C.emitReport(std::move(R));
}
@@ -758,10 +760,11 @@ private:
/// Usually if a failure return value exists for function, that function
/// needs different cases for success and failure with different errno
/// constraints (and different return value constraints).
- const NoErrnoConstraint ErrnoIrrelevant;
- const SuccessErrnoConstraint ErrnoMustNotBeChecked;
- const ZeroRelatedErrnoConstraint ErrnoNEZeroIrrelevant{
- clang::BinaryOperatorKind::BO_NE, errno_modeling::Irrelevant};
+ const NoErrnoConstraint ErrnoUnchanged{};
+ const ResetErrnoConstraint ErrnoIrrelevant{};
+ const ErrnoMustBeCheckedConstraint ErrnoMustBeChecked{};
+ const SuccessErrnoConstraint ErrnoMustNotBeChecked{};
+ const FailureErrnoConstraint ErrnoNEZeroIrrelevant{};
};
int StdLibraryFunctionsChecker::ErrnoConstraintBase::Tag = 0;
@@ -778,24 +781,26 @@ static BasicValueFactory &getBVF(ProgramStateRef State) {
}
std::string StdLibraryFunctionsChecker::NotNullConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
SmallString<48> Result;
- Result += "The ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the ";
Result += getArgDesc(ArgN);
- Result += " should not be NULL";
+ Result += DK == Violation ? " should not be NULL" : " is not NULL";
return Result.c_str();
}
std::string StdLibraryFunctionsChecker::RangeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
BasicValueFactory &BVF = getBVF(State);
QualType T = Summary.getArgType(getArgNo());
SmallString<48> Result;
- Result += "The ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the ";
Result += getArgDesc(ArgN);
- Result += " should be ";
+ Result += DK == Violation ? " should be " : " is ";
// Range kind as a string.
Kind == OutOfRange ? Result += "out of" : Result += "within";
@@ -827,16 +832,18 @@ StdLibraryFunctionsChecker::getArgDesc(StdLibraryFunctionsChecker::ArgNo ArgN) {
SmallString<8> Result;
Result += std::to_string(ArgN + 1);
Result += llvm::getOrdinalSuffix(ArgN + 1);
- Result += " arg";
+ Result += " argument";
return Result;
}
std::string StdLibraryFunctionsChecker::BufferSizeConstraint::describe(
- ProgramStateRef State, const Summary &Summary) const {
+ DescriptionKind DK, ProgramStateRef State, const Summary &Summary) const {
SmallString<96> Result;
- Result += "The size of the ";
+ const auto Violation = ValueConstraint::DescriptionKind::Violation;
+ Result += "the size of the ";
Result += getArgDesc(ArgN);
- Result += " should be equal to or less than the value of ";
+ Result += DK == Violation ? " should be " : " is ";
+ Result += "equal to or greater than the value of ";
if (ConcreteSize) {
ConcreteSize->toString(Result);
} else if (SizeArgN) {
@@ -962,7 +969,7 @@ ProgramStateRef StdLibraryFunctionsChecker::ComparisonConstraint::apply(
void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return;
@@ -970,31 +977,43 @@ void StdLibraryFunctionsChecker::checkPreCall(const CallEvent &Call,
ProgramStateRef State = C.getState();
ProgramStateRef NewState = State;
+ ExplodedNode *NewNode = C.getPredecessor();
for (const ValueConstraintPtr &Constraint : Summary.getArgConstraints()) {
ProgramStateRef SuccessSt = Constraint->apply(NewState, Call, Summary, C);
ProgramStateRef FailureSt =
Constraint->negate()->apply(NewState, Call, Summary, C);
// The argument constraint is not satisfied.
if (FailureSt && !SuccessSt) {
- if (ExplodedNode *N = C.generateErrorNode(NewState))
+ if (ExplodedNode *N = C.generateErrorNode(NewState, NewNode))
reportBug(Call, N, Constraint.get(), Summary, C);
break;
- } else {
- // We will apply the constraint even if we cannot reason about the
- // argument. This means both SuccessSt and FailureSt can be true. If we
- // weren't applying the constraint that would mean that symbolic
- // execution continues on a code whose behaviour is undefined.
- assert(SuccessSt);
- NewState = SuccessSt;
+ }
+ // We will apply the constraint even if we cannot reason about the
+ // argument. This means both SuccessSt and FailureSt can be true. If we
+ // weren't applying the constraint that would mean that symbolic
+ // execution continues on a code whose behaviour is undefined.
+ assert(SuccessSt);
+ NewState = SuccessSt;
+ if (NewState != State) {
+ SmallString<64> Msg;
+ Msg += "Assuming ";
+ Msg += Constraint->describe(ValueConstraint::DescriptionKind::Assumption,
+ NewState, Summary);
+ const auto ArgSVal = Call.getArgSVal(Constraint->getArgNo());
+ NewNode = C.addTransition(
+ NewState, NewNode,
+ C.getNoteTag([Msg = std::move(Msg), ArgSVal](
+ PathSensitiveBugReport &BR, llvm::raw_ostream &OS) {
+ if (BR.isInteresting(ArgSVal))
+ OS << Msg;
+ }));
}
}
- if (NewState && NewState != State)
- C.addTransition(NewState);
}
void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return;
@@ -1017,13 +1036,10 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
if (NewState && NewState != State) {
if (Case.getNote().empty()) {
- std::string Note;
+ const NoteTag *NT = nullptr;
if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
- Note = Case.getErrnoConstraint().describe(D->getNameAsString());
- if (Note.empty())
- C.addTransition(NewState);
- else
- C.addTransition(NewState, errno_modeling::getErrnoNoteTag(C, Note));
+ NT = Case.getErrnoConstraint().describe(C, D->getNameAsString());
+ C.addTransition(NewState, NT);
} else {
StringRef Note = Case.getNote();
const NoteTag *Tag = C.getNoteTag(
@@ -1036,13 +1052,23 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
/*IsPrunable=*/true);
C.addTransition(NewState, Tag);
}
+ } else if (NewState == State) {
+ // It is possible that the function was evaluated in a checker callback
+ // where the state constraints are already applied, then no change happens
+ // here to the state (if the ErrnoConstraint did not change it either).
+ // If the evaluated function requires a NoteTag for errno change, it is
+ // added here.
+ if (const auto *D = dyn_cast_or_null<FunctionDecl>(Call.getDecl()))
+ if (const NoteTag *NT =
+ Case.getErrnoConstraint().describe(C, D->getNameAsString()))
+ C.addTransition(NewState, NT);
}
}
}
bool StdLibraryFunctionsChecker::evalCall(const CallEvent &Call,
CheckerContext &C) const {
- Optional<Summary> FoundSummary = findFunctionSummary(Call, C);
+ std::optional<Summary> FoundSummary = findFunctionSummary(Call, C);
if (!FoundSummary)
return false;
@@ -1109,26 +1135,26 @@ bool StdLibraryFunctionsChecker::Signature::matches(
return true;
}
-Optional<StdLibraryFunctionsChecker::Summary>
+std::optional<StdLibraryFunctionsChecker::Summary>
StdLibraryFunctionsChecker::findFunctionSummary(const FunctionDecl *FD,
CheckerContext &C) const {
if (!FD)
- return None;
+ return std::nullopt;
initFunctionSummaries(C);
auto FSMI = FunctionSummaryMap.find(FD->getCanonicalDecl());
if (FSMI == FunctionSummaryMap.end())
- return None;
+ return std::nullopt;
return FSMI->second;
}
-Optional<StdLibraryFunctionsChecker::Summary>
+std::optional<StdLibraryFunctionsChecker::Summary>
StdLibraryFunctionsChecker::findFunctionSummary(const CallEvent &Call,
CheckerContext &C) const {
const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
if (!FD)
- return None;
+ return std::nullopt;
return findFunctionSummary(FD, C);
}
@@ -1149,11 +1175,11 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
LookupType(const ASTContext &ACtx) : ACtx(ACtx) {}
// Find the type. If not found then the optional is not set.
- llvm::Optional<QualType> operator()(StringRef Name) {
+ std::optional<QualType> operator()(StringRef Name) {
IdentifierInfo &II = ACtx.Idents.get(Name);
auto LookupRes = ACtx.getTranslationUnitDecl()->lookup(&II);
if (LookupRes.empty())
- return None;
+ return std::nullopt;
// Prioritze typedef declarations.
// This is needed in case of C struct typedefs. E.g.:
@@ -1171,7 +1197,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
for (Decl *D : LookupRes)
if (auto *TD = dyn_cast<TypeDecl>(D))
return ACtx.getTypeDeclType(TD).getCanonicalType();
- return None;
+ return std::nullopt;
}
} lookupTy(ACtx);
@@ -1185,10 +1211,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
QualType operator()(QualType Ty) {
return ACtx.getLangOpts().C99 ? ACtx.getRestrictType(Ty) : Ty;
}
- Optional<QualType> operator()(Optional<QualType> Ty) {
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
if (Ty)
return operator()(*Ty);
- return None;
+ return std::nullopt;
}
} getRestrictTy(ACtx);
class GetPointerTy {
@@ -1197,16 +1223,16 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
public:
GetPointerTy(const ASTContext &ACtx) : ACtx(ACtx) {}
QualType operator()(QualType Ty) { return ACtx.getPointerType(Ty); }
- Optional<QualType> operator()(Optional<QualType> Ty) {
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
if (Ty)
return operator()(*Ty);
- return None;
+ return std::nullopt;
}
} getPointerTy(ACtx);
class {
public:
- Optional<QualType> operator()(Optional<QualType> Ty) {
- return Ty ? Optional<QualType>(Ty->withConst()) : None;
+ std::optional<QualType> operator()(std::optional<QualType> Ty) {
+ return Ty ? std::optional<QualType>(Ty->withConst()) : std::nullopt;
}
QualType operator()(QualType Ty) { return Ty.withConst(); }
} getConstTy;
@@ -1215,14 +1241,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
public:
GetMaxValue(BasicValueFactory &BVF) : BVF(BVF) {}
- Optional<RangeInt> operator()(QualType Ty) {
+ std::optional<RangeInt> operator()(QualType Ty) {
return BVF.getMaxValue(Ty).getLimitedValue();
}
- Optional<RangeInt> operator()(Optional<QualType> Ty) {
+ std::optional<RangeInt> operator()(std::optional<QualType> Ty) {
if (Ty) {
return operator()(*Ty);
}
- return None;
+ return std::nullopt;
}
} getMaxValue(BVF);
@@ -1278,7 +1304,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// The platform dependent value of EOF.
// Try our best to parse this from the Preprocessor, otherwise fallback to -1.
const auto EOFv = [&C]() -> RangeInt {
- if (const llvm::Optional<int> OptInt =
+ if (const std::optional<int> OptInt =
tryExpandAsInteger("EOF", C.getPreprocessor()))
return *OptInt;
return -1;
@@ -1351,13 +1377,13 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto operator()(RangeInt b, RangeInt e) {
return IntRangeVector{std::pair<RangeInt, RangeInt>{b, e}};
}
- auto operator()(RangeInt b, Optional<RangeInt> e) {
+ auto operator()(RangeInt b, std::optional<RangeInt> e) {
if (e)
return IntRangeVector{std::pair<RangeInt, RangeInt>{b, *e}};
return IntRangeVector{};
}
auto operator()(std::pair<RangeInt, RangeInt> i0,
- std::pair<RangeInt, Optional<RangeInt>> i1) {
+ std::pair<RangeInt, std::optional<RangeInt>> i1) {
if (i1.second)
return IntRangeVector{i0, {i1.first, *(i1.second)}};
return IntRangeVector{i0};
@@ -1370,10 +1396,18 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto NotNull = [&](ArgNo ArgN) {
return std::make_shared<NotNullConstraint>(ArgN);
};
+ auto IsNull = [&](ArgNo ArgN) {
+ return std::make_shared<NotNullConstraint>(ArgN, false);
+ };
- Optional<QualType> FileTy = lookupTy("FILE");
- Optional<QualType> FilePtrTy = getPointerTy(FileTy);
- Optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
+ std::optional<QualType> FileTy = lookupTy("FILE");
+ std::optional<QualType> FilePtrTy = getPointerTy(FileTy);
+ std::optional<QualType> FilePtrRestrictTy = getRestrictTy(FilePtrTy);
+
+ std::optional<QualType> FPosTTy = lookupTy("fpos_t");
+ std::optional<QualType> FPosTPtrTy = getPointerTy(FPosTTy);
+ std::optional<QualType> ConstFPosTPtrTy = getPointerTy(getConstTy(FPosTTy));
+ std::optional<QualType> FPosTPtrRestrictTy = getRestrictTy(FPosTPtrTy);
// We are finally ready to define specifications for all supported functions.
//
@@ -1599,11 +1633,23 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// read()-like functions that never return more than buffer size.
auto FreadSummary =
Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
+ .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
+ ArgumentCondition(2U, WithinRange, Range(1, SizeMax)),
+ ReturnValueCondition(BO_LT, ArgNo(2)),
ReturnValueCondition(WithinRange, Range(0, SizeMax))},
- ErrnoIrrelevant)
+ ErrnoNEZeroIrrelevant)
+ .Case({ArgumentCondition(1U, WithinRange, Range(1, SizeMax)),
+ ReturnValueCondition(BO_EQ, ArgNo(2)),
+ ReturnValueCondition(WithinRange, Range(0, SizeMax))},
+ ErrnoMustNotBeChecked)
+ .Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
+ ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoMustNotBeChecked)
.ArgConstraint(NotNull(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(3)))
+ // FIXME: It should be allowed to have a null buffer if any of
+ // args 1 or 2 are zero. Remove NotNull check of arg 0, add a check
+ // for non-null buffer if non-zero size to BufferSizeConstraint?
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
/*BufSizeMultiplier=*/ArgNo(2)));
@@ -1622,8 +1668,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
RetType{SizeTy}),
FreadSummary);
- Optional<QualType> Ssize_tTy = lookupTy("ssize_t");
- Optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
+ std::optional<QualType> Ssize_tTy = lookupTy("ssize_t");
+ std::optional<RangeInt> Ssize_tMax = getMaxValue(Ssize_tTy);
auto ReadSummary =
Summary(NoEvalCall)
@@ -1689,6 +1735,142 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
}
if (ModelPOSIX) {
+ const auto ReturnsZeroOrMinusOne =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
+ const auto ReturnsZero =
+ ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
+ const auto ReturnsMinusOne =
+ ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
+ const auto ReturnsNonnegative =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
+ const auto ReturnsNonZero =
+ ConstraintSet{ReturnValueCondition(OutOfRange, SingleValue(0))};
+ const auto ReturnsFileDescriptor =
+ ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
+ const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
+
+ // FILE *fopen(const char *restrict pathname, const char *restrict mode);
+ addToFunctionSummaryMap(
+ "fopen",
+ Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy},
+ RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({NotNull(Ret)}, ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // FILE *tmpfile(void);
+ addToFunctionSummaryMap("tmpfile",
+ Signature(ArgTypes{}, RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({NotNull(Ret)}, ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant));
+
+ // FILE *freopen(const char *restrict pathname, const char *restrict mode,
+ // FILE *restrict stream);
+ addToFunctionSummaryMap(
+ "freopen",
+ Signature(ArgTypes{ConstCharPtrRestrictTy, ConstCharPtrRestrictTy,
+ FilePtrRestrictTy},
+ RetType{FilePtrTy}),
+ Summary(NoEvalCall)
+ .Case({ReturnValueCondition(BO_EQ, ArgNo(2))},
+ ErrnoMustNotBeChecked)
+ .Case({IsNull(Ret)}, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(1)))
+ .ArgConstraint(NotNull(ArgNo(2))));
+
+ // int fclose(FILE *stream);
+ addToFunctionSummaryMap(
+ "fclose", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoMustNotBeChecked)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
+ ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // int fseek(FILE *stream, long offset, int whence);
+ // FIXME: It can be possible to get the 'SEEK_' values (like EOFv) and use
+ // these for condition of arg 2.
+ // Now the range [0,2] is used (the `SEEK_*` constants are usually 0,1,2).
+ addToFunctionSummaryMap(
+ "fseek", Signature(ArgTypes{FilePtrTy, LongTy, IntTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoMustNotBeChecked)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(ArgumentCondition(2, WithinRange, {{0, 2}})));
+
+ // int fgetpos(FILE *restrict stream, fpos_t *restrict pos);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The fgetpos() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "fgetpos",
+ Signature(ArgTypes{FilePtrRestrictTy, FPosTPtrRestrictTy},
+ RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoUnchanged)
+ .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // int fsetpos(FILE *stream, const fpos_t *pos);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The fsetpos() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "fsetpos",
+ Signature(ArgTypes{FilePtrTy, ConstFPosTPtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsZero, ErrnoUnchanged)
+ .Case(ReturnsNonZero, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0)))
+ .ArgConstraint(NotNull(ArgNo(1))));
+
+ // long ftell(FILE *stream);
+ // From 'The Open Group Base Specifications Issue 7, 2018 edition':
+ // "The ftell() function shall not change the setting of errno if
+ // successful."
+ addToFunctionSummaryMap(
+ "ftell", Signature(ArgTypes{FilePtrTy}, RetType{LongTy}),
+ Summary(NoEvalCall)
+ .Case({ReturnValueCondition(WithinRange, Range(1, LongMax))},
+ ErrnoUnchanged)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // int fileno(FILE *stream);
+ addToFunctionSummaryMap(
+ "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall)
+ .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
+ .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // void rewind(FILE *stream);
+ // This function indicates error only by setting of 'errno'.
+ addToFunctionSummaryMap("rewind",
+ Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
+ Summary(NoEvalCall)
+ .Case({}, ErrnoMustBeChecked)
+ .ArgConstraint(NotNull(ArgNo(0))));
+
+ // void clearerr(FILE *stream);
+ addToFunctionSummaryMap(
+ "clearerr", Signature(ArgTypes{FilePtrTy}, RetType{VoidTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+ // int feof(FILE *stream);
+ addToFunctionSummaryMap(
+ "feof", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
+
+ // int ferror(FILE *stream);
+ addToFunctionSummaryMap(
+ "ferror", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
+ Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
// long a64l(const char *str64);
addToFunctionSummaryMap(
@@ -1702,18 +1884,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(
0, WithinRange, Range(0, LongMax))));
- const auto ReturnsZeroOrMinusOne =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, 0))};
- const auto ReturnsZero =
- ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(0))};
- const auto ReturnsMinusOne =
- ConstraintSet{ReturnValueCondition(WithinRange, SingleValue(-1))};
- const auto ReturnsNonnegative =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(0, IntMax))};
- const auto ReturnsFileDescriptor =
- ConstraintSet{ReturnValueCondition(WithinRange, Range(-1, IntMax))};
- const auto &ReturnsValidFileDescriptor = ReturnsNonnegative;
-
// int access(const char *pathname, int amode);
addToFunctionSummaryMap(
"access", Signature(ArgTypes{ConstCharPtrTy, IntTy}, RetType{IntTy}),
@@ -1777,7 +1947,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(
0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Off_tTy = lookupTy("off_t");
+ std::optional<QualType> Off_tTy = lookupTy("off_t");
// int truncate(const char *path, off_t length);
addToFunctionSummaryMap(
@@ -1819,7 +1989,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Mode_tTy = lookupTy("mode_t");
+ std::optional<QualType> Mode_tTy = lookupTy("mode_t");
// int creat(const char *pathname, mode_t mode);
addToFunctionSummaryMap(
@@ -1836,8 +2006,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, UnsignedIntMax))));
- Optional<QualType> DirTy = lookupTy("DIR");
- Optional<QualType> DirPtrTy = getPointerTy(DirTy);
+ std::optional<QualType> DirTy = lookupTy("DIR");
+ std::optional<QualType> DirPtrTy = getPointerTy(DirTy);
// int dirfd(DIR *dirp);
addToFunctionSummaryMap(
@@ -1920,7 +2090,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Dev_tTy = lookupTy("dev_t");
+ std::optional<QualType> Dev_tTy = lookupTy("dev_t");
// int mknod(const char *pathname, mode_t mode, dev_t dev);
addToFunctionSummaryMap(
@@ -1969,8 +2139,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(0, WithinRange, Range(0, IntMax))));
- Optional<QualType> Uid_tTy = lookupTy("uid_t");
- Optional<QualType> Gid_tTy = lookupTy("gid_t");
+ std::optional<QualType> Uid_tTy = lookupTy("uid_t");
+ std::optional<QualType> Gid_tTy = lookupTy("gid_t");
// int fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group,
// int flags);
@@ -2069,9 +2239,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructStatTy = lookupTy("stat");
- Optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
- Optional<QualType> StructStatPtrRestrictTy = getRestrictTy(StructStatPtrTy);
+ std::optional<QualType> StructStatTy = lookupTy("stat");
+ std::optional<QualType> StructStatPtrTy = getPointerTy(StructStatTy);
+ std::optional<QualType> StructStatPtrRestrictTy =
+ getRestrictTy(StructStatPtrTy);
// int fstat(int fd, struct stat *statbuf);
addToFunctionSummaryMap(
@@ -2200,14 +2371,6 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"rand_r", Signature(ArgTypes{UnsignedIntPtrTy}, RetType{IntTy}),
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- // int fileno(FILE *stream);
- addToFunctionSummaryMap(
- "fileno", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
- Summary(NoEvalCall)
- .Case(ReturnsValidFileDescriptor, ErrnoMustNotBeChecked)
- .Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
- .ArgConstraint(NotNull(ArgNo(0))));
-
// int fseeko(FILE *stream, off_t offset, int whence);
addToFunctionSummaryMap(
"fseeko",
@@ -2233,7 +2396,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(4, WithinRange, Range(-1, IntMax))));
- Optional<QualType> Off64_tTy = lookupTy("off64_t");
+ std::optional<QualType> Off64_tTy = lookupTy("off64_t");
// void *mmap64(void *addr, size_t length, int prot, int flags, int fd,
// off64_t offset);
// FIXME: Improve for errno modeling.
@@ -2358,18 +2521,20 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(NotNull(ArgNo(1)))
.ArgConstraint(NotNull(ArgNo(2))));
- Optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
- Optional<QualType> StructSockaddrPtrTy = getPointerTy(StructSockaddrTy);
- Optional<QualType> ConstStructSockaddrPtrTy =
+ std::optional<QualType> StructSockaddrTy = lookupTy("sockaddr");
+ std::optional<QualType> StructSockaddrPtrTy =
+ getPointerTy(StructSockaddrTy);
+ std::optional<QualType> ConstStructSockaddrPtrTy =
getPointerTy(getConstTy(StructSockaddrTy));
- Optional<QualType> StructSockaddrPtrRestrictTy =
+ std::optional<QualType> StructSockaddrPtrRestrictTy =
getRestrictTy(StructSockaddrPtrTy);
- Optional<QualType> ConstStructSockaddrPtrRestrictTy =
+ std::optional<QualType> ConstStructSockaddrPtrRestrictTy =
getRestrictTy(ConstStructSockaddrPtrTy);
- Optional<QualType> Socklen_tTy = lookupTy("socklen_t");
- Optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
- Optional<QualType> Socklen_tPtrRestrictTy = getRestrictTy(Socklen_tPtrTy);
- Optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
+ std::optional<QualType> Socklen_tTy = lookupTy("socklen_t");
+ std::optional<QualType> Socklen_tPtrTy = getPointerTy(Socklen_tTy);
+ std::optional<QualType> Socklen_tPtrRestrictTy =
+ getRestrictTy(Socklen_tPtrTy);
+ std::optional<RangeInt> Socklen_tMax = getMaxValue(Socklen_tTy);
// In 'socket.h' of some libc implementations with C99, sockaddr parameter
// is a transparent union of the underlying sockaddr_ family of pointers
@@ -2568,9 +2733,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(1),
/*BufSize=*/ArgNo(2))));
- Optional<QualType> StructMsghdrTy = lookupTy("msghdr");
- Optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
- Optional<QualType> ConstStructMsghdrPtrTy =
+ std::optional<QualType> StructMsghdrTy = lookupTy("msghdr");
+ std::optional<QualType> StructMsghdrPtrTy = getPointerTy(StructMsghdrTy);
+ std::optional<QualType> ConstStructMsghdrPtrTy =
getPointerTy(getConstTy(StructMsghdrTy));
// ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
@@ -2676,8 +2841,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(
ArgumentCondition(5, WithinRange, Range(0, Socklen_tMax))));
- Optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
- Optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
+ std::optional<QualType> StructUtimbufTy = lookupTy("utimbuf");
+ std::optional<QualType> StructUtimbufPtrTy = getPointerTy(StructUtimbufTy);
// int utime(const char *filename, struct utimbuf *buf);
addToFunctionSummaryMap(
@@ -2688,9 +2853,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> StructTimespecTy = lookupTy("timespec");
- Optional<QualType> StructTimespecPtrTy = getPointerTy(StructTimespecTy);
- Optional<QualType> ConstStructTimespecPtrTy =
+ std::optional<QualType> StructTimespecTy = lookupTy("timespec");
+ std::optional<QualType> StructTimespecPtrTy =
+ getPointerTy(StructTimespecTy);
+ std::optional<QualType> ConstStructTimespecPtrTy =
getPointerTy(getConstTy(StructTimespecTy));
// int futimens(int fd, const struct timespec times[2]);
@@ -2714,8 +2880,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructTimevalTy = lookupTy("timeval");
- Optional<QualType> ConstStructTimevalPtrTy =
+ std::optional<QualType> StructTimevalTy = lookupTy("timeval");
+ std::optional<QualType> ConstStructTimevalPtrTy =
getPointerTy(getConstTy(StructTimevalTy));
// int utimes(const char *filename, const struct timeval times[2]);
@@ -2738,17 +2904,19 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Time_tTy = lookupTy("time_t");
- Optional<QualType> ConstTime_tPtrTy = getPointerTy(getConstTy(Time_tTy));
- Optional<QualType> ConstTime_tPtrRestrictTy =
+ std::optional<QualType> Time_tTy = lookupTy("time_t");
+ std::optional<QualType> ConstTime_tPtrTy =
+ getPointerTy(getConstTy(Time_tTy));
+ std::optional<QualType> ConstTime_tPtrRestrictTy =
getRestrictTy(ConstTime_tPtrTy);
- Optional<QualType> StructTmTy = lookupTy("tm");
- Optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
- Optional<QualType> StructTmPtrRestrictTy = getRestrictTy(StructTmPtrTy);
- Optional<QualType> ConstStructTmPtrTy =
+ std::optional<QualType> StructTmTy = lookupTy("tm");
+ std::optional<QualType> StructTmPtrTy = getPointerTy(StructTmTy);
+ std::optional<QualType> StructTmPtrRestrictTy =
+ getRestrictTy(StructTmPtrTy);
+ std::optional<QualType> ConstStructTmPtrTy =
getPointerTy(getConstTy(StructTmTy));
- Optional<QualType> ConstStructTmPtrRestrictTy =
+ std::optional<QualType> ConstStructTmPtrRestrictTy =
getRestrictTy(ConstStructTmPtrTy);
// struct tm * localtime(const time_t *tp);
@@ -2804,7 +2972,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"gmtime", Signature(ArgTypes{ConstTime_tPtrTy}, RetType{StructTmPtrTy}),
Summary(NoEvalCall).ArgConstraint(NotNull(ArgNo(0))));
- Optional<QualType> Clockid_tTy = lookupTy("clockid_t");
+ std::optional<QualType> Clockid_tTy = lookupTy("clockid_t");
// int clock_gettime(clockid_t clock_id, struct timespec *tp);
addToFunctionSummaryMap(
@@ -2815,8 +2983,9 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> StructItimervalTy = lookupTy("itimerval");
- Optional<QualType> StructItimervalPtrTy = getPointerTy(StructItimervalTy);
+ std::optional<QualType> StructItimervalTy = lookupTy("itimerval");
+ std::optional<QualType> StructItimervalPtrTy =
+ getPointerTy(StructItimervalTy);
// int getitimer(int which, struct itimerval *curr_value);
addToFunctionSummaryMap(
@@ -2827,25 +2996,30 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant)
.ArgConstraint(NotNull(ArgNo(1))));
- Optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
- Optional<QualType> Pthread_cond_tPtrTy = getPointerTy(Pthread_cond_tTy);
- Optional<QualType> Pthread_tTy = lookupTy("pthread_t");
- Optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
- Optional<QualType> Pthread_tPtrRestrictTy = getRestrictTy(Pthread_tPtrTy);
- Optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
- Optional<QualType> Pthread_mutex_tPtrTy = getPointerTy(Pthread_mutex_tTy);
- Optional<QualType> Pthread_mutex_tPtrRestrictTy =
+ std::optional<QualType> Pthread_cond_tTy = lookupTy("pthread_cond_t");
+ std::optional<QualType> Pthread_cond_tPtrTy =
+ getPointerTy(Pthread_cond_tTy);
+ std::optional<QualType> Pthread_tTy = lookupTy("pthread_t");
+ std::optional<QualType> Pthread_tPtrTy = getPointerTy(Pthread_tTy);
+ std::optional<QualType> Pthread_tPtrRestrictTy =
+ getRestrictTy(Pthread_tPtrTy);
+ std::optional<QualType> Pthread_mutex_tTy = lookupTy("pthread_mutex_t");
+ std::optional<QualType> Pthread_mutex_tPtrTy =
+ getPointerTy(Pthread_mutex_tTy);
+ std::optional<QualType> Pthread_mutex_tPtrRestrictTy =
getRestrictTy(Pthread_mutex_tPtrTy);
- Optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
- Optional<QualType> Pthread_attr_tPtrTy = getPointerTy(Pthread_attr_tTy);
- Optional<QualType> ConstPthread_attr_tPtrTy =
+ std::optional<QualType> Pthread_attr_tTy = lookupTy("pthread_attr_t");
+ std::optional<QualType> Pthread_attr_tPtrTy =
+ getPointerTy(Pthread_attr_tTy);
+ std::optional<QualType> ConstPthread_attr_tPtrTy =
getPointerTy(getConstTy(Pthread_attr_tTy));
- Optional<QualType> ConstPthread_attr_tPtrRestrictTy =
+ std::optional<QualType> ConstPthread_attr_tPtrRestrictTy =
getRestrictTy(ConstPthread_attr_tPtrTy);
- Optional<QualType> Pthread_mutexattr_tTy = lookupTy("pthread_mutexattr_t");
- Optional<QualType> ConstPthread_mutexattr_tPtrTy =
+ std::optional<QualType> Pthread_mutexattr_tTy =
+ lookupTy("pthread_mutexattr_t");
+ std::optional<QualType> ConstPthread_mutexattr_tPtrTy =
getPointerTy(getConstTy(Pthread_mutexattr_tTy));
- Optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
+ std::optional<QualType> ConstPthread_mutexattr_tPtrRestrictTy =
getRestrictTy(ConstPthread_mutexattr_tPtrTy);
QualType PthreadStartRoutineTy = getPointerTy(
@@ -2929,6 +3103,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
// Test range values.
addToFunctionSummaryMap(
+ "__single_val_0", Signature(ArgTypes{IntTy}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(0))));
+ addToFunctionSummaryMap(
"__single_val_1", Signature(ArgTypes{IntTy}, RetType{IntTy}),
Summary(EvalCallAsPure)
.ArgConstraint(ArgumentCondition(0U, WithinRange, SingleValue(1))));
@@ -2996,6 +3174,15 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
"__test_restrict_param_2"},
Signature(ArgTypes{VoidPtrRestrictTy}, RetType{VoidTy}),
Summary(EvalCallAsPure));
+
+ // Test the application of cases.
+ addToFunctionSummaryMap(
+ "__test_case_note", Signature(ArgTypes{}, RetType{IntTy}),
+ Summary(EvalCallAsPure)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoIrrelevant, "Function returns 0")
+ .Case({ReturnValueCondition(WithinRange, SingleValue(1))},
+ ErrnoIrrelevant, "Function returns 1"));
}
SummariesInitialized = true;
diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index 1aa665f0ef45..3f61dd823940 100644
--- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -17,10 +17,12 @@
#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/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include <functional>
+#include <optional>
using namespace clang;
using namespace ento;
@@ -85,10 +87,10 @@ const StreamErrorState ErrorFError{false, false, true};
/// Full state information about a stream pointer.
struct StreamState {
/// The last file operation called in the stream.
+ /// Can be nullptr.
const FnDescription *LastOperation;
/// State of a stream symbol.
- /// FIXME: We need maybe an "escaped" state later.
enum KindTy {
Opened, /// Stream is opened.
Closed, /// Closed stream (an invalid stream pointer after it was closed).
@@ -202,13 +204,12 @@ ProgramStateRef bindAndAssumeTrue(ProgramStateRef State, CheckerContext &C,
ProgramStateRef bindInt(uint64_t Value, ProgramStateRef State,
CheckerContext &C, const CallExpr *CE) {
State = State->BindExpr(CE, C.getLocationContext(),
- C.getSValBuilder().makeIntVal(Value, false));
+ C.getSValBuilder().makeIntVal(Value, CE->getType()));
return State;
}
class StreamChecker : public Checker<check::PreCall, eval::Call,
check::DeadSymbols, check::PointerEscape> {
- BugType BT_FileNull{this, "NULL stream pointer", "Stream handling error"};
BugType BT_UseAfterClose{this, "Closed stream", "Stream handling error"};
BugType BT_UseAfterOpenFailed{this, "Invalid stream",
"Stream handling error"};
@@ -236,48 +237,55 @@ public:
private:
CallDescriptionMap<FnDescription> FnDescriptions = {
- {{"fopen"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
- {{"freopen", 3},
+ {{{"fopen"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"freopen"}, 3},
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
- {{"tmpfile"}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
- {{"fclose", 1},
+ {{{"tmpfile"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"fclose"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
- {{"fread", 4},
+ {{{"fread"}, 4},
{&StreamChecker::preFread,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true), 3}},
- {{"fwrite", 4},
+ {{{"fwrite"}, 4},
{&StreamChecker::preFwrite,
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false), 3}},
- {{"fseek", 3}, {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
- {{"ftell", 1}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"rewind", 1}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"fgetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"fsetpos", 2}, {&StreamChecker::preDefault, nullptr, 0}},
- {{"clearerr", 1},
+ {{{"fseek"}, 3},
+ {&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
+ {{{"ftell"}, 1},
+ {&StreamChecker::preDefault, &StreamChecker::evalFtell, 0}},
+ {{{"rewind"}, 1},
+ {&StreamChecker::preDefault, &StreamChecker::evalRewind, 0}},
+ {{{"fgetpos"}, 2},
+ {&StreamChecker::preDefault, &StreamChecker::evalFgetpos, 0}},
+ {{{"fsetpos"}, 2},
+ {&StreamChecker::preDefault, &StreamChecker::evalFsetpos, 0}},
+ {{{"clearerr"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalClearerr, 0}},
- {{"feof", 1},
+ {{{"feof"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFEof),
0}},
- {{"ferror", 1},
+ {{{"ferror"}, 1},
{&StreamChecker::preDefault,
std::bind(&StreamChecker::evalFeofFerror, _1, _2, _3, _4, ErrorFError),
0}},
- {{"fileno", 1}, {&StreamChecker::preDefault, nullptr, 0}},
+ {{{"fileno"}, 1}, {&StreamChecker::preDefault, nullptr, 0}},
};
CallDescriptionMap<FnDescription> FnTestDescriptions = {
- {{"StreamTesterChecker_make_feof_stream", 1},
+ {{{"StreamTesterChecker_make_feof_stream"}, 1},
{nullptr,
std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4, ErrorFEof),
0}},
- {{"StreamTesterChecker_make_ferror_stream", 1},
+ {{{"StreamTesterChecker_make_ferror_stream"}, 1},
{nullptr,
std::bind(&StreamChecker::evalSetFeofFerror, _1, _2, _3, _4,
ErrorFError),
0}},
};
+ mutable std::optional<int> EofVal;
+
void evalFopen(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
@@ -303,6 +311,18 @@ private:
void evalFseek(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
+ void evalFgetpos(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalFsetpos(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalFtell(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
+ void evalRewind(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const;
+
void preDefault(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
@@ -318,7 +338,7 @@ private:
const StreamErrorState &ErrorKind) const;
/// Check that the stream (in StreamVal) is not NULL.
- /// If it can only be NULL a fatal error is emitted and nullptr returned.
+ /// If it can only be NULL a sink node is generated and nullptr returned.
/// Otherwise the return value is a new state where the stream is constrained
/// to be non-null.
ProgramStateRef ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
@@ -368,7 +388,7 @@ private:
// (and matching name) as stream functions.
if (!Call.isGlobalCFunction())
return nullptr;
- for (auto P : Call.parameters()) {
+ for (auto *P : Call.parameters()) {
QualType T = P->getType();
if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
return nullptr;
@@ -411,6 +431,17 @@ private:
});
}
+ void initEof(CheckerContext &C) const {
+ if (EofVal)
+ return;
+
+ if (const std::optional<int> OptInt =
+ tryExpandAsInteger("EOF", C.getPreprocessor()))
+ EofVal = *OptInt;
+ else
+ EofVal = -1;
+ }
+
/// Searches for the ExplodedNode where the file descriptor was acquired for
/// StreamSym.
static const ExplodedNode *getAcquisitionSite(const ExplodedNode *N,
@@ -426,8 +457,7 @@ private:
REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
inline void assertStreamStateOpened(const StreamState *SS) {
- assert(SS->isOpened() &&
- "Previous create of error node for non-opened stream failed?");
+ assert(SS->isOpened() && "Stream is expected to be opened");
}
const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N,
@@ -457,6 +487,8 @@ const ExplodedNode *StreamChecker::getAcquisitionSite(const ExplodedNode *N,
void StreamChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
+ initEof(C);
+
const FnDescription *Desc = lookupFn(Call);
if (!Desc || !Desc->PreFn)
return;
@@ -526,7 +558,7 @@ void StreamChecker::evalFreopen(const FnDescription *Desc,
if (!CE)
return;
- Optional<DefinedSVal> StreamVal =
+ std::optional<DefinedSVal> StreamVal =
getStreamArg(Desc, Call).getAs<DefinedSVal>();
if (!StreamVal)
return;
@@ -574,6 +606,10 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
if (!SS)
return;
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
assertStreamStateOpened(SS);
// Close the File Descriptor.
@@ -581,7 +617,16 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
// and can not be used any more.
State = State->set<StreamMap>(Sym, StreamState::getClosed(Desc));
- C.addTransition(State);
+ // Return 0 on success, EOF on failure.
+ SValBuilder &SVB = C.getSValBuilder();
+ ProgramStateRef StateSuccess = State->BindExpr(
+ CE, C.getLocationContext(), SVB.makeIntVal(0, C.getASTContext().IntTy));
+ ProgramStateRef StateFailure =
+ State->BindExpr(CE, C.getLocationContext(),
+ SVB.makeIntVal(*EofVal, C.getASTContext().IntTy));
+
+ C.addTransition(StateSuccess);
+ C.addTransition(StateFailure);
}
void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call,
@@ -639,10 +684,10 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
if (!CE)
return;
- Optional<NonLoc> SizeVal = Call.getArgSVal(1).getAs<NonLoc>();
+ std::optional<NonLoc> SizeVal = Call.getArgSVal(1).getAs<NonLoc>();
if (!SizeVal)
return;
- Optional<NonLoc> NMembVal = Call.getArgSVal(2).getAs<NonLoc>();
+ std::optional<NonLoc> NMembVal = Call.getArgSVal(2).getAs<NonLoc>();
if (!NMembVal)
return;
@@ -766,6 +811,131 @@ void StreamChecker::evalFseek(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateFailed, constructSetEofNoteTag(C, StreamSym));
}
+void StreamChecker::evalFgetpos(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef Sym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!Sym)
+ return;
+
+ // Do not evaluate if stream is not found.
+ if (!State->get<StreamMap>(Sym))
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ DefinedSVal RetVal = makeRetVal(C, CE);
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
+ ProgramStateRef StateNotFailed, StateFailed;
+ std::tie(StateFailed, StateNotFailed) =
+ C.getConstraintManager().assumeDual(State, RetVal);
+
+ // This function does not affect the stream state.
+ // Still we add success and failure state with the appropriate return value.
+ // StdLibraryFunctionsChecker can change these states (set the 'errno' state).
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalFsetpos(const FnDescription *Desc,
+ const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const StreamState *SS = State->get<StreamMap>(StreamSym);
+ if (!SS)
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ assertStreamStateOpened(SS);
+
+ DefinedSVal RetVal = makeRetVal(C, CE);
+ State = State->BindExpr(CE, C.getLocationContext(), RetVal);
+ ProgramStateRef StateNotFailed, StateFailed;
+ std::tie(StateFailed, StateNotFailed) =
+ C.getConstraintManager().assumeDual(State, RetVal);
+
+ StateNotFailed = StateNotFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpened(Desc, ErrorNone, false));
+
+ // At failure ferror could be set.
+ // The standards do not tell what happens with the file position at failure.
+ // But we can assume that it is dangerous to make a next I/O operation after
+ // the position was not set correctly (similar to 'fseek').
+ StateFailed = StateFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpened(Desc, ErrorNone | ErrorFError, true));
+
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef Sym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!Sym)
+ return;
+
+ if (!State->get<StreamMap>(Sym))
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ SValBuilder &SVB = C.getSValBuilder();
+ NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), RetVal);
+ auto Cond = SVB.evalBinOp(State, BO_GE, RetVal,
+ SVB.makeZeroVal(C.getASTContext().LongTy),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+ if (!Cond)
+ return;
+ StateNotFailed = StateNotFailed->assume(*Cond, true);
+ if (!StateNotFailed)
+ return;
+
+ ProgramStateRef StateFailed = State->BindExpr(
+ CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy));
+
+ C.addTransition(StateNotFailed);
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalRewind(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const StreamState *SS = State->get<StreamMap>(StreamSym);
+ if (!SS)
+ return;
+
+ auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ assertStreamStateOpened(SS);
+
+ State = State->set<StreamMap>(StreamSym,
+ StreamState::getOpened(Desc, ErrorNone, false));
+
+ C.addTransition(State);
+}
+
void StreamChecker::evalClearerr(const FnDescription *Desc,
const CallEvent &Call,
CheckerContext &C) const {
@@ -869,13 +1039,11 @@ StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
std::tie(StateNotNull, StateNull) = CM.assumeDual(C.getState(), *Stream);
if (!StateNotNull && StateNull) {
- if (ExplodedNode *N = C.generateErrorNode(StateNull)) {
- auto R = std::make_unique<PathSensitiveBugReport>(
- BT_FileNull, "Stream pointer might be NULL.", N);
- if (StreamE)
- bugreporter::trackExpressionValue(N, StreamE, *R);
- C.emitReport(std::move(R));
- }
+ // Stream argument is NULL, stop analysis on this path.
+ // This case should occur only if StdLibraryFunctionsChecker (or ModelPOSIX
+ // option of it) is not turned on, otherwise that checker ensures non-null
+ // argument.
+ C.generateSink(StateNull, C.getPredecessor());
return nullptr;
}
@@ -976,7 +1144,8 @@ ProgramStateRef StreamChecker::ensureNoFilePositionIndeterminate(
ProgramStateRef
StreamChecker::ensureFseekWhenceCorrect(SVal WhenceVal, CheckerContext &C,
ProgramStateRef State) const {
- Optional<nonloc::ConcreteInt> CI = WhenceVal.getAs<nonloc::ConcreteInt>();
+ std::optional<nonloc::ConcreteInt> CI =
+ WhenceVal.getAs<nonloc::ConcreteInt>();
if (!CI)
return State;
diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
index 44162094e49a..a95c0e183284 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -13,6 +13,7 @@
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -63,7 +64,7 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
// their parent region, which is a conjured symbol default-bound to the base
// region of the parent region.
if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
- if (Optional<SVal> binding =
+ if (std::optional<SVal> binding =
State->getStateManager().getStoreManager().getDefaultBinding(
*LCV)) {
if (SymbolRef Sym = binding->getAsSymbol())
diff --git a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index eeec807ccee4..28fe11d5ed06 100644
--- a/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "llvm/ADT/FoldingSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -100,7 +101,7 @@ DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC,
const Expr *E = nullptr;
- if (Optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
+ if (std::optional<PostStmt> P = Succ->getLocationAs<PostStmt>())
if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) {
BinaryOperator::Opcode Op = BO->getOpcode();
if (Op == BO_Div || Op == BO_Rem || Op == BO_DivAssign ||
@@ -132,7 +133,7 @@ DivisionBRVisitor::VisitNode(const ExplodedNode *Succ, BugReporterContext &BRC,
}
bool TestAfterDivZeroChecker::isZero(SVal S, CheckerContext &C) const {
- Optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
+ std::optional<DefinedSVal> DSV = S.getAs<DefinedSVal>();
if (!DSV)
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index ebe5ad53cc30..b17b983f0345 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -18,6 +18,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include <optional>
#include <utility>
using namespace clang;
@@ -93,7 +94,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
- if (Optional<PostStmt> PS = P.getAs<PostStmt>())
+ if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 816a547cadc3..27f3345e67ac 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,8 +70,8 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
continue;
// Get the VarRegion associated with VD in the local stack frame.
- if (Optional<UndefinedVal> V =
- state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
+ if (std::optional<UndefinedVal> V =
+ state->getSVal(I.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT)
BT.reset(
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 05f8f6084c0b..0fa3d6043971 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -92,7 +92,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (const auto *CD =
dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
if (CD->isImplicit()) {
- for (auto I : CD->inits()) {
+ for (auto *I : CD->inits()) {
if (I->getInit()->IgnoreImpCasts() == StoreE) {
OS << "Value assigned to field '" << I->getMember()->getName()
<< "' in implicit constructor is garbage or undefined";
diff --git a/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
new file mode 100644
index 000000000000..f053ee887a1a
--- /dev/null
+++ b/clang/lib/StaticAnalyzer/Checkers/UndefinedNewArraySizeChecker.cpp
@@ -0,0 +1,80 @@
+//===--- UndefinedNewArraySizeChecker.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 defines UndefinedNewArraySizeChecker, a builtin check in ExprEngine
+// that checks if the size of the array in a new[] expression is undefined.
+//
+//===----------------------------------------------------------------------===//
+
+#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/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class UndefinedNewArraySizeChecker : public Checker<check::PreCall> {
+
+private:
+ BugType BT{this, "Undefined array element count in new[]",
+ categories::LogicError};
+
+public:
+ void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
+ void HandleUndefinedArrayElementCount(CheckerContext &C, SVal ArgVal,
+ const Expr *Init,
+ SourceRange Range) const;
+};
+} // namespace
+
+void UndefinedNewArraySizeChecker::checkPreCall(const CallEvent &Call,
+ CheckerContext &C) const {
+ if (const auto *AC = dyn_cast<CXXAllocatorCall>(&Call)) {
+ if (!AC->isArray())
+ return;
+
+ auto *SizeEx = *AC->getArraySizeExpr();
+ auto SizeVal = AC->getArraySizeVal();
+
+ if (SizeVal.isUndef())
+ HandleUndefinedArrayElementCount(C, SizeVal, SizeEx,
+ SizeEx->getSourceRange());
+ }
+}
+
+void UndefinedNewArraySizeChecker::HandleUndefinedArrayElementCount(
+ CheckerContext &C, SVal ArgVal, const Expr *Init, SourceRange Range) const {
+
+ if (ExplodedNode *N = C.generateErrorNode()) {
+
+ SmallString<100> buf;
+ llvm::raw_svector_ostream os(buf);
+
+ os << "Element count in new[] is a garbage value";
+
+ auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
+ R->markInteresting(ArgVal);
+ R->addRange(Range);
+ bugreporter::trackExpressionValue(N, Init, *R);
+
+ C.emitReport(std::move(R));
+ }
+}
+
+void ento::registerUndefinedNewArraySizeChecker(CheckerManager &mgr) {
+ mgr.registerChecker<UndefinedNewArraySizeChecker>();
+}
+
+bool ento::shouldRegisterUndefinedNewArraySizeChecker(
+ const CheckerManager &mgr) {
+ return mgr.getLangOpts().CPlusPlus;
+}
diff --git a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
index f5bd765ff679..54e1e0e11909 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedPointee.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include <optional>
using namespace clang;
using namespace clang::ento;
@@ -121,9 +122,9 @@ struct DereferenceInfo {
/// Dereferences \p FR and returns with the pointee's region, and whether it
/// needs to be casted back to it's location type. If for whatever reason
-/// dereferencing fails, returns with None.
-static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR);
+/// dereferencing fails, returns std::nullopt.
+static std::optional<DereferenceInfo> dereference(ProgramStateRef State,
+ const FieldRegion *FR);
/// Returns whether \p T can be (transitively) dereferenced to a void pointer
/// type (void*, void**, ...).
@@ -159,7 +160,7 @@ bool FindUninitializedFields::isDereferencableUninit(
// At this point the pointer itself is initialized and points to a valid
// location, we'll now check the pointee.
- llvm::Optional<DereferenceInfo> DerefInfo = dereference(State, FR);
+ std::optional<DereferenceInfo> DerefInfo = dereference(State, FR);
if (!DerefInfo) {
IsAnyFieldInitialized = true;
return false;
@@ -217,8 +218,8 @@ bool FindUninitializedFields::isDereferencableUninit(
// Utility functions.
//===----------------------------------------------------------------------===//
-static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
- const FieldRegion *FR) {
+static std::optional<DereferenceInfo> dereference(ProgramStateRef State,
+ const FieldRegion *FR) {
llvm::SmallSet<const TypedValueRegion *, 5> VisitedRegions;
@@ -234,7 +235,7 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
// The region we'd like to acquire.
const auto *R = V.getAsRegion()->getAs<TypedValueRegion>();
if (!R)
- return None;
+ return std::nullopt;
VisitedRegions.insert(R);
@@ -245,7 +246,7 @@ static llvm::Optional<DereferenceInfo> dereference(ProgramStateRef State,
R = Tmp->getAs<TypedValueRegion>();
if (!R)
- return None;
+ return std::nullopt;
// We found a cyclic pointer, like int *ptr = (int *)&ptr.
if (!VisitedRegions.insert(R).second)
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
index aa3f4524798a..f503b3e88bb3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
@@ -17,11 +17,11 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -40,7 +40,7 @@ namespace {
class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
- mutable Optional<uint64_t> Val_O_CREAT;
+ mutable std::optional<uint64_t> Val_O_CREAT;
public:
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
@@ -234,7 +234,7 @@ void UnixAPIMisuseChecker::CheckOpenVariant(CheckerContext &C,
}
NonLoc oflags = V.castAs<NonLoc>();
NonLoc ocreateFlag = C.getSValBuilder()
- .makeIntVal(Val_O_CREAT.value(), oflagsEx->getType())
+ .makeIntVal(*Val_O_CREAT, oflagsEx->getType())
.castAs<NonLoc>();
SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
oflags, ocreateFlag,
diff --git a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
index d231be64c2e1..3ad6858ead46 100644
--- a/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -24,6 +24,7 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
#include "llvm/ADT/SmallSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -74,7 +75,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
if (!PM)
PM = &LC->getParentMap();
- if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
+ if (std::optional<BlockEntrance> BE = P.getAs<BlockEntrance>()) {
const CFGBlock *CB = BE->getBlock();
reachable.insert(CB->getBlockID());
}
@@ -129,7 +130,7 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
bool foundUnreachable = false;
for (CFGBlock::const_iterator ci = CB->begin(), ce = CB->end();
ci != ce; ++ci) {
- if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
+ if (std::optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
CE->isBuiltinAssumeFalse(Eng.getContext())) {
@@ -199,7 +200,7 @@ void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB,
// Find the Stmt* in a CFGBlock for reporting a warning
const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (Optional<CFGStmt> S = I->getAs<CFGStmt>()) {
+ if (std::optional<CFGStmt> S = I->getAs<CFGStmt>()) {
if (!isa<DeclStmt>(S->getStmt()))
return S->getStmt();
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index cf519b085892..fe910ce35302 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -24,6 +24,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/raw_ostream.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -192,7 +193,7 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
DefinedOrUnknownSVal Zero = SVB.makeZeroVal(SizeTy);
SVal LessThanZeroVal = SVB.evalBinOp(State, BO_LT, SizeD, Zero, SizeTy);
- if (Optional<DefinedSVal> LessThanZeroDVal =
+ if (std::optional<DefinedSVal> LessThanZeroDVal =
LessThanZeroVal.getAs<DefinedSVal>()) {
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef StatePos, StateNeg;
diff --git a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
index fbefd5f9ffdc..2d1b873abf73 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ValistChecker.cpp
@@ -100,27 +100,26 @@ private:
};
const SmallVector<ValistChecker::VAListAccepter, 15>
- ValistChecker::VAListAccepters = {
- {{"vfprintf", 3}, 2},
- {{"vfscanf", 3}, 2},
- {{"vprintf", 2}, 1},
- {{"vscanf", 2}, 1},
- {{"vsnprintf", 4}, 3},
- {{"vsprintf", 3}, 2},
- {{"vsscanf", 3}, 2},
- {{"vfwprintf", 3}, 2},
- {{"vfwscanf", 3}, 2},
- {{"vwprintf", 2}, 1},
- {{"vwscanf", 2}, 1},
- {{"vswprintf", 4}, 3},
- // vswprintf is the wide version of vsnprintf,
- // vsprintf has no wide version
- {{"vswscanf", 3}, 2}};
-
-const CallDescription
- ValistChecker::VaStart("__builtin_va_start", /*Args=*/2, /*Params=*/1),
- ValistChecker::VaCopy("__builtin_va_copy", 2),
- ValistChecker::VaEnd("__builtin_va_end", 1);
+ ValistChecker::VAListAccepters = {{{{"vfprintf"}, 3}, 2},
+ {{{"vfscanf"}, 3}, 2},
+ {{{"vprintf"}, 2}, 1},
+ {{{"vscanf"}, 2}, 1},
+ {{{"vsnprintf"}, 4}, 3},
+ {{{"vsprintf"}, 3}, 2},
+ {{{"vsscanf"}, 3}, 2},
+ {{{"vfwprintf"}, 3}, 2},
+ {{{"vfwscanf"}, 3}, 2},
+ {{{"vwprintf"}, 2}, 1},
+ {{{"vwscanf"}, 2}, 1},
+ {{{"vswprintf"}, 4}, 3},
+ // vswprintf is the wide version of
+ // vsnprintf, vsprintf has no wide version
+ {{{"vswscanf"}, 3}, 2}};
+
+const CallDescription ValistChecker::VaStart({"__builtin_va_start"}, /*Args=*/2,
+ /*Params=*/1),
+ ValistChecker::VaCopy({"__builtin_va_copy"}, 2),
+ ValistChecker::VaEnd({"__builtin_va_end"}, 1);
} // end anonymous namespace
void ValistChecker::checkPreCall(const CallEvent &Call,
diff --git a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
index 04e6603b4cbe..86a4e6fbcd6a 100644
--- a/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
@@ -35,6 +35,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/AST/ParentMap.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -154,8 +155,8 @@ void VforkChecker::checkPostCall(const CallEvent &Call,
// Get return value of vfork.
SVal VforkRetVal = Call.getReturnValue();
- Optional<DefinedOrUnknownSVal> DVal =
- VforkRetVal.getAs<DefinedOrUnknownSVal>();
+ std::optional<DefinedOrUnknownSVal> DVal =
+ VforkRetVal.getAs<DefinedOrUnknownSVal>();
if (!DVal)
return;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
index 9c7a59971763..64028b277021 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/ASTUtils.cpp
@@ -12,8 +12,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
+#include <optional>
-using llvm::Optional;
namespace clang {
std::pair<const Expr *, bool>
@@ -34,8 +34,7 @@ tryToFindPtrOrigin(const Expr *E, bool StopAtFirstRefCountedObj) {
}
if (auto *call = dyn_cast<CallExpr>(E)) {
if (auto *memberCall = dyn_cast<CXXMemberCallExpr>(call)) {
- Optional<bool> IsGetterOfRefCt =
- isGetterOfRefCounted(memberCall->getMethodDecl());
+ std::optional<bool> IsGetterOfRefCt = isGetterOfRefCounted(memberCall->getMethodDecl());
if (IsGetterOfRefCt && *IsGetterOfRefCt) {
E = memberCall->getImplicitObjectArgument();
if (StopAtFirstRefCountedObj) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
index 97f75135bf92..66d8588e2531 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Casting.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -69,7 +70,7 @@ public:
if (shouldSkipDecl(RD))
return;
- for (auto Member : RD->fields()) {
+ for (auto *Member : RD->fields()) {
const Type *MemberType = Member->getType().getTypePtrOrNull();
if (!MemberType)
continue;
@@ -77,9 +78,9 @@ public:
if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl()) {
// If we don't see the definition we just don't know.
if (MemberCXXRD->hasDefinition()) {
- llvm::Optional<bool> isRCAble = isRefCountable(MemberCXXRD);
- if (isRCAble && *isRCAble)
- reportBug(Member, MemberType, MemberCXXRD, RD);
+ std::optional<bool> isRCAble = isRefCountable(MemberCXXRD);
+ if (isRCAble && *isRCAble)
+ reportBug(Member, MemberType, MemberCXXRD, RD);
}
}
}
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index a198943c9433..9b1d7ae3e6a3 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -12,9 +12,8 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
-#include "llvm/ADT/Optional.h"
+#include <optional>
-using llvm::Optional;
using namespace clang;
namespace {
@@ -45,29 +44,31 @@ bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
namespace clang {
-llvm::Optional<const clang::CXXRecordDecl *>
-isRefCountable(const CXXBaseSpecifier *Base) {
+std::optional<const clang::CXXRecordDecl*>
+isRefCountable(const CXXBaseSpecifier* Base)
+{
assert(Base);
const Type *T = Base->getType().getTypePtrOrNull();
if (!T)
- return llvm::None;
+ return std::nullopt;
const CXXRecordDecl *R = T->getAsCXXRecordDecl();
if (!R)
- return llvm::None;
+ return std::nullopt;
if (!R->hasDefinition())
- return llvm::None;
+ return std::nullopt;
return hasPublicRefAndDeref(R) ? R : nullptr;
}
-llvm::Optional<bool> isRefCountable(const CXXRecordDecl *R) {
+std::optional<bool> isRefCountable(const CXXRecordDecl* R)
+{
assert(R);
R = R->getDefinition();
if (!R)
- return llvm::None;
+ return std::nullopt;
if (hasPublicRefAndDeref(R))
return true;
@@ -77,20 +78,19 @@ llvm::Optional<bool> isRefCountable(const CXXRecordDecl *R) {
bool AnyInconclusiveBase = false;
const auto isRefCountableBase =
- [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
- Optional<const clang::CXXRecordDecl *> IsRefCountable =
- clang::isRefCountable(Base);
- if (!IsRefCountable) {
- AnyInconclusiveBase = true;
- return false;
- }
- return (*IsRefCountable) != nullptr;
+ [&AnyInconclusiveBase](const CXXBaseSpecifier* Base, CXXBasePath&) {
+ std::optional<const clang::CXXRecordDecl*> IsRefCountable = clang::isRefCountable(Base);
+ if (!IsRefCountable) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*IsRefCountable) != nullptr;
};
bool BasesResult = R->lookupInBases(isRefCountableBase, Paths,
/*LookupInDependent =*/true);
if (AnyInconclusiveBase)
- return llvm::None;
+ return std::nullopt;
return BasesResult;
}
@@ -112,19 +112,21 @@ bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
|| FunctionName == "Identifier";
}
-llvm::Optional<bool> isUncounted(const CXXRecordDecl *Class) {
+std::optional<bool> isUncounted(const CXXRecordDecl* Class)
+{
// Keep isRefCounted first as it's cheaper.
if (isRefCounted(Class))
return false;
- llvm::Optional<bool> IsRefCountable = isRefCountable(Class);
+ std::optional<bool> IsRefCountable = isRefCountable(Class);
if (!IsRefCountable)
- return llvm::None;
+ return std::nullopt;
return (*IsRefCountable);
}
-llvm::Optional<bool> isUncountedPtr(const Type *T) {
+std::optional<bool> isUncountedPtr(const Type* T)
+{
assert(T);
if (T->isPointerType() || T->isReferenceType()) {
@@ -135,7 +137,8 @@ llvm::Optional<bool> isUncountedPtr(const Type *T) {
return false;
}
-Optional<bool> isGetterOfRefCounted(const CXXMethodDecl *M) {
+std::optional<bool> isGetterOfRefCounted(const CXXMethodDecl* M)
+{
assert(M);
if (isa<CXXMethodDecl>(M)) {
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 753adea0d14d..91e3ccf2ec30 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -10,6 +10,7 @@
#define LLVM_CLANG_ANALYZER_WEBKIT_PTRTYPESEMANTICS_H
#include "llvm/ADT/APInt.h"
+#include <optional>
namespace clang {
class CXXBaseSpecifier;
@@ -26,31 +27,31 @@ class Type;
// Ref<T>.
/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if
-/// not, None if inconclusive.
-llvm::Optional<const clang::CXXRecordDecl *>
-isRefCountable(const clang::CXXBaseSpecifier *Base);
+/// not, std::nullopt if inconclusive.
+std::optional<const clang::CXXRecordDecl*>
+isRefCountable(const clang::CXXBaseSpecifier* Base);
-/// \returns true if \p Class is ref-countable, false if not, None if
+/// \returns true if \p Class is ref-countable, false if not, std::nullopt if
/// inconclusive.
-llvm::Optional<bool> isRefCountable(const clang::CXXRecordDecl *Class);
+std::optional<bool> isRefCountable(const clang::CXXRecordDecl* Class);
/// \returns true if \p Class is ref-counted, false if not.
bool isRefCounted(const clang::CXXRecordDecl *Class);
/// \returns true if \p Class is ref-countable AND not ref-counted, false if
-/// not, None if inconclusive.
-llvm::Optional<bool> isUncounted(const clang::CXXRecordDecl *Class);
+/// not, std::nullopt if inconclusive.
+std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
/// \returns true if \p T is either a raw pointer or reference to an uncounted
-/// class, false if not, None if inconclusive.
-llvm::Optional<bool> isUncountedPtr(const clang::Type *T);
+/// class, false if not, std::nullopt if inconclusive.
+std::optional<bool> isUncountedPtr(const clang::Type* T);
/// \returns true if \p F creates ref-countable object from uncounted parameter,
/// false if not.
bool isCtorOfRefCounted(const clang::FunctionDecl *F);
/// \returns true if \p M is getter of a ref-counted class, false if not.
-llvm::Optional<bool> isGetterOfRefCounted(const clang::CXXMethodDecl *Method);
+std::optional<bool> isGetterOfRefCounted(const clang::CXXMethodDecl* Method);
/// \returns true if \p F is a conversion between ref-countable or ref-counted
/// pointer types.
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
index fa9ece217cc0..48dcfc4a3c46 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -76,8 +77,7 @@ public:
(AccSpec == AS_none && RD->isClass()))
return false;
- llvm::Optional<const CXXRecordDecl *> RefCntblBaseRD =
- isRefCountable(Base);
+ std::optional<const CXXRecordDecl*> RefCntblBaseRD = isRefCountable(Base);
if (!RefCntblBaseRD || !(*RefCntblBaseRD))
return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index e6d0948f71bb..4ae8c442fa70 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -19,6 +19,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -85,7 +86,7 @@ public:
continue; // FIXME? Should we bail?
// FIXME: more complex types (arrays, references to raw pointers, etc)
- Optional<bool> IsUncounted = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncounted = isUncountedPtr(ArgType);
if (!IsUncounted || !(*IsUncounted))
continue;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
index deebbd603b2c..004b0b9d398b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLambdaCapturesChecker.cpp
@@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -57,18 +58,18 @@ public:
void visitLambdaExpr(LambdaExpr *L) const {
for (const LambdaCapture &C : L->captures()) {
if (C.capturesVariable()) {
- VarDecl *CapturedVar = C.getCapturedVar();
+ ValueDecl *CapturedVar = C.getCapturedVar();
if (auto *CapturedVarType = CapturedVar->getType().getTypePtrOrNull()) {
- Optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
- if (IsUncountedPtr && *IsUncountedPtr) {
- reportBug(C, CapturedVar, CapturedVarType);
- }
+ std::optional<bool> IsUncountedPtr = isUncountedPtr(CapturedVarType);
+ if (IsUncountedPtr && *IsUncountedPtr) {
+ reportBug(C, CapturedVar, CapturedVarType);
+ }
}
}
}
}
- void reportBug(const LambdaCapture &Capture, VarDecl *CapturedVar,
+ void reportBug(const LambdaCapture &Capture, ValueDecl *CapturedVar,
const Type *T) const {
assert(CapturedVar);
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
index 7e86f28cb70f..fa7475934981 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
@@ -20,6 +20,7 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "llvm/ADT/DenseSet.h"
+#include <optional>
using namespace clang;
using namespace ento;
@@ -169,7 +170,7 @@ public:
if (!ArgType)
return;
- Optional<bool> IsUncountedPtr = isUncountedPtr(ArgType);
+ std::optional<bool> IsUncountedPtr = isUncountedPtr(ArgType);
if (IsUncountedPtr && *IsUncountedPtr) {
const Expr *const InitExpr = V->getInit();
if (!InitExpr)
diff --git a/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
index 497189f4c160..4159e14105f8 100644
--- a/clang/lib/StaticAnalyzer/Checkers/Yaml.h
+++ b/clang/lib/StaticAnalyzer/Checkers/Yaml.h
@@ -17,6 +17,7 @@
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/YAMLTraits.h"
+#include <optional>
namespace clang {
namespace ento {
@@ -25,10 +26,10 @@ namespace ento {
/// template parameter must have a yaml MappingTraits.
/// Emit diagnostic error in case of any failure.
template <class T, class Checker>
-llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
- StringRef Option, StringRef ConfigFile) {
+std::optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
+ StringRef Option, StringRef ConfigFile) {
if (ConfigFile.trim().empty())
- return None;
+ return std::nullopt;
llvm::vfs::FileSystem *FS = llvm::vfs::getRealFileSystem().get();
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
@@ -38,7 +39,7 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
Mgr.reportInvalidCheckerOptionValue(Chk, Option,
"a valid filename instead of '" +
std::string(ConfigFile) + "'");
- return None;
+ return std::nullopt;
}
llvm::yaml::Input Input(Buffer.get()->getBuffer());
@@ -48,7 +49,7 @@ llvm::Optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
if (std::error_code ec = Input.error()) {
Mgr.reportInvalidCheckerOptionValue(Chk, Option,
"a valid yaml file: " + ec.message());
- return None;
+ return std::nullopt;
}
return Config;
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index 084789509533..aae1a17bc0ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -39,11 +39,11 @@ private:
// 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},
+ {{{"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,
@@ -51,13 +51,15 @@ private:
// SEI CERT ENV34-C
const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
- {{"getenv", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"setlocale", 2},
+ {{{"getenv"}, 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"setlocale"}, 2},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"strerror", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"localeconv", 0},
+ {{{"strerror"}, 1},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"localeconv"}, 0},
+ &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
+ {{{"asctime"}, 1},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
- {{"asctime", 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
};
public:
diff --git a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
index ed3bdafad084..eae162cda693 100644
--- a/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/cert/PutenvWithAutoChecker.cpp
@@ -30,7 +30,7 @@ class PutenvWithAutoChecker : public Checker<check::PostCall> {
private:
BugType BT{this, "'putenv' function should not be called with auto variables",
categories::SecurityError};
- const CallDescription Putenv{"putenv", 1};
+ const CallDescription Putenv{{"putenv"}, 1};
public:
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;