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: FuchsiaHandleChecker.cpp
//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- 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 checker checks if the handle of Fuchsia is properly used according to // following rules. // - If a handle is acquired, it should be released before execution // ends. // - If a handle is released, it should not be released again. // - If a handle is released, it should not be used for other purposes // such as I/O. // // In this checker, each tracked handle is associated with a state. When the // handle variable is passed to different function calls or syscalls, its state // changes. The state changes can be generally represented by following ASCII // Art: // // // +-+---------v-+ +------------+ // acquire_func succeeded | | Escape | | // +-----------------> Allocated +---------> Escaped <--+ // | | | | | | // | +-----+------++ +------------+ | // | | | | // | release_func | +--+ | // | | | handle +--------+ | // | | | dies | | | // | +----v-----+ +---------> Leaked | | // | | | |(REPORT)| | // +----------+--+ | Released | Escape +--------+ | // | | | +---------------------------+ // | Not tracked <--+ +----+---+-+ // | | | | | As argument by value // +------+------+ | release_func | +------+ in function call // | | | | or by reference in // | | | | use_func call // +---------+ +----v-----+ | +-----------+ // acquire_func failed | Double | +-----> Use after | // | released | | released | // | (REPORT) | | (REPORT) | // +----------+ +-----------+ // // acquire_func represents the functions or syscalls that may acquire a handle. // release_func represents the functions or syscalls that may release a handle. // use_func represents the functions or syscall that requires an open handle. // // If a tracked handle dies in "Released" or "Not Tracked" state, we assume it // is properly used. Otherwise a bug and will be reported. // // Note that, the analyzer does not always know for sure if a function failed // or succeeded. In those cases we use the state MaybeAllocated. // Thus, the diagramm above captures the intent, not implementation details. // // Due to the fact that the number of handle related syscalls in Fuchsia // is large, we adopt the annotation attributes to descript syscalls' // operations(acquire/release/use) on handles instead of hardcoding // everything in the checker. // // We use following annotation attributes for handle related syscalls or // functions: // 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired // 2. __attribute__((release_handle("Fuchsia"))) |handle will be released // 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to // escaped state, it also needs to be open. // // For example, an annotated syscall: // zx_status_t zx_channel_create( // uint32_t options, // zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) , // zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia")))); // denotes a syscall which will acquire two handles and save them to 'out0' and // 'out1' when succeeded. // //===----------------------------------------------------------------------===// #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #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/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" #include "llvm/ADT/StringExtras.h" using namespace clang; using namespace ento; namespace { static const StringRef HandleTypeName = "zx_handle_t"; static const StringRef ErrorTypeName = "zx_status_t"; class HandleState { private: enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K; SymbolRef ErrorSym; HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {} public: bool operator==(const HandleState &Other) const { return K == Other.K && ErrorSym == Other.ErrorSym; } bool isAllocated() const { return K == Kind::Allocated; } bool maybeAllocated() const { return K == Kind::MaybeAllocated; } bool isReleased() const { return K == Kind::Released; } bool isEscaped() const { return K == Kind::Escaped; } static HandleState getMaybeAllocated(SymbolRef ErrorSym) { return HandleState(Kind::MaybeAllocated, ErrorSym); } static HandleState getAllocated(ProgramStateRef State, HandleState S) { assert(S.maybeAllocated()); assert(State->getConstraintManager() .isNull(State, S.getErrorSym()) .isConstrained()); return HandleState(Kind::Allocated, nullptr); } static HandleState getReleased() { return HandleState(Kind::Released, nullptr); } static HandleState getEscaped() { return HandleState(Kind::Escaped, nullptr); } SymbolRef getErrorSym() const { return ErrorSym; } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(static_cast<int>(K)); ID.AddPointer(ErrorSym); } LLVM_DUMP_METHOD void dump(raw_ostream &OS) const { switch (K) { #define CASE(ID) \ case ID: \ OS << #ID; \ break; CASE(Kind::MaybeAllocated) CASE(Kind::Allocated) CASE(Kind::Released) CASE(Kind::Escaped) } if (ErrorSym) { OS << " ErrorSym: "; ErrorSym->dumpToStream(OS); } } LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } }; template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) { return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia"; } class FuchsiaHandleChecker : public Checker<check::PostCall, check::PreCall, check::DeadSymbols, check::PointerEscape, eval::Assume> { BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error", /*SuppressOnSink=*/true}; BugType DoubleReleaseBugType{this, "Fuchsia handle double release", "Fuchsia Handle Error"}; BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release", "Fuchsia Handle Error"}; public: void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, bool Assumption) const; ProgramStateRef checkPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const; ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles, CheckerContext &C, ExplodedNode *Pred) const; void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range, CheckerContext &C) const; void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range, CheckerContext &C) const; void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C, const SourceRange *Range, const BugType &Type, StringRef Msg) const; void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const override; }; } // end anonymous namespace REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState) static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym, CheckerContext &Ctx) { ProgramStateRef State = N->getState(); // When bug type is handle leak, exploded node N does not have state info for // leaking handle. Get the predecessor of N instead. if (!State->get<HStateMap>(Sym)) N = N->getFirstPred(); const ExplodedNode *Pred = N; while (N) { State = N->getState(); if (!State->get<HStateMap>(Sym)) { const HandleState *HState = Pred->getState()->get<HStateMap>(Sym); if (HState && (HState->isAllocated() || HState->maybeAllocated())) return N; } Pred = N; N = N->getFirstPred(); } return nullptr; } /// Returns the symbols extracted from the argument or null if it cannot be /// found. static SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg, ProgramStateRef State) { int PtrToHandleLevel = 0; while (QT->isAnyPointerType() || QT->isReferenceType()) { ++PtrToHandleLevel; QT = QT->getPointeeType(); } if (const auto *HandleType = QT->getAs<TypedefType>()) { if (HandleType->getDecl()->getName() != HandleTypeName) return nullptr; if (PtrToHandleLevel > 1) { // Not supported yet. return nullptr; } if (PtrToHandleLevel == 0) { return Arg.getAsSymbol(); } else { assert(PtrToHandleLevel == 1); if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) return State->getSVal(*ArgLoc).getAsSymbol(); } } return nullptr; } void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef State = C.getState(); const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); if (!FuncDecl) { // Unknown call, escape by value handles. They are not covered by // PointerEscape callback. for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol()) State = State->set<HStateMap>(Handle, HandleState::getEscaped()); } C.addTransition(State); return; } for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { if (Arg >= FuncDecl->getNumParams()) break; const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); SymbolRef Handle = getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); if (!Handle) continue; // Handled in checkPostCall. if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) || hasFuchsiaAttr<AcquireHandleAttr>(PVD)) continue; const HandleState *HState = State->get<HStateMap>(Handle); if (!HState || HState->isEscaped()) continue; if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) { if (HState->isReleased()) { reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C); return; } } if (!hasFuchsiaAttr<UseHandleAttr>(PVD) && PVD->getType()->isIntegerType()) { // Working around integer by-value escapes. State = State->set<HStateMap>(Handle, HandleState::getEscaped()); } } C.addTransition(State); } void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); if (!FuncDecl) return; ProgramStateRef State = C.getState(); std::vector<std::function<std::string(BugReport & BR)>> Notes; SymbolRef ResultSymbol = nullptr; if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>()) if (TypeDefTy->getDecl()->getName() == ErrorTypeName) ResultSymbol = Call.getReturnValue().getAsSymbol(); // Function returns an open handle. if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) { 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)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Function '" << FuncDecl->getNameAsString() << "' returns an open handle"; return OS.str(); } else return ""; }); State = State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr)); } for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { if (Arg >= FuncDecl->getNumParams()) break; const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1; SymbolRef Handle = getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); if (!Handle) continue; const HandleState *HState = State->get<HStateMap>(Handle); if (HState && HState->isEscaped()) continue; if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) { if (HState && HState->isReleased()) { reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C); return; } else { Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR); if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Handle released through " << ParamDiagIdx << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter"; return OS.str(); } else return ""; }); State = State->set<HStateMap>(Handle, HandleState::getReleased()); } } 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)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Handle allocated through " << ParamDiagIdx << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter"; return OS.str(); } else return ""; }); State = State->set<HStateMap>( Handle, HandleState::getMaybeAllocated(ResultSymbol)); } } const NoteTag *T = nullptr; if (!Notes.empty()) { T = C.getNoteTag([this, Notes{std::move(Notes)}]( PathSensitiveBugReport &BR) -> std::string { if (&BR.getBugType() != &UseAfterReleaseBugType && &BR.getBugType() != &LeakBugType && &BR.getBugType() != &DoubleReleaseBugType) return ""; for (auto &Note : Notes) { std::string Text = Note(BR); if (!Text.empty()) return Text; } return ""; }); } C.addTransition(State, T); } void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SmallVector<SymbolRef, 2> LeakedSyms; HStateMapTy TrackedHandles = State->get<HStateMap>(); for (auto &CurItem : TrackedHandles) { SymbolRef ErrorSym = CurItem.second.getErrorSym(); // Keeping zombie handle symbols. In case the error symbol is dying later // than the handle symbol we might produce spurious leak warnings (in case // we find out later from the status code that the handle allocation failed // in the first place). if (!SymReaper.isDead(CurItem.first) || (ErrorSym && !SymReaper.isDead(ErrorSym))) continue; if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated()) LeakedSyms.push_back(CurItem.first); State = State->remove<HStateMap>(CurItem.first); } ExplodedNode *N = C.getPredecessor(); if (!LeakedSyms.empty()) N = reportLeaks(LeakedSyms, C, N); C.addTransition(State, N); } // Acquiring a handle is not always successful. In Fuchsia most functions // return a status code that determines the status of the handle. // When we split the path based on this status code we know that on one // path we do have the handle and on the other path the acquire failed. // This method helps avoiding false positive leak warnings on paths where // the function failed. // Moreover, when a handle is known to be zero (the invalid handle), // we no longer can follow the symbol on the path, becaue the constant // zero will be used instead of the symbol. We also do not need to release // an invalid handle, so we remove the corresponding symbol from the state. ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State, SVal Cond, bool Assumption) const { // TODO: add notes about successes/fails for APIs. ConstraintManager &Cmr = State->getConstraintManager(); HStateMapTy TrackedHandles = State->get<HStateMap>(); for (auto &CurItem : TrackedHandles) { ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first); if (HandleVal.isConstrainedTrue()) { // The handle is invalid. We can no longer follow the symbol on this path. State = State->remove<HStateMap>(CurItem.first); } SymbolRef ErrorSym = CurItem.second.getErrorSym(); if (!ErrorSym) continue; ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym); if (ErrorVal.isConstrainedTrue()) { // Allocation succeeded. if (CurItem.second.maybeAllocated()) State = State->set<HStateMap>( CurItem.first, HandleState::getAllocated(State, CurItem.second)); } else if (ErrorVal.isConstrainedFalse()) { // Allocation failed. if (CurItem.second.maybeAllocated()) State = State->remove<HStateMap>(CurItem.first); } } return State; } ProgramStateRef FuchsiaHandleChecker::checkPointerEscape( ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind) const { const FunctionDecl *FuncDecl = Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr; llvm::DenseSet<SymbolRef> UnEscaped; // Not all calls should escape our symbols. if (FuncDecl && (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall || Kind == PSK_EscapeOutParameters)) { for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) { if (Arg >= FuncDecl->getNumParams()) break; const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); SymbolRef Handle = getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State); if (!Handle) continue; if (hasFuchsiaAttr<UseHandleAttr>(PVD) || hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) UnEscaped.insert(Handle); } } // For out params, we have to deal with derived symbols. See // MacOSKeychainAPIChecker for details. for (auto I : State->get<HStateMap>()) { if (Escaped.count(I.first) && !UnEscaped.count(I.first)) State = State->set<HStateMap>(I.first, HandleState::getEscaped()); if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) { auto ParentSym = SD->getParentSymbol(); if (Escaped.count(ParentSym)) State = State->set<HStateMap>(I.first, HandleState::getEscaped()); } } return State; } ExplodedNode * FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles, CheckerContext &C, ExplodedNode *Pred) const { ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred); for (SymbolRef LeakedHandle : LeakedHandles) { reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType, "Potential leak of handle"); } return ErrNode; } void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range, CheckerContext &C) const { ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType, "Releasing a previously released handle"); } void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range, CheckerContext &C) const { ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType, "Using a previously released handle"); } void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C, const SourceRange *Range, const BugType &Type, StringRef Msg) const { if (!ErrorNode) return; std::unique_ptr<PathSensitiveBugReport> R; if (Type.isSuppressOnSink()) { const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C); if (AcquireNode) { PathDiagnosticLocation LocUsedForUniqueing = PathDiagnosticLocation::createBegin( AcquireNode->getStmtForDiagnostics(), C.getSourceManager(), AcquireNode->getLocationContext()); R = std::make_unique<PathSensitiveBugReport>( Type, Msg, ErrorNode, LocUsedForUniqueing, AcquireNode->getLocationContext()->getDecl()); } } if (!R) R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode); if (Range) R->addRange(*Range); R->markInteresting(Sym); C.emitReport(std::move(R)); } void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) { mgr.registerChecker<FuchsiaHandleChecker>(); } bool ento::shouldRegisterFuchsiaHandleChecker(const CheckerManager &mgr) { return true; } void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { HStateMapTy StateMap = State->get<HStateMap>(); if (!StateMap.isEmpty()) { Out << Sep << "FuchsiaHandleChecker :" << NL; for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E; ++I) { I.getKey()->dumpToStream(Out); Out << " : "; I.getData().dump(Out); Out << NL; } } }
Upload File
Create Folder