003 File Manager
Current Path:
/usr/src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers
usr
/
src
/
contrib
/
llvm-project
/
clang
/
lib
/
StaticAnalyzer
/
Checkers
/
📁
..
📄
AllocationState.h
(1.41 KB)
📄
AnalysisOrderChecker.cpp
(8.62 KB)
📄
AnalyzerStatsChecker.cpp
(5.04 KB)
📄
ArrayBoundChecker.cpp
(3.22 KB)
📄
ArrayBoundCheckerV2.cpp
(13.07 KB)
📄
BasicObjCFoundationChecks.cpp
(43.82 KB)
📄
BlockInCriticalSectionChecker.cpp
(6.69 KB)
📄
BoolAssignmentChecker.cpp
(3.45 KB)
📄
BuiltinFunctionChecker.cpp
(5 KB)
📄
CStringChecker.cpp
(93.24 KB)
📄
CStringSyntaxChecker.cpp
(9.8 KB)
📄
CXXSelfAssignmentChecker.cpp
(3.08 KB)
📄
CallAndMessageChecker.cpp
(26.57 KB)
📄
CastSizeChecker.cpp
(4.96 KB)
📄
CastToStructChecker.cpp
(4.43 KB)
📄
CastValueChecker.cpp
(19.65 KB)
📄
CheckObjCDealloc.cpp
(37.83 KB)
📄
CheckObjCInstMethSignature.cpp
(4.8 KB)
📄
CheckPlacementNew.cpp
(11.91 KB)
📄
CheckSecuritySyntaxOnly.cpp
(38.79 KB)
📄
CheckSizeofPointer.cpp
(3.16 KB)
📄
CheckerDocumentation.cpp
(14.64 KB)
📄
ChrootChecker.cpp
(4.88 KB)
📄
CloneChecker.cpp
(8.28 KB)
📄
ContainerModeling.cpp
(39.85 KB)
📄
ConversionChecker.cpp
(7.11 KB)
📄
DeadStoresChecker.cpp
(17.82 KB)
📄
DebugCheckers.cpp
(10.41 KB)
📄
DebugContainerModeling.cpp
(4.94 KB)
📄
DebugIteratorModeling.cpp
(5.15 KB)
📄
DeleteWithNonVirtualDtorChecker.cpp
(5.35 KB)
📄
DereferenceChecker.cpp
(10.54 KB)
📄
DirectIvarAssignment.cpp
(8.02 KB)
📄
DivZeroChecker.cpp
(3.42 KB)
📄
DynamicTypeChecker.cpp
(7.31 KB)
📄
DynamicTypePropagation.cpp
(42.11 KB)
📄
EnumCastOutOfRangeChecker.cpp
(5.75 KB)
📄
ExprInspectionChecker.cpp
(15.6 KB)
📄
FixedAddressChecker.cpp
(2.33 KB)
📄
FuchsiaHandleChecker.cpp
(23.1 KB)
📄
GCDAntipatternChecker.cpp
(7.85 KB)
📄
GTestChecker.cpp
(10.52 KB)
📄
GenericTaintChecker.cpp
(34.31 KB)
📄
IdenticalExprChecker.cpp
(18.88 KB)
📄
InnerPointerChecker.cpp
(11.54 KB)
📄
InterCheckerAPI.h
(1.09 KB)
📄
InvalidatedIteratorChecker.cpp
(4.93 KB)
📄
Iterator.cpp
(10.62 KB)
📄
Iterator.h
(6.32 KB)
📄
IteratorModeling.cpp
(31.33 KB)
📄
IteratorRangeChecker.cpp
(12.64 KB)
📄
IvarInvalidationChecker.cpp
(27.63 KB)
📄
LLVMConventionsChecker.cpp
(9.9 KB)
📄
LocalizationChecker.cpp
(52.38 KB)
📄
MIGChecker.cpp
(11.3 KB)
📁
MPI-Checker
📄
MacOSKeychainAPIChecker.cpp
(25.21 KB)
📄
MacOSXAPIChecker.cpp
(6.61 KB)
📄
MallocChecker.cpp
(127.38 KB)
📄
MallocOverflowSecurityChecker.cpp
(11.91 KB)
📄
MallocSizeofChecker.cpp
(8.03 KB)
📄
MismatchedIteratorChecker.cpp
(11.01 KB)
📄
MmapWriteExecChecker.cpp
(3.22 KB)
📄
Move.h
(1.07 KB)
📄
MoveChecker.cpp
(27 KB)
📄
NSAutoreleasePoolChecker.cpp
(2.93 KB)
📄
NSErrorChecker.cpp
(10.6 KB)
📄
NoReturnFunctionChecker.cpp
(5.48 KB)
📄
NonNullParamChecker.cpp
(11.22 KB)
📄
NonnullGlobalConstantsChecker.cpp
(5.09 KB)
📄
NullabilityChecker.cpp
(46.95 KB)
📄
NumberObjectConversionChecker.cpp
(13.69 KB)
📄
OSObjectCStyleCast.cpp
(3.14 KB)
📄
ObjCAtSyncChecker.cpp
(3.34 KB)
📄
ObjCAutoreleaseWriteChecker.cpp
(8.62 KB)
📄
ObjCContainersASTChecker.cpp
(5.5 KB)
📄
ObjCContainersChecker.cpp
(6.71 KB)
📄
ObjCMissingSuperCallChecker.cpp
(9.23 KB)
📄
ObjCPropertyChecker.cpp
(3.03 KB)
📄
ObjCSelfInitChecker.cpp
(16.21 KB)
📄
ObjCSuperDeallocChecker.cpp
(9.33 KB)
📄
ObjCUnusedIVarsChecker.cpp
(6.01 KB)
📄
PaddingChecker.cpp
(14.26 KB)
📄
PointerArithChecker.cpp
(12.18 KB)
📄
PointerIterationChecker.cpp
(3.79 KB)
📄
PointerSortingChecker.cpp
(4.5 KB)
📄
PointerSubChecker.cpp
(2.56 KB)
📄
PthreadLockChecker.cpp
(28.42 KB)
📁
RetainCountChecker
📄
ReturnPointerRangeChecker.cpp
(3.39 KB)
📄
ReturnUndefChecker.cpp
(4.1 KB)
📄
ReturnValueChecker.cpp
(5.79 KB)
📄
RunLoopAutoreleaseLeakChecker.cpp
(7.2 KB)
📄
STLAlgorithmModeling.cpp
(7 KB)
📄
SimpleStreamChecker.cpp
(9.43 KB)
📄
SmartPtr.h
(1.17 KB)
📄
SmartPtrChecker.cpp
(2.68 KB)
📄
SmartPtrModeling.cpp
(8.05 KB)
📄
StackAddrEscapeChecker.cpp
(15 KB)
📄
StdLibraryFunctionsChecker.cpp
(74.86 KB)
📄
StreamChecker.cpp
(37.36 KB)
📄
Taint.cpp
(9.04 KB)
📄
Taint.h
(4.19 KB)
📄
TaintTesterChecker.cpp
(2.17 KB)
📄
TestAfterDivZeroChecker.cpp
(8.19 KB)
📄
TraversalChecker.cpp
(4.38 KB)
📄
TrustNonnullChecker.cpp
(9.12 KB)
📄
UndefBranchChecker.cpp
(3.82 KB)
📄
UndefCapturedBlockVarChecker.cpp
(3.64 KB)
📄
UndefResultChecker.cpp
(7.19 KB)
📄
UndefinedArraySubscriptChecker.cpp
(2.36 KB)
📄
UndefinedAssignmentChecker.cpp
(3.74 KB)
📁
UninitializedObject
📄
UnixAPIChecker.cpp
(18.05 KB)
📄
UnreachableCodeChecker.cpp
(9.59 KB)
📄
VLASizeChecker.cpp
(10.95 KB)
📄
ValistChecker.cpp
(15.65 KB)
📄
VforkChecker.cpp
(7.67 KB)
📄
VirtualCallChecker.cpp
(8.11 KB)
📁
WebKit
📄
Yaml.h
(2.06 KB)
📁
cert
Editing: PointerArithChecker.cpp
//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- 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 files defines PointerArithChecker, a builtin checker that checks for // pointer arithmetic on locations other than array elements. // //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.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" using namespace clang; using namespace ento; namespace { enum class AllocKind { SingleObject, Array, Unknown, Reinterpreted // Single object interpreted as an array. }; } // end namespace namespace llvm { template <> struct FoldingSetTrait<AllocKind> { static inline void Profile(AllocKind X, FoldingSetNodeID &ID) { ID.AddInteger(static_cast<int>(X)); } }; } // end namespace llvm namespace { class PointerArithChecker : public Checker< check::PreStmt<BinaryOperator>, check::PreStmt<UnaryOperator>, check::PreStmt<ArraySubscriptExpr>, check::PreStmt<CastExpr>, check::PostStmt<CastExpr>, check::PostStmt<CXXNewExpr>, check::PostStmt<CallExpr>, check::DeadSymbols> { AllocKind getKindOfNewOp(const CXXNewExpr *NE, const FunctionDecl *FD) const; const MemRegion *getArrayRegion(const MemRegion *Region, bool &Polymorphic, AllocKind &AKind, CheckerContext &C) const; const MemRegion *getPointedRegion(const MemRegion *Region, CheckerContext &C) const; void reportPointerArithMisuse(const Expr *E, CheckerContext &C, bool PointedNeeded = false) const; void initAllocIdentifiers(ASTContext &C) const; mutable std::unique_ptr<BuiltinBug> BT_pointerArith; mutable std::unique_ptr<BuiltinBug> BT_polyArray; mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions; public: void checkPreStmt(const UnaryOperator *UOp, CheckerContext &C) const; void checkPreStmt(const BinaryOperator *BOp, CheckerContext &C) const; void checkPreStmt(const ArraySubscriptExpr *SubExpr, CheckerContext &C) const; void checkPreStmt(const CastExpr *CE, CheckerContext &C) const; void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; void checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; }; } // end namespace REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, const MemRegion *, AllocKind) void PointerArithChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { // TODO: intentional leak. Some information is garbage collected too early, // see http://reviews.llvm.org/D14203 for further information. /*ProgramStateRef State = C.getState(); RegionStateTy RegionStates = State->get<RegionState>(); for (RegionStateTy::iterator I = RegionStates.begin(), E = RegionStates.end(); I != E; ++I) { if (!SR.isLiveRegion(I->first)) State = State->remove<RegionState>(I->first); } C.addTransition(State);*/ } AllocKind PointerArithChecker::getKindOfNewOp(const CXXNewExpr *NE, const FunctionDecl *FD) const { // This checker try not to assume anything about placement and overloaded // new to avoid false positives. if (isa<CXXMethodDecl>(FD)) return AllocKind::Unknown; if (FD->getNumParams() != 1 || FD->isVariadic()) return AllocKind::Unknown; if (NE->isArray()) return AllocKind::Array; return AllocKind::SingleObject; } const MemRegion * PointerArithChecker::getPointedRegion(const MemRegion *Region, CheckerContext &C) const { assert(Region); ProgramStateRef State = C.getState(); SVal S = State->getSVal(Region); return S.getAsRegion(); } /// Checks whether a region is the part of an array. /// In case there is a derived to base cast above the array element, the /// Polymorphic output value is set to true. AKind output value is set to the /// allocation kind of the inspected region. const MemRegion *PointerArithChecker::getArrayRegion(const MemRegion *Region, bool &Polymorphic, AllocKind &AKind, CheckerContext &C) const { assert(Region); while (const auto *BaseRegion = dyn_cast<CXXBaseObjectRegion>(Region)) { Region = BaseRegion->getSuperRegion(); Polymorphic = true; } if (const auto *ElemRegion = dyn_cast<ElementRegion>(Region)) { Region = ElemRegion->getSuperRegion(); } ProgramStateRef State = C.getState(); if (const AllocKind *Kind = State->get<RegionState>(Region)) { AKind = *Kind; if (*Kind == AllocKind::Array) return Region; else return nullptr; } // When the region is symbolic and we do not have any information about it, // assume that this is an array to avoid false positives. if (isa<SymbolicRegion>(Region)) return Region; // No AllocKind stored and not symbolic, assume that it points to a single // object. return nullptr; } void PointerArithChecker::reportPointerArithMisuse(const Expr *E, CheckerContext &C, bool PointedNeeded) const { SourceRange SR = E->getSourceRange(); if (SR.isInvalid()) return; ProgramStateRef State = C.getState(); const MemRegion *Region = C.getSVal(E).getAsRegion(); if (!Region) return; if (PointedNeeded) Region = getPointedRegion(Region, C); if (!Region) return; bool IsPolymorphic = false; AllocKind Kind = AllocKind::Unknown; if (const MemRegion *ArrayRegion = getArrayRegion(Region, IsPolymorphic, Kind, C)) { if (!IsPolymorphic) 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); R->addRange(E->getSourceRange()); R->markInteresting(ArrayRegion); C.emitReport(std::move(R)); } return; } if (Kind == AllocKind::Reinterpreted) return; // We might not have enough information about symbolic regions. if (Kind != AllocKind::SingleObject && Region->getKind() == MemRegion::Kind::SymbolicRegionKind) return; 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); R->addRange(SR); R->markInteresting(Region); C.emitReport(std::move(R)); } } void PointerArithChecker::initAllocIdentifiers(ASTContext &C) const { if (!AllocFunctions.empty()) return; AllocFunctions.insert(&C.Idents.get("alloca")); AllocFunctions.insert(&C.Idents.get("malloc")); AllocFunctions.insert(&C.Idents.get("realloc")); AllocFunctions.insert(&C.Idents.get("calloc")); AllocFunctions.insert(&C.Idents.get("valloc")); } void PointerArithChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { ProgramStateRef State = C.getState(); const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD) return; IdentifierInfo *FunI = FD->getIdentifier(); initAllocIdentifiers(C.getASTContext()); if (AllocFunctions.count(FunI) == 0) return; SVal SV = C.getSVal(CE); const MemRegion *Region = SV.getAsRegion(); if (!Region) return; // Assume that C allocation functions allocate arrays to avoid false // positives. // TODO: Add heuristics to distinguish alloc calls that allocates single // objecs. State = State->set<RegionState>(Region, AllocKind::Array); C.addTransition(State); } void PointerArithChecker::checkPostStmt(const CXXNewExpr *NE, CheckerContext &C) const { const FunctionDecl *FD = NE->getOperatorNew(); if (!FD) return; AllocKind Kind = getKindOfNewOp(NE, FD); ProgramStateRef State = C.getState(); SVal AllocedVal = C.getSVal(NE); const MemRegion *Region = AllocedVal.getAsRegion(); if (!Region) return; State = State->set<RegionState>(Region, Kind); C.addTransition(State); } void PointerArithChecker::checkPostStmt(const CastExpr *CE, CheckerContext &C) const { if (CE->getCastKind() != CastKind::CK_BitCast) return; const Expr *CastedExpr = CE->getSubExpr(); ProgramStateRef State = C.getState(); SVal CastedVal = C.getSVal(CastedExpr); const MemRegion *Region = CastedVal.getAsRegion(); if (!Region) return; // Suppress reinterpret casted hits. State = State->set<RegionState>(Region, AllocKind::Reinterpreted); C.addTransition(State); } void PointerArithChecker::checkPreStmt(const CastExpr *CE, CheckerContext &C) const { if (CE->getCastKind() != CastKind::CK_ArrayToPointerDecay) return; const Expr *CastedExpr = CE->getSubExpr(); ProgramStateRef State = C.getState(); SVal CastedVal = C.getSVal(CastedExpr); const MemRegion *Region = CastedVal.getAsRegion(); if (!Region) return; if (const AllocKind *Kind = State->get<RegionState>(Region)) { if (*Kind == AllocKind::Array || *Kind == AllocKind::Reinterpreted) return; } State = State->set<RegionState>(Region, AllocKind::Array); C.addTransition(State); } void PointerArithChecker::checkPreStmt(const UnaryOperator *UOp, CheckerContext &C) const { if (!UOp->isIncrementDecrementOp() || !UOp->getType()->isPointerType()) return; reportPointerArithMisuse(UOp->getSubExpr(), C, true); } void PointerArithChecker::checkPreStmt(const ArraySubscriptExpr *SubsExpr, CheckerContext &C) const { SVal Idx = C.getSVal(SubsExpr->getIdx()); // Indexing with 0 is OK. if (Idx.isZeroConstant()) return; // Indexing vector-type expressions is also OK. if (SubsExpr->getBase()->getType()->isVectorType()) return; reportPointerArithMisuse(SubsExpr->getBase(), C); } void PointerArithChecker::checkPreStmt(const BinaryOperator *BOp, CheckerContext &C) const { BinaryOperatorKind OpKind = BOp->getOpcode(); if (!BOp->isAdditiveOp() && OpKind != BO_AddAssign && OpKind != BO_SubAssign) return; const Expr *Lhs = BOp->getLHS(); const Expr *Rhs = BOp->getRHS(); ProgramStateRef State = C.getState(); if (Rhs->getType()->isIntegerType() && Lhs->getType()->isPointerType()) { SVal RHSVal = C.getSVal(Rhs); if (State->isNull(RHSVal).isConstrainedTrue()) return; reportPointerArithMisuse(Lhs, C, !BOp->isAdditiveOp()); } // The int += ptr; case is not valid C++. if (Lhs->getType()->isIntegerType() && Rhs->getType()->isPointerType()) { SVal LHSVal = C.getSVal(Lhs); if (State->isNull(LHSVal).isConstrainedTrue()) return; reportPointerArithMisuse(Rhs, C); } } void ento::registerPointerArithChecker(CheckerManager &mgr) { mgr.registerChecker<PointerArithChecker>(); } bool ento::shouldRegisterPointerArithChecker(const CheckerManager &mgr) { return true; }
Upload File
Create Folder