aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-12-18 20:30:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2024-04-06 20:11:55 +0000
commit5f757f3ff9144b609b3c433dfd370cc6bdc191ad (patch)
tree1b4e980b866cd26a00af34c0a653eb640bd09caf /contrib/llvm-project/clang/lib/StaticAnalyzer
parent3e1c8a35f741a5d114d0ba670b15191355711fe9 (diff)
parent312c0ed19cc5276a17bacf2120097bec4515b0f1 (diff)
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer')
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp10
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp464
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp370
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp28
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp97
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp248
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp30
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp115
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp5
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp155
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp20
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp62
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h16
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp18
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp15
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp15
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp8
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp27
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp51
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp29
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp14
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h1
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp13
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp22
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp37
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp149
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp298
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp238
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h99
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp74
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp9
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp65
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h8
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp49
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp1
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Yaml.h2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp145
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp12
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp35
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp61
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp169
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CallEvent.cpp41
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp5
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp72
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp18
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp3
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp18
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp35
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp29
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp6
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp22
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp51
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp87
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp144
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Core/Store.cpp2
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp62
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp10
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp4
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp3
96 files changed, 2865 insertions, 1209 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 03e85b9c4373..ce1265412655 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
public Checker<check::Location> {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkLocation(SVal l, bool isLoad, const Stmt* S,
@@ -66,17 +66,15 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
return;
if (!BT)
- BT.reset(new BuiltinBug(
- this, "Out-of-bound array access",
- "Access out-of-bound array element (buffer overflow)"));
+ BT.reset(new BugType(this, "Out-of-bound array access"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
// Generate a report for this bug.
- auto report =
- std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+ auto report = std::make_unique<PathSensitiveBugReport>(
+ *BT, "Access out-of-bound array element (buffer overflow)", N);
report->addRange(LoadS->getSourceRange());
C.emitReport(std::move(report));
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
index 269277aaf357..6c7a1601402e 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/AST/CharUnits.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
@@ -22,52 +23,114 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
using namespace clang;
using namespace ento;
using namespace taint;
+using llvm::formatv;
namespace {
-class ArrayBoundCheckerV2 :
- public Checker<check::Location> {
- mutable std::unique_ptr<BuiltinBug> BT;
- mutable std::unique_ptr<BugType> TaintBT;
+enum OOB_Kind { OOB_Precedes, OOB_Exceeds, OOB_Taint };
- enum OOB_Kind { OOB_Precedes, OOB_Excedes };
+struct Messages {
+ std::string Short, Full;
+};
+
+// NOTE: The `ArraySubscriptExpr` and `UnaryOperator` callbacks are `PostStmt`
+// instead of `PreStmt` because the current implementation passes the whole
+// expression to `CheckerContext::getSVal()` which only works after the
+// symbolic evaluation of the expression. (To turn them into `PreStmt`
+// callbacks, we'd need to duplicate the logic that evaluates these
+// expressions.) The `MemberExpr` callback would work as `PreStmt` but it's
+// defined as `PostStmt` for the sake of consistency with the other callbacks.
+class ArrayBoundCheckerV2 : public Checker<check::PostStmt<ArraySubscriptExpr>,
+ check::PostStmt<UnaryOperator>,
+ check::PostStmt<MemberExpr>> {
+ BugType BT{this, "Out-of-bound access"};
+ BugType TaintBT{this, "Out-of-bound access", categories::TaintedData};
+
+ void performCheck(const Expr *E, CheckerContext &C) const;
- void reportOOB(CheckerContext &C, ProgramStateRef errorState,
- OOB_Kind kind) const;
- void reportTaintOOB(CheckerContext &C, ProgramStateRef errorState,
- SVal TaintedSVal) const;
+ void reportOOB(CheckerContext &C, ProgramStateRef ErrorState, OOB_Kind Kind,
+ NonLoc Offset, Messages Msgs) const;
static bool isFromCtypeMacro(const Stmt *S, ASTContext &AC);
+ static bool isInAddressOf(const Stmt *S, ASTContext &AC);
+
public:
- void checkLocation(SVal l, bool isLoad, const Stmt *S,
- CheckerContext &C) const;
+ void checkPostStmt(const ArraySubscriptExpr *E, CheckerContext &C) const {
+ performCheck(E, C);
+ }
+ void checkPostStmt(const UnaryOperator *E, CheckerContext &C) const {
+ if (E->getOpcode() == UO_Deref)
+ performCheck(E, C);
+ }
+ void checkPostStmt(const MemberExpr *E, CheckerContext &C) const {
+ if (E->isArrow())
+ performCheck(E->getBase(), C);
+ }
};
-// FIXME: Eventually replace RegionRawOffset with this class.
-class RegionRawOffsetV2 {
-private:
- const SubRegion *baseRegion;
- NonLoc byteOffset;
+} // anonymous namespace
-public:
- RegionRawOffsetV2(const SubRegion *base, NonLoc offset)
- : baseRegion(base), byteOffset(offset) { assert(base); }
+/// For a given Location that can be represented as a symbolic expression
+/// Arr[Idx] (or perhaps Arr[Idx1][Idx2] etc.), return the parent memory block
+/// Arr and the distance of Location from the beginning of Arr (expressed in a
+/// NonLoc that specifies the number of CharUnits). Returns nullopt when these
+/// cannot be determined.
+static std::optional<std::pair<const SubRegion *, NonLoc>>
+computeOffset(ProgramStateRef State, SValBuilder &SVB, SVal Location) {
+ QualType T = SVB.getArrayIndexType();
+ auto EvalBinOp = [&SVB, State, T](BinaryOperatorKind Op, NonLoc L, NonLoc R) {
+ // We will use this utility to add and multiply values.
+ return SVB.evalBinOpNN(State, Op, L, R, T).getAs<NonLoc>();
+ };
- NonLoc getByteOffset() const { return byteOffset; }
- const SubRegion *getRegion() const { return baseRegion; }
+ const SubRegion *OwnerRegion = nullptr;
+ std::optional<NonLoc> Offset = SVB.makeZeroArrayIndex();
+
+ const ElementRegion *CurRegion =
+ dyn_cast_or_null<ElementRegion>(Location.getAsRegion());
+
+ while (CurRegion) {
+ const auto Index = CurRegion->getIndex().getAs<NonLoc>();
+ if (!Index)
+ return std::nullopt;
+
+ QualType ElemType = CurRegion->getElementType();
+
+ // FIXME: The following early return was presumably added to safeguard the
+ // getTypeSizeInChars() call (which doesn't accept an incomplete type), but
+ // it seems that `ElemType` cannot be incomplete at this point.
+ if (ElemType->isIncompleteType())
+ return std::nullopt;
+
+ // Calculate Delta = Index * sizeof(ElemType).
+ NonLoc Size = SVB.makeArrayIndex(
+ SVB.getContext().getTypeSizeInChars(ElemType).getQuantity());
+ auto Delta = EvalBinOp(BO_Mul, *Index, Size);
+ if (!Delta)
+ return std::nullopt;
+
+ // Perform Offset += Delta.
+ Offset = EvalBinOp(BO_Add, *Offset, *Delta);
+ if (!Offset)
+ return std::nullopt;
+
+ OwnerRegion = CurRegion->getSuperRegion()->getAs<SubRegion>();
+ // When this is just another ElementRegion layer, we need to continue the
+ // offset calculations:
+ CurRegion = dyn_cast_or_null<ElementRegion>(OwnerRegion);
+ }
- static std::optional<RegionRawOffsetV2>
- computeOffset(ProgramStateRef State, SValBuilder &SVB, SVal Location);
+ if (OwnerRegion)
+ return std::make_pair(OwnerRegion, *Offset);
- void dump() const;
- void dumpToStream(raw_ostream &os) const;
-};
+ return std::nullopt;
}
// TODO: once the constraint manager is smart enough to handle non simplified
@@ -86,8 +149,8 @@ getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent,
APSIntType(extent.getValue()).convert(SIE->getRHS());
switch (SIE->getOpcode()) {
case BO_Mul:
- // The constant should never be 0 here, since it the result of scaling
- // based on the size of a type which is never 0.
+ // The constant should never be 0 here, becasue multiplication by zero
+ // is simplified by the engine.
if ((extent.getValue() % constant) != 0)
return std::pair<NonLoc, nonloc::ConcreteInt>(offset, extent);
else
@@ -113,9 +176,11 @@ getSimplifiedOffsets(NonLoc offset, nonloc::ConcreteInt extent,
// where the first one corresponds to "value below threshold" and the second
// corresponds to "value at or above threshold". Returns {nullptr, nullptr} in
// the case when the evaluation fails.
+// If the optional argument CheckEquality is true, then use BO_EQ instead of
+// the default BO_LT after consistently applying the same simplification steps.
static std::pair<ProgramStateRef, ProgramStateRef>
compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
- SValBuilder &SVB) {
+ SValBuilder &SVB, bool CheckEquality = false) {
if (auto ConcreteThreshold = Threshold.getAs<nonloc::ConcreteInt>()) {
std::tie(Value, Threshold) = getSimplifiedOffsets(Value, *ConcreteThreshold, SVB);
}
@@ -131,8 +196,10 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
return {nullptr, State};
}
}
+ const BinaryOperatorKind OpKind = CheckEquality ? BO_EQ : BO_LT;
auto BelowThreshold =
- SVB.evalBinOpNN(State, BO_LT, Value, Threshold, SVB.getConditionType()).getAs<NonLoc>();
+ SVB.evalBinOpNN(State, OpKind, Value, Threshold, SVB.getConditionType())
+ .getAs<NonLoc>();
if (BelowThreshold)
return State->assume(*BelowThreshold);
@@ -140,10 +207,118 @@ compareValueToThreshold(ProgramStateRef State, NonLoc Value, NonLoc Threshold,
return {nullptr, nullptr};
}
-void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
- const Stmt* LoadS,
- CheckerContext &checkerContext) const {
+static std::string getRegionName(const SubRegion *Region) {
+ if (std::string RegName = Region->getDescriptiveName(); !RegName.empty())
+ return RegName;
+
+ // Field regions only have descriptive names when their parent has a
+ // descriptive name; so we provide a fallback representation for them:
+ if (const auto *FR = Region->getAs<FieldRegion>()) {
+ if (StringRef Name = FR->getDecl()->getName(); !Name.empty())
+ return formatv("the field '{0}'", Name);
+ return "the unnamed field";
+ }
+
+ if (isa<AllocaRegion>(Region))
+ return "the memory returned by 'alloca'";
+
+ if (isa<SymbolicRegion>(Region) &&
+ isa<HeapSpaceRegion>(Region->getMemorySpace()))
+ return "the heap area";
+
+ if (isa<StringRegion>(Region))
+ return "the string literal";
+
+ return "the region";
+}
+
+static std::optional<int64_t> getConcreteValue(NonLoc SV) {
+ if (auto ConcreteVal = SV.getAs<nonloc::ConcreteInt>()) {
+ return ConcreteVal->getValue().tryExtValue();
+ }
+ return std::nullopt;
+}
+
+static std::string getShortMsg(OOB_Kind Kind, std::string RegName) {
+ static const char *ShortMsgTemplates[] = {
+ "Out of bound access to memory preceding {0}",
+ "Out of bound access to memory after the end of {0}",
+ "Potential out of bound access to {0} with tainted offset"};
+
+ return formatv(ShortMsgTemplates[Kind], RegName);
+}
+
+static Messages getPrecedesMsgs(const SubRegion *Region, NonLoc Offset) {
+ std::string RegName = getRegionName(Region);
+ SmallString<128> Buf;
+ llvm::raw_svector_ostream Out(Buf);
+ Out << "Access of " << RegName << " at negative byte offset";
+ if (auto ConcreteIdx = Offset.getAs<nonloc::ConcreteInt>())
+ Out << ' ' << ConcreteIdx->getValue();
+ return {getShortMsg(OOB_Precedes, RegName), std::string(Buf)};
+}
+
+static Messages getExceedsMsgs(ASTContext &ACtx, const SubRegion *Region,
+ NonLoc Offset, NonLoc Extent, SVal Location) {
+ std::string RegName = getRegionName(Region);
+ const auto *EReg = Location.getAsRegion()->getAs<ElementRegion>();
+ assert(EReg && "this checker only handles element access");
+ QualType ElemType = EReg->getElementType();
+
+ std::optional<int64_t> OffsetN = getConcreteValue(Offset);
+ std::optional<int64_t> ExtentN = getConcreteValue(Extent);
+
+ bool UseByteOffsets = true;
+ if (int64_t ElemSize = ACtx.getTypeSizeInChars(ElemType).getQuantity()) {
+ const bool OffsetHasRemainder = OffsetN && *OffsetN % ElemSize;
+ const bool ExtentHasRemainder = ExtentN && *ExtentN % ElemSize;
+ if (!OffsetHasRemainder && !ExtentHasRemainder) {
+ UseByteOffsets = false;
+ if (OffsetN)
+ *OffsetN /= ElemSize;
+ if (ExtentN)
+ *ExtentN /= ElemSize;
+ }
+ }
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream Out(Buf);
+ Out << "Access of ";
+ if (!ExtentN && !UseByteOffsets)
+ Out << "'" << ElemType.getAsString() << "' element in ";
+ Out << RegName << " at ";
+ if (OffsetN) {
+ Out << (UseByteOffsets ? "byte offset " : "index ") << *OffsetN;
+ } else {
+ Out << "an overflowing " << (UseByteOffsets ? "byte offset" : "index");
+ }
+ if (ExtentN) {
+ Out << ", while it holds only ";
+ if (*ExtentN != 1)
+ Out << *ExtentN;
+ else
+ Out << "a single";
+ if (UseByteOffsets)
+ Out << " byte";
+ else
+ Out << " '" << ElemType.getAsString() << "' element";
+
+ if (*ExtentN > 1)
+ Out << "s";
+ }
+
+ return {getShortMsg(OOB_Exceeds, RegName), std::string(Buf)};
+}
+
+static Messages getTaintMsgs(const SubRegion *Region, const char *OffsetName) {
+ std::string RegName = getRegionName(Region);
+ return {formatv("Potential out of bound access to {0} with tainted {1}",
+ RegName, OffsetName),
+ formatv("Access of {0} with a tainted {1} that may be too large",
+ RegName, OffsetName)};
+}
+void ArrayBoundCheckerV2::performCheck(const Expr *E, CheckerContext &C) const {
// NOTE: Instead of using ProgramState::assumeInBound(), we are prototyping
// some new logic here that reasons directly about memory region extents.
// Once that logic is more mature, we can bring it back to assumeInBound()
@@ -154,124 +329,120 @@ void ArrayBoundCheckerV2::checkLocation(SVal location, bool isLoad,
// have some flexibility in defining the base region, we can achieve
// various levels of conservatism in our buffer overflow checking.
+ const SVal Location = C.getSVal(E);
+
// The header ctype.h (from e.g. glibc) implements the isXXXXX() macros as
// #define isXXXXX(arg) (LOOKUP_TABLE[arg] & BITMASK_FOR_XXXXX)
// and incomplete analysis of these leads to false positives. As even
// accurate reports would be confusing for the users, just disable reports
// from these macros:
- if (isFromCtypeMacro(LoadS, checkerContext.getASTContext()))
+ if (isFromCtypeMacro(E, C.getASTContext()))
return;
- ProgramStateRef state = checkerContext.getState();
+ ProgramStateRef State = C.getState();
+ SValBuilder &SVB = C.getSValBuilder();
- SValBuilder &svalBuilder = checkerContext.getSValBuilder();
- const std::optional<RegionRawOffsetV2> &RawOffset =
- RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
+ const std::optional<std::pair<const SubRegion *, NonLoc>> &RawOffset =
+ computeOffset(State, SVB, Location);
if (!RawOffset)
return;
- NonLoc ByteOffset = RawOffset->getByteOffset();
+ auto [Reg, ByteOffset] = *RawOffset;
// CHECK LOWER BOUND
- const MemSpaceRegion *SR = RawOffset->getRegion()->getMemorySpace();
- if (!llvm::isa<UnknownSpaceRegion>(SR)) {
- // A pointer to UnknownSpaceRegion may point to the middle of
- // an allocated region.
-
- auto [state_precedesLowerBound, state_withinLowerBound] =
- compareValueToThreshold(state, ByteOffset,
- svalBuilder.makeZeroArrayIndex(), svalBuilder);
-
- if (state_precedesLowerBound && !state_withinLowerBound) {
+ const MemSpaceRegion *Space = Reg->getMemorySpace();
+ if (!(isa<SymbolicRegion>(Reg) && isa<UnknownSpaceRegion>(Space))) {
+ // A symbolic region in unknown space represents an unknown pointer that
+ // may point into the middle of an array, so we don't look for underflows.
+ // Both conditions are significant because we want to check underflows in
+ // symbolic regions on the heap (which may be introduced by checkers like
+ // MallocChecker that call SValBuilder::getConjuredHeapSymbolVal()) and
+ // non-symbolic regions (e.g. a field subregion of a symbolic region) in
+ // unknown space.
+ auto [PrecedesLowerBound, WithinLowerBound] = compareValueToThreshold(
+ State, ByteOffset, SVB.makeZeroArrayIndex(), SVB);
+
+ if (PrecedesLowerBound && !WithinLowerBound) {
// We know that the index definitely precedes the lower bound.
- reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
+ Messages Msgs = getPrecedesMsgs(Reg, ByteOffset);
+ reportOOB(C, PrecedesLowerBound, OOB_Precedes, ByteOffset, Msgs);
return;
}
- if (state_withinLowerBound)
- state = state_withinLowerBound;
+ if (WithinLowerBound)
+ State = WithinLowerBound;
}
// CHECK UPPER BOUND
- DefinedOrUnknownSVal Size =
- getDynamicExtent(state, RawOffset->getRegion(), svalBuilder);
+ DefinedOrUnknownSVal Size = getDynamicExtent(State, Reg, SVB);
if (auto KnownSize = Size.getAs<NonLoc>()) {
- auto [state_withinUpperBound, state_exceedsUpperBound] =
- compareValueToThreshold(state, ByteOffset, *KnownSize, svalBuilder);
+ auto [WithinUpperBound, ExceedsUpperBound] =
+ compareValueToThreshold(State, ByteOffset, *KnownSize, SVB);
- if (state_exceedsUpperBound) {
- if (!state_withinUpperBound) {
+ if (ExceedsUpperBound) {
+ if (!WithinUpperBound) {
// We know that the index definitely exceeds the upper bound.
- reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
+ if (isa<ArraySubscriptExpr>(E) && isInAddressOf(E, C.getASTContext())) {
+ // ...but this is within an addressof expression, so we need to check
+ // for the exceptional case that `&array[size]` is valid.
+ auto [EqualsToThreshold, NotEqualToThreshold] =
+ compareValueToThreshold(ExceedsUpperBound, ByteOffset, *KnownSize,
+ SVB, /*CheckEquality=*/true);
+ if (EqualsToThreshold && !NotEqualToThreshold) {
+ // We are definitely in the exceptional case, so return early
+ // instead of reporting a bug.
+ C.addTransition(EqualsToThreshold);
+ return;
+ }
+ }
+ Messages Msgs = getExceedsMsgs(C.getASTContext(), Reg, ByteOffset,
+ *KnownSize, Location);
+ reportOOB(C, ExceedsUpperBound, OOB_Exceeds, ByteOffset, Msgs);
return;
}
- if (isTainted(state, ByteOffset)) {
- // Both cases are possible, but the index is tainted, so report.
- reportTaintOOB(checkerContext, state_exceedsUpperBound, ByteOffset);
+ if (isTainted(State, ByteOffset)) {
+ // Both cases are possible, but the offset is tainted, so report.
+ std::string RegName = getRegionName(Reg);
+
+ // Diagnostic detail: "tainted offset" is always correct, but the
+ // common case is that 'idx' is tainted in 'arr[idx]' and then it's
+ // nicer to say "tainted index".
+ const char *OffsetName = "offset";
+ if (const auto *ASE = dyn_cast<ArraySubscriptExpr>(E))
+ if (isTainted(State, ASE->getIdx(), C.getLocationContext()))
+ OffsetName = "index";
+
+ Messages Msgs = getTaintMsgs(Reg, OffsetName);
+ reportOOB(C, ExceedsUpperBound, OOB_Taint, ByteOffset, Msgs);
return;
}
}
- if (state_withinUpperBound)
- state = state_withinUpperBound;
+ if (WithinUpperBound)
+ State = WithinUpperBound;
}
- checkerContext.addTransition(state);
+ C.addTransition(State);
}
-void ArrayBoundCheckerV2::reportTaintOOB(CheckerContext &checkerContext,
- ProgramStateRef errorState,
- SVal TaintedSVal) const {
- ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState);
- if (!errorNode)
- return;
+void ArrayBoundCheckerV2::reportOOB(CheckerContext &C,
+ ProgramStateRef ErrorState, OOB_Kind Kind,
+ NonLoc Offset, Messages Msgs) const {
- if (!TaintBT)
- TaintBT.reset(
- new BugType(this, "Out-of-bound access", categories::TaintedData));
+ ExplodedNode *ErrorNode = C.generateErrorNode(ErrorState);
+ if (!ErrorNode)
+ return;
- SmallString<256> buf;
- llvm::raw_svector_ostream os(buf);
- os << "Out of bound memory access (index is tainted)";
- auto BR =
- std::make_unique<PathSensitiveBugReport>(*TaintBT, os.str(), errorNode);
+ auto BR = std::make_unique<PathSensitiveBugReport>(
+ Kind == OOB_Taint ? TaintBT : BT, Msgs.Short, Msgs.Full, ErrorNode);
// Track back the propagation of taintedness.
- for (SymbolRef Sym : getTaintedSymbols(errorState, TaintedSVal)) {
- BR->markInteresting(Sym);
- }
-
- checkerContext.emitReport(std::move(BR));
-}
-
-void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
- ProgramStateRef errorState,
- OOB_Kind kind) const {
+ if (Kind == OOB_Taint)
+ for (SymbolRef Sym : getTaintedSymbols(ErrorState, Offset))
+ BR->markInteresting(Sym);
- ExplodedNode *errorNode = checkerContext.generateErrorNode(errorState);
- if (!errorNode)
- return;
-
- if (!BT)
- BT.reset(new BuiltinBug(this, "Out-of-bound access"));
-
- // FIXME: This diagnostics are preliminary. We should get far better
- // diagnostics for explaining buffer overruns.
-
- SmallString<256> buf;
- llvm::raw_svector_ostream os(buf);
- os << "Out of bound memory access ";
- switch (kind) {
- case OOB_Precedes:
- os << "(accessed memory precedes memory block)";
- break;
- case OOB_Excedes:
- os << "(access exceeds upper limit of memory block)";
- break;
- }
- auto BR = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), errorNode);
- checkerContext.emitReport(std::move(BR));
+ C.emitReport(std::move(BR));
}
bool ArrayBoundCheckerV2::isFromCtypeMacro(const Stmt *S, ASTContext &ACtx) {
@@ -293,65 +464,16 @@ bool ArrayBoundCheckerV2::isFromCtypeMacro(const Stmt *S, ASTContext &ACtx) {
(MacroName == "isupper") || (MacroName == "isxdigit"));
}
-#ifndef NDEBUG
-LLVM_DUMP_METHOD void RegionRawOffsetV2::dump() const {
- dumpToStream(llvm::errs());
-}
-
-void RegionRawOffsetV2::dumpToStream(raw_ostream &os) const {
- os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}';
-}
-#endif
-
-/// For a given Location that can be represented as a symbolic expression
-/// Arr[Idx] (or perhaps Arr[Idx1][Idx2] etc.), return the parent memory block
-/// Arr and the distance of Location from the beginning of Arr (expressed in a
-/// NonLoc that specifies the number of CharUnits). Returns nullopt when these
-/// cannot be determined.
-std::optional<RegionRawOffsetV2>
-RegionRawOffsetV2::computeOffset(ProgramStateRef State, SValBuilder &SVB,
- SVal Location) {
- QualType T = SVB.getArrayIndexType();
- auto Calc = [&SVB, State, T](BinaryOperatorKind Op, NonLoc LHS, NonLoc RHS) {
- // We will use this utility to add and multiply values.
- return SVB.evalBinOpNN(State, Op, LHS, RHS, T).getAs<NonLoc>();
- };
-
- const MemRegion *Region = Location.getAsRegion();
- NonLoc Offset = SVB.makeZeroArrayIndex();
-
- while (Region) {
- if (const auto *ERegion = dyn_cast<ElementRegion>(Region)) {
- if (const auto Index = ERegion->getIndex().getAs<NonLoc>()) {
- QualType ElemType = ERegion->getElementType();
- // If the element is an incomplete type, go no further.
- if (ElemType->isIncompleteType())
- return std::nullopt;
-
- // Perform Offset += Index * sizeof(ElemType); then continue the offset
- // calculations with SuperRegion:
- NonLoc Size = SVB.makeArrayIndex(
- SVB.getContext().getTypeSizeInChars(ElemType).getQuantity());
- if (auto Delta = Calc(BO_Mul, *Index, Size)) {
- if (auto NewOffset = Calc(BO_Add, Offset, *Delta)) {
- Offset = *NewOffset;
- Region = ERegion->getSuperRegion();
- continue;
- }
- }
- }
- } else if (const auto *SRegion = dyn_cast<SubRegion>(Region)) {
- // NOTE: The dyn_cast<>() is expected to succeed, it'd be very surprising
- // to see a MemSpaceRegion at this point.
- // FIXME: We may return with {<Region>, 0} even if we didn't handle any
- // ElementRegion layers. I think that this behavior was introduced
- // accidentally by 8a4c760c204546aba566e302f299f7ed2e00e287 in 2011, so
- // it may be useful to review it in the future.
- return RegionRawOffsetV2(SRegion, Offset);
- }
- return std::nullopt;
- }
- return std::nullopt;
+bool ArrayBoundCheckerV2::isInAddressOf(const Stmt *S, ASTContext &ACtx) {
+ ParentMapContext &ParentCtx = ACtx.getParentMapContext();
+ do {
+ const DynTypedNodeList Parents = ParentCtx.getParents(*S);
+ if (Parents.empty())
+ return false;
+ S = Parents[0].get<Stmt>();
+ } while (isa_and_nonnull<ParenExpr, ImplicitCastExpr>(S));
+ const auto *UnaryOp = dyn_cast_or_null<UnaryOperator>(S);
+ return UnaryOp && UnaryOp->getOpcode() == UO_AddrOf;
}
void ento::registerArrayBoundCheckerV2(CheckerManager &mgr) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 4a5b8913c22f..5e25153a148f 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -352,9 +352,9 @@ void NilArgChecker::checkPostStmt(const ObjCDictionaryLiteral *DL,
namespace {
class CFNumberChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<APIMisuse> BT;
- mutable IdentifierInfo *ICreate, *IGetValue;
+ mutable IdentifierInfo *ICreate = nullptr, *IGetValue = nullptr;
public:
- CFNumberChecker() : ICreate(nullptr), IGetValue(nullptr) {}
+ CFNumberChecker() = default;
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
};
@@ -819,13 +819,13 @@ class ObjCLoopChecker
check::PostObjCMessage,
check::DeadSymbols,
check::PointerEscape > {
- mutable IdentifierInfo *CountSelectorII;
+ mutable IdentifierInfo *CountSelectorII = nullptr;
bool isCollectionCountMethod(const ObjCMethodCall &M,
CheckerContext &C) const;
public:
- ObjCLoopChecker() : CountSelectorII(nullptr) {}
+ ObjCLoopChecker() = default;
void checkPostStmt(const ObjCForCollectionStmt *FCS, CheckerContext &C) const;
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const;
@@ -1145,13 +1145,13 @@ class ObjCNonNilReturnValueChecker
check::PostStmt<ObjCArrayLiteral>,
check::PostStmt<ObjCDictionaryLiteral>,
check::PostStmt<ObjCBoxedExpr> > {
- mutable bool Initialized;
+ mutable bool Initialized = false;
mutable Selector ObjectAtIndex;
mutable Selector ObjectAtIndexedSubscript;
mutable Selector NullSelector;
public:
- ObjCNonNilReturnValueChecker() : Initialized(false) {}
+ ObjCNonNilReturnValueChecker() = default;
ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr,
ProgramStateRef State,
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
new file mode 100644
index 000000000000..339927c165fe
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BitwiseShiftChecker.cpp
@@ -0,0 +1,370 @@
+//== BitwiseShiftChecker.cpp ------------------------------------*- C++ -*--==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines BitwiseShiftChecker, which is a path-sensitive checker
+// that looks for undefined behavior when the operands of the bitwise shift
+// operators '<<' and '>>' are invalid (negative or too large).
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/CharUnits.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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/APSIntType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <memory>
+
+using namespace clang;
+using namespace ento;
+using llvm::formatv;
+
+namespace {
+enum class OperandSide { Left, Right };
+
+using BugReportPtr = std::unique_ptr<PathSensitiveBugReport>;
+
+struct NoteTagTemplate {
+ llvm::StringLiteral SignInfo;
+ llvm::StringLiteral UpperBoundIntro;
+};
+
+constexpr NoteTagTemplate NoteTagTemplates[] = {
+ {"", "right operand of bit shift is less than "},
+ {"left operand of bit shift is non-negative", " and right operand is less than "},
+ {"right operand of bit shift is non-negative", " but less than "},
+ {"both operands of bit shift are non-negative", " and right operand is less than "}
+};
+
+/// An implementation detail class which is introduced to split the checker
+/// logic into several methods while maintaining a consistently updated state
+/// and access to other contextual data.
+class BitwiseShiftValidator {
+ CheckerContext &Ctx;
+ ProgramStateRef FoldedState;
+ const BinaryOperator *const Op;
+ const BugType &BT;
+ const bool PedanticFlag;
+
+ // The following data members are only used for note tag creation:
+ enum { NonNegLeft = 1, NonNegRight = 2 };
+ unsigned NonNegOperands = 0;
+
+ std::optional<unsigned> UpperBoundBitCount = std::nullopt;
+
+public:
+ BitwiseShiftValidator(const BinaryOperator *O, CheckerContext &C,
+ const BugType &B, bool P)
+ : Ctx(C), FoldedState(C.getState()), Op(O), BT(B), PedanticFlag(P) {}
+ void run();
+
+private:
+ const Expr *operandExpr(OperandSide Side) const {
+ return Side == OperandSide::Left ? Op->getLHS() : Op->getRHS();
+ }
+
+ bool shouldPerformPedanticChecks() const {
+ // The pedantic flag has no effect under C++20 because the affected issues
+ // are no longer undefined under that version of the standard.
+ return PedanticFlag && !Ctx.getASTContext().getLangOpts().CPlusPlus20;
+ }
+
+ bool assumeRequirement(OperandSide Side, BinaryOperator::Opcode Cmp, unsigned Limit);
+
+ void recordAssumption(OperandSide Side, BinaryOperator::Opcode Cmp, unsigned Limit);
+ const NoteTag *createNoteTag() const;
+
+ BugReportPtr createBugReport(StringRef ShortMsg, StringRef Msg) const;
+
+ BugReportPtr checkOvershift();
+ BugReportPtr checkOperandNegative(OperandSide Side);
+ BugReportPtr checkLeftShiftOverflow();
+
+ bool isLeftShift() const { return Op->getOpcode() == BO_Shl; }
+ StringRef shiftDir() const { return isLeftShift() ? "left" : "right"; }
+ static StringRef pluralSuffix(unsigned n) { return n <= 1 ? "" : "s"; }
+ static StringRef verbSuffix(unsigned n) { return n <= 1 ? "s" : ""; }
+};
+
+void BitwiseShiftValidator::run() {
+ // Report a bug if the right operand is >= the bit width of the type of the
+ // left operand:
+ if (BugReportPtr BR = checkOvershift()) {
+ Ctx.emitReport(std::move(BR));
+ return;
+ }
+
+ // Report a bug if the right operand is negative:
+ if (BugReportPtr BR = checkOperandNegative(OperandSide::Right)) {
+ Ctx.emitReport(std::move(BR));
+ return;
+ }
+
+ if (shouldPerformPedanticChecks()) {
+ // Report a bug if the left operand is negative:
+ if (BugReportPtr BR = checkOperandNegative(OperandSide::Left)) {
+ Ctx.emitReport(std::move(BR));
+ return;
+ }
+
+ // Report a bug when left shift of a concrete signed value overflows:
+ if (BugReportPtr BR = checkLeftShiftOverflow()) {
+ Ctx.emitReport(std::move(BR));
+ return;
+ }
+ }
+
+ // No bugs detected, update the state and add a single note tag which
+ // summarizes the new assumptions.
+ Ctx.addTransition(FoldedState, createNoteTag());
+}
+
+/// This method checks a requirement that must be satisfied by the value on the
+/// given Side of a bitwise shift operator in well-defined code. If the
+/// requirement is incompatible with prior knowledge, this method reports
+/// failure by returning false.
+bool BitwiseShiftValidator::assumeRequirement(OperandSide Side,
+ BinaryOperator::Opcode Comparison,
+ unsigned Limit) {
+ SValBuilder &SVB = Ctx.getSValBuilder();
+
+ const SVal OperandVal = Ctx.getSVal(operandExpr(Side));
+ const auto LimitVal = SVB.makeIntVal(Limit, Ctx.getASTContext().IntTy);
+ // Note that the type of `LimitVal` must be a signed, because otherwise a
+ // negative `Val` could be converted to a large positive value.
+
+ auto ResultVal = SVB.evalBinOp(FoldedState, Comparison, OperandVal, LimitVal,
+ SVB.getConditionType());
+ if (auto DURes = ResultVal.getAs<DefinedOrUnknownSVal>()) {
+ auto [StTrue, StFalse] = FoldedState->assume(DURes.value());
+ if (!StTrue) {
+ // We detected undefined behavior (the caller will report it).
+ FoldedState = StFalse;
+ return false;
+ }
+ // The code may be valid, so let's assume that it's valid:
+ FoldedState = StTrue;
+ if (StFalse) {
+ // Record note tag data for the assumption that we made
+ recordAssumption(Side, Comparison, Limit);
+ }
+ }
+ return true;
+}
+
+BugReportPtr BitwiseShiftValidator::checkOvershift() {
+ const QualType LHSTy = Op->getLHS()->getType();
+ const unsigned LHSBitWidth = Ctx.getASTContext().getIntWidth(LHSTy);
+
+ if (assumeRequirement(OperandSide::Right, BO_LT, LHSBitWidth))
+ return nullptr;
+
+ const SVal Right = Ctx.getSVal(operandExpr(OperandSide::Right));
+
+ std::string RightOpStr = "", LowerBoundStr = "";
+ if (auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>())
+ RightOpStr = formatv(" '{0}'", ConcreteRight->getValue());
+ else {
+ SValBuilder &SVB = Ctx.getSValBuilder();
+ if (const llvm::APSInt *MinRight = SVB.getMinValue(FoldedState, Right)) {
+ LowerBoundStr = formatv(" >= {0},", MinRight->getExtValue());
+ }
+ }
+
+ std::string ShortMsg = formatv(
+ "{0} shift{1}{2} overflows the capacity of '{3}'",
+ isLeftShift() ? "Left" : "Right", RightOpStr.empty() ? "" : " by",
+ RightOpStr, LHSTy.getAsString());
+ std::string Msg = formatv(
+ "The result of {0} shift is undefined because the right "
+ "operand{1} is{2} not smaller than {3}, the capacity of '{4}'",
+ shiftDir(), RightOpStr, LowerBoundStr, LHSBitWidth, LHSTy.getAsString());
+ return createBugReport(ShortMsg, Msg);
+}
+
+// Before C++20, at 5.8 [expr.shift] (N4296, 2014-11-19) the standard says
+// 1. "... The behaviour is undefined if the right operand is negative..."
+// 2. "The value of E1 << E2 ...
+// if E1 has a signed type and non-negative value ...
+// otherwise, the behavior is undefined."
+// 3. "The value of E1 >> E2 ...
+// If E1 has a signed type and a negative value,
+// the resulting value is implementation-defined."
+// However, negative left arguments work in practice and the C++20 standard
+// eliminates conditions 2 and 3.
+BugReportPtr BitwiseShiftValidator::checkOperandNegative(OperandSide Side) {
+ // If the type is unsigned, it cannot be negative
+ if (!operandExpr(Side)->getType()->isSignedIntegerType())
+ return nullptr;
+
+ // Main check: determine whether the operand is constrained to be negative
+ if (assumeRequirement(Side, BO_GE, 0))
+ return nullptr;
+
+ std::string ShortMsg = formatv("{0} operand is negative in {1} shift",
+ Side == OperandSide::Left ? "Left" : "Right",
+ shiftDir())
+ .str();
+ std::string Msg = formatv("The result of {0} shift is undefined "
+ "because the {1} operand is negative",
+ shiftDir(),
+ Side == OperandSide::Left ? "left" : "right")
+ .str();
+
+ return createBugReport(ShortMsg, Msg);
+}
+
+BugReportPtr BitwiseShiftValidator::checkLeftShiftOverflow() {
+ // A right shift cannot be an overflowing left shift...
+ if (!isLeftShift())
+ return nullptr;
+
+ // In C++ it's well-defined to shift to the sign bit. In C however, it's UB.
+ // 5.8.2 [expr.shift] (N4296, 2014-11-19)
+ const bool ShouldPreserveSignBit = !Ctx.getLangOpts().CPlusPlus;
+
+ const Expr *LHS = operandExpr(OperandSide::Left);
+ const QualType LHSTy = LHS->getType();
+ const unsigned LeftBitWidth = Ctx.getASTContext().getIntWidth(LHSTy);
+ assert(LeftBitWidth > 0);
+
+ // Quote "For unsigned lhs, the value of LHS << RHS is the value of LHS *
+ // 2^RHS, reduced modulo maximum value of the return type plus 1."
+ if (LHSTy->isUnsignedIntegerType())
+ return nullptr;
+
+ // We only support concrete integers as left operand.
+ const auto Left = Ctx.getSVal(LHS).getAs<nonloc::ConcreteInt>();
+ if (!Left.has_value())
+ return nullptr;
+
+ // We should have already reported a bug if the left operand of the shift was
+ // negative, so it cannot be negative here.
+ assert(Left->getValue().isNonNegative());
+
+ const unsigned LeftAvailableBitWidth =
+ LeftBitWidth - static_cast<unsigned>(ShouldPreserveSignBit);
+ const unsigned UsedBitsInLeftOperand = Left->getValue().getActiveBits();
+ assert(LeftBitWidth >= UsedBitsInLeftOperand);
+ const unsigned MaximalAllowedShift =
+ LeftAvailableBitWidth - UsedBitsInLeftOperand;
+
+ if (assumeRequirement(OperandSide::Right, BO_LT, MaximalAllowedShift + 1))
+ return nullptr;
+
+ const std::string CapacityMsg =
+ formatv("because '{0}' can hold only {1} bits ({2} the sign bit)",
+ LHSTy.getAsString(), LeftAvailableBitWidth,
+ ShouldPreserveSignBit ? "excluding" : "including");
+
+ const SVal Right = Ctx.getSVal(Op->getRHS());
+
+ std::string ShortMsg, Msg;
+ if (const auto ConcreteRight = Right.getAs<nonloc::ConcreteInt>()) {
+ // Here ConcreteRight must contain a small non-negative integer, because
+ // otherwise one of the earlier checks should've reported a bug.
+ const unsigned RHS = ConcreteRight->getValue().getExtValue();
+ assert(RHS > MaximalAllowedShift);
+ const unsigned OverflownBits = RHS - MaximalAllowedShift;
+ ShortMsg = formatv(
+ "The shift '{0} << {1}' overflows the capacity of '{2}'",
+ Left->getValue(), ConcreteRight->getValue(), LHSTy.getAsString());
+ Msg = formatv(
+ "The shift '{0} << {1}' is undefined {2}, so {3} bit{4} overflow{5}",
+ Left->getValue(), ConcreteRight->getValue(), CapacityMsg, OverflownBits,
+ pluralSuffix(OverflownBits), verbSuffix(OverflownBits));
+ } else {
+ ShortMsg = formatv("Left shift of '{0}' overflows the capacity of '{1}'",
+ Left->getValue(), LHSTy.getAsString());
+ Msg = formatv(
+ "Left shift of '{0}' is undefined {1}, so some bits overflow",
+ Left->getValue(), CapacityMsg);
+ }
+
+ return createBugReport(ShortMsg, Msg);
+}
+
+void BitwiseShiftValidator::recordAssumption(OperandSide Side,
+ BinaryOperator::Opcode Comparison,
+ unsigned Limit) {
+ switch (Comparison) {
+ case BO_GE:
+ assert(Limit == 0);
+ NonNegOperands |= (Side == OperandSide::Left ? NonNegLeft : NonNegRight);
+ break;
+ case BO_LT:
+ assert(Side == OperandSide::Right);
+ if (!UpperBoundBitCount || Limit < UpperBoundBitCount.value())
+ UpperBoundBitCount = Limit;
+ break;
+ default:
+ llvm_unreachable("this checker does not use other comparison operators");
+ }
+}
+
+const NoteTag *BitwiseShiftValidator::createNoteTag() const {
+ if (!NonNegOperands && !UpperBoundBitCount)
+ return nullptr;
+
+ SmallString<128> Buf;
+ llvm::raw_svector_ostream Out(Buf);
+ Out << "Assuming ";
+ NoteTagTemplate Templ = NoteTagTemplates[NonNegOperands];
+ Out << Templ.SignInfo;
+ if (UpperBoundBitCount)
+ Out << Templ.UpperBoundIntro << UpperBoundBitCount.value();
+ const std::string Msg(Out.str());
+
+ return Ctx.getNoteTag(Msg, /*isPrunable=*/true);
+}
+
+std::unique_ptr<PathSensitiveBugReport>
+BitwiseShiftValidator::createBugReport(StringRef ShortMsg, StringRef Msg) const {
+ ProgramStateRef State = Ctx.getState();
+ if (ExplodedNode *ErrNode = Ctx.generateErrorNode(State)) {
+ auto BR =
+ std::make_unique<PathSensitiveBugReport>(BT, ShortMsg, Msg, ErrNode);
+ bugreporter::trackExpressionValue(ErrNode, Op->getLHS(), *BR);
+ bugreporter::trackExpressionValue(ErrNode, Op->getRHS(), *BR);
+ return BR;
+ }
+ return nullptr;
+}
+} // anonymous namespace
+
+class BitwiseShiftChecker : public Checker<check::PreStmt<BinaryOperator>> {
+ BugType BT{this, "Bitwise shift", "Suspicious operation"};
+
+public:
+ void checkPreStmt(const BinaryOperator *B, CheckerContext &Ctx) const {
+ BinaryOperator::Opcode Op = B->getOpcode();
+
+ if (Op != BO_Shl && Op != BO_Shr)
+ return;
+
+ BitwiseShiftValidator(B, Ctx, BT, Pedantic).run();
+ }
+
+ bool Pedantic = false;
+};
+
+void ento::registerBitwiseShiftChecker(CheckerManager &Mgr) {
+ auto *Chk = Mgr.registerChecker<BitwiseShiftChecker>();
+ const AnalyzerOptions &Opts = Mgr.getAnalyzerOptions();
+ Chk->Pedantic = Opts.getCheckerBooleanOption(Chk, "Pedantic");
+}
+
+bool ento::shouldRegisterBitwiseShiftChecker(const CheckerManager &mgr) {
+ return true;
+}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
index 2d20e394681d..361a4eed9221 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class BoolAssignmentChecker : public Checker< check::Bind > {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
void emitReport(ProgramStateRef state, CheckerContext &C,
bool IsTainted = false) const;
@@ -37,7 +37,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C,
bool IsTainted) const {
if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT)
- BT.reset(new BuiltinBug(this, "Assignment of a non-Boolean value"));
+ BT.reset(new BugType(this, "Assignment of a non-Boolean value"));
StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"
: "Assignment of a non-Boolean value";
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
index 4a56156de4b2..61521c259ca9 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp
@@ -81,22 +81,20 @@ bool BuiltinFunctionChecker::evalCall(const CallEvent &Call,
case Builtin::BI__builtin_alloca_with_align:
case Builtin::BI__builtin_alloca: {
- // FIXME: Refactor into StoreManager itself?
- MemRegionManager& RM = C.getStoreManager().getRegionManager();
- const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext());
-
- // Set the extent of the region in bytes. This enables us to use the
- // SVal of the argument directly. If we save the extent in bits, we
- // cannot represent values like symbol*8.
- auto Size = Call.getArgSVal(0);
- if (Size.isUndef())
- return true; // Return true to model purity.
-
- state = setDynamicExtent(state, R, Size.castAs<DefinedOrUnknownSVal>(),
- C.getSValBuilder());
+ SValBuilder &SVB = C.getSValBuilder();
+ const loc::MemRegionVal R =
+ SVB.getAllocaRegionVal(CE, C.getLocationContext(), C.blockCount());
- C.addTransition(state->BindExpr(CE, LCtx, loc::MemRegionVal(R)));
+ // Set the extent of the region in bytes. This enables us to use the SVal
+ // of the argument directly. If we saved the extent in bits, it'd be more
+ // difficult to reason about values like symbol*8.
+ auto Size = Call.getArgSVal(0);
+ if (auto DefSize = Size.getAs<DefinedOrUnknownSVal>()) {
+ // This `getAs()` is mostly paranoia, because core.CallAndMessage reports
+ // undefined function arguments (unless it's disabled somehow).
+ state = setDynamicExtent(state, R.getRegion(), *DefSize, SVB);
+ }
+ C.addTransition(state->BindExpr(CE, LCtx, R));
return true;
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 387edd8c3b18..31f5b03dcdeb 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -480,6 +480,14 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
if (!Filter.CheckCStringOutOfBounds)
return State;
+ SVal BufStart =
+ svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
+
+ // Check if the first byte of the buffer is accessible.
+ State = CheckLocation(C, State, Buffer, BufStart, Access, CK);
+ if (!State)
+ return nullptr;
+
// Get the access length and make sure it is known.
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
@@ -496,8 +504,6 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
NonLoc LastOffset = Offset.castAs<NonLoc>();
// Check that the first buffer is sufficiently long.
- SVal BufStart =
- svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
if (std::optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
SVal BufEnd =
@@ -653,13 +659,15 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
const Stmt *S, StringRef WarningMsg) const {
if (ExplodedNode *N = C.generateErrorNode(State)) {
- if (!BT_Null)
- BT_Null.reset(new BuiltinBug(
- Filter.CheckNameCStringNullArg, categories::UnixAPI,
- "Null pointer argument in call to byte string function"));
+ if (!BT_Null) {
+ // FIXME: This call uses the string constant 'categories::UnixAPI' as the
+ // description of the bug; it should be replaced by a real description.
+ BT_Null.reset(
+ new BugType(Filter.CheckNameCStringNullArg, categories::UnixAPI));
+ }
- BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get());
- auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
Report->addRange(S->getSourceRange());
if (const auto *Ex = dyn_cast<Expr>(S))
bugreporter::trackExpressionValue(N, Ex, *Report);
@@ -674,13 +682,11 @@ void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
const char *Msg =
"Bytes string function accesses uninitialized/garbage values";
if (!BT_UninitRead)
- BT_UninitRead.reset(
- new BuiltinBug(Filter.CheckNameCStringUninitializedRead,
- "Accessing unitialized/garbage values", Msg));
+ BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead,
+ "Accessing unitialized/garbage values"));
- BuiltinBug *BT = static_cast<BuiltinBug *>(BT_UninitRead.get());
-
- auto Report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
Report->addRange(E->getSourceRange());
bugreporter::trackExpressionValue(N, E, *Report);
C.emitReport(std::move(Report));
@@ -692,18 +698,16 @@ void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
StringRef WarningMsg) const {
if (ExplodedNode *N = C.generateErrorNode(State)) {
if (!BT_Bounds)
- BT_Bounds.reset(new BuiltinBug(
- Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds
- : Filter.CheckNameCStringNullArg,
- "Out-of-bound array access",
- "Byte string function accesses out-of-bound array element"));
-
- BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get());
+ BT_Bounds.reset(new BugType(Filter.CheckCStringOutOfBounds
+ ? Filter.CheckNameCStringOutOfBounds
+ : Filter.CheckNameCStringNullArg,
+ "Out-of-bound array access"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
- auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
+ auto Report =
+ std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
Report->addRange(S->getSourceRange());
C.emitReport(std::move(Report));
}
@@ -713,10 +717,12 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
const Stmt *S,
StringRef WarningMsg) const {
if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
- if (!BT_NotCString)
- BT_NotCString.reset(new BuiltinBug(
- Filter.CheckNameCStringNotNullTerm, categories::UnixAPI,
- "Argument is not a null-terminated string."));
+ if (!BT_NotCString) {
+ // FIXME: This call uses the string constant 'categories::UnixAPI' as the
+ // description of the bug; it should be replaced by a real description.
+ BT_NotCString.reset(
+ new BugType(Filter.CheckNameCStringNotNullTerm, categories::UnixAPI));
+ }
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
@@ -729,10 +735,13 @@ void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
ProgramStateRef State) const {
if (ExplodedNode *N = C.generateErrorNode(State)) {
- if (!BT_AdditionOverflow)
+ if (!BT_AdditionOverflow) {
+ // FIXME: This call uses the word "API" as the description of the bug;
+ // it should be replaced by a better error message (if this unlikely
+ // situation continues to exist as a separate bug type).
BT_AdditionOverflow.reset(
- new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API",
- "Sum of expressions causes overflow."));
+ new BugType(Filter.CheckNameCStringOutOfBounds, "API"));
+ }
// This isn't a great error message, but this should never occur in real
// code anyway -- you'd have to create a buffer longer than a size_t can
@@ -872,8 +881,8 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
fourInt);
NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
- SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn,
- maxLength, sizeTy);
+ SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, maxLength,
+ svalBuilder.getConditionType());
state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true);
}
state = state->set<CStringLength>(MR, strLength);
@@ -921,9 +930,23 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
}
+ case MemRegion::NonParamVarRegionKind: {
+ // If we have a global constant with a string literal initializer,
+ // compute the initializer's length.
+ const VarDecl *Decl = cast<NonParamVarRegion>(MR)->getDecl();
+ if (Decl->getType().isConstQualified() && Decl->hasGlobalStorage()) {
+ if (const Expr *Init = Decl->getInit()) {
+ if (auto *StrLit = dyn_cast<StringLiteral>(Init)) {
+ SValBuilder &SvalBuilder = C.getSValBuilder();
+ QualType SizeTy = SvalBuilder.getContext().getSizeType();
+ return SvalBuilder.makeIntVal(StrLit->getLength(), SizeTy);
+ }
+ }
+ }
+ [[fallthrough]];
+ }
case MemRegion::SymbolicRegionKind:
case MemRegion::AllocaRegionKind:
- case MemRegion::NonParamVarRegionKind:
case MemRegion::ParamVarRegionKind:
case MemRegion::FieldRegionKind:
case MemRegion::ObjCIvarRegionKind:
@@ -2006,6 +2029,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
SVal maxLastElement =
svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
+ // Check if the first byte of the destination is writable.
+ state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
+ if (!state)
+ return;
+ // Check if the last byte of the destination is writable.
state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write);
if (!state)
return;
@@ -2018,6 +2046,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// ...and we haven't checked the bound, we'll check the actual copy.
if (!boundWarning) {
+ // Check if the first byte of the destination is writable.
+ state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
+ if (!state)
+ return;
+ // Check if the last byte of the destination is writable.
state = CheckLocation(C, state, Dst, lastElement, AccessKind::write);
if (!state)
return;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp
new file mode 100644
index 000000000000..eb265f4dde68
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CXXDeleteChecker.cpp
@@ -0,0 +1,248 @@
+//=== CXXDeleteChecker.cpp -------------------------------------*- C++ -*--===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the following new checkers for C++ delete expressions:
+//
+// * DeleteWithNonVirtualDtorChecker
+// Defines a checker for the OOP52-CPP CERT rule: Do not delete a
+// polymorphic object without a virtual destructor.
+//
+// Diagnostic flags -Wnon-virtual-dtor and -Wdelete-non-virtual-dtor
+// report if an object with a virtual function but a non-virtual
+// destructor exists or is deleted, respectively.
+//
+// This check exceeds them by comparing the dynamic and static types of
+// the object at the point of destruction and only warns if it happens
+// through a pointer to a base type without a virtual destructor. The
+// check places a note at the last point where the conversion from
+// derived to base happened.
+//
+// * CXXArrayDeleteChecker
+// Defines a checker for the EXP51-CPP CERT rule: Do not delete an array
+// through a pointer of the incorrect type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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"
+#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+class CXXDeleteChecker : public Checker<check::PreStmt<CXXDeleteExpr>> {
+protected:
+ class PtrCastVisitor : public BugReporterVisitor {
+ public:
+ void Profile(llvm::FoldingSetNodeID &ID) const override {
+ static int X = 0;
+ ID.AddPointer(&X);
+ }
+ PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) override;
+ };
+
+ virtual void
+ checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,
+ const TypedValueRegion *BaseClassRegion,
+ const SymbolicRegion *DerivedClassRegion) const = 0;
+
+public:
+ void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
+};
+
+class DeleteWithNonVirtualDtorChecker : public CXXDeleteChecker {
+ mutable std::unique_ptr<BugType> BT;
+
+ void
+ checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,
+ const TypedValueRegion *BaseClassRegion,
+ const SymbolicRegion *DerivedClassRegion) const override;
+};
+
+class CXXArrayDeleteChecker : public CXXDeleteChecker {
+ mutable std::unique_ptr<BugType> BT;
+
+ void
+ checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,
+ const TypedValueRegion *BaseClassRegion,
+ const SymbolicRegion *DerivedClassRegion) const override;
+};
+} // namespace
+
+void CXXDeleteChecker::checkPreStmt(const CXXDeleteExpr *DE,
+ CheckerContext &C) const {
+ const Expr *DeletedObj = DE->getArgument();
+ const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion();
+ if (!MR)
+ return;
+
+ OverloadedOperatorKind DeleteKind =
+ DE->getOperatorDelete()->getOverloadedOperator();
+
+ if (DeleteKind != OO_Delete && DeleteKind != OO_Array_Delete)
+ return;
+
+ const auto *BaseClassRegion = MR->getAs<TypedValueRegion>();
+ const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>();
+ if (!BaseClassRegion || !DerivedClassRegion)
+ return;
+
+ checkTypedDeleteExpr(DE, C, BaseClassRegion, DerivedClassRegion);
+}
+
+void DeleteWithNonVirtualDtorChecker::checkTypedDeleteExpr(
+ const CXXDeleteExpr *DE, CheckerContext &C,
+ const TypedValueRegion *BaseClassRegion,
+ const SymbolicRegion *DerivedClassRegion) const {
+ const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();
+ const auto *DerivedClass =
+ DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();
+ if (!BaseClass || !DerivedClass)
+ return;
+
+ if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
+ return;
+
+ if (BaseClass->getDestructor()->isVirtual())
+ return;
+
+ if (!DerivedClass->isDerivedFrom(BaseClass))
+ return;
+
+ if (!BT)
+ BT.reset(new BugType(this,
+ "Destruction of a polymorphic object with no "
+ "virtual destructor",
+ "Logic error"));
+
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+
+ // Mark region of problematic base class for later use in the BugVisitor.
+ R->markInteresting(BaseClassRegion);
+ R->addVisitor<PtrCastVisitor>();
+ C.emitReport(std::move(R));
+}
+
+void CXXArrayDeleteChecker::checkTypedDeleteExpr(
+ const CXXDeleteExpr *DE, CheckerContext &C,
+ const TypedValueRegion *BaseClassRegion,
+ const SymbolicRegion *DerivedClassRegion) const {
+ const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();
+ const auto *DerivedClass =
+ DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();
+ if (!BaseClass || !DerivedClass)
+ return;
+
+ if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
+ return;
+
+ if (DE->getOperatorDelete()->getOverloadedOperator() != OO_Array_Delete)
+ return;
+
+ if (!DerivedClass->isDerivedFrom(BaseClass))
+ return;
+
+ if (!BT)
+ BT.reset(new BugType(this,
+ "Deleting an array of polymorphic objects "
+ "is undefined",
+ "Logic error"));
+
+ ExplodedNode *N = C.generateNonFatalErrorNode();
+ if (!N)
+ return;
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream OS(Buf);
+
+ QualType SourceType = BaseClassRegion->getValueType();
+ QualType TargetType =
+ DerivedClassRegion->getSymbol()->getType()->getPointeeType();
+
+ OS << "Deleting an array of '" << TargetType.getAsString()
+ << "' objects as their base class '"
+ << SourceType.getAsString(C.getASTContext().getPrintingPolicy())
+ << "' is undefined";
+
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
+
+ // Mark region of problematic base class for later use in the BugVisitor.
+ R->markInteresting(BaseClassRegion);
+ R->addVisitor<PtrCastVisitor>();
+ C.emitReport(std::move(R));
+}
+
+PathDiagnosticPieceRef
+CXXDeleteChecker::PtrCastVisitor::VisitNode(const ExplodedNode *N,
+ BugReporterContext &BRC,
+ PathSensitiveBugReport &BR) {
+ const Stmt *S = N->getStmtForDiagnostics();
+ if (!S)
+ return nullptr;
+
+ const auto *CastE = dyn_cast<CastExpr>(S);
+ if (!CastE)
+ return nullptr;
+
+ // FIXME: This way of getting base types does not support reference types.
+ QualType SourceType = CastE->getSubExpr()->getType()->getPointeeType();
+ QualType TargetType = CastE->getType()->getPointeeType();
+
+ if (SourceType.isNull() || TargetType.isNull() || SourceType == TargetType)
+ return nullptr;
+
+ // Region associated with the current cast expression.
+ const MemRegion *M = N->getSVal(CastE).getAsRegion();
+ if (!M)
+ return nullptr;
+
+ // Check if target region was marked as problematic previously.
+ if (!BR.isInteresting(M))
+ return nullptr;
+
+ SmallString<256> Buf;
+ llvm::raw_svector_ostream OS(Buf);
+
+ OS << "Casting from '" << SourceType.getAsString() << "' to '"
+ << TargetType.getAsString() << "' here";
+
+ PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
+ N->getLocationContext());
+ return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(),
+ /*addPosRange=*/true);
+}
+
+void ento::registerCXXArrayDeleteChecker(CheckerManager &mgr) {
+ mgr.registerChecker<CXXArrayDeleteChecker>();
+}
+
+bool ento::shouldRegisterCXXArrayDeleteChecker(const CheckerManager &mgr) {
+ return true;
+}
+
+void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {
+ mgr.registerChecker<DeleteWithNonVirtualDtorChecker>();
+}
+
+bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker(
+ const CheckerManager &mgr) {
+ return true;
+}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 79225e8e6ca3..ea74256935ca 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -123,7 +123,7 @@ private:
void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
if (!BT)
- BT.reset(new BuiltinBug(OriginalName, desc));
+ BT.reset(new BugType(OriginalName, desc));
}
bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
SourceRange ArgRange, const Expr *ArgEx,
@@ -379,7 +379,7 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
return nullptr;
}
if (!BT_call_undef)
- BT_call_undef.reset(new BuiltinBug(
+ BT_call_undef.reset(new BugType(
OriginalName,
"Called function pointer is an uninitialized pointer value"));
emitBadCall(BT_call_undef.get(), C, Callee);
@@ -395,7 +395,7 @@ ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
return nullptr;
}
if (!BT_call_null)
- BT_call_null.reset(new BuiltinBug(
+ BT_call_null.reset(new BugType(
OriginalName, "Called function pointer is null (null dereference)"));
emitBadCall(BT_call_null.get(), C, Callee);
return nullptr;
@@ -450,7 +450,7 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
return nullptr;
}
if (!BT_cxx_call_undef)
- BT_cxx_call_undef.reset(new BuiltinBug(
+ BT_cxx_call_undef.reset(new BugType(
OriginalName, "Called C++ object pointer is uninitialized"));
emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
return nullptr;
@@ -466,7 +466,7 @@ ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
}
if (!BT_cxx_call_null)
BT_cxx_call_null.reset(
- new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
+ new BugType(OriginalName, "Called C++ object pointer is null"));
emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
return nullptr;
}
@@ -495,13 +495,13 @@ CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
return nullptr;
if (!BT_cxx_delete_undef)
BT_cxx_delete_undef.reset(
- new BuiltinBug(OriginalName, "Uninitialized argument value"));
+ new BugType(OriginalName, "Uninitialized argument value"));
if (DE->isArrayFormAsWritten())
Desc = "Argument to 'delete[]' is uninitialized";
else
Desc = "Argument to 'delete' is uninitialized";
- BugType *BT = BT_cxx_delete_undef.get();
- auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
+ auto R =
+ std::make_unique<PathSensitiveBugReport>(*BT_cxx_delete_undef, Desc, N);
bugreporter::trackExpressionValue(N, DE, *R);
C.emitReport(std::move(R));
return nullptr;
@@ -585,21 +585,21 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
switch (msg.getMessageKind()) {
case OCM_Message:
if (!BT_msg_undef)
- BT_msg_undef.reset(new BuiltinBug(OriginalName,
- "Receiver in message expression "
- "is an uninitialized value"));
+ BT_msg_undef.reset(new BugType(OriginalName,
+ "Receiver in message expression "
+ "is an uninitialized value"));
BT = BT_msg_undef.get();
break;
case OCM_PropertyAccess:
if (!BT_objc_prop_undef)
- BT_objc_prop_undef.reset(new BuiltinBug(
+ BT_objc_prop_undef.reset(new BugType(
OriginalName,
"Property access on an uninitialized object pointer"));
BT = BT_objc_prop_undef.get();
break;
case OCM_Subscript:
if (!BT_objc_subscript_undef)
- BT_objc_subscript_undef.reset(new BuiltinBug(
+ BT_objc_subscript_undef.reset(new BugType(
OriginalName,
"Subscript access on an uninitialized object pointer"));
BT = BT_objc_subscript_undef.get();
@@ -634,8 +634,8 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
}
if (!BT_msg_ret)
- BT_msg_ret.reset(new BuiltinBug(OriginalName,
- "Receiver in message expression is 'nil'"));
+ BT_msg_ret.reset(
+ new BugType(OriginalName, "Receiver in message expression is 'nil'"));
const ObjCMessageExpr *ME = msg.getOriginExpr();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
index 2d2e14de3f2b..d1d4f3baf6a8 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -132,11 +132,11 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
if (ExplodedNode *errorNode = C.generateErrorNode()) {
if (!BT)
- BT.reset(new BuiltinBug(this, "Cast region with wrong size.",
- "Cast a region whose size is not a multiple"
- " of the destination type size."));
- auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(),
- errorNode);
+ BT.reset(new BugType(this, "Cast region with wrong size."));
+ constexpr llvm::StringLiteral Msg =
+ "Cast a region whose size is not a multiple of the destination type "
+ "size.";
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, errorNode);
R->addRange(CE->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
index bd6655cc1e3f..fedc6db3723a 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp
@@ -1045,8 +1045,8 @@ bool ObjCDeallocChecker::isReleasedByCIFilterDealloc(
StringRef IvarName = PropImpl->getPropertyIvarDecl()->getName();
const char *ReleasePrefix = "input";
- if (!(PropName.startswith(ReleasePrefix) ||
- IvarName.startswith(ReleasePrefix))) {
+ if (!(PropName.starts_with(ReleasePrefix) ||
+ IvarName.starts_with(ReleasePrefix))) {
return false;
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
index 18d575041ba7..afc5e6b48008 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
@@ -27,7 +27,6 @@ using namespace ento;
static bool isArc4RandomAvailable(const ASTContext &Ctx) {
const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
return T.getVendor() == llvm::Triple::Apple ||
- T.getOS() == llvm::Triple::CloudABI ||
T.isOSFreeBSD() ||
T.isOSNetBSD() ||
T.isOSOpenBSD() ||
@@ -141,42 +140,43 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (!II) // if no identifier, not a simple C function
return;
StringRef Name = II->getName();
- if (Name.startswith("__builtin_"))
+ if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
// Set the evaluation function by switching on the callee name.
- FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
- .Case("bcmp", &WalkAST::checkCall_bcmp)
- .Case("bcopy", &WalkAST::checkCall_bcopy)
- .Case("bzero", &WalkAST::checkCall_bzero)
- .Case("gets", &WalkAST::checkCall_gets)
- .Case("getpw", &WalkAST::checkCall_getpw)
- .Case("mktemp", &WalkAST::checkCall_mktemp)
- .Case("mkstemp", &WalkAST::checkCall_mkstemp)
- .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
- .Case("mkstemps", &WalkAST::checkCall_mkstemp)
- .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
- .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
- .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
- "vscanf", "vwscanf", "vfscanf", "vfwscanf",
- &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
- .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
- "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
- &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
- .Cases("strncpy", "strncat", "memset",
- &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
- .Case("drand48", &WalkAST::checkCall_rand)
- .Case("erand48", &WalkAST::checkCall_rand)
- .Case("jrand48", &WalkAST::checkCall_rand)
- .Case("lrand48", &WalkAST::checkCall_rand)
- .Case("mrand48", &WalkAST::checkCall_rand)
- .Case("nrand48", &WalkAST::checkCall_rand)
- .Case("lcong48", &WalkAST::checkCall_rand)
- .Case("rand", &WalkAST::checkCall_rand)
- .Case("rand_r", &WalkAST::checkCall_rand)
- .Case("random", &WalkAST::checkCall_random)
- .Case("vfork", &WalkAST::checkCall_vfork)
- .Default(nullptr);
+ FnCheck evalFunction =
+ llvm::StringSwitch<FnCheck>(Name)
+ .Case("bcmp", &WalkAST::checkCall_bcmp)
+ .Case("bcopy", &WalkAST::checkCall_bcopy)
+ .Case("bzero", &WalkAST::checkCall_bzero)
+ .Case("gets", &WalkAST::checkCall_gets)
+ .Case("getpw", &WalkAST::checkCall_getpw)
+ .Case("mktemp", &WalkAST::checkCall_mktemp)
+ .Case("mkstemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
+ .Case("mkstemps", &WalkAST::checkCall_mkstemp)
+ .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
+ .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
+ .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
+ "vscanf", "vwscanf", "vfscanf", "vfwscanf",
+ &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
+ .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
+ "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
+ &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
+ .Cases("strncpy", "strncat", "memset", "fprintf",
+ &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
+ .Case("drand48", &WalkAST::checkCall_rand)
+ .Case("erand48", &WalkAST::checkCall_rand)
+ .Case("jrand48", &WalkAST::checkCall_rand)
+ .Case("lrand48", &WalkAST::checkCall_rand)
+ .Case("mrand48", &WalkAST::checkCall_rand)
+ .Case("nrand48", &WalkAST::checkCall_rand)
+ .Case("lcong48", &WalkAST::checkCall_rand)
+ .Case("rand", &WalkAST::checkCall_rand)
+ .Case("rand_r", &WalkAST::checkCall_rand)
+ .Case("random", &WalkAST::checkCall_random)
+ .Case("vfork", &WalkAST::checkCall_vfork)
+ .Default(nullptr);
// If the callee isn't defined, it is not of security concern.
// Check and evaluate the call.
@@ -219,7 +219,6 @@ void WalkAST::VisitForStmt(ForStmt *FS) {
//===----------------------------------------------------------------------===//
// Check: floating point variable used as loop counter.
-// Originally: <rdar://problem/6336718>
// Implements: CERT security coding advisory FLP-30.
//===----------------------------------------------------------------------===//
@@ -467,8 +466,8 @@ void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
//===----------------------------------------------------------------------===//
-// Check: Any use of 'gets' is insecure.
-// Originally: <rdar://problem/6335715>
+// Check: Any use of 'gets' is insecure. Most man pages literally says this.
+//
// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
// CWE-242: Use of Inherently Dangerous Function
//===----------------------------------------------------------------------===//
@@ -739,10 +738,10 @@ void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
// Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
// 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
-// 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
-// is deprecated since C11.
+// 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset',
+// 'fprintf' is deprecated since C11.
//
-// Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
+// Use of 'sprintf', 'fprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
// 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
// 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
// is insecure.
@@ -764,14 +763,15 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
StringRef Name = FD->getIdentifier()->getName();
- if (Name.startswith("__builtin_"))
+ if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
int ArgIndex =
llvm::StringSwitch<int>(Name)
.Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
- .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
- "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
+ .Cases("fscanf", "fwscanf", "vfscanf", "vfwscanf", "sscanf",
+ "swscanf", "vsscanf", "vswscanf", 1)
+ .Cases("sprintf", "vsprintf", "fprintf", 1)
.Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
"memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
.Default(UNKNOWN_CALL);
@@ -847,8 +847,13 @@ bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
}
//===----------------------------------------------------------------------===//
-// Check: Linear congruent random number generators should not be used
-// Originally: <rdar://problem/63371000>
+// Check: Linear congruent random number generators should not be used,
+// i.e. rand(), random().
+//
+// E. Bach, "Efficient prediction of Marsaglia-Zaman random number generators,"
+// in IEEE Transactions on Information Theory, vol. 44, no. 3, pp. 1253-1257,
+// May 1998, https://doi.org/10.1109/18.669305
+//
// CWE-338: Use of cryptographically weak prng
//===----------------------------------------------------------------------===//
@@ -890,11 +895,7 @@ void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
CE->getCallee()->getSourceRange());
}
-//===----------------------------------------------------------------------===//
-// Check: 'random' should not be used
-// Originally: <rdar://problem/63371000>
-//===----------------------------------------------------------------------===//
-
+// See justification for rand().
void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
if (!CheckRand || !filter.check_rand)
return;
@@ -990,8 +991,18 @@ void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
}
//===----------------------------------------------------------------------===//
-// Check: Should check whether privileges are dropped successfully.
-// Originally: <rdar://problem/6337132>
+// Check: The caller should always verify that the privileges
+// were dropped successfully.
+//
+// Some library functions, like setuid() and setgid(), should always be used
+// with a check of the return value to verify that the function completed
+// successfully. If the drop fails, the software will continue to run
+// with the raised privileges, which might provide additional access
+// to unprivileged users.
+//
+// (Note that this check predates __attribute__((warn_unused_result)).
+// Do we still need it now that we have a compiler warning for this?
+// Are these standard functions already annotated this way?)
//===----------------------------------------------------------------------===//
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
index 9ace1583eb53..9e11d8d9ecbc 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp
@@ -41,7 +41,7 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
// bug<--foo()-- JAIL_ENTERED<--foo()--
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;
+ mutable std::unique_ptr<BugType> BT_BreakJail;
const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
@@ -125,11 +125,11 @@ void ChrootChecker::checkPreCall(const CallEvent &Call,
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_BreakJail)
- BT_BreakJail.reset(new BuiltinBug(
- this, "Break out of jail", "No call of chdir(\"/\") immediately "
- "after chroot"));
- C.emitReport(std::make_unique<PathSensitiveBugReport>(
- *BT_BreakJail, BT_BreakJail->getDescription(), N));
+ BT_BreakJail.reset(new BugType(this, "Break out of jail"));
+ constexpr llvm::StringLiteral Msg =
+ "No call of chdir(\"/\") immediately after chroot";
+ C.emitReport(
+ std::make_unique<PathSensitiveBugReport>(*BT_BreakJail, Msg, N));
}
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
index 6ea39fb95e9a..8b34b41bab21 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -42,7 +42,7 @@ public:
void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
private:
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
CheckerContext &C) const;
@@ -127,8 +127,7 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E,
CheckerContext &C, const char Msg[]) const {
if (!BT)
- BT.reset(
- new BuiltinBug(this, "Conversion", "Possible loss of sign/precision."));
+ BT.reset(new BugType(this, "Conversion"));
// Generate a report for this bug.
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
index 5f44c9476928..86f446fc411c 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -183,7 +183,7 @@ public:
// Files autogenerated by DriverKit IIG contain some dead stores that
// we don't want to report.
- if (Data.startswith("/* iig"))
+ if (Data.starts_with("/* iig"))
return true;
return false;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
index 2fe91467c8c5..04bbe85473c0 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp
@@ -322,7 +322,7 @@ bool ento::shouldRegisterExplodedGraphViewer(const CheckerManager &mgr) {
namespace {
class ReportStmts : public Checker<check::PreStmt<Stmt>> {
- BuiltinBug BT_stmtLoc{this, "Statement"};
+ BugType BT_stmtLoc{this, "Statement"};
public:
void checkPreStmt(const Stmt *S, CheckerContext &C) const {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
deleted file mode 100644
index 7c5833762008..000000000000
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DeleteWithNonVirtualDtorChecker.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-//===-- DeleteWithNonVirtualDtorChecker.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
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines a checker for the OOP52-CPP CERT rule: Do not delete a polymorphic
-// object without a virtual destructor.
-//
-// Diagnostic flags -Wnon-virtual-dtor and -Wdelete-non-virtual-dtor report if
-// an object with a virtual function but a non-virtual destructor exists or is
-// deleted, respectively.
-//
-// This check exceeds them by comparing the dynamic and static types of the
-// object at the point of destruction and only warns if it happens through a
-// pointer to a base type without a virtual destructor. The check places a note
-// at the last point where the conversion from derived to base happened.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.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"
-#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class DeleteWithNonVirtualDtorChecker
- : public Checker<check::PreStmt<CXXDeleteExpr>> {
- mutable std::unique_ptr<BugType> BT;
-
- class DeleteBugVisitor : public BugReporterVisitor {
- public:
- DeleteBugVisitor() : Satisfied(false) {}
- void Profile(llvm::FoldingSetNodeID &ID) const override {
- static int X = 0;
- ID.AddPointer(&X);
- }
- PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
- BugReporterContext &BRC,
- PathSensitiveBugReport &BR) override;
-
- private:
- bool Satisfied;
- };
-
-public:
- void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
-};
-} // end anonymous namespace
-
-void DeleteWithNonVirtualDtorChecker::checkPreStmt(const CXXDeleteExpr *DE,
- CheckerContext &C) const {
- const Expr *DeletedObj = DE->getArgument();
- const MemRegion *MR = C.getSVal(DeletedObj).getAsRegion();
- if (!MR)
- return;
-
- const auto *BaseClassRegion = MR->getAs<TypedValueRegion>();
- const auto *DerivedClassRegion = MR->getBaseRegion()->getAs<SymbolicRegion>();
- if (!BaseClassRegion || !DerivedClassRegion)
- return;
-
- const auto *BaseClass = BaseClassRegion->getValueType()->getAsCXXRecordDecl();
- const auto *DerivedClass =
- DerivedClassRegion->getSymbol()->getType()->getPointeeCXXRecordDecl();
- if (!BaseClass || !DerivedClass)
- return;
-
- if (!BaseClass->hasDefinition() || !DerivedClass->hasDefinition())
- return;
-
- if (BaseClass->getDestructor()->isVirtual())
- return;
-
- if (!DerivedClass->isDerivedFrom(BaseClass))
- return;
-
- if (!BT)
- BT.reset(new BugType(this,
- "Destruction of a polymorphic object with no "
- "virtual destructor",
- "Logic error"));
-
- ExplodedNode *N = C.generateNonFatalErrorNode();
- if (!N)
- return;
- auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
-
- // Mark region of problematic base class for later use in the BugVisitor.
- R->markInteresting(BaseClassRegion);
- R->addVisitor(std::make_unique<DeleteBugVisitor>());
- C.emitReport(std::move(R));
-}
-
-PathDiagnosticPieceRef
-DeleteWithNonVirtualDtorChecker::DeleteBugVisitor::VisitNode(
- const ExplodedNode *N, BugReporterContext &BRC,
- PathSensitiveBugReport &BR) {
- // Stop traversal after the first conversion was found on a path.
- if (Satisfied)
- return nullptr;
-
- const Stmt *S = N->getStmtForDiagnostics();
- if (!S)
- return nullptr;
-
- const auto *CastE = dyn_cast<CastExpr>(S);
- if (!CastE)
- return nullptr;
-
- // Only interested in DerivedToBase implicit casts.
- // Explicit casts can have different CastKinds.
- if (const auto *ImplCastE = dyn_cast<ImplicitCastExpr>(CastE)) {
- if (ImplCastE->getCastKind() != CK_DerivedToBase)
- return nullptr;
- }
-
- // Region associated with the current cast expression.
- const MemRegion *M = N->getSVal(CastE).getAsRegion();
- if (!M)
- return nullptr;
-
- // Check if target region was marked as problematic previously.
- if (!BR.isInteresting(M))
- return nullptr;
-
- // Stop traversal on this path.
- Satisfied = true;
-
- SmallString<256> Buf;
- llvm::raw_svector_ostream OS(Buf);
- OS << "Conversion from derived to base happened here";
- PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
- N->getLocationContext());
- return std::make_shared<PathDiagnosticEventPiece>(Pos, OS.str(), true);
-}
-
-void ento::registerDeleteWithNonVirtualDtorChecker(CheckerManager &mgr) {
- mgr.registerChecker<DeleteWithNonVirtualDtorChecker>();
-}
-
-bool ento::shouldRegisterDeleteWithNonVirtualDtorChecker(
- const CheckerManager &mgr) {
- return true;
-}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
index 1f3e9e00d3e6..034774a252b1 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
@@ -268,12 +268,12 @@ void DynamicTypePropagation::checkPreCall(const CallEvent &Call,
// a more-derived class.
switch (Ctor->getOriginExpr()->getConstructionKind()) {
- case CXXConstructExpr::CK_Complete:
- case CXXConstructExpr::CK_Delegating:
+ case CXXConstructionKind::Complete:
+ case CXXConstructionKind::Delegating:
// No additional type info necessary.
return;
- case CXXConstructExpr::CK_NonVirtualBase:
- case CXXConstructExpr::CK_VirtualBase:
+ case CXXConstructionKind::NonVirtualBase:
+ case CXXConstructionKind::VirtualBase:
if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion())
recordFixedType(Target, Ctor->getDecl(), C);
return;
@@ -360,16 +360,16 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call,
if (const CXXConstructorCall *Ctor = dyn_cast<CXXConstructorCall>(&Call)) {
// We may need to undo the effects of our pre-call check.
switch (Ctor->getOriginExpr()->getConstructionKind()) {
- case CXXConstructExpr::CK_Complete:
- case CXXConstructExpr::CK_Delegating:
+ case CXXConstructionKind::Complete:
+ case CXXConstructionKind::Delegating:
// No additional work necessary.
// Note: This will leave behind the actual type of the object for
// complete constructors, but arguably that's a good thing, since it
// means the dynamic type info will be correct even for objects
// constructed with operator new.
return;
- case CXXConstructExpr::CK_NonVirtualBase:
- case CXXConstructExpr::CK_VirtualBase:
+ case CXXConstructionKind::NonVirtualBase:
+ case CXXConstructionKind::VirtualBase:
if (const MemRegion *Target = Ctor->getCXXThisVal().getAsRegion()) {
// We just finished a base constructor. Now we can use the subclass's
// type when resolving virtual calls.
@@ -713,7 +713,7 @@ static bool isObjCTypeParamDependent(QualType Type) {
class IsObjCTypeParamDependentTypeVisitor
: public RecursiveASTVisitor<IsObjCTypeParamDependentTypeVisitor> {
public:
- IsObjCTypeParamDependentTypeVisitor() : Result(false) {}
+ IsObjCTypeParamDependentTypeVisitor() = default;
bool VisitObjCTypeParamType(const ObjCTypeParamType *Type) {
if (isa<ObjCTypeParamDecl>(Type->getDecl())) {
Result = true;
@@ -722,7 +722,7 @@ static bool isObjCTypeParamDependent(QualType Type) {
return true;
}
- bool Result;
+ bool Result = false;
};
IsObjCTypeParamDependentTypeVisitor Visitor;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
index 1077ceb6288e..7c51673422a0 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/EnumCastOutOfRangeChecker.cpp
@@ -22,10 +22,12 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/Support/FormatVariadic.h"
#include <optional>
using namespace clang;
using namespace ento;
+using llvm::formatv;
namespace {
// This evaluator checks two SVals for equality. The first SVal is provided via
@@ -58,8 +60,9 @@ public:
// Being conservative, it does not warn if there is slight possibility the
// value can be matching.
class EnumCastOutOfRangeChecker : public Checker<check::PreStmt<CastExpr>> {
- mutable std::unique_ptr<BuiltinBug> EnumValueCastOutOfRange;
- void reportWarning(CheckerContext &C) const;
+ mutable std::unique_ptr<BugType> EnumValueCastOutOfRange;
+ void reportWarning(CheckerContext &C, const CastExpr *CE,
+ const EnumDecl *E) const;
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@@ -72,21 +75,43 @@ EnumValueVector getDeclValuesForEnum(const EnumDecl *ED) {
EnumValueVector DeclValues(
std::distance(ED->enumerator_begin(), ED->enumerator_end()));
llvm::transform(ED->enumerators(), DeclValues.begin(),
- [](const EnumConstantDecl *D) { return D->getInitVal(); });
+ [](const EnumConstantDecl *D) { return D->getInitVal(); });
return DeclValues;
}
} // namespace
-void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C) const {
+void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C,
+ const CastExpr *CE,
+ const EnumDecl *E) const {
+ assert(E && "valid EnumDecl* is expected");
if (const ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!EnumValueCastOutOfRange)
EnumValueCastOutOfRange.reset(
- new BuiltinBug(this, "Enum cast out of range",
- "The value provided to the cast expression is not in "
- "the valid range of values for the enum"));
- C.emitReport(std::make_unique<PathSensitiveBugReport>(
- *EnumValueCastOutOfRange, EnumValueCastOutOfRange->getDescription(),
- N));
+ new BugType(this, "Enum cast out of range"));
+
+ std::string ValueStr = "", NameStr = "the enum";
+
+ // Try to add details to the message:
+ const auto ConcreteValue =
+ C.getSVal(CE->getSubExpr()).getAs<nonloc::ConcreteInt>();
+ if (ConcreteValue) {
+ ValueStr = formatv(" '{0}'", ConcreteValue->getValue());
+ }
+ if (StringRef EnumName{E->getName()}; !EnumName.empty()) {
+ NameStr = formatv("'{0}'", EnumName);
+ }
+
+ std::string Msg = formatv("The value{0} provided to the cast expression is "
+ "not in the valid range of values for {1}",
+ ValueStr, NameStr);
+
+ auto BR = std::make_unique<PathSensitiveBugReport>(*EnumValueCastOutOfRange,
+ Msg, N);
+ bugreporter::trackExpressionValue(N, CE->getSubExpr(), *BR);
+ BR->addNote("enum declared here",
+ PathDiagnosticLocation::create(E, C.getSourceManager()),
+ {E->getSourceRange()});
+ C.emitReport(std::move(BR));
}
}
@@ -129,14 +154,25 @@ void EnumCastOutOfRangeChecker::checkPreStmt(const CastExpr *CE,
const EnumDecl *ED = T->castAs<EnumType>()->getDecl();
EnumValueVector DeclValues = getDeclValuesForEnum(ED);
+
+ // If the declarator list is empty, bail out.
+ // Every initialization an enum with a fixed underlying type but without any
+ // enumerators would produce a warning if we were to continue at this point.
+ // The most notable example is std::byte in the C++17 standard library.
+ // TODO: Create heuristics to bail out when the enum type is intended to be
+ // used to store combinations of flag values (to mitigate the limitation
+ // described in the docs).
+ if (DeclValues.size() == 0)
+ return;
+
// Check if any of the enum values possibly match.
- bool PossibleValueMatch = llvm::any_of(
- DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
+ bool PossibleValueMatch =
+ llvm::any_of(DeclValues, ConstraintBasedEQEvaluator(C, *ValueToCast));
// If there is no value that can possibly match any of the enum values, then
// warn.
if (!PossibleValueMatch)
- reportWarning(C);
+ reportWarning(C, CE, ED);
}
void ento::registerEnumCastOutOfRangeChecker(CheckerManager &mgr) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
index be2fa91b994a..1b34ea0e056e 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.cpp
@@ -312,18 +312,6 @@ ProgramStateRef setErrnoStdMustBeChecked(ProgramStateRef State,
return setErrnoState(State, MustBeChecked);
}
-const NoteTag *getNoteTagForStdSuccess(CheckerContext &C, llvm::StringRef Fn) {
- return getErrnoNoteTag(
- C, llvm::formatv(
- "'errno' may be undefined after successful call to '{0}'", Fn));
-}
-
-const NoteTag *getNoteTagForStdMustBeChecked(CheckerContext &C,
- llvm::StringRef Fn) {
- return getErrnoNoteTag(
- C, llvm::formatv("'{0}' indicates failure only by setting 'errno'", Fn));
-}
-
} // namespace errno_modeling
} // namespace ento
} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
index 0707fd16d6e6..6b53572fe5e2 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ErrnoModeling.h
@@ -84,8 +84,7 @@ 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.
+/// affected).
ProgramStateRef setErrnoForStdSuccess(ProgramStateRef State, CheckerContext &C);
/// Set errno state for the common case when a standard function fails.
@@ -100,23 +99,10 @@ ProgramStateRef setErrnoForStdFailure(ProgramStateRef State, CheckerContext &C,
/// Set errno state for the common case when a standard function indicates
/// failure only by \c errno. Sets \c ErrnoCheckState to \c MustBeChecked, and
/// invalidates the errno region (clear of previous value).
-/// 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/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
index 15ba29050e90..2c7bacac33a6 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -325,12 +325,12 @@ void ExprInspectionChecker::analyzerDump(const CallExpr *CE,
void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
CheckerContext &C) const {
- const MemRegion *MR = getArgRegion(CE, C);
- if (!MR)
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
ProgramStateRef State = C.getState();
- DefinedOrUnknownSVal Size = getDynamicExtent(State, MR, C.getSValBuilder());
+ SVal Size = getDynamicExtentWithOffset(State, C.getSVal(Arg));
State = State->BindExpr(CE, C.getLocationContext(), Size);
C.addTransition(State);
@@ -338,12 +338,12 @@ void ExprInspectionChecker::analyzerGetExtent(const CallExpr *CE,
void ExprInspectionChecker::analyzerDumpExtent(const CallExpr *CE,
CheckerContext &C) const {
- const MemRegion *MR = getArgRegion(CE, C);
- if (!MR)
+ const Expr *Arg = getArgExpr(CE, C);
+ if (!Arg)
return;
- DefinedOrUnknownSVal Size =
- getDynamicExtent(C.getState(), MR, C.getSValBuilder());
+ ProgramStateRef State = C.getState();
+ SVal Size = getDynamicExtentWithOffset(State, C.getSVal(Arg));
printAndReport(C, Size);
}
@@ -362,8 +362,8 @@ void ExprInspectionChecker::analyzerDumpElementCount(const CallExpr *CE,
assert(!ElementTy->isPointerType());
- DefinedOrUnknownSVal ElementCount =
- getDynamicElementCount(C.getState(), MR, C.getSValBuilder(), ElementTy);
+ DefinedOrUnknownSVal ElementCount = getDynamicElementCountWithOffset(
+ C.getState(), C.getSVal(getArgExpr(CE, C)), ElementTy);
printAndReport(C, ElementCount);
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
index 6275e49e51ae..2ee201b64008 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp
@@ -24,7 +24,7 @@ using namespace ento;
namespace {
class FixedAddressChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -49,14 +49,13 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
return;
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+ // FIXME: improve grammar in the following strings:
if (!BT)
- BT.reset(
- new BuiltinBug(this, "Use fixed address",
- "Using a fixed address is not portable because that "
- "address will probably not be valid in all "
- "environments or platforms."));
- auto R =
- std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+ BT.reset(new BugType(this, "Use fixed address"));
+ constexpr llvm::StringLiteral Msg =
+ "Using a fixed address is not portable because that address will "
+ "probably not be valid in all environments or platforms.";
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
R->addRange(B->getRHS()->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
index 38b4caa12aef..079bc61a87d9 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp
@@ -381,7 +381,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
- if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
+ if (PathBR->getInterestingnessKind(RetSym)) {
std::string SBuf;
llvm::raw_string_ostream OS(SBuf);
OS << "Function '" << FuncDecl->getDeclName()
@@ -397,7 +397,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
SymbolRef RetSym = Call.getReturnValue().getAsSymbol();
Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string {
auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
- if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) {
+ if (PathBR->getInterestingnessKind(RetSym)) {
std::string SBuf;
llvm::raw_string_ostream OS(SBuf);
OS << "Function '" << FuncDecl->getDeclName()
@@ -431,7 +431,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
} else {
Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
- if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
+ if (PathBR->getInterestingnessKind(Handle)) {
std::string SBuf;
llvm::raw_string_ostream OS(SBuf);
OS << "Handle released through " << ParamDiagIdx
@@ -445,7 +445,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
} else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) {
Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
- if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
+ if (PathBR->getInterestingnessKind(Handle)) {
std::string SBuf;
llvm::raw_string_ostream OS(SBuf);
OS << "Handle allocated through " << ParamDiagIdx
@@ -459,7 +459,7 @@ void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call,
} else if (hasFuchsiaUnownedAttr<AcquireHandleAttr>(PVD)) {
Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string {
auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR);
- if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) {
+ if (PathBR->getInterestingnessKind(Handle)) {
std::string SBuf;
llvm::raw_string_ostream OS(SBuf);
OS << "Unowned handle allocated through " << ParamDiagIdx
@@ -653,10 +653,11 @@ void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode,
if (Type.isSuppressOnSink()) {
const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C);
if (AcquireNode) {
+ const Stmt *S = AcquireNode->getStmtForDiagnostics();
+ assert(S && "Statement cannot be null.");
PathDiagnosticLocation LocUsedForUniqueing =
PathDiagnosticLocation::createBegin(
- AcquireNode->getStmtForDiagnostics(), C.getSourceManager(),
- AcquireNode->getLocationContext());
+ S, C.getSourceManager(), AcquireNode->getLocationContext());
R = std::make_unique<PathSensitiveBugReport>(
Type, Msg, ErrorNode, LocUsedForUniqueing,
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
index 8e02ef74c668..5637941a58f0 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GCDAntipatternChecker.cpp
@@ -73,7 +73,7 @@ decltype(auto) bindAssignmentToDecl(const char *DeclName) {
static bool isTest(const Decl *D) {
if (const auto* ND = dyn_cast<NamedDecl>(D)) {
std::string DeclName = ND->getNameAsString();
- if (StringRef(DeclName).startswith("test"))
+ if (StringRef(DeclName).starts_with("test"))
return true;
}
if (const auto *OD = dyn_cast<ObjCMethodDecl>(D)) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
index 43d2eeeb4b27..6c32a8dec844 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GTestChecker.cpp
@@ -92,11 +92,11 @@ using namespace ento;
namespace {
class GTestChecker : public Checker<check::PostCall> {
- mutable IdentifierInfo *AssertionResultII;
- mutable IdentifierInfo *SuccessII;
+ mutable IdentifierInfo *AssertionResultII = nullptr;
+ mutable IdentifierInfo *SuccessII = nullptr;
public:
- GTestChecker();
+ GTestChecker() = default;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
@@ -120,8 +120,6 @@ private:
};
} // End anonymous namespace.
-GTestChecker::GTestChecker() : AssertionResultII(nullptr), SuccessII(nullptr) {}
-
/// Model a call to an un-inlined AssertionResult(bool) or
/// AssertionResult(bool &, ...).
/// To do so, constrain the value of the newly-constructed instance's 'success_'
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
index 3dcb45c0b110..4ceaf933d0bf 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -104,8 +104,7 @@ bool isStdin(SVal Val, const ASTContext &ACtx) {
// variable named stdin with the proper type.
if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
D = D->getCanonicalDecl();
- // FIXME: This should look for an exact match.
- if (D->getName().contains("stdin") && D->isExternC()) {
+ if (D->getName() == "stdin" && D->hasExternalStorage() && D->isExternC()) {
const QualType FILETy = ACtx.getFILEType().getCanonicalType();
const QualType Ty = D->getType().getCanonicalType();
@@ -622,12 +621,14 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"getlogin_r"}}, TR::Source({{0}})},
// Props
+ {{{"accept"}}, TR::Prop({{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}})},
+ {{{"fgetws"}}, TR::Prop({{2}}, {{0, ReturnValueIndex}})},
{{{"fscanf"}}, TR::Prop({{0}}, {{}, 2})},
{{{"fscanf_s"}}, TR::Prop({{0}}, {{}, {2}})},
{{{"sscanf"}}, TR::Prop({{0}}, {{}, 2})},
@@ -694,8 +695,10 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
{{{"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}})},
+
+ // strlen, wcslen, strnlen and alike intentionally don't propagate taint.
+ // See the details here: https://github.com/llvm/llvm-project/pull/66086
+
{{{"strtol"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
{{{"strtoll"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
{{{"strtoul"}}, TR::Prop({{0}}, {{1, ReturnValueIndex}})},
@@ -731,6 +734,8 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strcat"}}},
TR::Prop({{1}}, {{0, ReturnValueIndex}})},
+ {{CDF_MaybeBuiltin, {{"wcsncat"}}},
+ TR::Prop({{1}}, {{0, ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdup"}}}, TR::Prop({{0}}, {{ReturnValueIndex}})},
{{CDF_MaybeBuiltin, {{"strdupa"}}},
TR::Prop({{0}}, {{ReturnValueIndex}})},
@@ -739,12 +744,14 @@ void GenericTaintChecker::initTaintRules(CheckerContext &C) const {
// 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)},
+ {{{"execl"}}, TR::Sink({{}, {0}}, MsgSanitizeSystemArgs)},
+ {{{"execle"}}, TR::Sink({{}, {0}}, MsgSanitizeSystemArgs)},
+ {{{"execlp"}}, TR::Sink({{}, {0}}, MsgSanitizeSystemArgs)},
+ {{{"execv"}}, TR::Sink({{0, 1}}, MsgSanitizeSystemArgs)},
+ {{{"execve"}}, TR::Sink({{0, 1, 2}}, MsgSanitizeSystemArgs)},
+ {{{"fexecve"}}, TR::Sink({{0, 1, 2}}, MsgSanitizeSystemArgs)},
+ {{{"execvp"}}, TR::Sink({{0, 1}}, MsgSanitizeSystemArgs)},
+ {{{"execvpe"}}, TR::Sink({{0, 1, 2}}, MsgSanitizeSystemArgs)},
{{{"dlopen"}}, TR::Sink({{0}}, MsgSanitizeSystemArgs)},
{{CDF_MaybeBuiltin, {{"malloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
{{CDF_MaybeBuiltin, {{"calloc"}}}, TR::Sink({{0}}, MsgTaintedBufferSize)},
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
index c682449921ac..7740c3d4da1e 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp
@@ -228,7 +228,7 @@ void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C,
Value = State->getRawSVal(*ValAsLoc);
}
- if (Value.isUnknownOrUndef())
+ if (Value.isUnknownOrUndef() || !isa<NonLoc>(Value))
return;
// Incremention or decremention by 0 is never a bug.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
index 3496af731aa6..f0276a57bdf9 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp
@@ -64,12 +64,12 @@ class IvarInvalidationCheckerImpl {
struct InvalidationInfo {
/// Has the ivar been invalidated?
- bool IsInvalidated;
+ bool IsInvalidated = false;
/// The methods which can be used to invalidate the ivar.
MethodSet InvalidationMethods;
- InvalidationInfo() : IsInvalidated(false) {}
+ InvalidationInfo() = default;
void addInvalidationMethod(const ObjCMethodDecl *MD) {
InvalidationMethods.insert(MD);
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
index b77e9bf09a33..70f911fc66ab 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp
@@ -817,9 +817,9 @@ void NonLocalizedStringChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
// Handle the case where the receiver is an NSString
// These special NSString methods draw to the screen
- if (!(SelectorName.startswith("drawAtPoint") ||
- SelectorName.startswith("drawInRect") ||
- SelectorName.startswith("drawWithRect")))
+ if (!(SelectorName.starts_with("drawAtPoint") ||
+ SelectorName.starts_with("drawInRect") ||
+ SelectorName.starts_with("drawWithRect")))
return;
SVal svTitle = msg.getReceiverSVal();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index d2b564d022b5..79ab05f2c786 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1141,22 +1141,28 @@ MallocChecker::performKernelMalloc(const CallEvent &Call, CheckerContext &C,
llvm::Triple::OSType OS = Ctx.getTargetInfo().getTriple().getOS();
if (!KernelZeroFlagVal) {
- if (OS == llvm::Triple::FreeBSD)
+ switch (OS) {
+ case llvm::Triple::FreeBSD:
KernelZeroFlagVal = 0x0100;
- else if (OS == llvm::Triple::NetBSD)
+ break;
+ case llvm::Triple::NetBSD:
KernelZeroFlagVal = 0x0002;
- else if (OS == llvm::Triple::OpenBSD)
+ break;
+ case llvm::Triple::OpenBSD:
KernelZeroFlagVal = 0x0008;
- else if (OS == llvm::Triple::Linux)
+ break;
+ case llvm::Triple::Linux:
// __GFP_ZERO
KernelZeroFlagVal = 0x8000;
- else
+ break;
+ default:
// FIXME: We need a more general way of getting the M_ZERO value.
// See also: O_CREAT in UnixAPIChecker.cpp.
// Fall back to normal malloc behavior on platforms where we don't
// know M_ZERO.
return std::nullopt;
+ }
}
// We treat the last argument as the flags argument, and callers fall-back to
@@ -1722,13 +1728,15 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
return nullptr;
// Bind the return value to the symbolic value from the heap region.
- // TODO: We could rewrite post visit to eval call; 'malloc' does not have
- // side effects other than what we model here.
+ // TODO: move use of this functions to an EvalCall callback, becasue
+ // BindExpr() should'nt be used elsewhere.
unsigned Count = C.blockCount();
- SValBuilder &svalBuilder = C.getSValBuilder();
+ SValBuilder &SVB = C.getSValBuilder();
const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
- DefinedSVal RetVal = svalBuilder.getConjuredHeapSymbolVal(CE, LCtx, Count)
- .castAs<DefinedSVal>();
+ DefinedSVal RetVal =
+ ((Family == AF_Alloca) ? SVB.getAllocaRegionVal(CE, LCtx, Count)
+ : SVB.getConjuredHeapSymbolVal(CE, LCtx, Count)
+ .castAs<DefinedSVal>());
State = State->BindExpr(CE, C.getLocationContext(), RetVal);
// Fill the region with the initialization value.
@@ -1740,7 +1748,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C,
// Set the region's extent.
State = setDynamicExtent(State, RetVal.getAsRegion(),
- Size.castAs<DefinedOrUnknownSVal>(), svalBuilder);
+ Size.castAs<DefinedOrUnknownSVal>(), SVB);
return MallocUpdateRefState(C, CE, State, Family);
}
@@ -1955,13 +1963,10 @@ ProgramStateRef MallocChecker::FreeMemAux(
// Parameters, locals, statics, globals, and memory returned by
// __builtin_alloca() shouldn't be freed.
if (!isa<UnknownSpaceRegion, HeapSpaceRegion>(MS)) {
- // FIXME: at the time this code was written, malloc() regions were
- // represented by conjured symbols, which are all in UnknownSpaceRegion.
- // This means that there isn't actually anything from HeapSpaceRegion
- // that should be freed, even though we allow it here.
- // Of course, free() can work on memory allocated outside the current
- // function, so UnknownSpaceRegion is always a possibility.
- // False negatives are better than false positives.
+ // Regions returned by malloc() are represented by SymbolicRegion objects
+ // within HeapSpaceRegion. Of course, free() can work on memory allocated
+ // outside the current function, so UnknownSpaceRegion is also a
+ // possibility here.
if (isa<AllocaRegion>(R))
HandleFreeAlloca(C, ArgVal, ArgExpr->getSourceRange());
@@ -3145,16 +3150,16 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// transferred. Again, though, we can't be sure that the object will use
// free() to deallocate the memory, so we can't model it explicitly.
StringRef FirstSlot = Msg->getSelector().getNameForSlot(0);
- if (FirstSlot.endswith("NoCopy"))
+ if (FirstSlot.ends_with("NoCopy"))
return true;
// If the first selector starts with addPointer, insertPointer,
// or replacePointer, assume we are dealing with NSPointerArray or similar.
// This is similar to C++ containers (vector); we still might want to check
// that the pointers get freed by following the container itself.
- if (FirstSlot.startswith("addPointer") ||
- FirstSlot.startswith("insertPointer") ||
- FirstSlot.startswith("replacePointer") ||
+ if (FirstSlot.starts_with("addPointer") ||
+ FirstSlot.starts_with("insertPointer") ||
+ FirstSlot.starts_with("replacePointer") ||
FirstSlot.equals("valueWithPointer")) {
return true;
}
@@ -3194,7 +3199,7 @@ bool MallocChecker::mayFreeAnyEscapedMemoryOrIsModeledExplicitly(
// White list the 'XXXNoCopy' CoreFoundation functions.
// We specifically check these before
- if (FName.endswith("NoCopy")) {
+ if (FName.ends_with("NoCopy")) {
// Look for the deallocator argument. We know that the memory ownership
// is not transferred only if the deallocator argument is
// 'kCFAllocatorNull'.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
index 0b3d635a50a3..8fc44e78be6f 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp
@@ -48,8 +48,10 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
if (matchesAny(Call, MmapFn, MprotectFn)) {
SVal ProtVal = Call.getArgSVal(2);
- auto ProtLoc = ProtVal.castAs<nonloc::ConcreteInt>();
- int64_t Prot = ProtLoc.getValue().getSExtValue();
+ auto ProtLoc = ProtVal.getAs<nonloc::ConcreteInt>();
+ if (!ProtLoc)
+ return;
+ int64_t Prot = ProtLoc->getValue().getSExtValue();
if (ProtExecOv != ProtExec)
ProtExec = ProtExecOv;
if (ProtReadOv != ProtRead)
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
index 59741dde1eea..54870bcb4bb2 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp
@@ -39,10 +39,10 @@ static bool IsCFError(QualType T, IdentifierInfo *II);
namespace {
class NSErrorMethodChecker
: public Checker< check::ASTDecl<ObjCMethodDecl> > {
- mutable IdentifierInfo *II;
+ mutable IdentifierInfo *II = nullptr;
public:
- NSErrorMethodChecker() : II(nullptr) {}
+ NSErrorMethodChecker() = default;
void checkASTDecl(const ObjCMethodDecl *D,
AnalysisManager &mgr, BugReporter &BR) const;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
index fd47e19cb786..44b69ef31911 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NonNullParamChecker.cpp
@@ -303,7 +303,7 @@ std::unique_ptr<PathSensitiveBugReport>
NonNullParamChecker::genReportReferenceToNullPointer(
const ExplodedNode *ErrorNode, const Expr *ArgE) const {
if (!BTNullRefArg)
- BTNullRefArg.reset(new BuiltinBug(this, "Dereference of null pointer"));
+ BTNullRefArg.reset(new BugType(this, "Dereference of null pointer"));
auto R = std::make_unique<PathSensitiveBugReport>(
*BTNullRefArg, "Forming reference to null pointer", ErrorNode);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
index 906f4e85a8e5..06f1ad00eaf2 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp
@@ -890,7 +890,7 @@ void NullabilityChecker::checkPostCall(const CallEvent &Call,
// of CG calls.
const SourceManager &SM = C.getSourceManager();
StringRef FilePath = SM.getFilename(SM.getSpellingLoc(Decl->getBeginLoc()));
- if (llvm::sys::path::filename(FilePath).startswith("CG")) {
+ if (llvm::sys::path::filename(FilePath).starts_with("CG")) {
State = State->set<NullabilityMap>(Region, Nullability::Contradicted);
C.addTransition(State);
return;
@@ -899,6 +899,14 @@ void NullabilityChecker::checkPostCall(const CallEvent &Call,
const NullabilityState *TrackedNullability =
State->get<NullabilityMap>(Region);
+ // ObjCMessageExpr gets the actual type through
+ // Sema::getMessageSendResultType, instead of using the return type of
+ // MethodDecl directly. The final type is generated by considering the
+ // nullability of receiver and MethodDecl together. Thus, The type of
+ // ObjCMessageExpr is prefer.
+ if (const Expr *E = Call.getOriginExpr())
+ ReturnType = E->getType();
+
if (!TrackedNullability &&
getNullabilityAnnotation(ReturnType) == Nullability::Nullable) {
State = State->set<NullabilityMap>(Region, Nullability::Nullable);
@@ -984,7 +992,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
// In order to reduce the noise in the diagnostics generated by this checker,
// some framework and programming style based heuristics are used. These
// heuristics are for Cocoa APIs which have NS prefix.
- if (Name.startswith("NS")) {
+ if (Name.starts_with("NS")) {
// Developers rely on dynamic invariants such as an item should be available
// in a collection, or a collection is not empty often. Those invariants can
// not be inferred by any static analysis tool. To not to bother the users
@@ -1053,7 +1061,7 @@ void NullabilityChecker::checkPostObjCMessage(const ObjCMethodCall &M,
}
// No tracked information. Use static type information for return value.
- Nullability RetNullability = getNullabilityAnnotation(RetType);
+ Nullability RetNullability = getNullabilityAnnotation(Message->getType());
// Properties might be computed, which means the property value could
// theoretically change between calls even in commonly-observed cases like
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
index a6383009e1fe..7906b787cd53 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp
@@ -25,8 +25,8 @@ using namespace ento;
namespace {
class ObjCAtSyncChecker
: public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
- mutable std::unique_ptr<BuiltinBug> BT_null;
- mutable std::unique_ptr<BuiltinBug> BT_undef;
+ mutable std::unique_ptr<BugType> BT_null;
+ mutable std::unique_ptr<BugType> BT_undef;
public:
void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
@@ -44,8 +44,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
if (isa<UndefinedVal>(V)) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_undef)
- BT_undef.reset(new BuiltinBug(this, "Uninitialized value used as mutex "
- "for @synchronized"));
+ BT_undef.reset(new BugType(this, "Uninitialized value used as mutex "
+ "for @synchronized"));
auto report = std::make_unique<PathSensitiveBugReport>(
*BT_undef, BT_undef->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
@@ -67,9 +67,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) {
if (!BT_null)
- BT_null.reset(new BuiltinBug(
- this, "Nil value used as mutex for @synchronized() "
- "(no synchronization will occur)"));
+ BT_null.reset(
+ new BugType(this, "Nil value used as mutex for @synchronized() "
+ "(no synchronization will occur)"));
auto report = std::make_unique<PathSensitiveBugReport>(
*BT_null, BT_null->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
index fbbc32a40e89..598b368e74d4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp
@@ -64,7 +64,7 @@ private:
class ObjCSuperCallChecker : public Checker<
check::ASTDecl<ObjCImplementationDecl> > {
public:
- ObjCSuperCallChecker() : IsInitialized(false) {}
+ ObjCSuperCallChecker() = default;
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr,
BugReporter &BR) const;
@@ -75,7 +75,7 @@ private:
void fillSelectors(ASTContext &Ctx, ArrayRef<SelectorDescriptor> Sel,
StringRef ClassName) const;
mutable llvm::StringMap<llvm::SmallPtrSet<Selector, 16>> SelectorsForClass;
- mutable bool IsInitialized;
+ mutable bool IsInitialized = false;
};
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
index 4636fd160511..08ad6877cbe6 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ObjCPropertyChecker.cpp
@@ -50,7 +50,7 @@ void ObjCPropertyChecker::checkCopyMutable(const ObjCPropertyDecl *D,
const std::string &PropTypeName(T->getPointeeType().getCanonicalType()
.getUnqualifiedType()
.getAsString());
- if (!StringRef(PropTypeName).startswith("NSMutable"))
+ if (!StringRef(PropTypeName).starts_with("NSMutable"))
return;
const ObjCImplDecl *ImplD = nullptr;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
index 27364eb72523..1d63c0dd01f3 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp
@@ -11,13 +11,14 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprCXX.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/StringRef.h"
using namespace clang;
using namespace ento;
@@ -55,8 +56,8 @@ class PointerArithChecker
bool PointedNeeded = false) const;
void initAllocIdentifiers(ASTContext &C) const;
- mutable std::unique_ptr<BuiltinBug> BT_pointerArith;
- mutable std::unique_ptr<BuiltinBug> BT_polyArray;
+ mutable std::unique_ptr<BugType> BT_pointerArith;
+ mutable std::unique_ptr<BugType> BT_polyArray;
mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
public:
@@ -168,12 +169,11 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
return;
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_polyArray)
- BT_polyArray.reset(new BuiltinBug(
- this, "Dangerous pointer arithmetic",
- "Pointer arithmetic on a pointer to base class is dangerous "
- "because derived and base class may have different size."));
- auto R = std::make_unique<PathSensitiveBugReport>(
- *BT_polyArray, BT_polyArray->getDescription(), N);
+ BT_polyArray.reset(new BugType(this, "Dangerous pointer arithmetic"));
+ constexpr llvm::StringLiteral Msg =
+ "Pointer arithmetic on a pointer to base class is dangerous "
+ "because derived and base class may have different size.";
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_polyArray, Msg, N);
R->addRange(E->getSourceRange());
R->markInteresting(ArrayRegion);
C.emitReport(std::move(R));
@@ -191,12 +191,11 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_pointerArith)
- BT_pointerArith.reset(new BuiltinBug(this, "Dangerous pointer arithmetic",
- "Pointer arithmetic on non-array "
- "variables relies on memory layout, "
- "which is dangerous."));
- auto R = std::make_unique<PathSensitiveBugReport>(
- *BT_pointerArith, BT_pointerArith->getDescription(), N);
+ BT_pointerArith.reset(new BugType(this, "Dangerous pointer arithmetic"));
+ constexpr llvm::StringLiteral Msg =
+ "Pointer arithmetic on non-array variables relies on memory layout, "
+ "which is dangerous.";
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT_pointerArith, Msg, N);
R->addRange(SR);
R->markInteresting(Region);
C.emitReport(std::move(R));
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index 81c19d9a0940..96d38eef3c03 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.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 "llvm/ADT/StringRef.h"
using namespace clang;
using namespace ento;
@@ -24,7 +25,7 @@ using namespace ento;
namespace {
class PointerSubChecker
: public Checker< check::PreStmt<BinaryOperator> > {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@@ -59,12 +60,11 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
- BT.reset(
- new BuiltinBug(this, "Pointer subtraction",
- "Subtraction of two pointers that do not point to "
- "the same memory chunk may cause incorrect result."));
- auto R =
- std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+ BT.reset(new BugType(this, "Pointer subtraction"));
+ constexpr llvm::StringLiteral Msg =
+ "Subtraction of two pointers that do not point to the same memory "
+ "chunk may cause incorrect result.";
+ auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
R->addRange(B->getSourceRange());
C.emitReport(std::move(R));
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
index 223e28c2c5b8..d4d7c4c74c56 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountChecker.h
@@ -36,7 +36,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/ImmutableList.h"
-#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
index 379163e12787..c3acb73ba717 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp
@@ -786,9 +786,6 @@ RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
assert(RV);
if (RV->getKind() == RefVal::ErrorLeakReturned) {
- // FIXME: Per comments in rdar://6320065, "create" only applies to CF
- // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
- // to the caller for NS objects.
const Decl *D = &EndN->getCodeDecl();
os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
index b85d0adb8eaf..11dca1ff8831 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp
@@ -26,7 +26,7 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
public Checker< check::PreStmt<ReturnStmt> > {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
@@ -79,14 +79,13 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
if (!BT)
- BT.reset(new BuiltinBug(
- this, "Buffer overflow",
- "Returned pointer value points outside the original object "
- "(potential buffer overflow)"));
+ BT.reset(new BugType(this, "Buffer overflow"));
+ constexpr llvm::StringLiteral Msg =
+ "Returned pointer value points outside the original object "
+ "(potential buffer overflow)";
// Generate a report for this bug.
- auto Report =
- std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
Report->addRange(RetE->getSourceRange());
const auto ConcreteElementCount = ElementCount.getAs<nonloc::ConcreteInt>();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
index 5266cbf86b44..78cd0100bea4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp
@@ -24,8 +24,8 @@ using namespace ento;
namespace {
class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
- mutable std::unique_ptr<BuiltinBug> BT_Undef;
- mutable std::unique_ptr<BuiltinBug> BT_NullReference;
+ mutable std::unique_ptr<BugType> BT_Undef;
+ mutable std::unique_ptr<BugType> BT_NullReference;
void emitUndef(CheckerContext &C, const Expr *RetE) const;
void checkReference(CheckerContext &C, const Expr *RetE,
@@ -77,14 +77,13 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
}
}
-static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
- const Expr *TrackingE = nullptr) {
+static void emitBug(CheckerContext &C, BugType &BT, StringRef Msg,
+ const Expr *RetE, const Expr *TrackingE = nullptr) {
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
- auto Report =
- std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
+ auto Report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
Report->addRange(RetE->getSourceRange());
bugreporter::trackExpressionValue(N, TrackingE ? TrackingE : RetE, *Report);
@@ -94,10 +93,8 @@ static void emitBug(CheckerContext &C, BuiltinBug &BT, const Expr *RetE,
void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
if (!BT_Undef)
- BT_Undef.reset(
- new BuiltinBug(this, "Garbage return value",
- "Undefined or garbage value returned to caller"));
- emitBug(C, *BT_Undef, RetE);
+ BT_Undef.reset(new BugType(this, "Garbage return value"));
+ emitBug(C, *BT_Undef, "Undefined or garbage value returned to caller", RetE);
}
void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
@@ -113,9 +110,10 @@ void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
// The return value is known to be null. Emit a bug report.
if (!BT_NullReference)
- BT_NullReference.reset(new BuiltinBug(this, "Returning null reference"));
+ BT_NullReference.reset(new BugType(this, "Returning null reference"));
- emitBug(C, *BT_NullReference, RetE, bugreporter::getDerefExpr(RetE));
+ emitBug(C, *BT_NullReference, BT_NullReference->getDescription(), RetE,
+ bugreporter::getDerefExpr(RetE));
}
void ento::registerReturnUndefChecker(CheckerManager &mgr) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
index 32d95e944195..2ac9f65c9793 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp
+++ b/contrib/llvm-project/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"}, 2), CloseFn({"fclose"}, 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
index a20d24db158f..268fc742f050 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/SmartPtrModeling.cpp
@@ -32,7 +32,6 @@
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringMap.h"
#include "llvm/Support/ErrorHandling.h"
#include <optional>
#include <string>
@@ -202,7 +201,7 @@ static QualType getInnerPointerType(CheckerContext C, const CXXRecordDecl *RD) {
static QualType getPointerTypeFromTemplateArg(const CallEvent &Call,
CheckerContext &C) {
const auto *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
- if (!FD || !FD->isFunctionTemplateSpecialization())
+ if (!FD || !FD->getPrimaryTemplate())
return {};
const auto &TemplateArgs = FD->getTemplateSpecializationArgs()->asArray();
if (TemplateArgs.size() == 0)
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
index abf9914f2ca4..ea09c43cc5ce 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp
@@ -30,10 +30,10 @@ class StackAddrEscapeChecker
: public Checker<check::PreCall, check::PreStmt<ReturnStmt>,
check::EndFunction> {
mutable IdentifierInfo *dispatch_semaphore_tII = nullptr;
- mutable std::unique_ptr<BuiltinBug> BT_stackleak;
- mutable std::unique_ptr<BuiltinBug> BT_returnstack;
- mutable std::unique_ptr<BuiltinBug> BT_capturedstackasync;
- mutable std::unique_ptr<BuiltinBug> BT_capturedstackret;
+ mutable std::unique_ptr<BugType> BT_stackleak;
+ mutable std::unique_ptr<BugType> BT_returnstack;
+ mutable std::unique_ptr<BugType> BT_capturedstackasync;
+ mutable std::unique_ptr<BugType> BT_capturedstackret;
public:
enum CheckKind {
@@ -154,7 +154,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C,
if (!N)
return;
if (!BT_returnstack)
- BT_returnstack = std::make_unique<BuiltinBug>(
+ BT_returnstack = std::make_unique<BugType>(
CheckNames[CK_StackAddrEscapeChecker],
"Return of address to stack-allocated memory");
// Generate a report for this bug.
@@ -194,7 +194,7 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
if (!N)
continue;
if (!BT_capturedstackasync)
- BT_capturedstackasync = std::make_unique<BuiltinBug>(
+ BT_capturedstackasync = std::make_unique<BugType>(
CheckNames[CK_StackAddrAsyncEscapeChecker],
"Address of stack-allocated memory is captured");
SmallString<128> Buf;
@@ -218,7 +218,7 @@ void StackAddrEscapeChecker::checkReturnedBlockCaptures(
if (!N)
continue;
if (!BT_capturedstackret)
- BT_capturedstackret = std::make_unique<BuiltinBug>(
+ BT_capturedstackret = std::make_unique<BugType>(
CheckNames[CK_StackAddrEscapeChecker],
"Address of stack-allocated memory is captured");
SmallString<128> Buf;
@@ -364,15 +364,12 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
return;
if (!BT_stackleak)
- BT_stackleak = std::make_unique<BuiltinBug>(
- CheckNames[CK_StackAddrEscapeChecker],
- "Stack address stored into global variable",
- "Stack address was saved into a global variable. "
- "This is dangerous because the address will become "
- "invalid after returning from the function");
+ BT_stackleak =
+ std::make_unique<BugType>(CheckNames[CK_StackAddrEscapeChecker],
+ "Stack address stored into global variable");
for (const auto &P : Cb.V) {
- const MemRegion *Referrer = P.first;
+ const MemRegion *Referrer = P.first->getBaseRegion();
const MemRegion *Referred = P.second;
// Generate a report for this bug.
@@ -387,6 +384,8 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
<< CommonSuffix;
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT_stackleak, Out.str(), N);
+ if (Range.isValid())
+ Report->addRange(Range);
Ctx.emitReport(std::move(Report));
return;
}
@@ -400,8 +399,14 @@ void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
return "stack";
}(Referrer->getMemorySpace());
- // This cast supposed to succeed.
- const VarRegion *ReferrerVar = cast<VarRegion>(Referrer->getBaseRegion());
+ // We should really only have VarRegions here.
+ // Anything else is really surprising, and we should get notified if such
+ // ever happens.
+ const auto *ReferrerVar = dyn_cast<VarRegion>(Referrer);
+ if (!ReferrerVar) {
+ assert(false && "We should have a VarRegion here");
+ continue; // Defensively skip this one.
+ }
const std::string ReferrerVarName =
ReferrerVar->getDecl()->getDeclName().getAsString();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
index d18e6f63df44..fffcaf7ed18f 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdLibraryFunctionsChecker.cpp
@@ -533,13 +533,11 @@ class StdLibraryFunctionsChecker
virtual ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
const Summary &Summary,
CheckerContext &C) const = 0;
- /// 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;
- }
+ /// Get a description about what happens with 'errno' here and how it causes
+ /// a later bug report created by ErrnoChecker.
+ /// Empty return value means that 'errno' related bug may not happen from
+ /// the current analyzed function.
+ virtual const std::string describe(CheckerContext &C) const { return ""; }
virtual ~ErrnoConstraintBase() {}
@@ -596,7 +594,8 @@ class StdLibraryFunctionsChecker
};
/// Set errno constraint at success cases of standard functions.
- /// Success case: 'errno' is not allowed to be used.
+ /// Success case: 'errno' is not allowed to be used because the value is
+ /// undefined after successful call.
/// \c ErrnoChecker can emit bug report after such a function call if errno
/// is used.
class SuccessErrnoConstraint : public ErrnoConstraintBase {
@@ -607,12 +606,15 @@ class StdLibraryFunctionsChecker
return errno_modeling::setErrnoForStdSuccess(State, C);
}
- const NoteTag *describe(CheckerContext &C,
- StringRef FunctionName) const override {
- return errno_modeling::getNoteTagForStdSuccess(C, FunctionName);
+ const std::string describe(CheckerContext &C) const override {
+ return "'errno' becomes undefined after the call";
}
};
+ /// Set errno constraint at functions that indicate failure only with 'errno'.
+ /// In this case 'errno' is required to be observed.
+ /// \c ErrnoChecker can emit bug report after such a function call if errno
+ /// is overwritten without a read before.
class ErrnoMustBeCheckedConstraint : public ErrnoConstraintBase {
public:
ProgramStateRef apply(ProgramStateRef State, const CallEvent &Call,
@@ -622,9 +624,8 @@ class StdLibraryFunctionsChecker
Call.getOriginExpr());
}
- const NoteTag *describe(CheckerContext &C,
- StringRef FunctionName) const override {
- return errno_modeling::getNoteTagForStdMustBeChecked(C, FunctionName);
+ const std::string describe(CheckerContext &C) const override {
+ return "reading 'errno' is required to find out if the call has failed";
}
};
@@ -1387,22 +1388,33 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
if (!NewState)
continue;
- // It is possible that NewState == State is true.
- // It can occur if another checker has applied the state before us.
+ // Here it's possible that NewState == State, e.g. when other checkers
+ // already applied the same constraints (or stricter ones).
// Still add these note tags, the other checker should add only its
// specialized note tags. These general note tags are handled always by
// StdLibraryFunctionsChecker.
+
ExplodedNode *Pred = Node;
- if (!Case.getNote().empty()) {
- const SVal RV = Call.getReturnValue();
- // If there is a description for this execution branch (summary case),
- // use it as a note tag.
- std::string Note =
- llvm::formatv(Case.getNote().str().c_str(),
- cast<NamedDecl>(Call.getDecl())->getDeclName());
- if (Summary.getInvalidationKd() == EvalCallAsPure) {
+ DeclarationName FunctionName =
+ cast<NamedDecl>(Call.getDecl())->getDeclName();
+
+ std::string ErrnoNote = Case.getErrnoConstraint().describe(C);
+ std::string CaseNote;
+ if (Case.getNote().empty()) {
+ if (!ErrnoNote.empty())
+ ErrnoNote =
+ llvm::formatv("After calling '{0}' {1}", FunctionName, ErrnoNote);
+ } else {
+ CaseNote = llvm::formatv(Case.getNote().str().c_str(), FunctionName);
+ }
+ const SVal RV = Call.getReturnValue();
+
+ if (Summary.getInvalidationKd() == EvalCallAsPure) {
+ // Do not expect that errno is interesting (the "pure" functions do not
+ // affect it).
+ if (!CaseNote.empty()) {
const NoteTag *Tag = C.getNoteTag(
- [Node, Note, RV](PathSensitiveBugReport &BR) -> std::string {
+ [Node, CaseNote, RV](PathSensitiveBugReport &BR) -> std::string {
// Try to omit the note if we know in advance which branch is
// taken (this means, only one branch exists).
// This check is performed inside the lambda, after other
@@ -1414,32 +1426,42 @@ void StdLibraryFunctionsChecker::checkPostCall(const CallEvent &Call,
// the successors). This is why this check is only used in the
// EvalCallAsPure case.
if (BR.isInteresting(RV) && Node->succ_size() > 1)
- return Note;
+ return CaseNote;
return "";
});
Pred = C.addTransition(NewState, Pred, Tag);
- } else {
+ }
+ } else {
+ if (!CaseNote.empty() || !ErrnoNote.empty()) {
const NoteTag *Tag =
- C.getNoteTag([Note, RV](PathSensitiveBugReport &BR) -> std::string {
- if (BR.isInteresting(RV))
- return Note;
+ C.getNoteTag([CaseNote, ErrnoNote,
+ RV](PathSensitiveBugReport &BR) -> std::string {
+ // If 'errno' is interesting, show the user a note about the case
+ // (what happened at the function call) and about how 'errno'
+ // causes the problem. ErrnoChecker sets the errno (but not RV) to
+ // interesting.
+ // If only the return value is interesting, show only the case
+ // note.
+ std::optional<Loc> ErrnoLoc =
+ errno_modeling::getErrnoLoc(BR.getErrorNode()->getState());
+ bool ErrnoImportant = !ErrnoNote.empty() && ErrnoLoc &&
+ BR.isInteresting(ErrnoLoc->getAsRegion());
+ if (ErrnoImportant) {
+ BR.markNotInteresting(ErrnoLoc->getAsRegion());
+ if (CaseNote.empty())
+ return ErrnoNote;
+ return llvm::formatv("{0}; {1}", CaseNote, ErrnoNote);
+ } else {
+ if (BR.isInteresting(RV))
+ return CaseNote;
+ }
return "";
});
Pred = C.addTransition(NewState, Pred, Tag);
}
- if (!Pred)
- continue;
}
- // If we can get a note tag for the errno change, add this additionally to
- // the previous. This note is only about value of 'errno' and is displayed
- // if 'errno' is interesting.
- if (const auto *D = dyn_cast<FunctionDecl>(Call.getDecl()))
- if (const NoteTag *NT =
- Case.getErrnoConstraint().describe(C, D->getNameAsString()))
- Pred = C.addTransition(NewState, Pred, NT);
-
- // Add the transition if no note tag could be added.
+ // Add the transition if no note tag was added.
if (Pred == Node && NewState != State)
C.addTransition(NewState);
}
@@ -2033,7 +2055,8 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case({ArgumentCondition(1U, WithinRange, SingleValue(0)),
ReturnValueCondition(WithinRange, SingleValue(0))},
- ErrnoMustNotBeChecked, GenericSuccessMsg)
+ ErrnoMustNotBeChecked,
+ "Assuming that argument 'size' to '{0}' is 0")
.ArgConstraint(NotNullBuffer(ArgNo(0), ArgNo(1), ArgNo(2)))
.ArgConstraint(NotNull(ArgNo(3)))
.ArgConstraint(BufferSize(/*Buffer=*/ArgNo(0), /*BufSize=*/ArgNo(1),
@@ -2860,9 +2883,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
Signature(ArgTypes{ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
RetType{Ssize_tTy}),
Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ .Case({ArgumentCondition(2, WithinRange, Range(1, IntMax)),
+ ReturnValueCondition(LessThanOrEq, ArgNo(2)),
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ArgumentCondition(2, WithinRange, SingleValue(0)),
+ ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoMustNotBeChecked,
+ "Assuming that argument 'bufsize' is 0")
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(NotNull(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
@@ -2879,9 +2907,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
ArgTypes{IntTy, ConstCharPtrRestrictTy, CharPtrRestrictTy, SizeTy},
RetType{Ssize_tTy}),
Summary(NoEvalCall)
- .Case({ReturnValueCondition(LessThanOrEq, ArgNo(3)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ .Case({ArgumentCondition(3, WithinRange, Range(1, IntMax)),
+ ReturnValueCondition(LessThanOrEq, ArgNo(3)),
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ArgumentCondition(3, WithinRange, SingleValue(0)),
+ ReturnValueCondition(WithinRange, SingleValue(0))},
+ ErrnoMustNotBeChecked,
+ "Assuming that argument 'bufsize' is 0")
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(ValidFileDescriptorOrAtFdcwd(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1)))
@@ -3096,7 +3129,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto Recvfrom =
Summary(NoEvalCall)
.Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
+ ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
+ ArgumentCondition(2, WithinRange, SingleValue(0))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
@@ -3123,7 +3159,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
auto Sendto =
Summary(NoEvalCall)
.Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
+ ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
+ ArgumentCondition(2, WithinRange, SingleValue(0))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
@@ -3161,7 +3200,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
RetType{Ssize_tTy}),
Summary(NoEvalCall)
.Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
+ ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
+ ArgumentCondition(2, WithinRange, SingleValue(0))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
@@ -3179,7 +3221,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
Signature(ArgTypes{IntTy, StructMsghdrPtrTy, IntTy},
RetType{Ssize_tTy}),
Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(
@@ -3191,7 +3233,7 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
Signature(ArgTypes{IntTy, ConstStructMsghdrPtrTy, IntTy},
RetType{Ssize_tTy}),
Summary(NoEvalCall)
- .Case({ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ .Case({ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(
@@ -3233,7 +3275,10 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
RetType{Ssize_tTy}),
Summary(NoEvalCall)
.Case({ReturnValueCondition(LessThanOrEq, ArgNo(2)),
- ReturnValueCondition(WithinRange, Range(0, Ssize_tMax))},
+ ReturnValueCondition(WithinRange, Range(1, Ssize_tMax))},
+ ErrnoMustNotBeChecked, GenericSuccessMsg)
+ .Case({ReturnValueCondition(WithinRange, SingleValue(0)),
+ ArgumentCondition(2, WithinRange, SingleValue(0))},
ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case(ReturnsMinusOne, ErrnoNEZeroIrrelevant, GenericFailureMsg)
.ArgConstraint(ArgumentCondition(0, WithinRange, Range(0, IntMax)))
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
new file mode 100644
index 000000000000..f7b7befe28ee
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StdVariantChecker.cpp
@@ -0,0 +1,298 @@
+//===- StdVariantChecker.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Type.h"
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include <optional>
+#include <string_view>
+
+#include "TaggedUnionModeling.h"
+
+using namespace clang;
+using namespace ento;
+using namespace tagged_union_modeling;
+
+REGISTER_MAP_WITH_PROGRAMSTATE(VariantHeldTypeMap, const MemRegion *, QualType)
+
+namespace clang::ento::tagged_union_modeling {
+
+const CXXConstructorDecl *
+getConstructorDeclarationForCall(const CallEvent &Call) {
+ const auto *ConstructorCall = dyn_cast<CXXConstructorCall>(&Call);
+ if (!ConstructorCall)
+ return nullptr;
+
+ return ConstructorCall->getDecl();
+}
+
+bool isCopyConstructorCall(const CallEvent &Call) {
+ if (const CXXConstructorDecl *ConstructorDecl =
+ getConstructorDeclarationForCall(Call))
+ return ConstructorDecl->isCopyConstructor();
+ return false;
+}
+
+bool isCopyAssignmentCall(const CallEvent &Call) {
+ const Decl *CopyAssignmentDecl = Call.getDecl();
+
+ if (const auto *AsMethodDecl =
+ dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl))
+ return AsMethodDecl->isCopyAssignmentOperator();
+ return false;
+}
+
+bool isMoveConstructorCall(const CallEvent &Call) {
+ const CXXConstructorDecl *ConstructorDecl =
+ getConstructorDeclarationForCall(Call);
+ if (!ConstructorDecl)
+ return false;
+
+ return ConstructorDecl->isMoveConstructor();
+}
+
+bool isMoveAssignmentCall(const CallEvent &Call) {
+ const Decl *CopyAssignmentDecl = Call.getDecl();
+
+ const auto *AsMethodDecl =
+ dyn_cast_or_null<CXXMethodDecl>(CopyAssignmentDecl);
+ if (!AsMethodDecl)
+ return false;
+
+ return AsMethodDecl->isMoveAssignmentOperator();
+}
+
+bool isStdType(const Type *Type, llvm::StringRef TypeName) {
+ auto *Decl = Type->getAsRecordDecl();
+ if (!Decl)
+ return false;
+ return (Decl->getName() == TypeName) && Decl->isInStdNamespace();
+}
+
+bool isStdVariant(const Type *Type) {
+ return isStdType(Type, llvm::StringLiteral("variant"));
+}
+
+} // end of namespace clang::ento::tagged_union_modeling
+
+static std::optional<ArrayRef<TemplateArgument>>
+getTemplateArgsFromVariant(const Type *VariantType) {
+ const auto *TempSpecType = VariantType->getAs<TemplateSpecializationType>();
+ if (!TempSpecType)
+ return {};
+
+ return TempSpecType->template_arguments();
+}
+
+static std::optional<QualType>
+getNthTemplateTypeArgFromVariant(const Type *varType, unsigned i) {
+ std::optional<ArrayRef<TemplateArgument>> VariantTemplates =
+ getTemplateArgsFromVariant(varType);
+ if (!VariantTemplates)
+ return {};
+
+ return (*VariantTemplates)[i].getAsType();
+}
+
+static bool isVowel(char a) {
+ switch (a) {
+ case 'a':
+ case 'e':
+ case 'i':
+ case 'o':
+ case 'u':
+ return true;
+ default:
+ return false;
+ }
+}
+
+static llvm::StringRef indefiniteArticleBasedOnVowel(char a) {
+ if (isVowel(a))
+ return "an";
+ return "a";
+}
+
+class StdVariantChecker : public Checker<eval::Call, check::RegionChanges> {
+ // Call descriptors to find relevant calls
+ CallDescription VariantConstructor{{"std", "variant", "variant"}};
+ CallDescription VariantAssignmentOperator{{"std", "variant", "operator="}};
+ CallDescription StdGet{{"std", "get"}, 1, 1};
+
+ BugType BadVariantType{this, "BadVariantType", "BadVariantType"};
+
+public:
+ ProgramStateRef checkRegionChanges(ProgramStateRef State,
+ const InvalidatedSymbols *,
+ ArrayRef<const MemRegion *>,
+ ArrayRef<const MemRegion *> Regions,
+ const LocationContext *,
+ const CallEvent *Call) const {
+ if (!Call)
+ return State;
+
+ return removeInformationStoredForDeadInstances<VariantHeldTypeMap>(
+ *Call, State, Regions);
+ }
+
+ bool evalCall(const CallEvent &Call, CheckerContext &C) const {
+ // Check if the call was not made from a system header. If it was then
+ // we do an early return because it is part of the implementation.
+ if (Call.isCalledFromSystemHeader())
+ return false;
+
+ if (StdGet.matches(Call))
+ return handleStdGetCall(Call, C);
+
+ // First check if a constructor call is happening. If it is a
+ // constructor call, check if it is an std::variant constructor call.
+ bool IsVariantConstructor =
+ isa<CXXConstructorCall>(Call) && VariantConstructor.matches(Call);
+ bool IsVariantAssignmentOperatorCall =
+ isa<CXXMemberOperatorCall>(Call) &&
+ VariantAssignmentOperator.matches(Call);
+
+ if (IsVariantConstructor || IsVariantAssignmentOperatorCall) {
+ if (Call.getNumArgs() == 0 && IsVariantConstructor) {
+ handleDefaultConstructor(cast<CXXConstructorCall>(&Call), C);
+ return true;
+ }
+
+ // FIXME Later this checker should be extended to handle constructors
+ // with multiple arguments.
+ if (Call.getNumArgs() != 1)
+ return false;
+
+ SVal ThisSVal;
+ if (IsVariantConstructor) {
+ const auto &AsConstructorCall = cast<CXXConstructorCall>(Call);
+ ThisSVal = AsConstructorCall.getCXXThisVal();
+ } else if (IsVariantAssignmentOperatorCall) {
+ const auto &AsMemberOpCall = cast<CXXMemberOperatorCall>(Call);
+ ThisSVal = AsMemberOpCall.getCXXThisVal();
+ } else {
+ return false;
+ }
+
+ handleConstructorAndAssignment<VariantHeldTypeMap>(Call, C, ThisSVal);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ // The default constructed std::variant must be handled separately
+ // by default the std::variant is going to hold a default constructed instance
+ // of the first type of the possible types
+ void handleDefaultConstructor(const CXXConstructorCall *ConstructorCall,
+ CheckerContext &C) const {
+ SVal ThisSVal = ConstructorCall->getCXXThisVal();
+
+ const auto *const ThisMemRegion = ThisSVal.getAsRegion();
+ if (!ThisMemRegion)
+ return;
+
+ std::optional<QualType> DefaultType = getNthTemplateTypeArgFromVariant(
+ ThisSVal.getType(C.getASTContext())->getPointeeType().getTypePtr(), 0);
+ if (!DefaultType)
+ return;
+
+ ProgramStateRef State = ConstructorCall->getState();
+ State = State->set<VariantHeldTypeMap>(ThisMemRegion, *DefaultType);
+ C.addTransition(State);
+ }
+
+ bool handleStdGetCall(const CallEvent &Call, CheckerContext &C) const {
+ ProgramStateRef State = Call.getState();
+
+ const auto &ArgType = Call.getArgSVal(0)
+ .getType(C.getASTContext())
+ ->getPointeeType()
+ .getTypePtr();
+ // We have to make sure that the argument is an std::variant.
+ // There is another std::get with std::pair argument
+ if (!isStdVariant(ArgType))
+ return false;
+
+ // Get the mem region of the argument std::variant and look up the type
+ // information that we know about it.
+ const MemRegion *ArgMemRegion = Call.getArgSVal(0).getAsRegion();
+ const QualType *StoredType = State->get<VariantHeldTypeMap>(ArgMemRegion);
+ if (!StoredType)
+ return false;
+
+ const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr());
+ const FunctionDecl *FD = CE->getDirectCallee();
+ if (FD->getTemplateSpecializationArgs()->size() < 1)
+ return false;
+
+ const auto &TypeOut = FD->getTemplateSpecializationArgs()->asArray()[0];
+ // std::get's first template parameter can be the type we want to get
+ // out of the std::variant or a natural number which is the position of
+ // the requested type in the argument type list of the std::variant's
+ // argument.
+ QualType RetrievedType;
+ switch (TypeOut.getKind()) {
+ case TemplateArgument::ArgKind::Type:
+ RetrievedType = TypeOut.getAsType();
+ break;
+ case TemplateArgument::ArgKind::Integral:
+ // In the natural number case we look up which type corresponds to the
+ // number.
+ if (std::optional<QualType> NthTemplate =
+ getNthTemplateTypeArgFromVariant(
+ ArgType, TypeOut.getAsIntegral().getSExtValue())) {
+ RetrievedType = *NthTemplate;
+ break;
+ }
+ [[fallthrough]];
+ default:
+ return false;
+ }
+
+ QualType RetrievedCanonicalType = RetrievedType.getCanonicalType();
+ QualType StoredCanonicalType = StoredType->getCanonicalType();
+ if (RetrievedCanonicalType == StoredCanonicalType)
+ return true;
+
+ ExplodedNode *ErrNode = C.generateNonFatalErrorNode();
+ if (!ErrNode)
+ return false;
+ llvm::SmallString<128> Str;
+ llvm::raw_svector_ostream OS(Str);
+ std::string StoredTypeName = StoredType->getAsString();
+ std::string RetrievedTypeName = RetrievedType.getAsString();
+ OS << "std::variant " << ArgMemRegion->getDescriptiveName() << " held "
+ << indefiniteArticleBasedOnVowel(StoredTypeName[0]) << " \'"
+ << StoredTypeName << "\', not "
+ << indefiniteArticleBasedOnVowel(RetrievedTypeName[0]) << " \'"
+ << RetrievedTypeName << "\'";
+ auto R = std::make_unique<PathSensitiveBugReport>(BadVariantType, OS.str(),
+ ErrNode);
+ C.emitReport(std::move(R));
+ return true;
+ }
+};
+
+bool clang::ento::shouldRegisterStdVariantChecker(
+ clang::ento::CheckerManager const &mgr) {
+ return true;
+}
+
+void clang::ento::registerStdVariantChecker(clang::ento::CheckerManager &mgr) {
+ mgr.registerChecker<StdVariantChecker>();
+} \ No newline at end of file
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
index bad86682c91e..925fc90e3554 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp
@@ -238,18 +238,30 @@ public:
private:
CallDescriptionMap<FnDescription> FnDescriptions = {
- {{{"fopen"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"fopen"}, 2}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
{{{"freopen"}, 3},
{&StreamChecker::preFreopen, &StreamChecker::evalFreopen, 2}},
- {{{"tmpfile"}}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
+ {{{"tmpfile"}, 0}, {nullptr, &StreamChecker::evalFopen, ArgNone}},
{{{"fclose"}, 1},
{&StreamChecker::preDefault, &StreamChecker::evalFclose, 0}},
{{{"fread"}, 4},
- {&StreamChecker::preFread,
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, true),
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, true), 3}},
{{{"fwrite"}, 4},
- {&StreamChecker::preFwrite,
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
std::bind(&StreamChecker::evalFreadFwrite, _1, _2, _3, _4, false), 3}},
+ {{{"fgetc"}, 1},
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, true),
+ std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, true), 0}},
+ {{{"fgets"}, 3},
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, true),
+ std::bind(&StreamChecker::evalFgetx, _1, _2, _3, _4, false), 2}},
+ {{{"fputc"}, 2},
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
+ std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, true), 1}},
+ {{{"fputs"}, 2},
+ {std::bind(&StreamChecker::preReadWrite, _1, _2, _3, _4, false),
+ std::bind(&StreamChecker::evalFputx, _1, _2, _3, _4, false), 1}},
{{{"fseek"}, 3},
{&StreamChecker::preFseek, &StreamChecker::evalFseek, 0}},
{{{"ftell"}, 1},
@@ -305,15 +317,18 @@ private:
void evalFclose(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
- void preFread(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const;
-
- void preFwrite(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const;
+ void preReadWrite(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C, bool IsRead) const;
void evalFreadFwrite(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C, bool IsFread) const;
+ void evalFgetx(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C, bool SingleChar) const;
+
+ void evalFputx(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C, bool IsSingleChar) const;
+
void preFseek(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const;
void evalFseek(const FnDescription *Desc, const CallEvent &Call,
@@ -407,23 +422,14 @@ private:
/// Generate a message for BugReporterVisitor if the stored symbol is
/// marked as interesting by the actual bug report.
- // FIXME: Use lambda instead.
- struct NoteFn {
- const BugType *BT_ResourceLeak;
- SymbolRef StreamSym;
- std::string Message;
-
- std::string operator()(PathSensitiveBugReport &BR) const {
- if (BR.isInteresting(StreamSym) && &BR.getBugType() == BT_ResourceLeak)
- return Message;
-
- return "";
- }
- };
-
const NoteTag *constructNoteTag(CheckerContext &C, SymbolRef StreamSym,
const std::string &Message) const {
- return C.getNoteTag(NoteFn{&BT_ResourceLeak, StreamSym, Message});
+ return C.getNoteTag([this, StreamSym,
+ Message](PathSensitiveBugReport &BR) -> std::string {
+ if (BR.isInteresting(StreamSym) && &BR.getBugType() == &BT_ResourceLeak)
+ return Message;
+ return "";
+ });
}
const NoteTag *constructSetEofNoteTag(CheckerContext &C,
@@ -646,8 +652,9 @@ void StreamChecker::evalFclose(const FnDescription *Desc, const CallEvent &Call,
C.addTransition(StateFailure);
}
-void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const {
+void StreamChecker::preReadWrite(const FnDescription *Desc,
+ const CallEvent &Call, CheckerContext &C,
+ bool IsRead) const {
ProgramStateRef State = C.getState();
SVal StreamVal = getStreamArg(Desc, Call);
State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
@@ -661,6 +668,11 @@ void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call,
if (!State)
return;
+ if (!IsRead) {
+ C.addTransition(State);
+ return;
+ }
+
SymbolRef Sym = StreamVal.getAsSymbol();
if (Sym && State->get<StreamMap>(Sym)) {
const StreamState *SS = State->get<StreamMap>(Sym);
@@ -671,24 +683,6 @@ void StreamChecker::preFread(const FnDescription *Desc, const CallEvent &Call,
}
}
-void StreamChecker::preFwrite(const FnDescription *Desc, const CallEvent &Call,
- CheckerContext &C) const {
- ProgramStateRef State = C.getState();
- SVal StreamVal = getStreamArg(Desc, Call);
- State = ensureStreamNonNull(StreamVal, Call.getArgExpr(Desc->StreamArgNo), C,
- State);
- if (!State)
- return;
- State = ensureStreamOpened(StreamVal, C, State);
- if (!State)
- return;
- State = ensureNoFilePositionIndeterminate(StreamVal, C, State);
- if (!State)
- return;
-
- C.addTransition(State);
-}
-
void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
const CallEvent &Call, CheckerContext &C,
bool IsFread) const {
@@ -743,9 +737,9 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
ProgramStateRef StateFailed =
State->BindExpr(CE, C.getLocationContext(), RetVal);
+ SValBuilder &SVB = C.getSValBuilder();
auto Cond =
- C.getSValBuilder()
- .evalBinOpNN(State, BO_LT, RetVal, *NMembVal, C.getASTContext().IntTy)
+ SVB.evalBinOpNN(State, BO_LT, RetVal, *NMembVal, SVB.getConditionType())
.getAs<DefinedOrUnknownSVal>();
if (!Cond)
return;
@@ -769,6 +763,150 @@ void StreamChecker::evalFreadFwrite(const FnDescription *Desc,
C.addTransition(StateFailed);
}
+void StreamChecker::evalFgetx(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C, bool SingleChar) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ const StreamState *OldSS = State->get<StreamMap>(StreamSym);
+ if (!OldSS)
+ return;
+
+ assertStreamStateOpened(OldSS);
+
+ // `fgetc` returns the read character on success, otherwise returns EOF.
+ // `fgets` returns the read buffer address on success, otherwise returns NULL.
+
+ if (OldSS->ErrorState != ErrorFEof) {
+ if (SingleChar) {
+ // Generate a transition for the success state of `fgetc`.
+ NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), RetVal);
+ SValBuilder &SVB = C.getSValBuilder();
+ ASTContext &ASTC = C.getASTContext();
+ // The returned 'unsigned char' of `fgetc` is converted to 'int',
+ // so we need to check if it is in range [0, 255].
+ auto CondLow =
+ SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(ASTC.IntTy),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+ auto CondHigh =
+ SVB.evalBinOp(State, BO_LE, RetVal,
+ SVB.makeIntVal(SVB.getBasicValueFactory()
+ .getMaxValue(ASTC.UnsignedCharTy)
+ .getLimitedValue(),
+ ASTC.IntTy),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+ if (!CondLow || !CondHigh)
+ return;
+ StateNotFailed = StateNotFailed->assume(*CondLow, true);
+ if (!StateNotFailed)
+ return;
+ StateNotFailed = StateNotFailed->assume(*CondHigh, true);
+ if (!StateNotFailed)
+ return;
+ C.addTransition(StateNotFailed);
+ } else {
+ // Generate a transition for the success state of `fgets`.
+ std::optional<DefinedSVal> GetBuf =
+ Call.getArgSVal(0).getAs<DefinedSVal>();
+ if (!GetBuf)
+ return;
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), *GetBuf);
+ StateNotFailed = StateNotFailed->set<StreamMap>(
+ StreamSym, StreamState::getOpened(Desc));
+ C.addTransition(StateNotFailed);
+ }
+ }
+
+ // Add transition for the failed state.
+ ProgramStateRef StateFailed;
+ if (SingleChar)
+ StateFailed = bindInt(*EofVal, State, C, CE);
+ else
+ StateFailed =
+ State->BindExpr(CE, C.getLocationContext(),
+ C.getSValBuilder().makeNullWithType(CE->getType()));
+
+ // If a (non-EOF) error occurs, the resulting value of the file position
+ // indicator for the stream is indeterminate.
+ StreamErrorState NewES =
+ OldSS->ErrorState == ErrorFEof ? ErrorFEof : ErrorFEof | ErrorFError;
+ StreamState NewSS = StreamState::getOpened(Desc, NewES, !NewES.isFEof());
+ StateFailed = StateFailed->set<StreamMap>(StreamSym, NewSS);
+ if (OldSS->ErrorState != ErrorFEof)
+ C.addTransition(StateFailed, constructSetEofNoteTag(C, StreamSym));
+ else
+ C.addTransition(StateFailed);
+}
+
+void StreamChecker::evalFputx(const FnDescription *Desc, const CallEvent &Call,
+ CheckerContext &C, bool IsSingleChar) const {
+ ProgramStateRef State = C.getState();
+ SymbolRef StreamSym = getStreamArg(Desc, Call).getAsSymbol();
+ if (!StreamSym)
+ return;
+
+ const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
+ if (!CE)
+ return;
+
+ const StreamState *OldSS = State->get<StreamMap>(StreamSym);
+ if (!OldSS)
+ return;
+
+ assertStreamStateOpened(OldSS);
+
+ // `fputc` returns the written character on success, otherwise returns EOF.
+ // `fputs` returns a non negative value on sucecess, otherwise returns EOF.
+
+ if (IsSingleChar) {
+ // Generate a transition for the success state of `fputc`.
+ std::optional<NonLoc> PutVal = Call.getArgSVal(0).getAs<NonLoc>();
+ if (!PutVal)
+ return;
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), *PutVal);
+ StateNotFailed =
+ StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc));
+ C.addTransition(StateNotFailed);
+ } else {
+ // Generate a transition for the success state of `fputs`.
+ NonLoc RetVal = makeRetVal(C, CE).castAs<NonLoc>();
+ ProgramStateRef StateNotFailed =
+ State->BindExpr(CE, C.getLocationContext(), RetVal);
+ SValBuilder &SVB = C.getSValBuilder();
+ auto &ASTC = C.getASTContext();
+ auto Cond = SVB.evalBinOp(State, BO_GE, RetVal, SVB.makeZeroVal(ASTC.IntTy),
+ SVB.getConditionType())
+ .getAs<DefinedOrUnknownSVal>();
+ if (!Cond)
+ return;
+ StateNotFailed = StateNotFailed->assume(*Cond, true);
+ if (!StateNotFailed)
+ return;
+ StateNotFailed =
+ StateNotFailed->set<StreamMap>(StreamSym, StreamState::getOpened(Desc));
+ C.addTransition(StateNotFailed);
+ }
+
+ // Add transition for the failed state. The resulting value of the file
+ // position indicator for the stream is indeterminate.
+ ProgramStateRef StateFailed = bindInt(*EofVal, State, C, CE);
+ StreamState NewSS = StreamState::getOpened(Desc, ErrorFError, true);
+ StateFailed = StateFailed->set<StreamMap>(StreamSym, NewSS);
+ C.addTransition(StateFailed);
+}
+
void StreamChecker::preFseek(const FnDescription *Desc, const CallEvent &Call,
CheckerContext &C) const {
ProgramStateRef State = C.getState();
@@ -934,6 +1072,9 @@ void StreamChecker::evalFtell(const FnDescription *Desc, const CallEvent &Call,
ProgramStateRef StateFailed = State->BindExpr(
CE, C.getLocationContext(), SVB.makeIntVal(-1, C.getASTContext().LongTy));
+ // 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);
}
@@ -1061,7 +1202,7 @@ StreamChecker::ensureStreamNonNull(SVal StreamVal, const Expr *StreamE,
ConstraintManager &CM = C.getConstraintManager();
ProgramStateRef StateNotNull, StateNull;
- std::tie(StateNotNull, StateNull) = CM.assumeDual(C.getState(), *Stream);
+ std::tie(StateNotNull, StateNull) = CM.assumeDual(State, *Stream);
if (!StateNotNull && StateNull) {
if (ExplodedNode *N = C.generateErrorNode(StateNull)) {
@@ -1117,7 +1258,6 @@ ProgramStateRef StreamChecker::ensureStreamOpened(SVal StreamVal,
N));
return nullptr;
}
- return State;
}
return State;
@@ -1231,7 +1371,7 @@ StreamChecker::reportLeaks(const SmallVector<SymbolRef, 2> &LeakedSyms,
PathDiagnosticLocation LocUsedForUniqueing;
if (const Stmt *StreamStmt = StreamOpenNode->getStmtForDiagnostics())
- LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
+ LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
StreamStmt, C.getSourceManager(),
StreamOpenNode->getLocationContext());
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h
new file mode 100644
index 000000000000..557e8a76506e
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TaggedUnionModeling.h
@@ -0,0 +1,99 @@
+//===- TaggedUnionModeling.h -------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_TAGGEDUNIONMODELING_H
+#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_TAGGEDUNIONMODELING_H
+
+#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
+#include "clang/StaticAnalyzer/Core/Checker.h"
+#include "clang/StaticAnalyzer/Core/CheckerManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
+#include "llvm/ADT/FoldingSet.h"
+#include <numeric>
+
+namespace clang::ento::tagged_union_modeling {
+
+// The implementation of all these functions can be found in the file
+// StdVariantChecker.cpp under the same directory as this file.
+
+bool isCopyConstructorCall(const CallEvent &Call);
+bool isCopyAssignmentCall(const CallEvent &Call);
+bool isMoveAssignmentCall(const CallEvent &Call);
+bool isMoveConstructorCall(const CallEvent &Call);
+bool isStdType(const Type *Type, const std::string &TypeName);
+bool isStdVariant(const Type *Type);
+
+// When invalidating regions, we also have to follow that by invalidating the
+// corresponding custom data in the program state.
+template <class TypeMap>
+ProgramStateRef
+removeInformationStoredForDeadInstances(const CallEvent &Call,
+ ProgramStateRef State,
+ ArrayRef<const MemRegion *> Regions) {
+ // If we do not know anything about the call we shall not continue.
+ // If the call is happens within a system header it is implementation detail.
+ // We should not take it into consideration.
+ if (Call.isInSystemHeader())
+ return State;
+
+ for (const MemRegion *Region : Regions)
+ State = State->remove<TypeMap>(Region);
+
+ return State;
+}
+
+template <class TypeMap>
+void handleConstructorAndAssignment(const CallEvent &Call, CheckerContext &C,
+ const SVal &ThisSVal) {
+ ProgramStateRef State = Call.getState();
+
+ if (!State)
+ return;
+
+ auto ArgSVal = Call.getArgSVal(0);
+ const auto *ThisRegion = ThisSVal.getAsRegion();
+ const auto *ArgMemRegion = ArgSVal.getAsRegion();
+
+ // Make changes to the state according to type of constructor/assignment
+ bool IsCopy = isCopyConstructorCall(Call) || isCopyAssignmentCall(Call);
+ bool IsMove = isMoveConstructorCall(Call) || isMoveAssignmentCall(Call);
+ // First we handle copy and move operations
+ if (IsCopy || IsMove) {
+ const QualType *OtherQType = State->get<TypeMap>(ArgMemRegion);
+
+ // If the argument of a copy constructor or assignment is unknown then
+ // we will not know the argument of the copied to object.
+ if (!OtherQType) {
+ State = State->remove<TypeMap>(ThisRegion);
+ } else {
+ // When move semantics is used we can only know that the moved from
+ // object must be in a destructible state. Other usage of the object
+ // than destruction is undefined.
+ if (IsMove)
+ State = State->remove<TypeMap>(ArgMemRegion);
+
+ State = State->set<TypeMap>(ThisRegion, *OtherQType);
+ }
+ } else {
+ // Value constructor
+ auto ArgQType = ArgSVal.getType(C.getASTContext());
+ const Type *ArgTypePtr = ArgQType.getTypePtr();
+
+ QualType WoPointer = ArgTypePtr->getPointeeType();
+ State = State->set<TypeMap>(ThisRegion, WoPointer);
+ }
+
+ C.addTransition(State);
+}
+
+} // namespace clang::ento::tagged_union_modeling
+
+#endif // LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_TAGGEDUNIONMODELING_H \ No newline at end of file
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
index 9d3a909f50c1..5cdcc1075f44 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/TestAfterDivZeroChecker.cpp
@@ -78,7 +78,7 @@ public:
class TestAfterDivZeroChecker
: public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
check::EndFunction> {
- mutable std::unique_ptr<BuiltinBug> DivZeroBug;
+ mutable std::unique_ptr<BugType> DivZeroBug;
void reportBug(SVal Val, CheckerContext &C) const;
public:
@@ -166,7 +166,7 @@ bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
if (!DivZeroBug)
- DivZeroBug.reset(new BuiltinBug(this, "Division by zero"));
+ DivZeroBug.reset(new BugType(this, "Division by zero"));
auto R = std::make_unique<PathSensitiveBugReport>(
*DivZeroBug, "Value being compared against zero has already been used "
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
index b17b983f0345..db886501a162 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp
@@ -27,7 +27,7 @@ using namespace ento;
namespace {
class UndefBranchChecker : public Checker<check::BranchCondition> {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
struct FindUndefExpr {
ProgramStateRef St;
@@ -71,8 +71,8 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
ExplodedNode *N = Ctx.generateErrorNode();
if (N) {
if (!BT)
- BT.reset(new BuiltinBug(
- this, "Branch condition evaluates to a garbage value"));
+ BT.reset(
+ new BugType(this, "Branch condition evaluates to a garbage value"));
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
index 2973dd5457c6..ecb6ed36ee40 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp
@@ -72,7 +72,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT)
BT.reset(
- new BuiltinBug(this, "uninitialized variable captured by block"));
+ new BugType(this, "uninitialized variable captured by block"));
// Generate a bug report.
SmallString<128> buf;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
index f20b38a53151..d593a6bd74cf 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp
@@ -58,28 +58,12 @@ static bool isArrayIndexOutOfBounds(CheckerContext &C, const Expr *Ex) {
return StOutBound && !StInBound;
}
-static bool isShiftOverflow(const BinaryOperator *B, CheckerContext &C) {
- return C.isGreaterOrEqual(
- B->getRHS(), C.getASTContext().getIntWidth(B->getLHS()->getType()));
-}
-
-static bool isLeftShiftResultUnrepresentable(const BinaryOperator *B,
- CheckerContext &C) {
- SValBuilder &SB = C.getSValBuilder();
- ProgramStateRef State = C.getState();
- const llvm::APSInt *LHS = SB.getKnownValue(State, C.getSVal(B->getLHS()));
- const llvm::APSInt *RHS = SB.getKnownValue(State, C.getSVal(B->getRHS()));
- assert(LHS && RHS && "Values unknown, inconsistent state");
- return (unsigned)RHS->getZExtValue() > LHS->countl_zero();
-}
-
void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
CheckerContext &C) const {
if (C.getSVal(B).isUndef()) {
// Do not report assignments of uninitialized values inside swap functions.
// This should allow to swap partially uninitialized structs
- // (radar://14129997)
if (const FunctionDecl *EnclosingFunctionDecl =
dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
@@ -92,7 +76,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
if (!BT)
BT.reset(
- new BuiltinBug(this, "Result of operation is garbage or undefined"));
+ new BugType(this, "Result of operation is garbage or undefined"));
SmallString<256> sbuf;
llvm::raw_svector_ostream OS(sbuf);
@@ -116,59 +100,9 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
OS << " due to array index out of bounds";
} else {
// Neither operand was undefined, but the result is undefined.
- if ((B->getOpcode() == BinaryOperatorKind::BO_Shl ||
- B->getOpcode() == BinaryOperatorKind::BO_Shr) &&
- C.isNegative(B->getRHS())) {
- OS << "The result of the "
- << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left"
- : "right")
- << " shift is undefined because the right operand is negative";
- Ex = B->getRHS();
- } else if ((B->getOpcode() == BinaryOperatorKind::BO_Shl ||
- B->getOpcode() == BinaryOperatorKind::BO_Shr) &&
- isShiftOverflow(B, C)) {
-
- OS << "The result of the "
- << ((B->getOpcode() == BinaryOperatorKind::BO_Shl) ? "left"
- : "right")
- << " shift is undefined due to shifting by ";
- Ex = B->getRHS();
-
- SValBuilder &SB = C.getSValBuilder();
- const llvm::APSInt *I =
- SB.getKnownValue(C.getState(), C.getSVal(B->getRHS()));
- if (!I)
- OS << "a value that is";
- else if (I->isUnsigned())
- OS << '\'' << I->getZExtValue() << "\', which is";
- else
- OS << '\'' << I->getSExtValue() << "\', which is";
-
- OS << " greater or equal to the width of type '"
- << B->getLHS()->getType() << "'.";
- } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl &&
- C.isNegative(B->getLHS())) {
- OS << "The result of the left shift is undefined because the left "
- "operand is negative";
- Ex = B->getLHS();
- } else if (B->getOpcode() == BinaryOperatorKind::BO_Shl &&
- isLeftShiftResultUnrepresentable(B, C)) {
- ProgramStateRef State = C.getState();
- SValBuilder &SB = C.getSValBuilder();
- const llvm::APSInt *LHS =
- SB.getKnownValue(State, C.getSVal(B->getLHS()));
- const llvm::APSInt *RHS =
- SB.getKnownValue(State, C.getSVal(B->getRHS()));
- OS << "The result of the left shift is undefined due to shifting \'"
- << LHS->getSExtValue() << "\' by \'" << RHS->getZExtValue()
- << "\', which is unrepresentable in the unsigned version of "
- << "the return type \'" << B->getLHS()->getType() << "\'";
- Ex = B->getLHS();
- } else {
- OS << "The result of the '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' expression is undefined";
- }
+ OS << "The result of the '"
+ << BinaryOperator::getOpcodeStr(B->getOpcode())
+ << "' expression is undefined";
}
auto report = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
if (Ex) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
index fdefe75e8201..a6cc8cac8c99 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp
@@ -49,7 +49,7 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
if (!N)
return;
if (!BT)
- BT.reset(new BuiltinBug(this, "Array subscript is undefined"));
+ BT.reset(new BugType(this, "Array subscript is undefined"));
// Generate a report for this bug.
auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
index 0fa3d6043971..49ac94f65dd0 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp
@@ -39,7 +39,6 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
// Do not report assignments of uninitialized values inside swap functions.
// This should allow to swap partially uninitialized structs
- // (radar://14129997)
if (const FunctionDecl *EnclosingFunctionDecl =
dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
@@ -53,7 +52,7 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
static const char *const DefaultMsg =
"Assigned value is garbage or undefined";
if (!BT)
- BT.reset(new BuiltinBug(this, DefaultMsg));
+ BT.reset(new BugType(this, DefaultMsg));
// Generate a report for this bug.
llvm::SmallString<128> Str;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
index cd91fa9b090c..3647c49cf3f9 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/UninitializedObject/UninitializedObjectChecker.cpp
@@ -38,14 +38,14 @@ namespace {
class UninitializedObjectChecker
: public Checker<check::EndFunction, check::DeadSymbols> {
- std::unique_ptr<BuiltinBug> BT_uninitField;
+ std::unique_ptr<BugType> BT_uninitField;
public:
// The fields of this struct will be initialized when registering the checker.
UninitObjCheckerOptions Opts;
UninitializedObjectChecker()
- : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
+ : BT_uninitField(new BugType(this, "Uninitialized fields")) {}
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
index b195d912cadf..1d03d1656b3c 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp
@@ -188,7 +188,8 @@ ProgramStateRef VLASizeChecker::checkVLAIndexSize(CheckerContext &C,
QualType SizeTy = SizeE->getType();
DefinedOrUnknownSVal Zero = SVB.makeZeroVal(SizeTy);
- SVal LessThanZeroVal = SVB.evalBinOp(State, BO_LT, SizeD, Zero, SizeTy);
+ SVal LessThanZeroVal =
+ SVB.evalBinOp(State, BO_LT, SizeD, Zero, SVB.getConditionType());
if (std::optional<DefinedSVal> LessThanZeroDVal =
LessThanZeroVal.getAs<DefinedSVal>()) {
ConstraintManager &CM = C.getConstraintManager();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
index 86a4e6fbcd6a..8a1e02748c9b 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/VforkChecker.cpp
@@ -44,9 +44,9 @@ namespace {
class VforkChecker : public Checker<check::PreCall, check::PostCall,
check::Bind, check::PreStmt<ReturnStmt>> {
- mutable std::unique_ptr<BuiltinBug> BT;
+ mutable std::unique_ptr<BugType> BT;
mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkAllowlist;
- mutable const IdentifierInfo *II_vfork;
+ mutable const IdentifierInfo *II_vfork = nullptr;
static bool isChildProcess(const ProgramStateRef State);
@@ -58,7 +58,7 @@ class VforkChecker : public Checker<check::PreCall, check::PostCall,
const char *Details = nullptr) const;
public:
- VforkChecker() : II_vfork(nullptr) {}
+ VforkChecker() = default;
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
@@ -124,8 +124,7 @@ void VforkChecker::reportBug(const char *What, CheckerContext &C,
const char *Details) const {
if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
if (!BT)
- BT.reset(new BuiltinBug(this,
- "Dangerous construct in a vforked process"));
+ BT.reset(new BugType(this, "Dangerous construct in a vforked process"));
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
index 66d8588e2531..c753ed84a700 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/NoUncountedMembersChecker.cpp
@@ -17,7 +17,6 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Casting.h"
#include <optional>
@@ -104,7 +103,7 @@ public:
const auto Kind = RD->getTagKind();
// FIMXE: Should we check union members too?
- if (Kind != TTK_Struct && Kind != TTK_Class)
+ if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
return true;
// Ignore CXXRecords that come from system headers.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 9b1d7ae3e6a3..d2b663410580 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -18,24 +18,15 @@ using namespace clang;
namespace {
-bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
+bool hasPublicMethodInBaseClass(const CXXRecordDecl *R,
+ const char *NameToMatch) {
assert(R);
assert(R->hasDefinition());
- bool hasRef = false;
- bool hasDeref = false;
for (const CXXMethodDecl *MD : R->methods()) {
const auto MethodName = safeGetName(MD);
-
- if (MethodName == "ref" && MD->getAccess() == AS_public) {
- if (hasDeref)
- return true;
- hasRef = true;
- } else if (MethodName == "deref" && MD->getAccess() == AS_public) {
- if (hasRef)
- return true;
- hasDeref = true;
- }
+ if (MethodName == NameToMatch && MD->getAccess() == AS_public)
+ return true;
}
return false;
}
@@ -44,9 +35,8 @@ bool hasPublicRefAndDeref(const CXXRecordDecl *R) {
namespace clang {
-std::optional<const clang::CXXRecordDecl*>
-isRefCountable(const CXXBaseSpecifier* Base)
-{
+std::optional<const clang::CXXRecordDecl *>
+hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch) {
assert(Base);
const Type *T = Base->getType().getTypePtrOrNull();
@@ -59,7 +49,7 @@ isRefCountable(const CXXBaseSpecifier* Base)
if (!R->hasDefinition())
return std::nullopt;
- return hasPublicRefAndDeref(R) ? R : nullptr;
+ return hasPublicMethodInBaseClass(R, NameToMatch) ? R : nullptr;
}
std::optional<bool> isRefCountable(const CXXRecordDecl* R)
@@ -70,29 +60,45 @@ std::optional<bool> isRefCountable(const CXXRecordDecl* R)
if (!R)
return std::nullopt;
- if (hasPublicRefAndDeref(R))
+ bool hasRef = hasPublicMethodInBaseClass(R, "ref");
+ bool hasDeref = hasPublicMethodInBaseClass(R, "deref");
+ if (hasRef && hasDeref)
return true;
CXXBasePaths Paths;
Paths.setOrigin(const_cast<CXXRecordDecl *>(R));
bool AnyInconclusiveBase = false;
- const auto isRefCountableBase =
- [&AnyInconclusiveBase](const CXXBaseSpecifier* Base, CXXBasePath&) {
- std::optional<const clang::CXXRecordDecl*> IsRefCountable = clang::isRefCountable(Base);
- if (!IsRefCountable) {
- AnyInconclusiveBase = true;
- return false;
- }
- return (*IsRefCountable) != nullptr;
+ const auto hasPublicRefInBase =
+ [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
+ auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
+ if (!hasRefInBase) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*hasRefInBase) != nullptr;
};
- bool BasesResult = R->lookupInBases(isRefCountableBase, Paths,
+ hasRef = hasRef || R->lookupInBases(hasPublicRefInBase, Paths,
/*LookupInDependent =*/true);
if (AnyInconclusiveBase)
return std::nullopt;
- return BasesResult;
+ const auto hasPublicDerefInBase =
+ [&AnyInconclusiveBase](const CXXBaseSpecifier *Base, CXXBasePath &) {
+ auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
+ if (!hasDerefInBase) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*hasDerefInBase) != nullptr;
+ };
+ hasDeref = hasDeref || R->lookupInBases(hasPublicDerefInBase, Paths,
+ /*LookupInDependent =*/true);
+ if (AnyInconclusiveBase)
+ return std::nullopt;
+
+ return hasRef && hasDeref;
}
bool isCtorOfRefCounted(const clang::FunctionDecl *F) {
@@ -186,8 +192,7 @@ bool isPtrConversion(const FunctionDecl *F) {
// FIXME: check # of params == 1
const auto FunctionName = safeGetName(F);
if (FunctionName == "getPtr" || FunctionName == "WeakPtr" ||
- FunctionName == "makeWeakPtr"
-
+ FunctionName == "dynamicDowncast"
|| FunctionName == "downcast" || FunctionName == "bitwise_cast")
return true;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index 91e3ccf2ec30..45b21cc09184 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -26,10 +26,10 @@ class Type;
// In WebKit there are two ref-counted templated smart pointers: RefPtr<T> and
// Ref<T>.
-/// \returns CXXRecordDecl of the base if the type is ref-countable, nullptr if
-/// not, std::nullopt if inconclusive.
-std::optional<const clang::CXXRecordDecl*>
-isRefCountable(const clang::CXXBaseSpecifier* Base);
+/// \returns CXXRecordDecl of the base if the type has ref as a public method,
+/// nullptr if not, std::nullopt if inconclusive.
+std::optional<const clang::CXXRecordDecl *>
+hasPublicMethodInBase(const CXXBaseSpecifier *Base, const char *NameToMatch);
/// \returns true if \p Class is ref-countable, false if not, std::nullopt if
/// inconclusive.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
index 48dcfc4a3c46..d879c110b75d 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/RefCntblBaseVirtualDtorChecker.cpp
@@ -77,14 +77,53 @@ public:
(AccSpec == AS_none && RD->isClass()))
return false;
- std::optional<const CXXRecordDecl*> RefCntblBaseRD = isRefCountable(Base);
- if (!RefCntblBaseRD || !(*RefCntblBaseRD))
+ auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
+ auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
+
+ bool hasRef = hasRefInBase && *hasRefInBase != nullptr;
+ bool hasDeref = hasDerefInBase && *hasDerefInBase != nullptr;
+
+ QualType T = Base->getType();
+ if (T.isNull())
+ return false;
+
+ const CXXRecordDecl *C = T->getAsCXXRecordDecl();
+ if (!C)
+ return false;
+ bool AnyInconclusiveBase = false;
+ const auto hasPublicRefInBase =
+ [&AnyInconclusiveBase](const CXXBaseSpecifier *Base,
+ CXXBasePath &) {
+ auto hasRefInBase = clang::hasPublicMethodInBase(Base, "ref");
+ if (!hasRefInBase) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*hasRefInBase) != nullptr;
+ };
+ const auto hasPublicDerefInBase = [&AnyInconclusiveBase](
+ const CXXBaseSpecifier *Base,
+ CXXBasePath &) {
+ auto hasDerefInBase = clang::hasPublicMethodInBase(Base, "deref");
+ if (!hasDerefInBase) {
+ AnyInconclusiveBase = true;
+ return false;
+ }
+ return (*hasDerefInBase) != nullptr;
+ };
+ CXXBasePaths Paths;
+ Paths.setOrigin(C);
+ hasRef = hasRef || C->lookupInBases(hasPublicRefInBase, Paths,
+ /*LookupInDependent =*/true);
+ hasDeref = hasDeref || C->lookupInBases(hasPublicDerefInBase, Paths,
+ /*LookupInDependent =*/true);
+ if (AnyInconclusiveBase || !hasRef || !hasDeref)
return false;
- const auto *Dtor = (*RefCntblBaseRD)->getDestructor();
+ const auto *Dtor = C->getDestructor();
if (!Dtor || !Dtor->isVirtual()) {
ProblematicBaseSpecifier = Base;
- ProblematicBaseClass = *RefCntblBaseRD;
+ ProblematicBaseClass = C;
return true;
}
@@ -114,7 +153,7 @@ public:
return true;
const auto Kind = RD->getTagKind();
- if (Kind != TTK_Struct && Kind != TTK_Class)
+ if (Kind != TagTypeKind::Struct && Kind != TagTypeKind::Class)
return true;
// Ignore CXXRecords that come from system headers.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
index 4ae8c442fa70..31ccae8b097b 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp
@@ -18,7 +18,6 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "llvm/ADT/DenseSet.h"
#include <optional>
using namespace clang;
@@ -149,7 +148,7 @@ public:
auto name = safeGetName(Callee);
if (name == "adoptRef" || name == "getPtr" || name == "WeakPtr" ||
- name == "makeWeakPtr" || name == "downcast" || name == "bitwise_cast" ||
+ name == "dynamicDowncast" || name == "downcast" || name == "bitwise_cast" ||
name == "is" || name == "equal" || name == "hash" ||
name == "isType"
// FIXME: Most/all of these should be implemented via attributes.
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
index fa7475934981..5a72f53b12ed 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedLocalVarsChecker.cpp
@@ -19,7 +19,6 @@
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
-#include "llvm/ADT/DenseSet.h"
#include <optional>
using namespace clang;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Yaml.h b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Yaml.h
index 4159e14105f8..b2d17420686e 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Yaml.h
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Yaml.h
@@ -35,7 +35,7 @@ std::optional<T> getConfiguration(CheckerManager &Mgr, Checker *Chk,
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
FS->getBufferForFile(ConfigFile.str());
- if (std::error_code ec = Buffer.getError()) {
+ if (Buffer.getError()) {
Mgr.reportInvalidCheckerOptionValue(Chk, Option,
"a valid filename instead of '" +
std::string(ConfigFile) + "'");
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
index aae1a17bc0ae..e5dd907c660d 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/cert/InvalidPtrChecker.cpp
@@ -30,7 +30,10 @@ namespace {
class InvalidPtrChecker
: public Checker<check::Location, check::BeginFunction, check::PostCall> {
private:
- BugType BT{this, "Use of invalidated pointer", categories::MemoryError};
+ // For accurate emission of NoteTags, the BugType of this checker should have
+ // a unique address.
+ BugType InvalidPtrBugType{this, "Use of invalidated pointer",
+ categories::MemoryError};
void EnvpInvalidatingCall(const CallEvent &Call, CheckerContext &C) const;
@@ -38,6 +41,15 @@ private:
CheckerContext &C) const;
// SEI CERT ENV31-C
+
+ // If set to true, consider getenv calls as invalidating operations on the
+ // environment variable buffer. This is implied in the standard, but in
+ // practice does not cause problems (in the commonly used environments).
+ bool InvalidatingGetEnv = false;
+
+ // GetEnv can be treated invalidating and non-invalidating as well.
+ const CallDescription GetEnvCall{{"getenv"}, 1};
+
const CallDescriptionMap<HandlerFn> EnvpInvalidatingFunctions = {
{{{"setenv"}, 3}, &InvalidPtrChecker::EnvpInvalidatingCall},
{{{"unsetenv"}, 1}, &InvalidPtrChecker::EnvpInvalidatingCall},
@@ -51,7 +63,6 @@ private:
// SEI CERT ENV34-C
const CallDescriptionMap<HandlerFn> PreviousCallInvalidatingFunctions = {
- {{{"getenv"}, 1}, &InvalidPtrChecker::postPreviousReturnInvalidatingCall},
{{{"setlocale"}, 2},
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
{{{"strerror"}, 1},
@@ -62,6 +73,10 @@ private:
&InvalidPtrChecker::postPreviousReturnInvalidatingCall},
};
+ // The private members of this checker corresponding to commandline options
+ // are set in this function.
+ friend void ento::registerInvalidPtrChecker(CheckerManager &);
+
public:
// Obtain the environment pointer from 'main()' (if present).
void checkBeginFunction(CheckerContext &C) const;
@@ -76,6 +91,11 @@ public:
// Check if invalidated region is being dereferenced.
void checkLocation(SVal l, bool isLoad, const Stmt *S,
CheckerContext &C) const;
+
+private:
+ const NoteTag *createEnvInvalidationNote(CheckerContext &C,
+ ProgramStateRef State,
+ StringRef FunctionName) const;
};
} // namespace
@@ -84,33 +104,74 @@ public:
REGISTER_SET_WITH_PROGRAMSTATE(InvalidMemoryRegions, const MemRegion *)
// Stores the region of the environment pointer of 'main' (if present).
-REGISTER_TRAIT_WITH_PROGRAMSTATE(EnvPtrRegion, const MemRegion *)
+REGISTER_TRAIT_WITH_PROGRAMSTATE(MainEnvPtrRegion, const MemRegion *)
+
+// Stores the regions of environments returned by getenv calls.
+REGISTER_SET_WITH_PROGRAMSTATE(GetenvEnvPtrRegions, const MemRegion *)
// Stores key-value pairs, where key is function declaration and value is
// pointer to memory region returned by previous call of this function
REGISTER_MAP_WITH_PROGRAMSTATE(PreviousCallResultMap, const FunctionDecl *,
const MemRegion *)
+const NoteTag *InvalidPtrChecker::createEnvInvalidationNote(
+ CheckerContext &C, ProgramStateRef State, StringRef FunctionName) const {
+
+ const MemRegion *MainRegion = State->get<MainEnvPtrRegion>();
+ const auto GetenvRegions = State->get<GetenvEnvPtrRegions>();
+
+ return C.getNoteTag([this, MainRegion, GetenvRegions,
+ FunctionName = std::string{FunctionName}](
+ PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
+ // Only handle the BugType of this checker.
+ if (&BR.getBugType() != &InvalidPtrBugType)
+ return;
+
+ // Mark all regions that were interesting before as NOT interesting now
+ // to avoid extra notes coming from invalidation points higher up the
+ // bugpath. This ensures that only the last invalidation point is marked
+ // with a note tag.
+ llvm::SmallVector<std::string, 2> InvalidLocationNames;
+ if (BR.isInteresting(MainRegion)) {
+ BR.markNotInteresting(MainRegion);
+ InvalidLocationNames.push_back("the environment parameter of 'main'");
+ }
+ bool InterestingGetenvFound = false;
+ for (const MemRegion *MR : GetenvRegions) {
+ if (BR.isInteresting(MR)) {
+ BR.markNotInteresting(MR);
+ if (!InterestingGetenvFound) {
+ InterestingGetenvFound = true;
+ InvalidLocationNames.push_back(
+ "the environment returned by 'getenv'");
+ }
+ }
+ }
+
+ // Emit note tag message.
+ if (InvalidLocationNames.size() >= 1)
+ Out << '\'' << FunctionName << "' call may invalidate "
+ << InvalidLocationNames[0];
+ if (InvalidLocationNames.size() == 2)
+ Out << ", and " << InvalidLocationNames[1];
+ });
+}
+
void InvalidPtrChecker::EnvpInvalidatingCall(const CallEvent &Call,
CheckerContext &C) const {
- StringRef FunctionName = Call.getCalleeIdentifier()->getName();
+ // This callevent invalidates all previously generated pointers to the
+ // environment.
ProgramStateRef State = C.getState();
- const MemRegion *SymbolicEnvPtrRegion = State->get<EnvPtrRegion>();
- if (!SymbolicEnvPtrRegion)
- return;
-
- State = State->add<InvalidMemoryRegions>(SymbolicEnvPtrRegion);
+ if (const MemRegion *MainEnvPtr = State->get<MainEnvPtrRegion>())
+ State = State->add<InvalidMemoryRegions>(MainEnvPtr);
+ for (const MemRegion *EnvPtr : State->get<GetenvEnvPtrRegions>())
+ State = State->add<InvalidMemoryRegions>(EnvPtr);
- const NoteTag *Note =
- C.getNoteTag([SymbolicEnvPtrRegion, FunctionName](
- PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
- if (!BR.isInteresting(SymbolicEnvPtrRegion))
- return;
- Out << '\'' << FunctionName
- << "' call may invalidate the environment parameter of 'main'";
- });
+ StringRef FunctionName = Call.getCalleeIdentifier()->getName();
+ const NoteTag *InvalidationNote =
+ createEnvInvalidationNote(C, State, FunctionName);
- C.addTransition(State, Note);
+ C.addTransition(State, InvalidationNote);
}
void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
@@ -124,9 +185,9 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
if (const MemRegion *const *Reg = State->get<PreviousCallResultMap>(FD)) {
const MemRegion *PrevReg = *Reg;
State = State->add<InvalidMemoryRegions>(PrevReg);
- Note = C.getNoteTag([PrevReg, FD](PathSensitiveBugReport &BR,
- llvm::raw_ostream &Out) {
- if (!BR.isInteresting(PrevReg))
+ Note = C.getNoteTag([this, PrevReg, FD](PathSensitiveBugReport &BR,
+ llvm::raw_ostream &Out) {
+ if (!BR.isInteresting(PrevReg) || &BR.getBugType() != &InvalidPtrBugType)
return;
Out << '\'';
FD->getNameForDiagnostic(Out, FD->getASTContext().getLangOpts(), true);
@@ -146,16 +207,15 @@ void InvalidPtrChecker::postPreviousReturnInvalidatingCall(
// Remember to this region.
const auto *SymRegOfRetVal = cast<SymbolicRegion>(RetVal.getAsRegion());
- const MemRegion *MR =
- const_cast<MemRegion *>(SymRegOfRetVal->getBaseRegion());
+ const MemRegion *MR = SymRegOfRetVal->getBaseRegion();
State = State->set<PreviousCallResultMap>(FD, MR);
ExplodedNode *Node = C.addTransition(State, Note);
- const NoteTag *PreviousCallNote =
- C.getNoteTag([MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
- if (!BR.isInteresting(MR))
+ const NoteTag *PreviousCallNote = C.getNoteTag(
+ [this, MR](PathSensitiveBugReport &BR, llvm::raw_ostream &Out) {
+ if (!BR.isInteresting(MR) || &BR.getBugType() != &InvalidPtrBugType)
return;
- Out << '\'' << "'previous function call was here" << '\'';
+ Out << "previous function call was here";
});
C.addTransition(State, Node, PreviousCallNote);
@@ -185,6 +245,18 @@ static const MemRegion *findInvalidatedSymbolicBase(ProgramStateRef State,
// function call as an argument.
void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
+
+ ProgramStateRef State = C.getState();
+
+ // Model 'getenv' calls
+ if (GetEnvCall.matches(Call)) {
+ const MemRegion *Region = Call.getReturnValue().getAsRegion();
+ if (Region) {
+ State = State->add<GetenvEnvPtrRegions>(Region);
+ C.addTransition(State);
+ }
+ }
+
// Check if function invalidates 'envp' argument of 'main'
if (const auto *Handler = EnvpInvalidatingFunctions.lookup(Call))
(this->**Handler)(Call, C);
@@ -193,14 +265,16 @@ void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
if (const auto *Handler = PreviousCallInvalidatingFunctions.lookup(Call))
(this->**Handler)(Call, C);
+ // If pedantic mode is on, regard 'getenv' calls invalidating as well
+ if (InvalidatingGetEnv && GetEnvCall.matches(Call))
+ postPreviousReturnInvalidatingCall(Call, C);
+
// Check if one of the arguments of the function call is invalidated
// If call was inlined, don't report invalidated argument
if (C.wasInlined)
return;
- ProgramStateRef State = C.getState();
-
for (unsigned I = 0, NumArgs = Call.getNumArgs(); I < NumArgs; ++I) {
if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(
@@ -218,8 +292,8 @@ void InvalidPtrChecker::checkPostCall(const CallEvent &Call,
C.getASTContext().getPrintingPolicy());
Out << "' in a function call";
- auto Report =
- std::make_unique<PathSensitiveBugReport>(BT, Out.str(), ErrorNode);
+ auto Report = std::make_unique<PathSensitiveBugReport>(
+ InvalidPtrBugType, Out.str(), ErrorNode);
Report->markInteresting(InvalidatedSymbolicBase);
Report->addRange(Call.getArgSourceRange(I));
C.emitReport(std::move(Report));
@@ -243,7 +317,7 @@ void InvalidPtrChecker::checkBeginFunction(CheckerContext &C) const {
// Save the memory region pointed by the environment pointer parameter of
// 'main'.
- C.addTransition(State->set<EnvPtrRegion>(EnvpReg));
+ C.addTransition(State->set<MainEnvPtrRegion>(EnvpReg));
}
// Check if invalidated region is being dereferenced.
@@ -262,13 +336,16 @@ void InvalidPtrChecker::checkLocation(SVal Loc, bool isLoad, const Stmt *S,
return;
auto Report = std::make_unique<PathSensitiveBugReport>(
- BT, "dereferencing an invalid pointer", ErrorNode);
+ InvalidPtrBugType, "dereferencing an invalid pointer", ErrorNode);
Report->markInteresting(InvalidatedSymbolicBase);
C.emitReport(std::move(Report));
}
void ento::registerInvalidPtrChecker(CheckerManager &Mgr) {
- Mgr.registerChecker<InvalidPtrChecker>();
+ auto *Checker = Mgr.registerChecker<InvalidPtrChecker>();
+ Checker->InvalidatingGetEnv =
+ Mgr.getAnalyzerOptions().getCheckerBooleanOption(Checker,
+ "InvalidatingGetEnv");
}
bool ento::shouldRegisterInvalidPtrChecker(const CheckerManager &) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
index 5924f6a671c2..5c10e757244d 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BasicValueFactory.cpp
@@ -272,7 +272,7 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
// FIXME: This logic should probably go higher up, where we can
// test these conditions symbolically.
- if (V2.isSigned() && V2.isNegative())
+ if (V2.isNegative() || V2.getBitWidth() > 64)
return nullptr;
uint64_t Amt = V2.getZExtValue();
@@ -280,14 +280,6 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
if (Amt >= V1.getBitWidth())
return nullptr;
- if (!Ctx.getLangOpts().CPlusPlus20) {
- if (V1.isSigned() && V1.isNegative())
- return nullptr;
-
- if (V1.isSigned() && Amt > V1.countl_zero())
- return nullptr;
- }
-
return &getValue( V1.operator<<( (unsigned) Amt ));
}
@@ -295,7 +287,7 @@ BasicValueFactory::evalAPSInt(BinaryOperator::Opcode Op,
// FIXME: This logic should probably go higher up, where we can
// test these conditions symbolically.
- if (V2.isSigned() && V2.isNegative())
+ if (V2.isNegative() || V2.getBitWidth() > 64)
return nullptr;
uint64_t Amt = V2.getZExtValue();
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
index dc9820b61f1f..f3e0a5f9f314 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -12,12 +12,15 @@
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ParentMap.h"
+#include "clang/AST/ParentMapContext.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
@@ -2099,8 +2102,6 @@ PathDiagnosticBuilder::generate(const PathDiagnosticConsumer *PDC) const {
void BugType::anchor() {}
-void BuiltinBug::anchor() {}
-
//===----------------------------------------------------------------------===//
// Methods for BugReport and subclasses.
//===----------------------------------------------------------------------===//
@@ -2141,15 +2142,14 @@ PathSensitiveBugReport::PathSensitiveBugReport(
"checkers to emit warnings, because checkers should depend on "
"*modeling*, not *diagnostics*.");
- assert(
- (bt.getCheckerName().startswith("debug") ||
- !isHidden(ErrorNode->getState()
- ->getAnalysisManager()
- .getCheckerManager()
- ->getCheckerRegistryData(),
- bt.getCheckerName())) &&
- "Hidden checkers musn't emit diagnostics as they are by definition "
- "non-user facing!");
+ assert((bt.getCheckerName().starts_with("debug") ||
+ !isHidden(ErrorNode->getState()
+ ->getAnalysisManager()
+ .getCheckerManager()
+ ->getCheckerRegistryData(),
+ bt.getCheckerName())) &&
+ "Hidden checkers musn't emit diagnostics as they are by definition "
+ "non-user facing!");
}
void PathSensitiveBugReport::addVisitor(
@@ -2427,6 +2427,12 @@ PathSensitiveBugReport::getLocation() const {
}
if (S) {
+ // Attributed statements usually have corrupted begin locations,
+ // it's OK to ignore attributes for our purposes and deal with
+ // the actual annotated statement.
+ if (const auto *AS = dyn_cast<AttributedStmt>(S))
+ S = AS->getSubStmt();
+
// For member expressions, return the location of the '.' or '->'.
if (const auto *ME = dyn_cast<MemberExpr>(S))
return PathDiagnosticLocation::createMemberLoc(ME, SM);
@@ -2899,6 +2905,10 @@ void BugReporter::emitReport(std::unique_ptr<BugReport> R) {
if (!ValidSourceLoc)
return;
+ // If the user asked to suppress this report, we should skip it.
+ if (UserSuppressions.isSuppressed(*R))
+ return;
+
// Compute the bug report's hash to determine its equivalence class.
llvm::FoldingSetNodeID ID;
R->Profile(ID);
@@ -3066,8 +3076,7 @@ void BugReporter::FlushReport(BugReportEquivClass& EQ) {
// See whether we need to silence the checker/package.
for (const std::string &CheckerOrPackage :
getAnalyzerOptions().SilencedCheckersAndPackages) {
- if (report->getBugType().getCheckerName().startswith(
- CheckerOrPackage))
+ if (report->getBugType().getCheckerName().starts_with(CheckerOrPackage))
return;
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
index 42d03f67510c..2f9965036b9e 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -132,6 +132,16 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
}
// Pattern match for a few useful cases: a[0], p->f, *p etc.
else if (const auto *ME = dyn_cast<MemberExpr>(E)) {
+ // This handles the case when the dereferencing of a member reference
+ // happens. This is needed, because the AST for dereferencing a
+ // member reference looks like the following:
+ // |-MemberExpr
+ // `-DeclRefExpr
+ // Without this special case the notes would refer to the whole object
+ // (struct, class or union variable) instead of just the relevant member.
+
+ if (ME->getMemberDecl()->getType()->isReferenceType())
+ break;
E = ME->getBase();
} else if (const auto *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) {
E = IvarRef->getBase();
@@ -157,26 +167,42 @@ const Expr *bugreporter::getDerefExpr(const Stmt *S) {
return E;
}
+static const VarDecl *getVarDeclForExpression(const Expr *E) {
+ if (const auto *DR = dyn_cast<DeclRefExpr>(E))
+ return dyn_cast<VarDecl>(DR->getDecl());
+ return nullptr;
+}
+
static const MemRegion *
getLocationRegionIfReference(const Expr *E, const ExplodedNode *N,
bool LookingForReference = true) {
- if (const auto *DR = dyn_cast<DeclRefExpr>(E)) {
- if (const auto *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- if (LookingForReference && !VD->getType()->isReferenceType())
- return nullptr;
- return N->getState()
- ->getLValue(VD, N->getLocationContext())
- .getAsRegion();
+ if (const auto *ME = dyn_cast<MemberExpr>(E)) {
+ // This handles null references from FieldRegions, for example:
+ // struct Wrapper { int &ref; };
+ // Wrapper w = { *(int *)0 };
+ // w.ref = 1;
+ const Expr *Base = ME->getBase();
+ const VarDecl *VD = getVarDeclForExpression(Base);
+ if (!VD)
+ return nullptr;
+
+ const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
+ if (!FD)
+ return nullptr;
+
+ if (FD->getType()->isReferenceType()) {
+ SVal StructSVal = N->getState()->getLValue(VD, N->getLocationContext());
+ return N->getState()->getLValue(FD, StructSVal).getAsRegion();
}
+ return nullptr;
}
- // FIXME: This does not handle other kinds of null references,
- // for example, references from FieldRegions:
- // struct Wrapper { int &ref; };
- // Wrapper w = { *(int *)0 };
- // w.ref = 1;
-
- return nullptr;
+ const VarDecl *VD = getVarDeclForExpression(E);
+ if (!VD)
+ return nullptr;
+ if (LookingForReference && !VD->getType()->isReferenceType())
+ return nullptr;
+ return N->getState()->getLValue(VD, N->getLocationContext()).getAsRegion();
}
/// Comparing internal representations of symbolic values (via
@@ -606,7 +632,7 @@ static bool potentiallyWritesIntoIvar(const Decl *Parent,
if (const auto *DRE = dyn_cast<DeclRefExpr>(Base))
if (const auto *ID = dyn_cast<ImplicitParamDecl>(DRE->getDecl()))
- if (ID->getParameterKind() == ImplicitParamDecl::ObjCSelf)
+ if (ID->getParameterKind() == ImplicitParamKind::ObjCSelf)
return true;
return false;
@@ -1368,8 +1394,7 @@ static void showBRParamDiagnostics(llvm::raw_svector_ostream &OS,
VR->printPretty(OS);
}
} else if (const auto *ImplParam = dyn_cast<ImplicitParamDecl>(D)) {
- if (ImplParam->getParameterKind() ==
- ImplicitParamDecl::ImplicitParamKind::ObjCSelf) {
+ if (ImplParam->getParameterKind() == ImplicitParamKind::ObjCSelf) {
OS << " via implicit parameter 'self'";
}
}
@@ -3347,7 +3372,7 @@ void LikelyFalsePositiveSuppressionBRVisitor::finalizeVisitor(
FullSourceLoc Loc = BR.getLocation().asLocation();
while (Loc.isMacroID()) {
Loc = Loc.getSpellingLoc();
- if (SM.getFilename(Loc).endswith("sys/queue.h")) {
+ if (SM.getFilename(Loc).ends_with("sys/queue.h")) {
BR.markInvalid(getTag(), nullptr);
return;
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
new file mode 100644
index 000000000000..b5991e47a538
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -0,0 +1,169 @@
+//===- BugSuppression.cpp - Suppression interface -------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Core/BugReporter/BugSuppression.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+
+using Ranges = llvm::SmallVectorImpl<SourceRange>;
+
+inline bool hasSuppression(const Decl *D) {
+ // FIXME: Implement diagnostic identifier arguments
+ // (checker names, "hashtags").
+ if (const auto *Suppression = D->getAttr<SuppressAttr>())
+ return !Suppression->isGSL() &&
+ (Suppression->diagnosticIdentifiers().empty());
+ return false;
+}
+inline bool hasSuppression(const AttributedStmt *S) {
+ // FIXME: Implement diagnostic identifier arguments
+ // (checker names, "hashtags").
+ return llvm::any_of(S->getAttrs(), [](const Attr *A) {
+ const auto *Suppression = dyn_cast<SuppressAttr>(A);
+ return Suppression && !Suppression->isGSL() &&
+ (Suppression->diagnosticIdentifiers().empty());
+ });
+}
+
+template <class NodeType> inline SourceRange getRange(const NodeType *Node) {
+ return Node->getSourceRange();
+}
+template <> inline SourceRange getRange(const AttributedStmt *S) {
+ // Begin location for attributed statement node seems to be ALWAYS invalid.
+ //
+ // It is unlikely that we ever report any warnings on suppression
+ // attribute itself, but even if we do, we wouldn't want that warning
+ // to be suppressed by that same attribute.
+ //
+ // Long story short, we can use inner statement and it's not going to break
+ // anything.
+ return getRange(S->getSubStmt());
+}
+
+inline bool isLessOrEqual(SourceLocation LHS, SourceLocation RHS,
+ const SourceManager &SM) {
+ // SourceManager::isBeforeInTranslationUnit tests for strict
+ // inequality, when we need a non-strict comparison (bug
+ // can be reported directly on the annotated note).
+ // For this reason, we use the following equivalence:
+ //
+ // A <= B <==> !(B < A)
+ //
+ return !SM.isBeforeInTranslationUnit(RHS, LHS);
+}
+
+inline bool fullyContains(SourceRange Larger, SourceRange Smaller,
+ const SourceManager &SM) {
+ // Essentially this means:
+ //
+ // Larger.fullyContains(Smaller)
+ //
+ // However, that method has a very trivial implementation and couldn't
+ // compare regular locations and locations from macro expansions.
+ // We could've converted everything into regular locations as a solution,
+ // but the following solution seems to be the most bulletproof.
+ return isLessOrEqual(Larger.getBegin(), Smaller.getBegin(), SM) &&
+ isLessOrEqual(Smaller.getEnd(), Larger.getEnd(), SM);
+}
+
+class CacheInitializer : public RecursiveASTVisitor<CacheInitializer> {
+public:
+ static void initialize(const Decl *D, Ranges &ToInit) {
+ CacheInitializer(ToInit).TraverseDecl(const_cast<Decl *>(D));
+ }
+
+ bool VisitVarDecl(VarDecl *VD) {
+ // Bug location could be somewhere in the init value of
+ // a freshly declared variable. Even though it looks like the
+ // user applied attribute to a statement, it will apply to a
+ // variable declaration, and this is where we check for it.
+ return VisitAttributedNode(VD);
+ }
+
+ bool VisitAttributedStmt(AttributedStmt *AS) {
+ // When we apply attributes to statements, it actually creates
+ // a wrapper statement that only contains attributes and the wrapped
+ // statement.
+ return VisitAttributedNode(AS);
+ }
+
+private:
+ template <class NodeType> bool VisitAttributedNode(NodeType *Node) {
+ if (hasSuppression(Node)) {
+ // TODO: In the future, when we come up with good stable IDs for checkers
+ // we can return a list of kinds to ignore, or all if no arguments
+ // were provided.
+ addRange(getRange(Node));
+ }
+ // We should keep traversing AST.
+ return true;
+ }
+
+ void addRange(SourceRange R) {
+ if (R.isValid()) {
+ Result.push_back(R);
+ }
+ }
+
+ CacheInitializer(Ranges &R) : Result(R) {}
+ Ranges &Result;
+};
+
+} // end anonymous namespace
+
+// TODO: Introduce stable IDs for checkers and check for those here
+// to be more specific. Attribute without arguments should still
+// be considered as "suppress all".
+// It is already much finer granularity than what we have now
+// (i.e. removing the whole function from the analysis).
+bool BugSuppression::isSuppressed(const BugReport &R) {
+ PathDiagnosticLocation Location = R.getLocation();
+ PathDiagnosticLocation UniqueingLocation = R.getUniqueingLocation();
+ const Decl *DeclWithIssue = R.getDeclWithIssue();
+
+ return isSuppressed(Location, DeclWithIssue, {}) ||
+ isSuppressed(UniqueingLocation, DeclWithIssue, {});
+}
+
+bool BugSuppression::isSuppressed(const PathDiagnosticLocation &Location,
+ const Decl *DeclWithIssue,
+ DiagnosticIdentifierList Hashtags) {
+ if (!Location.isValid() || DeclWithIssue == nullptr)
+ return false;
+
+ // While some warnings are attached to AST nodes (mostly path-sensitive
+ // checks), others are simply associated with a plain source location
+ // or range. Figuring out the node based on locations can be tricky,
+ // so instead, we traverse the whole body of the declaration and gather
+ // information on ALL suppressions. After that we can simply check if
+ // any of those suppressions affect the warning in question.
+ //
+ // Traversing AST of a function is not a heavy operation, but for
+ // large functions with a lot of bugs it can make a dent in performance.
+ // In order to avoid this scenario, we cache traversal results.
+ auto InsertionResult = CachedSuppressionLocations.insert(
+ std::make_pair(DeclWithIssue, CachedRanges{}));
+ Ranges &SuppressionRanges = InsertionResult.first->second;
+ if (InsertionResult.second) {
+ // We haven't checked this declaration for suppressions yet!
+ CacheInitializer::initialize(DeclWithIssue, SuppressionRanges);
+ }
+
+ SourceRange BugRange = Location.asRange();
+ const SourceManager &SM = Location.getManager();
+
+ return llvm::any_of(SuppressionRanges,
+ [BugRange, &SM](SourceRange Suppression) {
+ return fullyContains(Suppression, BugRange, SM);
+ });
+}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index 195940e5e643..0ac1d91b79be 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -517,6 +517,26 @@ const ConstructionContext *CallEvent::getConstructionContext() const {
return nullptr;
}
+const CallEventRef<> CallEvent::getCaller() const {
+ const auto *CallLocationContext = this->getLocationContext();
+ if (!CallLocationContext || CallLocationContext->inTopFrame())
+ return nullptr;
+
+ const auto *CallStackFrameContext = CallLocationContext->getStackFrame();
+ if (!CallStackFrameContext)
+ return nullptr;
+
+ CallEventManager &CEMgr = State->getStateManager().getCallEventManager();
+ return CEMgr.getCaller(CallStackFrameContext, State);
+}
+
+bool CallEvent::isCalledFromSystemHeader() const {
+ if (const CallEventRef<> Caller = getCaller())
+ return Caller->isInSystemHeader();
+
+ return false;
+}
+
std::optional<SVal> CallEvent::getReturnValueUnderConstruction() const {
const auto *CC = getConstructionContext();
if (!CC)
@@ -639,17 +659,17 @@ bool AnyFunctionCall::argumentsMayEscape() const {
// - CoreFoundation functions that end with "NoCopy" can free a passed-in
// buffer even if it is const.
- if (FName.endswith("NoCopy"))
+ if (FName.ends_with("NoCopy"))
return true;
// - NSXXInsertXX, for example NSMapInsertIfAbsent, since they can
// be deallocated by NSMapRemove.
- if (FName.startswith("NS") && FName.contains("Insert"))
+ if (FName.starts_with("NS") && FName.contains("Insert"))
return true;
// - Many CF containers allow objects to escape through custom
// allocators/deallocators upon container construction. (PR12101)
- if (FName.startswith("CF") || FName.startswith("CG")) {
+ if (FName.starts_with("CF") || FName.starts_with("CG")) {
return StrInStrNoCase(FName, "InsertValue") != StringRef::npos ||
StrInStrNoCase(FName, "AddValue") != StringRef::npos ||
StrInStrNoCase(FName, "SetValue") != StringRef::npos ||
@@ -715,10 +735,14 @@ void CXXInstanceCall::getExtraInvalidatedValues(
SVal CXXInstanceCall::getCXXThisVal() const {
const Expr *Base = getCXXThisExpr();
// FIXME: This doesn't handle an overloaded ->* operator.
- if (!Base)
- return UnknownVal();
+ SVal ThisVal = Base ? getSVal(Base) : UnknownVal();
+
+ if (isa<NonLoc>(ThisVal)) {
+ SValBuilder &SVB = getState()->getStateManager().getSValBuilder();
+ QualType OriginalTy = ThisVal.getType(SVB.getContext());
+ return SVB.evalCast(ThisVal, Base->getType(), OriginalTy);
+ }
- SVal ThisVal = getSVal(Base);
assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal));
return ThisVal;
}
@@ -765,8 +789,9 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const {
// the static type. However, because we currently don't update
// DynamicTypeInfo when an object is cast, we can't actually be sure the
// DynamicTypeInfo is up to date. This assert should be re-enabled once
- // this is fixed. <rdar://problem/12287087>
- //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
+ // this is fixed.
+ //
+ // assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo");
return {};
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
index c25165cce128..d6d4cec9dd3d 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerContext.cpp
@@ -105,10 +105,11 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD,
if (FName.equals(Name))
return true;
- if (FName.startswith("__inline") && FName.contains(Name))
+ if (FName.starts_with("__inline") && FName.contains(Name))
return true;
- if (FName.startswith("__") && FName.endswith("_chk") && FName.contains(Name))
+ if (FName.starts_with("__") && FName.ends_with("_chk") &&
+ FName.contains(Name))
return true;
return false;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
index 1b3e8b11549d..b9c6278991f4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CheckerRegistryData.cpp
@@ -82,7 +82,7 @@ static constexpr char PackageSeparator = '.';
static bool isInPackage(const CheckerInfo &Checker, StringRef PackageName) {
// Does the checker's full name have the package as a prefix?
- if (!Checker.FullName.startswith(PackageName))
+ if (!Checker.FullName.starts_with(PackageName))
return false;
// Is the package actually just the name of a specific checker?
@@ -158,7 +158,7 @@ void CheckerRegistryData::printCheckerWithDescList(
continue;
}
- if (Checker.FullName.startswith("alpha")) {
+ if (Checker.FullName.starts_with("alpha")) {
if (AnOpts.ShowCheckerHelpAlpha)
Print(Out, Checker,
("(Enable only for development!) " + Checker.Desc).str());
@@ -228,7 +228,7 @@ void CheckerRegistryData::printCheckerOptionList(const AnalyzerOptions &AnOpts,
}
if (Option.DevelopmentStatus == "alpha" ||
- Entry.first.startswith("alpha")) {
+ Entry.first.starts_with("alpha")) {
if (AnOpts.ShowCheckerOptionAlphaList)
Print(Out, FullOption,
llvm::Twine("(Enable only for development!) " + Desc).str());
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
index 9ef3455a110a..c0b3f346b654 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ConstraintManager.cpp
@@ -91,7 +91,7 @@ ConstraintManager::assumeDualImpl(ProgramStateRef &State,
ConstraintManager::ProgramStatePair
ConstraintManager::assumeDual(ProgramStateRef State, DefinedSVal Cond) {
- auto AssumeFun = [&](bool Assumption) {
+ auto AssumeFun = [&, Cond](bool Assumption) {
return assumeInternal(State, Cond, Assumption);
};
return assumeDualImpl(State, AssumeFun);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
index 386a34f6cd4a..d3499e7a917d 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -503,8 +503,8 @@ void CoreEngine::HandleVirtualBaseBranch(const CFGBlock *B,
if (const auto *CallerCtor = dyn_cast_or_null<CXXConstructExpr>(
LCtx->getStackFrame()->getCallSite())) {
switch (CallerCtor->getConstructionKind()) {
- case CXXConstructExpr::CK_NonVirtualBase:
- case CXXConstructExpr::CK_VirtualBase: {
+ case CXXConstructionKind::NonVirtualBase:
+ case CXXConstructionKind::VirtualBase: {
BlockEdge Loc(B, *B->succ_begin(), LCtx);
HandleBlockEdge(Loc, Pred);
return;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
index 6a86536492cd..6cf06413b537 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/DynamicExtent.cpp
@@ -30,7 +30,9 @@ DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State,
MR = MR->StripCasts();
if (const DefinedOrUnknownSVal *Size = State->get<DynamicExtentMap>(MR))
- return *Size;
+ if (auto SSize =
+ SVB.convertToArrayIndex(*Size).getAs<DefinedOrUnknownSVal>())
+ return *SSize;
return MR->getMemRegionManager().getStaticSize(MR, SVB);
}
@@ -40,6 +42,32 @@ DefinedOrUnknownSVal getElementExtent(QualType Ty, SValBuilder &SVB) {
SVB.getArrayIndexType());
}
+static DefinedOrUnknownSVal getConstantArrayElementCount(SValBuilder &SVB,
+ const MemRegion *MR) {
+ MR = MR->StripCasts();
+
+ const auto *TVR = MR->getAs<TypedValueRegion>();
+ if (!TVR)
+ return UnknownVal();
+
+ if (const ConstantArrayType *CAT =
+ SVB.getContext().getAsConstantArrayType(TVR->getValueType()))
+ return SVB.makeIntVal(CAT->getSize(), /* isUnsigned = */ false);
+
+ return UnknownVal();
+}
+
+static DefinedOrUnknownSVal
+getDynamicElementCount(ProgramStateRef State, SVal Size,
+ DefinedOrUnknownSVal ElementSize) {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+
+ auto ElementCount =
+ SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType())
+ .getAs<DefinedOrUnknownSVal>();
+ return ElementCount.value_or(UnknownVal());
+}
+
DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
const MemRegion *MR,
SValBuilder &SVB,
@@ -47,17 +75,16 @@ DefinedOrUnknownSVal getDynamicElementCount(ProgramStateRef State,
assert(MR != nullptr && "Not-null region expected");
MR = MR->StripCasts();
- DefinedOrUnknownSVal Size = getDynamicExtent(State, MR, SVB);
- SVal ElementSize = getElementExtent(ElementTy, SVB);
+ DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB);
+ if (ElementSize.isZeroConstant())
+ return getConstantArrayElementCount(SVB, MR);
- SVal ElementCount =
- SVB.evalBinOp(State, BO_Div, Size, ElementSize, SVB.getArrayIndexType());
-
- return ElementCount.castAs<DefinedOrUnknownSVal>();
+ return getDynamicElementCount(State, getDynamicExtent(State, MR, SVB),
+ ElementSize);
}
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV) {
- SValBuilder &SvalBuilder = State->getStateManager().getSValBuilder();
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
const MemRegion *MRegion = BufV.getAsRegion();
if (!MRegion)
return UnknownVal();
@@ -68,15 +95,28 @@ SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV) {
if (!BaseRegion)
return UnknownVal();
- NonLoc OffsetInBytes = SvalBuilder.makeArrayIndex(
- Offset.getOffset() /
- MRegion->getMemRegionManager().getContext().getCharWidth());
- DefinedOrUnknownSVal ExtentInBytes =
- getDynamicExtent(State, BaseRegion, SvalBuilder);
+ NonLoc OffsetInChars =
+ SVB.makeArrayIndex(Offset.getOffset() / SVB.getContext().getCharWidth());
+ DefinedOrUnknownSVal ExtentInBytes = getDynamicExtent(State, BaseRegion, SVB);
+
+ return SVB.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, ExtentInBytes,
+ OffsetInChars, SVB.getArrayIndexType());
+}
+
+DefinedOrUnknownSVal getDynamicElementCountWithOffset(ProgramStateRef State,
+ SVal BufV,
+ QualType ElementTy) {
+ const MemRegion *MR = BufV.getAsRegion();
+ if (!MR)
+ return UnknownVal();
+
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ DefinedOrUnknownSVal ElementSize = getElementExtent(ElementTy, SVB);
+ if (ElementSize.isZeroConstant())
+ return getConstantArrayElementCount(SVB, MR);
- return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub,
- ExtentInBytes, OffsetInBytes,
- SvalBuilder.getArrayIndexType());
+ return getDynamicElementCount(State, getDynamicExtentWithOffset(State, BufV),
+ ElementSize);
}
ProgramStateRef setDynamicExtent(ProgramStateRef State, const MemRegion *MR,
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 144f034a9dfe..24e91a22fd68 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -299,7 +299,7 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) {
}
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
- if (!MD->isStatic()) {
+ if (MD->isImplicitObjectMemberFunction()) {
// Precondition: 'this' is always non-null upon entry to the
// top-level function. This is our starting assumption for
// analyzing an "open" program.
@@ -993,6 +993,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
return;
case CFGElement::LifetimeEnds:
+ case CFGElement::CleanupFunction:
case CFGElement::ScopeBegin:
case CFGElement::ScopeEnd:
return;
@@ -1221,6 +1222,14 @@ void ExprEngine::ProcessInitializer(const CFGInitializer CFGInit,
PostInitializer PP(BMI, FieldLoc.getAsRegion(), stackFrame);
evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP);
}
+ } else if (BMI->isBaseInitializer() && isa<InitListExpr>(Init)) {
+ // When the base class is initialized with an initialization list and the
+ // base class does not have a ctor, there will not be a CXXConstructExpr to
+ // initialize the base region. Hence, we need to make the bind for it.
+ SVal BaseLoc = getStoreManager().evalDerivedToBase(
+ thisVal, QualType(BMI->getBaseClass(), 0), BMI->isBaseVirtual());
+ SVal InitVal = State->getSVal(Init, stackFrame);
+ evalBind(Tmp, Init, Pred, BaseLoc, InitVal, /*isInit=*/true);
} else {
assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer());
Tmp.insert(Pred);
@@ -1746,6 +1755,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
case Stmt::OMPForSimdDirectiveClass:
case Stmt::OMPSectionsDirectiveClass:
case Stmt::OMPSectionDirectiveClass:
+ case Stmt::OMPScopeDirectiveClass:
case Stmt::OMPSingleDirectiveClass:
case Stmt::OMPMasterDirectiveClass:
case Stmt::OMPCriticalDirectiveClass:
@@ -2112,7 +2122,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
// valid region.
const Decl *Callee = OCE->getCalleeDecl();
if (const auto *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) {
- if (MD->isInstance()) {
+ if (MD->isImplicitObjectMemberFunction()) {
ProgramStateRef State = Pred->getState();
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef NewState =
@@ -2507,7 +2517,7 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 &&
AMgr.options.ShouldWidenLoops) {
const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt();
- if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt>(Term))
+ if (!isa_and_nonnull<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(Term))
return;
// Widen.
const LocationContext *LCtx = Pred->getLocationContext();
@@ -3355,7 +3365,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred,
// Handle C++ method calls.
if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) {
- if (MD->isInstance())
+ if (MD->isImplicitObjectMemberFunction())
state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr);
SVal MDVal = svalBuilder.getFunctionPointer(MD);
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
index 2a47116db55a..7e431f7e598c 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -264,7 +264,8 @@ ProgramStateRef ExprEngine::handleLValueBitCast(
}
// Delegate to SValBuilder to process.
SVal OrigV = state->getSVal(Ex, LCtx);
- SVal V = svalBuilder.evalCast(OrigV, T, ExTy);
+ SVal SimplifiedOrigV = svalBuilder.simplifySVal(state, OrigV);
+ SVal V = svalBuilder.evalCast(SimplifiedOrigV, T, ExTy);
// Negate the result if we're treating the boolean as a signed i1
if (CastE->getCastKind() == CK_BooleanToSignedIntegral && V.isValid())
V = svalBuilder.evalMinus(V.castAs<NonLoc>());
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 7ee7c1394a67..504fd7f05e0f 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -612,10 +612,10 @@ void ExprEngine::handleConstructor(const Expr *E,
assert(C || getCurrentCFGElement().getAs<CFGStmt>());
const ConstructionContext *CC = C ? C->getConstructionContext() : nullptr;
- const CXXConstructExpr::ConstructionKind CK =
+ const CXXConstructionKind CK =
CE ? CE->getConstructionKind() : CIE->getConstructionKind();
switch (CK) {
- case CXXConstructExpr::CK_Complete: {
+ case CXXConstructionKind::Complete: {
// Inherited constructors are always base class constructors.
assert(CE && !CIE && "A complete constructor is inherited?!");
@@ -666,21 +666,21 @@ void ExprEngine::handleConstructor(const Expr *E,
CE, State, currBldrCtx, LCtx, CC, CallOpts, Idx);
break;
}
- case CXXConstructExpr::CK_VirtualBase: {
+ case CXXConstructionKind::VirtualBase: {
// Make sure we are not calling virtual base class initializers twice.
// Only the most-derived object should initialize virtual base classes.
const auto *OuterCtor = dyn_cast_or_null<CXXConstructExpr>(
LCtx->getStackFrame()->getCallSite());
assert(
(!OuterCtor ||
- OuterCtor->getConstructionKind() == CXXConstructExpr::CK_Complete ||
- OuterCtor->getConstructionKind() == CXXConstructExpr::CK_Delegating) &&
+ OuterCtor->getConstructionKind() == CXXConstructionKind::Complete ||
+ OuterCtor->getConstructionKind() == CXXConstructionKind::Delegating) &&
("This virtual base should have already been initialized by "
"the most derived class!"));
(void)OuterCtor;
[[fallthrough]];
}
- case CXXConstructExpr::CK_NonVirtualBase:
+ case CXXConstructionKind::NonVirtualBase:
// In C++17, classes with non-virtual bases may be aggregates, so they would
// be initialized as aggregates without a constructor call, so we may have
// a base class constructed directly into an initializer list without
@@ -699,17 +699,17 @@ void ExprEngine::handleConstructor(const Expr *E,
break;
}
[[fallthrough]];
- case CXXConstructExpr::CK_Delegating: {
+ case CXXConstructionKind::Delegating: {
const CXXMethodDecl *CurCtor = cast<CXXMethodDecl>(LCtx->getDecl());
Loc ThisPtr = getSValBuilder().getCXXThis(CurCtor,
LCtx->getStackFrame());
SVal ThisVal = State->getSVal(ThisPtr);
- if (CK == CXXConstructExpr::CK_Delegating) {
+ if (CK == CXXConstructionKind::Delegating) {
Target = ThisVal;
} else {
// Cast to the base type.
- bool IsVirtual = (CK == CXXConstructExpr::CK_VirtualBase);
+ bool IsVirtual = (CK == CXXConstructionKind::VirtualBase);
SVal BaseVal =
getStoreManager().evalDerivedToBase(ThisVal, E->getType(), IsVirtual);
Target = BaseVal;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index b987ce278936..4755b6bfa6dc 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -888,7 +888,7 @@ ExprEngine::mayInlineCallKind(const CallEvent &Call, const ExplodedNode *Pred,
if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors))
return CIP_DisallowedAlways;
- if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) {
+ if (CtorExpr->getConstructionKind() == CXXConstructionKind::Complete) {
// If we don't handle temporary destructors, we shouldn't inline
// their constructors.
if (CallOpts.IsTemporaryCtorOrDtor &&
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
index 8072531ef6fd..f075df3ab5e4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp
@@ -167,19 +167,32 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME,
// intentionally drops coverage in order to prevent false alarms
// in the following scenario:
//
- // id result = [o someMethod]
- // if (result) {
- // if (!o) {
- // // <-- This program point should be unreachable because if o is nil
- // // it must the case that result is nil as well.
+ // id result = [o someMethod]
+ // if (result) {
+ // if (!o) {
+ // // <-- This program point should be unreachable because if o is nil
+ // // it must the case that result is nil as well.
+ // }
// }
- // }
//
- // We could avoid dropping coverage by performing an explicit case split
- // on each method call -- but this would get very expensive. An alternative
- // would be to introduce lazy constraints.
- // FIXME: This ignores many potential bugs (<rdar://problem/11733396>).
- // Revisit once we have lazier constraints.
+ // However, it also loses coverage of the nil path prematurely,
+ // leading to missed reports.
+ //
+ // It's possible to handle this by performing a state split on every call:
+ // explore the state where the receiver is non-nil, and independently
+ // explore the state where it's nil. But this is not only slow, but
+ // completely unwarranted. The mere presence of the message syntax in the code
+ // isn't sufficient evidence that nil is a realistic possibility.
+ //
+ // An ideal solution would be to add the following constraint that captures
+ // both possibilities without splitting the state:
+ //
+ // ($x == 0) => ($y == 0) (1)
+ //
+ // where in our case '$x' is the receiver symbol, '$y' is the returned symbol,
+ // and '=>' is logical implication. But RangeConstraintManager can't handle
+ // such constraints yet, so for now we go with a simpler, more restrictive
+ // constraint: $x != 0, from which (1) follows as a vacuous truth.
if (Msg->isInstanceMessage()) {
SVal recVal = Msg->getReceiverSVal();
if (!recVal.isUndef()) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
index 0fe0c93dc016..69d25120dcd4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp
@@ -112,7 +112,7 @@ public:
// Add HTML header/footers to file specified by FID
void FinalizeHTML(const PathDiagnostic &D, Rewriter &R,
const SourceManager &SMgr, const PathPieces &path,
- FileID FID, const FileEntry *Entry, const char *declName);
+ FileID FID, FileEntryRef Entry, const char *declName);
// Rewrite the file specified by FID with HTML formatting.
void RewriteFile(Rewriter &R, const PathPieces &path, FileID FID);
@@ -326,7 +326,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D,
FileID ReportFile =
path.back()->getLocation().asLocation().getExpansionLoc().getFileID();
- const FileEntry *Entry = SMgr.getFileEntryForID(ReportFile);
+ OptionalFileEntryRef Entry = SMgr.getFileEntryRefForID(ReportFile);
FileName << llvm::sys::path::filename(Entry->getName()).str() << "-"
<< declName.c_str() << "-" << offsetDecl << "-";
@@ -396,7 +396,7 @@ std::string HTMLDiagnostics::GenerateHTML(const PathDiagnostic& D, Rewriter &R,
os << "<div class=FileNav><a href=\"#File" << (I - 1)->getHashValue()
<< "\">&#x2190;</a></div>";
- os << "<h4 class=FileName>" << SMgr.getFileEntryForID(*I)->getName()
+ os << "<h4 class=FileName>" << SMgr.getFileEntryRefForID(*I)->getName()
<< "</h4>\n";
// Right nav arrow
@@ -429,8 +429,8 @@ std::string HTMLDiagnostics::GenerateHTML(const PathDiagnostic& D, Rewriter &R,
// Add CSS, header, and footer.
FileID FID =
path.back()->getLocation().asLocation().getExpansionLoc().getFileID();
- const FileEntry* Entry = SMgr.getFileEntryForID(FID);
- FinalizeHTML(D, R, SMgr, path, FileIDs[0], Entry, declName);
+ OptionalFileEntryRef Entry = SMgr.getFileEntryRefForID(FID);
+ FinalizeHTML(D, R, SMgr, path, FileIDs[0], *Entry, declName);
std::string file;
llvm::raw_string_ostream os(file);
@@ -537,16 +537,17 @@ document.addEventListener("DOMContentLoaded", function() {
return s;
}
-void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
- const SourceManager& SMgr, const PathPieces& path, FileID FID,
- const FileEntry *Entry, const char *declName) {
+void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic &D, Rewriter &R,
+ const SourceManager &SMgr,
+ const PathPieces &path, FileID FID,
+ FileEntryRef Entry, const char *declName) {
// This is a cludge; basically we want to append either the full
// working directory if we have no directory information. This is
// a work in progress.
llvm::SmallString<0> DirName;
- if (llvm::sys::path::is_relative(Entry->getName())) {
+ if (llvm::sys::path::is_relative(Entry.getName())) {
llvm::sys::fs::current_path(DirName);
DirName += '/';
}
@@ -575,7 +576,7 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
<< "<h3>Bug Summary</h3>\n<table class=\"simpletable\">\n"
"<tr><td class=\"rowname\">File:</td><td>"
<< html::EscapeText(DirName)
- << html::EscapeText(Entry->getName())
+ << html::EscapeText(Entry.getName())
<< "</td></tr>\n<tr><td class=\"rowname\">Warning:</td><td>"
"<a href=\"#EndPath\">line "
<< LineNumber
@@ -592,11 +593,11 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
P->getLocation().asLocation().getExpansionLineNumber();
int ColumnNumber =
P->getLocation().asLocation().getExpansionColumnNumber();
+ ++NumExtraPieces;
os << "<tr><td class=\"rowname\">Note:</td><td>"
<< "<a href=\"#Note" << NumExtraPieces << "\">line "
<< LineNumber << ", column " << ColumnNumber << "</a><br />"
<< P->getString() << "</td></tr>";
- ++NumExtraPieces;
}
}
@@ -656,9 +657,9 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
if (!BugCategory.empty())
os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n";
- os << "\n<!-- BUGFILE " << DirName << Entry->getName() << " -->\n";
+ os << "\n<!-- BUGFILE " << DirName << Entry.getName() << " -->\n";
- os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry->getName()) << " -->\n";
+ os << "\n<!-- FILENAME " << llvm::sys::path::filename(Entry.getName()) << " -->\n";
os << "\n<!-- FUNCTIONNAME " << declName << " -->\n";
@@ -682,7 +683,7 @@ void HTMLDiagnostics::FinalizeHTML(const PathDiagnostic& D, Rewriter &R,
R.InsertTextBefore(SMgr.getLocForStartOfFile(FID), os.str());
}
- html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry->getName());
+ html::AddHeaderFooterInternalBuiltinCSS(R, FID, Entry.getName());
}
StringRef HTMLDiagnostics::showHelpJavascript() {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
index 748c65f578a8..9e4280176062 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/LoopWidening.cpp
@@ -35,6 +35,8 @@ static const Expr *getLoopCondition(const Stmt *LoopStmt) {
return cast<WhileStmt>(LoopStmt)->getCond();
case Stmt::DoStmtClass:
return cast<DoStmt>(LoopStmt)->getCond();
+ case Stmt::CXXForRangeStmtClass:
+ return cast<CXXForRangeStmt>(LoopStmt)->getCond();
}
}
@@ -45,7 +47,7 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
const LocationContext *LCtx,
unsigned BlockCount, const Stmt *LoopStmt) {
- assert((isa<ForStmt, WhileStmt, DoStmt>(LoopStmt)));
+ assert((isa<ForStmt, WhileStmt, DoStmt, CXXForRangeStmt>(LoopStmt)));
// Invalidate values in the current state.
// TODO Make this more conservative by only invalidating values that might
@@ -84,7 +86,7 @@ ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
// pointer should remain unchanged. Ignore static methods, since they do not
// have 'this' pointers.
const CXXMethodDecl *CXXMD = dyn_cast<CXXMethodDecl>(STC->getDecl());
- if (CXXMD && !CXXMD->isStatic()) {
+ if (CXXMD && CXXMD->isImplicitObjectMemberFunction()) {
const CXXThisRegion *ThisR =
MRMgr.getCXXThisRegion(CXXMD->getThisType(), STC);
ITraits.setTrait(ThisR,
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
index bdf485364cef..be19a1c118ea 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp
@@ -804,7 +804,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl(
o << " <key>files</key>\n"
" <array>\n";
for (FileID FID : Fids)
- EmitString(o << " ", SM.getFileEntryForID(FID)->getName()) << '\n';
+ EmitString(o << " ", SM.getFileEntryRefForID(FID)->getName()) << '\n';
o << " </array>\n";
if (llvm::AreStatisticsEnabled() && DiagOpts.ShouldSerializeStats) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
index 5de99384449a..25d066c4652f 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1876,6 +1876,12 @@ public:
const llvm::APSInt *getSymVal(ProgramStateRef State,
SymbolRef Sym) const override;
+ const llvm::APSInt *getSymMinVal(ProgramStateRef State,
+ SymbolRef Sym) const override;
+
+ const llvm::APSInt *getSymMaxVal(ProgramStateRef State,
+ SymbolRef Sym) const override;
+
ProgramStateRef removeDeadBindings(ProgramStateRef State,
SymbolReaper &SymReaper) override;
@@ -2863,6 +2869,22 @@ const llvm::APSInt *RangeConstraintManager::getSymVal(ProgramStateRef St,
return T ? T->getConcreteValue() : nullptr;
}
+const llvm::APSInt *RangeConstraintManager::getSymMinVal(ProgramStateRef St,
+ SymbolRef Sym) const {
+ const RangeSet *T = getConstraint(St, Sym);
+ if (!T || T->isEmpty())
+ return nullptr;
+ return &T->getMinValue();
+}
+
+const llvm::APSInt *RangeConstraintManager::getSymMaxVal(ProgramStateRef St,
+ SymbolRef Sym) const {
+ const RangeSet *T = getConstraint(St, Sym);
+ if (!T || T->isEmpty())
+ return nullptr;
+ return &T->getMaxValue();
+}
+
//===----------------------------------------------------------------------===//
// Remove dead symbols from existing constraints
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
index 4fe828bdf768..eb9cde5c8918 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -114,7 +114,7 @@ nonloc::SymbolVal SValBuilder::makeNonLoc(const SymExpr *operand,
assert(operand);
assert(!Loc::isLocType(toTy));
if (fromTy == toTy)
- return operand;
+ return nonloc::SymbolVal(operand);
return nonloc::SymbolVal(SymMgr.getCastSymbol(operand, fromTy, toTy));
}
@@ -231,6 +231,14 @@ SValBuilder::getConjuredHeapSymbolVal(const Expr *E,
return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym));
}
+loc::MemRegionVal SValBuilder::getAllocaRegionVal(const Expr *E,
+ const LocationContext *LCtx,
+ unsigned VisitCount) {
+ const AllocaRegion *R =
+ getRegionManager().getAllocaRegion(E, VisitCount, LCtx);
+ return loc::MemRegionVal(R);
+}
+
DefinedSVal SValBuilder::getMetadataSymbolVal(const void *symbolTag,
const MemRegion *region,
const Expr *expr, QualType type,
@@ -275,7 +283,7 @@ DefinedSVal SValBuilder::getMemberPointer(const NamedDecl *ND) {
// We don't need to play a similar trick for static member fields
// because these are represented as plain VarDecls and not FieldDecls
// in the AST.
- if (MD->isStatic())
+ if (!MD->isImplicitObjectMemberFunction())
return getFunctionPointer(MD);
}
@@ -446,7 +454,7 @@ SVal SValBuilder::makeSymExprValNN(BinaryOperator::Opcode Op,
}
SVal SValBuilder::evalMinus(NonLoc X) {
- switch (X.getSubKind()) {
+ switch (X.getKind()) {
case nonloc::ConcreteIntKind:
return makeIntVal(-X.castAs<nonloc::ConcreteInt>().getValue());
case nonloc::SymbolValKind:
@@ -458,7 +466,7 @@ SVal SValBuilder::evalMinus(NonLoc X) {
}
SVal SValBuilder::evalComplement(NonLoc X) {
- switch (X.getSubKind()) {
+ switch (X.getKind()) {
case nonloc::ConcreteIntKind:
return makeIntVal(~X.castAs<nonloc::ConcreteInt>().getValue());
case nonloc::SymbolValKind:
@@ -598,11 +606,9 @@ SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
APSIntType ToType(getContext().getTypeSize(castTy),
castTy->isUnsignedIntegerType());
llvm::APSInt ToTypeMax = ToType.getMaxValue();
- NonLoc ToTypeMaxVal =
- makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
- : ToTypeMax.getSExtValue(),
- castTy)
- .castAs<NonLoc>();
+
+ NonLoc ToTypeMaxVal = makeIntVal(ToTypeMax);
+
// Check the range of the symbol being casted against the maximum value of the
// target type.
NonLoc FromVal = val.castAs<NonLoc>();
@@ -660,7 +666,7 @@ public:
}
SVal VisitUndefinedVal(UndefinedVal V) { return V; }
SVal VisitUnknownVal(UnknownVal V) { return V; }
- SVal VisitLocConcreteInt(loc::ConcreteInt V) {
+ SVal VisitConcreteInt(loc::ConcreteInt V) {
// Pointer to bool.
if (CastTy->isBooleanType())
return VB.makeTruthVal(V.getValue().getBoolValue(), CastTy);
@@ -682,7 +688,7 @@ public:
// Pointer to whatever else.
return UnknownVal();
}
- SVal VisitLocGotoLabel(loc::GotoLabel V) {
+ SVal VisitGotoLabel(loc::GotoLabel V) {
// Pointer to bool.
if (CastTy->isBooleanType())
// Labels are always true.
@@ -709,7 +715,7 @@ public:
// Pointer to whatever else.
return UnknownVal();
}
- SVal VisitLocMemRegionVal(loc::MemRegionVal V) {
+ SVal VisitMemRegionVal(loc::MemRegionVal V) {
// Pointer to bool.
if (CastTy->isBooleanType()) {
const MemRegion *R = V.getRegion();
@@ -854,11 +860,11 @@ public:
// necessary for bit-level reasoning as well.
return UnknownVal();
}
- SVal VisitNonLocCompoundVal(nonloc::CompoundVal V) {
+ SVal VisitCompoundVal(nonloc::CompoundVal V) {
// Compound to whatever.
return UnknownVal();
}
- SVal VisitNonLocConcreteInt(nonloc::ConcreteInt V) {
+ SVal VisitConcreteInt(nonloc::ConcreteInt V) {
auto CastedValue = [V, this]() {
llvm::APSInt Value = V.getValue();
VB.getBasicValueFactory().getAPSIntType(CastTy).apply(Value);
@@ -880,11 +886,11 @@ public:
// Pointer to whatever else.
return UnknownVal();
}
- SVal VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal V) {
+ SVal VisitLazyCompoundVal(nonloc::LazyCompoundVal V) {
// LazyCompound to whatever.
return UnknownVal();
}
- SVal VisitNonLocLocAsInteger(nonloc::LocAsInteger V) {
+ SVal VisitLocAsInteger(nonloc::LocAsInteger V) {
Loc L = V.getLoc();
// Pointer as integer to bool.
@@ -906,7 +912,7 @@ public:
const MemRegion *R = L.getAsRegion();
if (!IsUnknownOriginalType && R) {
if (CastTy->isIntegralOrEnumerationType())
- return VisitLocMemRegionVal(loc::MemRegionVal(R));
+ return VisitMemRegionVal(loc::MemRegionVal(R));
if (Loc::isLocType(CastTy)) {
assert(Loc::isLocType(OriginalTy) || OriginalTy->isFunctionType() ||
@@ -920,7 +926,7 @@ public:
} else {
if (Loc::isLocType(CastTy)) {
if (IsUnknownOriginalType)
- return VisitLocMemRegionVal(loc::MemRegionVal(R));
+ return VisitMemRegionVal(loc::MemRegionVal(R));
return L;
}
@@ -945,7 +951,7 @@ public:
// Pointer as integer to whatever else.
return UnknownVal();
}
- SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ SVal VisitSymbolVal(nonloc::SymbolVal V) {
SymbolRef SE = V.getSymbol();
const bool IsUnknownOriginalType = OriginalTy.isNull();
@@ -982,10 +988,15 @@ public:
return VB.makeNonLoc(SE, T, CastTy);
}
+ // FIXME: We should be able to cast NonLoc -> Loc
+ // (when Loc::isLocType(CastTy) is true)
+ // But it's hard to do as SymbolicRegions can't refer to SymbolCasts holding
+ // generic SymExprs. Check the commit message for the details.
+
// Symbol to pointer and whatever else.
return UnknownVal();
}
- SVal VisitNonLocPointerToMember(nonloc::PointerToMember V) {
+ SVal VisitPointerToMember(nonloc::PointerToMember V) {
// Member pointer to whatever.
return V;
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
index 2a43a01ff886..0e1351215bb4 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SVals.cpp
@@ -136,10 +136,10 @@ private:
public:
TypeRetrievingVisitor(const ASTContext &Context) : Context(Context) {}
- QualType VisitLocMemRegionVal(loc::MemRegionVal MRV) {
+ QualType VisitMemRegionVal(loc::MemRegionVal MRV) {
return Visit(MRV.getRegion());
}
- QualType VisitLocGotoLabel(loc::GotoLabel GL) {
+ QualType VisitGotoLabel(loc::GotoLabel GL) {
return QualType{Context.VoidPtrTy};
}
template <class ConcreteInt> QualType VisitConcreteInt(ConcreteInt CI) {
@@ -148,13 +148,7 @@ public:
return Context.BoolTy;
return Context.getIntTypeForBitwidth(Value.getBitWidth(), Value.isSigned());
}
- QualType VisitLocConcreteInt(loc::ConcreteInt CI) {
- return VisitConcreteInt(CI);
- }
- QualType VisitNonLocConcreteInt(nonloc::ConcreteInt CI) {
- return VisitConcreteInt(CI);
- }
- QualType VisitNonLocLocAsInteger(nonloc::LocAsInteger LI) {
+ QualType VisitLocAsInteger(nonloc::LocAsInteger LI) {
QualType NestedType = Visit(LI.getLoc());
if (NestedType.isNull())
return NestedType;
@@ -162,13 +156,13 @@ public:
return Context.getIntTypeForBitwidth(LI.getNumBits(),
NestedType->isSignedIntegerType());
}
- QualType VisitNonLocCompoundVal(nonloc::CompoundVal CV) {
+ QualType VisitCompoundVal(nonloc::CompoundVal CV) {
return CV.getValue()->getType();
}
- QualType VisitNonLocLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
+ QualType VisitLazyCompoundVal(nonloc::LazyCompoundVal LCV) {
return LCV.getRegion()->getValueType();
}
- QualType VisitNonLocSymbolVal(nonloc::SymbolVal SV) {
+ QualType VisitSymbolVal(nonloc::SymbolVal SV) {
return Visit(SV.getSymbol());
}
QualType VisitSymbolicRegion(const SymbolicRegion *SR) {
@@ -281,30 +275,33 @@ void SVal::printJson(raw_ostream &Out, bool AddQuotes) const {
}
void SVal::dumpToStream(raw_ostream &os) const {
- switch (getBaseKind()) {
- case UnknownValKind:
- os << "Unknown";
- break;
- case NonLocKind:
- castAs<NonLoc>().dumpToStream(os);
- break;
- case LocKind:
- castAs<Loc>().dumpToStream(os);
- break;
- case UndefinedValKind:
- os << "Undefined";
- break;
+ if (isUndef()) {
+ os << "Undefined";
+ return;
+ }
+ if (isUnknown()) {
+ os << "Unknown";
+ return;
+ }
+ if (NonLoc::classof(*this)) {
+ castAs<NonLoc>().dumpToStream(os);
+ return;
+ }
+ if (Loc::classof(*this)) {
+ castAs<Loc>().dumpToStream(os);
+ return;
}
+ llvm_unreachable("Unhandled SVal kind!");
}
void NonLoc::dumpToStream(raw_ostream &os) const {
- switch (getSubKind()) {
- case nonloc::ConcreteIntKind: {
- const auto &Value = castAs<nonloc::ConcreteInt>().getValue();
- os << Value << ' ' << (Value.isSigned() ? 'S' : 'U')
- << Value.getBitWidth() << 'b';
- break;
- }
+ switch (getKind()) {
+ case nonloc::ConcreteIntKind: {
+ const auto &Value = castAs<nonloc::ConcreteInt>().getValue();
+ os << Value << ' ' << (Value.isSigned() ? 'S' : 'U') << Value.getBitWidth()
+ << 'b';
+ break;
+ }
case nonloc::SymbolValKind:
os << castAs<nonloc::SymbolVal>().getSymbol();
break;
@@ -360,21 +357,21 @@ void NonLoc::dumpToStream(raw_ostream &os) const {
default:
assert(false && "Pretty-printed not implemented for this NonLoc.");
break;
- }
+ }
}
void Loc::dumpToStream(raw_ostream &os) const {
- switch (getSubKind()) {
- case loc::ConcreteIntKind:
- os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
- break;
- case loc::GotoLabelKind:
- os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
- break;
- case loc::MemRegionValKind:
- os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
- break;
- default:
- llvm_unreachable("Pretty-printing not implemented for this Loc.");
+ switch (getKind()) {
+ case loc::ConcreteIntKind:
+ os << castAs<loc::ConcreteInt>().getValue().getZExtValue() << " (Loc)";
+ break;
+ case loc::GotoLabelKind:
+ os << "&&" << castAs<loc::GotoLabel>().getLabel()->getName();
+ break;
+ case loc::MemRegionValKind:
+ os << '&' << castAs<loc::MemRegionVal>().getRegion()->getString();
+ break;
+ default:
+ llvm_unreachable("Pretty-printing not implemented for this Loc.");
}
}
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
index 3286d7f468f0..8ca2cdb9d3ab 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp
@@ -63,7 +63,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
return assumeSymUnsupported(State, Sym, Assumption);
}
- switch (Cond.getSubKind()) {
+ switch (Cond.getKind()) {
default:
llvm_unreachable("'Assume' not implemented for this NonLoc");
@@ -107,7 +107,7 @@ ProgramStateRef SimpleConstraintManager::assumeInclusiveRangeInternal(
return assumeSymInclusiveRange(State, Sym, From, To, InRange);
}
- switch (Value.getSubKind()) {
+ switch (Value.getKind()) {
default:
llvm_unreachable("'assumeInclusiveRange' is not implemented"
"for this NonLoc");
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
index 58d360a2e2db..45e48d435aca 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -28,7 +28,11 @@ class SimpleSValBuilder : public SValBuilder {
// returns NULL.
// This is an implementation detail. Checkers should use `getKnownValue()`
// instead.
- const llvm::APSInt *getConstValue(ProgramStateRef state, SVal V);
+ static const llvm::APSInt *getConstValue(ProgramStateRef state, SVal V);
+
+ // Helper function that returns the value stored in a nonloc::ConcreteInt or
+ // loc::ConcreteInt.
+ static const llvm::APSInt *getConcreteValue(SVal V);
// With one `simplifySValOnce` call, a compound symbols might collapse to
// simpler symbol tree that is still possible to further simplify. Thus, we
@@ -76,6 +80,16 @@ public:
/// (integer) value, that value is returned. Otherwise, returns NULL.
const llvm::APSInt *getKnownValue(ProgramStateRef state, SVal V) override;
+ /// Evaluates a given SVal by recursively evaluating and simplifying the
+ /// children SVals, then returns its minimal possible (integer) value. If the
+ /// constraint manager cannot provide a meaningful answer, this returns NULL.
+ const llvm::APSInt *getMinValue(ProgramStateRef state, SVal V) override;
+
+ /// Evaluates a given SVal by recursively evaluating and simplifying the
+ /// children SVals, then returns its maximal possible (integer) value. If the
+ /// constraint manager cannot provide a meaningful answer, this returns NULL.
+ const llvm::APSInt *getMaxValue(ProgramStateRef state, SVal V) override;
+
SVal simplifySVal(ProgramStateRef State, SVal V) override;
SVal MakeSymIntVal(const SymExpr *LHS, BinaryOperator::Opcode op,
@@ -445,11 +459,11 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
while (true) {
- switch (lhs.getSubKind()) {
+ switch (lhs.getKind()) {
default:
return makeSymExprValNN(op, lhs, rhs, resultTy);
case nonloc::PointerToMemberKind: {
- assert(rhs.getSubKind() == nonloc::PointerToMemberKind &&
+ assert(rhs.getKind() == nonloc::PointerToMemberKind &&
"Both SVals should have pointer-to-member-type");
auto LPTM = lhs.castAs<nonloc::PointerToMember>(),
RPTM = rhs.castAs<nonloc::PointerToMember>();
@@ -465,36 +479,36 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
}
case nonloc::LocAsIntegerKind: {
Loc lhsL = lhs.castAs<nonloc::LocAsInteger>().getLoc();
- switch (rhs.getSubKind()) {
- case nonloc::LocAsIntegerKind:
- // FIXME: at the moment the implementation
- // of modeling "pointers as integers" is not complete.
- if (!BinaryOperator::isComparisonOp(op))
- return UnknownVal();
- return evalBinOpLL(state, op, lhsL,
- rhs.castAs<nonloc::LocAsInteger>().getLoc(),
- resultTy);
- case nonloc::ConcreteIntKind: {
- // FIXME: at the moment the implementation
- // of modeling "pointers as integers" is not complete.
- if (!BinaryOperator::isComparisonOp(op))
- return UnknownVal();
- // Transform the integer into a location and compare.
- // FIXME: This only makes sense for comparisons. If we want to, say,
- // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
- // then pack it back into a LocAsInteger.
- llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
- // If the region has a symbolic base, pay attention to the type; it
- // might be coming from a non-default address space. For non-symbolic
- // regions it doesn't matter that much because such comparisons would
- // most likely evaluate to concrete false anyway. FIXME: We might
- // still need to handle the non-comparison case.
- if (SymbolRef lSym = lhs.getAsLocSymbol(true))
- BasicVals.getAPSIntType(lSym->getType()).apply(i);
- else
- BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
- return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
- }
+ switch (rhs.getKind()) {
+ case nonloc::LocAsIntegerKind:
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
+ return evalBinOpLL(state, op, lhsL,
+ rhs.castAs<nonloc::LocAsInteger>().getLoc(),
+ resultTy);
+ case nonloc::ConcreteIntKind: {
+ // FIXME: at the moment the implementation
+ // of modeling "pointers as integers" is not complete.
+ if (!BinaryOperator::isComparisonOp(op))
+ return UnknownVal();
+ // Transform the integer into a location and compare.
+ // FIXME: This only makes sense for comparisons. If we want to, say,
+ // add 1 to a LocAsInteger, we'd better unpack the Loc and add to it,
+ // then pack it back into a LocAsInteger.
+ llvm::APSInt i = rhs.castAs<nonloc::ConcreteInt>().getValue();
+ // If the region has a symbolic base, pay attention to the type; it
+ // might be coming from a non-default address space. For non-symbolic
+ // regions it doesn't matter that much because such comparisons would
+ // most likely evaluate to concrete false anyway. FIXME: We might
+ // still need to handle the non-comparison case.
+ if (SymbolRef lSym = lhs.getAsLocSymbol(true))
+ BasicVals.getAPSIntType(lSym->getType()).apply(i);
+ else
+ BasicVals.getAPSIntType(Context.VoidPtrTy).apply(i);
+ return evalBinOpLL(state, op, lhsL, makeLoc(i), resultTy);
+ }
default:
switch (op) {
case BO_EQ:
@@ -505,7 +519,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
// This case also handles pointer arithmetic.
return makeSymExprValNN(op, InputLHS, InputRHS, resultTy);
}
- }
+ }
}
case nonloc::ConcreteIntKind: {
llvm::APSInt LHSValue = lhs.castAs<nonloc::ConcreteInt>().getValue();
@@ -529,8 +543,21 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state,
const llvm::APSInt *Result =
BasicVals.evalAPSInt(op, LHSValue, RHSValue);
- if (!Result)
+ if (!Result) {
+ if (op == BO_Shl || op == BO_Shr) {
+ // FIXME: At this point the constant folding claims that the result
+ // of a bitwise shift is undefined. However, constant folding
+ // relies on the inaccurate type information that is stored in the
+ // bit size of APSInt objects, and if we reached this point, then
+ // the checker core.BitwiseShift already determined that the shift
+ // is valid (in a PreStmt callback, by querying the real type from
+ // the AST node).
+ // To avoid embarrassing false positives, let's just say that we
+ // don't know anything about the result of the shift.
+ return UnknownVal();
+ }
return UndefinedVal();
+ }
return nonloc::ConcreteInt(*Result);
}
@@ -752,8 +779,7 @@ static void assertEqualBitWidths(ProgramStateRef State, Loc RhsLoc,
RhsLoc.getType(Ctx).isNull() ? 0 : Ctx.getTypeSize(RhsLoc.getType(Ctx));
uint64_t LhsBitwidth =
LhsLoc.getType(Ctx).isNull() ? 0 : Ctx.getTypeSize(LhsLoc.getType(Ctx));
- if (RhsBitwidth && LhsBitwidth &&
- (LhsLoc.getSubKind() == RhsLoc.getSubKind())) {
+ if (RhsBitwidth && LhsBitwidth && (LhsLoc.getKind() == RhsLoc.getKind())) {
assert(RhsBitwidth == LhsBitwidth &&
"RhsLoc and LhsLoc bitwidth must be same!");
}
@@ -799,7 +825,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
}
}
- switch (lhs.getSubKind()) {
+ switch (lhs.getKind()) {
default:
llvm_unreachable("Ordering not implemented for this Loc.");
@@ -1170,18 +1196,22 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state,
const llvm::APSInt *SimpleSValBuilder::getConstValue(ProgramStateRef state,
SVal V) {
- if (V.isUnknownOrUndef())
- return nullptr;
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymVal(state, Sym);
+
+ return nullptr;
+}
+
+const llvm::APSInt *SimpleSValBuilder::getConcreteValue(SVal V) {
if (std::optional<loc::ConcreteInt> X = V.getAs<loc::ConcreteInt>())
return &X->getValue();
if (std::optional<nonloc::ConcreteInt> X = V.getAs<nonloc::ConcreteInt>())
return &X->getValue();
- if (SymbolRef Sym = V.getAsSymbol())
- return state->getConstraintManager().getSymVal(state, Sym);
-
return nullptr;
}
@@ -1190,6 +1220,32 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state,
return getConstValue(state, simplifySVal(state, V));
}
+const llvm::APSInt *SimpleSValBuilder::getMinValue(ProgramStateRef state,
+ SVal V) {
+ V = simplifySVal(state, V);
+
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymMinVal(state, Sym);
+
+ return nullptr;
+}
+
+const llvm::APSInt *SimpleSValBuilder::getMaxValue(ProgramStateRef state,
+ SVal V) {
+ V = simplifySVal(state, V);
+
+ if (const llvm::APSInt *Res = getConcreteValue(V))
+ return Res;
+
+ if (SymbolRef Sym = V.getAsSymbol())
+ return state->getConstraintManager().getSymMaxVal(state, Sym);
+
+ return nullptr;
+}
+
SVal SimpleSValBuilder::simplifyUntilFixpoint(ProgramStateRef State, SVal Val) {
SVal SimplifiedVal = simplifySValOnce(State, Val);
while (SimplifiedVal != Val) {
@@ -1359,7 +1415,7 @@ SVal SimpleSValBuilder::simplifySValOnce(ProgramStateRef State, SVal V) {
SVal VisitMemRegion(const MemRegion *R) { return loc::MemRegionVal(R); }
- SVal VisitNonLocSymbolVal(nonloc::SymbolVal V) {
+ SVal VisitSymbolVal(nonloc::SymbolVal V) {
// Simplification is much more costly than computing complexity.
// For high complexity, it may be not worth it.
return Visit(V.getSymbol());
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/Store.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/Store.cpp
index 7577b7682a95..67ca61bb56ba 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -402,7 +402,7 @@ SVal StoreManager::getLValueFieldOrIvar(const Decl *D, SVal Base) {
Loc BaseL = Base.castAs<Loc>();
const SubRegion* BaseR = nullptr;
- switch (BaseL.getSubKind()) {
+ switch (BaseL.getKind()) {
case loc::MemRegionValKind:
BaseR = cast<SubRegion>(BaseL.castAs<loc::MemRegionVal>().getRegion());
break;
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
index 54e0f4bee5eb..b6ef40595e3c 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp
@@ -87,7 +87,7 @@ public:
ASTContext *Ctx;
Preprocessor &PP;
const std::string OutDir;
- AnalyzerOptionsRef Opts;
+ AnalyzerOptions &Opts;
ArrayRef<std::string> Plugins;
CodeInjector *Injector;
cross_tu::CrossTranslationUnitContext CTU;
@@ -121,15 +121,15 @@ public:
FunctionSummariesTy FunctionSummaries;
AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,
- AnalyzerOptionsRef opts, ArrayRef<std::string> plugins,
+ AnalyzerOptions &opts, ArrayRef<std::string> plugins,
CodeInjector *injector)
: RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),
- PP(CI.getPreprocessor()), OutDir(outdir), Opts(std::move(opts)),
+ PP(CI.getPreprocessor()), OutDir(outdir), Opts(opts),
Plugins(plugins), Injector(injector), CTU(CI),
MacroExpansions(CI.getLangOpts()) {
DigestAnalyzerOptions();
- if (Opts->AnalyzerDisplayProgress || Opts->PrintStats ||
- Opts->ShouldSerializeStats) {
+ if (Opts.AnalyzerDisplayProgress || Opts.PrintStats ||
+ Opts.ShouldSerializeStats) {
AnalyzerTimers = std::make_unique<llvm::TimerGroup>(
"analyzer", "Analyzer timers");
SyntaxCheckTimer = std::make_unique<llvm::Timer>(
@@ -141,27 +141,27 @@ public:
*AnalyzerTimers);
}
- if (Opts->PrintStats || Opts->ShouldSerializeStats) {
+ if (Opts.PrintStats || Opts.ShouldSerializeStats) {
llvm::EnableStatistics(/* DoPrintOnExit= */ false);
}
- if (Opts->ShouldDisplayMacroExpansions)
+ if (Opts.ShouldDisplayMacroExpansions)
MacroExpansions.registerForPreprocessor(PP);
}
~AnalysisConsumer() override {
- if (Opts->PrintStats) {
+ if (Opts.PrintStats) {
llvm::PrintStatistics();
}
}
void DigestAnalyzerOptions() {
- switch (Opts->AnalysisDiagOpt) {
+ switch (Opts.AnalysisDiagOpt) {
case PD_NONE:
break;
#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \
case PD_##NAME: \
- CREATEFN(Opts->getDiagOpts(), PathConsumers, OutDir, PP, CTU, \
+ CREATEFN(Opts.getDiagOpts(), PathConsumers, OutDir, PP, CTU, \
MacroExpansions); \
break;
#include "clang/StaticAnalyzer/Core/Analyses.def"
@@ -172,7 +172,7 @@ public:
// Create the analyzer component creators.
CreateStoreMgr = &CreateRegionStoreManager;
- switch (Opts->AnalysisConstraintsOpt) {
+ switch (Opts.AnalysisConstraintsOpt) {
default:
llvm_unreachable("Unknown constraint manager.");
#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
@@ -182,7 +182,7 @@ public:
}
void DisplayTime(llvm::TimeRecord &Time) {
- if (!Opts->AnalyzerDisplayProgress) {
+ if (!Opts.AnalyzerDisplayProgress) {
return;
}
llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)
@@ -191,7 +191,7 @@ public:
void DisplayFunction(const Decl *D, AnalysisMode Mode,
ExprEngine::InliningModes IMode) {
- if (!Opts->AnalyzerDisplayProgress)
+ if (!Opts.AnalyzerDisplayProgress)
return;
SourceManager &SM = Mgr->getASTContext().getSourceManager();
@@ -222,12 +222,12 @@ public:
void Initialize(ASTContext &Context) override {
Ctx = &Context;
- checkerMgr = std::make_unique<CheckerManager>(*Ctx, *Opts, PP, Plugins,
+ checkerMgr = std::make_unique<CheckerManager>(*Ctx, Opts, PP, Plugins,
CheckerRegistrationFns);
Mgr = std::make_unique<AnalysisManager>(*Ctx, PP, PathConsumers,
CreateStoreMgr, CreateConstraintMgr,
- checkerMgr.get(), *Opts, Injector);
+ checkerMgr.get(), Opts, Injector);
}
/// Store the top level decls in the set to be processed later on.
@@ -278,7 +278,7 @@ public:
}
bool VisitVarDecl(VarDecl *VD) {
- if (!Opts->IsNaiveCTUEnabled)
+ if (!Opts.IsNaiveCTUEnabled)
return true;
if (VD->hasExternalStorage() || VD->isStaticDataMember()) {
@@ -293,8 +293,8 @@ public:
return true;
llvm::Expected<const VarDecl *> CTUDeclOrError =
- CTU.getCrossTUDefinition(VD, Opts->CTUDir, Opts->CTUIndexName,
- Opts->DisplayCTUProgress);
+ CTU.getCrossTUDefinition(VD, Opts.CTUDir, Opts.CTUIndexName,
+ Opts.DisplayCTUProgress);
if (!CTUDeclOrError) {
handleAllErrors(CTUDeclOrError.takeError(),
@@ -308,7 +308,7 @@ public:
bool VisitFunctionDecl(FunctionDecl *FD) {
IdentifierInfo *II = FD->getIdentifier();
- if (II && II->getName().startswith("__inline"))
+ if (II && II->getName().starts_with("__inline"))
return true;
// We skip function template definitions, as their semantics is
@@ -356,7 +356,7 @@ private:
AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);
void runAnalysisOnTranslationUnit(ASTContext &C);
- /// Print \p S to stderr if \c Opts->AnalyzerDisplayProgress is set.
+ /// Print \p S to stderr if \c Opts.AnalyzerDisplayProgress is set.
void reportAnalyzerProgress(StringRef S);
}; // namespace
} // end anonymous namespace
@@ -567,12 +567,12 @@ void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {
// name correctly.
// FIXME: The user might have analyzed the requested function in Syntax mode,
// but we are unaware of that.
- if (!Opts->AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0)
- reportAnalyzerFunctionMisuse(*Opts, *Ctx);
+ if (!Opts.AnalyzeSpecificFunction.empty() && NumFunctionsAnalyzed == 0)
+ reportAnalyzerFunctionMisuse(Opts, *Ctx);
}
void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {
- if (Opts->AnalyzerDisplayProgress)
+ if (Opts.AnalyzerDisplayProgress)
llvm::errs() << S;
}
@@ -589,13 +589,13 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
const auto DiagFlusherScopeExit =
llvm::make_scope_exit([this] { Mgr.reset(); });
- if (Opts->ShouldIgnoreBisonGeneratedFiles &&
+ if (Opts.ShouldIgnoreBisonGeneratedFiles &&
fileContainsString("/* A Bison parser, made by", C)) {
reportAnalyzerProgress("Skipping bison-generated file\n");
return;
}
- if (Opts->ShouldIgnoreFlexGeneratedFiles &&
+ if (Opts.ShouldIgnoreFlexGeneratedFiles &&
fileContainsString("/* A lexical scanner generated by flex", C)) {
reportAnalyzerProgress("Skipping flex-generated file\n");
return;
@@ -603,7 +603,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
// Don't analyze if the user explicitly asked for no checks to be performed
// on this file.
- if (Opts->DisableAllCheckers) {
+ if (Opts.DisableAllCheckers) {
reportAnalyzerProgress("All checks are disabled using a supplied option\n");
return;
}
@@ -623,8 +623,8 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
AnalysisConsumer::AnalysisMode
AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
- if (!Opts->AnalyzeSpecificFunction.empty() &&
- AnalysisDeclContext::getFunctionName(D) != Opts->AnalyzeSpecificFunction)
+ if (!Opts.AnalyzeSpecificFunction.empty() &&
+ AnalysisDeclContext::getFunctionName(D) != Opts.AnalyzeSpecificFunction)
return AM_None;
// Unless -analyze-all is specified, treat decls differently depending on
@@ -632,7 +632,7 @@ AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {
// - Main source file: run both path-sensitive and non-path-sensitive checks.
// - Header files: run non-path-sensitive checks only.
// - System headers: don't run any checks.
- if (Opts->AnalyzeAll)
+ if (Opts.AnalyzeAll)
return Mode;
const SourceManager &SM = Ctx->getSourceManager();
@@ -757,8 +757,8 @@ ento::CreateAnalysisConsumer(CompilerInstance &CI) {
// Disable the effects of '-Werror' when using the AnalysisConsumer.
CI.getPreprocessor().getDiagnostics().setWarningsAsErrors(false);
- AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
- bool hasModelPath = analyzerOpts->Config.count("model-path") > 0;
+ AnalyzerOptions &analyzerOpts = CI.getAnalyzerOpts();
+ bool hasModelPath = analyzerOpts.Config.count("model-path") > 0;
return std::make_unique<AnalysisConsumer>(
CI, CI.getFrontendOpts().OutputFile, analyzerOpts,
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
index 7cd15f0f6595..ea75c794f0b7 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/AnalyzerHelpFlags.cpp
@@ -30,18 +30,18 @@ void ento::printCheckerHelp(raw_ostream &out, CompilerInstance &CI) {
out << "USAGE: -analyzer-checker <CHECKER or PACKAGE,...>\n\n";
auto CheckerMgr = std::make_unique<CheckerManager>(
- *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
+ CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
CheckerMgr->getCheckerRegistryData().printCheckerWithDescList(
- *CI.getAnalyzerOpts(), out);
+ CI.getAnalyzerOpts(), out);
}
void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) {
out << "OVERVIEW: Clang Static Analyzer Enabled Checkers List\n\n";
auto CheckerMgr = std::make_unique<CheckerManager>(
- *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
+ CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
CheckerMgr->getCheckerRegistryData().printEnabledCheckerList(out);
@@ -50,11 +50,11 @@ void ento::printEnabledCheckerList(raw_ostream &out, CompilerInstance &CI) {
void ento::printCheckerConfigList(raw_ostream &out, CompilerInstance &CI) {
auto CheckerMgr = std::make_unique<CheckerManager>(
- *CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
+ CI.getAnalyzerOpts(), CI.getLangOpts(), CI.getDiagnostics(),
CI.getFrontendOpts().Plugins);
CheckerMgr->getCheckerRegistryData().printCheckerOptionList(
- *CI.getAnalyzerOpts(), out);
+ CI.getAnalyzerOpts(), out);
}
void ento::printAnalyzerConfigList(raw_ostream &out) {
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
index f0d3f43c414c..317df90a7781 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp
@@ -310,8 +310,8 @@ template <bool IsWeak> void CheckerRegistry::resolveDependencies() {
"Failed to find the dependency of a checker!");
// We do allow diagnostics from unit test/example dependency checkers.
- assert((DependencyIt->FullName.startswith("test") ||
- DependencyIt->FullName.startswith("example") || IsWeak ||
+ assert((DependencyIt->FullName.starts_with("test") ||
+ DependencyIt->FullName.starts_with("example") || IsWeak ||
DependencyIt->IsHidden) &&
"Strong dependencies are modeling checkers, and as such "
"non-user facing! Mark them hidden in Checkers.td!");
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
index 7baae6778ebd..ae11fbbe32b7 100644
--- a/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp
@@ -48,8 +48,7 @@ void ModelInjector::onBodySynthesis(const NamedDecl *D) {
SourceManager &SM = CI.getSourceManager();
FileID mainFileID = SM.getMainFileID();
- AnalyzerOptionsRef analyzerOpts = CI.getAnalyzerOpts();
- llvm::StringRef modelPath = analyzerOpts->ModelPath;
+ llvm::StringRef modelPath = CI.getAnalyzerOpts().ModelPath;
llvm::SmallString<128> fileName;