FuchsiaHandleChecker.cpp revision 360784
1139823Simp//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=// 21541Srgrimes// 31541Srgrimes// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4137668Smlaier// See https://llvm.org/LICENSE.txt for license information. 51541Srgrimes// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 61541Srgrimes// 71541Srgrimes//===----------------------------------------------------------------------===// 81541Srgrimes// 91541Srgrimes// This checker checks if the handle of Fuchsia is properly used according to 101541Srgrimes// following rules. 111541Srgrimes// - If a handle is acquired, it should be released before execution 121541Srgrimes// ends. 131541Srgrimes// - If a handle is released, it should not be released again. 141541Srgrimes// - If a handle is released, it should not be used for other purposes 151541Srgrimes// such as I/O. 161541Srgrimes// 171541Srgrimes// In this checker, each tracked handle is associated with a state. When the 181541Srgrimes// handle variable is passed to different function calls or syscalls, its state 191541Srgrimes// changes. The state changes can be generally represented by following ASCII 201541Srgrimes// Art: 211541Srgrimes// 221541Srgrimes// 231541Srgrimes// +-+---------v-+ +------------+ 241541Srgrimes// acquire_func succeeded | | Escape | | 251541Srgrimes// +-----------------> Allocated +---------> Escaped <--+ 261541Srgrimes// | | | | | | 271541Srgrimes// | +-----+------++ +------------+ | 281541Srgrimes// | | | | 291541Srgrimes// | release_func | +--+ | 3010939Swollman// | | | handle +--------+ | 311541Srgrimes// | | | dies | | | 321541Srgrimes// | +----v-----+ +---------> Leaked | | 33172467Ssilby// | | | |(REPORT)| | 34172467Ssilby// +----------+--+ | Released | Escape +--------+ | 35172467Ssilby// | | | +---------------------------+ 36204902Sqingli// | Not tracked <--+ +----+---+-+ 37143868Sglebius// | | | | | As argument by value 381541Srgrimes// +------+------+ | release_func | +------+ in function call 391549Srgrimes// | | | | or by reference in 4024204Sbde// | | | | use_func call 411541Srgrimes// +---------+ +----v-----+ | +-----------+ 42164033Srwatson// acquire_func failed | Double | +-----> Use after | 431541Srgrimes// | released | | released | 44186948Sbz// | (REPORT) | | (REPORT) | 4512704Sphk// +----------+ +-----------+ 46186948Sbz// 4712704Sphk// acquire_func represents the functions or syscalls that may acquire a handle. 48192011Sqingli// release_func represents the functions or syscalls that may release a handle. 491541Srgrimes// use_func represents the functions or syscall that requires an open handle. 501541Srgrimes// 51195914Sqingli// If a tracked handle dies in "Released" or "Not Tracked" state, we assume it 52215207Sgnn// is properly used. Otherwise a bug and will be reported. 53192011Sqingli// 54186119Sqingli// Note that, the analyzer does not always know for sure if a function failed 5555009Sshin// or succeeded. In those cases we use the state MaybeAllocated. 561541Srgrimes// Thus, the diagramm above captures the intent, not implementation details. 57192011Sqingli// 581541Srgrimes// Due to the fact that the number of handle related syscalls in Fuchsia 591541Srgrimes// is large, we adopt the annotation attributes to descript syscalls' 601541Srgrimes// operations(acquire/release/use) on handles instead of hardcoding 6181127Sume// everything in the checker. 62170613Sbms// 63189592Sbms// We use following annotation attributes for handle related syscalls or 64195699Srwatson// functions: 65195699Srwatson// 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired 661541Srgrimes// 2. __attribute__((release_handle("Fuchsia"))) |handle will be released 6792723Salfred// 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to 6892723Salfred// escaped state, it also needs to be open. 6992723Salfred// 7092723Salfred// For example, an annotated syscall: 7155009Sshin// zx_status_t zx_channel_create( 72137628Smlaier// uint32_t options, 73222143Sqingli// zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) , 7492723Salfred// zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia")))); 7592723Salfred// denotes a syscall which will acquire two handles and save them to 'out0' and 76228313Sglebius// 'out1' when succeeded. 77167729Sbms// 781541Srgrimes//===----------------------------------------------------------------------===// 79215701Sdim 80207369Sbz#include "clang/AST/Attr.h" 81195699Srwatson#include "clang/AST/Decl.h" 82195699Srwatson#include "clang/AST/Type.h" 83149221Sglebius#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 8421666Swollman#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 85207369Sbz#include "clang/StaticAnalyzer/Core/Checker.h" 86207369Sbz#include "clang/StaticAnalyzer/Core/CheckerManager.h" 87207369Sbz#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 88215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 89215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" 90215207Sgnn#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" 911541Srgrimes#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" 921541Srgrimes#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" 93226401Sglebius 941541Srgrimesusing namespace clang; 951549Srgrimesusing namespace ento; 96169454Srwatson 971541Srgrimesnamespace { 981541Srgrimes 991541Srgrimesstatic const StringRef HandleTypeName = "zx_handle_t"; 1001541Srgrimesstatic const StringRef ErrorTypeName = "zx_status_t"; 101194951Srwatson 102226401Sglebiusclass HandleState { 103226401Sglebiusprivate: 104226401Sglebius enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K; 105226401Sglebius SymbolRef ErrorSym; 106194951Srwatson HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {} 1071541Srgrimes 108194951Srwatsonpublic: 1091541Srgrimes bool operator==(const HandleState &Other) const { 1101541Srgrimes return K == Other.K && ErrorSym == Other.ErrorSym; 1111541Srgrimes } 1121541Srgrimes bool isAllocated() const { return K == Kind::Allocated; } 113133486Sandre bool maybeAllocated() const { return K == Kind::MaybeAllocated; } 114133486Sandre bool isReleased() const { return K == Kind::Released; } 115133486Sandre bool isEscaped() const { return K == Kind::Escaped; } 116133486Sandre 117169454Srwatson static HandleState getMaybeAllocated(SymbolRef ErrorSym) { 118133486Sandre return HandleState(Kind::MaybeAllocated, ErrorSym); 119133486Sandre } 120133486Sandre static HandleState getAllocated(ProgramStateRef State, HandleState S) { 121194951Srwatson assert(S.maybeAllocated()); 122133486Sandre assert(State->getConstraintManager() 123194951Srwatson .isNull(State, S.getErrorSym()) 124194951Srwatson .isConstrained()); 125184295Sbz return HandleState(Kind::Allocated, nullptr); 126194951Srwatson } 127133486Sandre static HandleState getReleased() { 128194951Srwatson return HandleState(Kind::Released, nullptr); 129184295Sbz } 130133486Sandre static HandleState getEscaped() { 131133486Sandre return HandleState(Kind::Escaped, nullptr); 132133486Sandre } 1331541Srgrimes 1341541Srgrimes SymbolRef getErrorSym() const { return ErrorSym; } 1351541Srgrimes 1361541Srgrimes void Profile(llvm::FoldingSetNodeID &ID) const { 1371549Srgrimes ID.AddInteger(static_cast<int>(K)); 138169454Srwatson ID.AddPointer(ErrorSym); 1391541Srgrimes } 1401541Srgrimes 1411541Srgrimes LLVM_DUMP_METHOD void dump(raw_ostream &OS) const { 1421541Srgrimes switch (K) { 143166450Sbms#define CASE(ID) \ 1441541Srgrimes case ID: \ 1451541Srgrimes OS << #ID; \ 1461541Srgrimes break; 1471541Srgrimes CASE(Kind::MaybeAllocated) 1481541Srgrimes CASE(Kind::Allocated) 1491541Srgrimes CASE(Kind::Released) 1501541Srgrimes CASE(Kind::Escaped) 1511541Srgrimes } 1521541Srgrimes } 1531541Srgrimes 1541541Srgrimes LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } 1551541Srgrimes}; 15612296Sphk 157169454Srwatsontemplate <typename Attr> static bool hasFuchsiaAttr(const Decl *D) { 1581541Srgrimes return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia"; 1591541Srgrimes} 1601541Srgrimes 1611541Srgrimesclass FuchsiaHandleChecker 1621541Srgrimes : public Checker<check::PostCall, check::PreCall, check::DeadSymbols, 1634127Swollman check::PointerEscape, eval::Assume> { 164133874Srwatson BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error", 1651541Srgrimes /*SuppressOnSink=*/true}; 1661541Srgrimes BugType DoubleReleaseBugType{this, "Fuchsia handle double release", 1671541Srgrimes "Fuchsia Handle Error"}; 1681541Srgrimes BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release", 1691541Srgrimes "Fuchsia Handle Error"}; 17055009Sshin 17155009Sshinpublic: 17255009Sshin void checkPreCall(const CallEvent &Call, CheckerContext &C) const; 17355009Sshin void checkPostCall(const CallEvent &Call, CheckerContext &C) const; 17455009Sshin void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; 17555009Sshin ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, 17655009Sshin bool Assumption) const; 17755009Sshin ProgramStateRef checkPointerEscape(ProgramStateRef State, 17855009Sshin const InvalidatedSymbols &Escaped, 17955009Sshin const CallEvent *Call, 18055009Sshin PointerEscapeKind Kind) const; 18155009Sshin 18255009Sshin ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles, 18355009Sshin CheckerContext &C, ExplodedNode *Pred) const; 18455009Sshin 18555009Sshin void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range, 18655009Sshin CheckerContext &C) const; 18755009Sshin 18855009Sshin void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range, 189184295Sbz CheckerContext &C) const; 19055009Sshin 19155009Sshin void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C, 19255009Sshin const SourceRange *Range, const BugType &Type, 193169454Srwatson StringRef Msg) const; 19455009Sshin 19555009Sshin void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, 19655009Sshin const char *Sep) const override; 19755009Sshin}; 19855009Sshin} // end anonymous namespace 19955009Sshin 20055009SshinREGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState) 20155009Sshin 20255009Sshinstatic const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym, 20355009Sshin CheckerContext &Ctx) { 20455009Sshin ProgramStateRef State = N->getState(); 20555009Sshin // When bug type is handle leak, exploded node N does not have state info for 2061541Srgrimes // leaking handle. Get the predecessor of N instead. 2071541Srgrimes if (!State->get<HStateMap>(Sym)) 208191443Srwatson N = N->getFirstPred(); 209191443Srwatson 2101541Srgrimes const ExplodedNode *Pred = N; 2111541Srgrimes while (N) { 2121549Srgrimes State = N->getState(); 213169454Srwatson if (!State->get<HStateMap>(Sym)) { 214169454Srwatson const HandleState *HState = Pred->getState()->get<HStateMap>(Sym); 2151541Srgrimes if (HState && (HState->isAllocated() || HState->maybeAllocated())) 2161541Srgrimes return N; 217184295Sbz } 2181541Srgrimes Pred = N; 219168032Sbms N = N->getFirstPred(); 22084102Sjlemon } 221189592Sbms return nullptr; 2221541Srgrimes} 2231541Srgrimes 224194951Srwatson/// Returns the symbols extracted from the argument or null if it cannot be 225168032Sbms/// found. 2261541Srgrimesstatic SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg, 227184295Sbz ProgramStateRef State) { 228168032Sbms int PtrToHandleLevel = 0; 22987124Sbrian while (QT->isAnyPointerType() || QT->isReferenceType()) { 230168032Sbms ++PtrToHandleLevel; 23187124Sbrian QT = QT->getPointeeType(); 232191443Srwatson } 233191443Srwatson if (const auto *HandleType = QT->getAs<TypedefType>()) { 234191443Srwatson if (HandleType->getDecl()->getName() != HandleTypeName) 235191443Srwatson return nullptr; 23655009Sshin if (PtrToHandleLevel > 1) { 237191443Srwatson // Not supported yet. 238191443Srwatson return nullptr; 239191443Srwatson } 240191443Srwatson 241227791Sglebius if (PtrToHandleLevel == 0) { 242227791Sglebius return Arg.getAsSymbol(); 243227791Sglebius } else { 244227791Sglebius assert(PtrToHandleLevel == 1); 245227791Sglebius if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) 246227791Sglebius return State->getSVal(*ArgLoc).getAsSymbol(); 247227791Sglebius } 248227791Sglebius } 249227791Sglebius return nullptr; 250227791Sglebius} 251227791Sglebius 252227831Sglebiusvoid FuchsiaHandleChecker::checkPreCall(const CallEvent &Call, 253227831Sglebius CheckerContext &C) const { 254227791Sglebius ProgramStateRef State = C.getState(); 255227791Sglebius const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 256227791Sglebius if (!FuncDecl) { 257227791Sglebius // Unknown call, escape by value handles. They are not covered by 258227791Sglebius // PointerEscape callback. 259227791Sglebius for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { 260227791Sglebius if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol()) 261227791Sglebius State = State->set<HStateMap>(Handle, HandleState::getEscaped()); 262227791Sglebius } 263227791Sglebius C.addTransition(State); 264227791Sglebius return; 265227791Sglebius } 266227791Sglebius 267191443Srwatson for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { 268191443Srwatson if (Arg >= FuncDecl->getNumParams()) 269191443Srwatson break; 270191443Srwatson const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); 271227791Sglebius SymbolRef Handle = 272227791Sglebius getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); 273227791Sglebius if (!Handle) 274191443Srwatson continue; 275191443Srwatson 27655009Sshin // Handled in checkPostCall. 277164033Srwatson if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) || 278164033Srwatson hasFuchsiaAttr<AcquireHandleAttr>(PVD)) 279164033Srwatson continue; 280164033Srwatson 281164033Srwatson const HandleState *HState = State->get<HStateMap>(Handle); 282184295Sbz if (!HState || HState->isEscaped()) 283184295Sbz continue; 284164033Srwatson 285164033Srwatson if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) { 28655009Sshin if (HState->isReleased()) { 287164033Srwatson reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C); 288164033Srwatson return; 289164033Srwatson } 290164033Srwatson } 291164033Srwatson if (!hasFuchsiaAttr<UseHandleAttr>(PVD) && 292184295Sbz PVD->getType()->isIntegerType()) { 293184295Sbz // Working around integer by-value escapes. 294164033Srwatson State = State->set<HStateMap>(Handle, HandleState::getEscaped()); 295164033Srwatson } 29655009Sshin } 297184295Sbz C.addTransition(State); 298184295Sbz} 29983366Sjulian 300191443Srwatsonvoid FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, 301191443Srwatson CheckerContext &C) const { 302191443Srwatson const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 303191443Srwatson if (!FuncDecl) 304191443Srwatson return; 30555009Sshin 30655009Sshin ProgramStateRef State = C.getState(); 307191443Srwatson 308191443Srwatson std::vector<std::function<std::string(BugReport & BR)>> Notes; 309191443Srwatson SymbolRef ResultSymbol = nullptr; 3101541Srgrimes if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>()) 311191456Srwatson if (TypeDefTy->getDecl()->getName() == ErrorTypeName) 312191456Srwatson ResultSymbol = Call.getReturnValue().getAsSymbol(); 313191456Srwatson 314191456Srwatson // Function returns an open handle. 315191456Srwatson if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) { 316191456Srwatson SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); 317191456Srwatson State = 318191456Srwatson State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr)); 319191456Srwatson } 320191456Srwatson 321191456Srwatson for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { 322191456Srwatson if (Arg >= FuncDecl->getNumParams()) 323191456Srwatson break; 324191456Srwatson const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); 325191456Srwatson SymbolRef Handle = 326191456Srwatson getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); 327191456Srwatson if (!Handle) 328191456Srwatson continue; 329191456Srwatson 330191456Srwatson const HandleState *HState = State->get<HStateMap>(Handle); 331191456Srwatson if (HState && HState->isEscaped()) 332191456Srwatson continue; 333191456Srwatson if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) { 334191456Srwatson if (HState && HState->isReleased()) { 335191456Srwatson reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C); 3361541Srgrimes return; 33714632Sfenner } else { 338191443Srwatson Notes.push_back([Handle](BugReport &BR) { 339191443Srwatson auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR); 3401541Srgrimes if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { 341191443Srwatson return "Handle released here."; 342194951Srwatson } else 343191443Srwatson return ""; 344191443Srwatson }); 345191443Srwatson State = State->set<HStateMap>(Handle, HandleState::getReleased()); 346191443Srwatson } 347191443Srwatson } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) { 348191443Srwatson Notes.push_back([Handle](BugReport &BR) { 349191443Srwatson auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR); 350191443Srwatson if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { 351191443Srwatson return "Handle allocated here."; 352194760Srwatson } else 353194760Srwatson return ""; 354194951Srwatson }); 355191443Srwatson State = State->set<HStateMap>( 356194760Srwatson Handle, HandleState::getMaybeAllocated(ResultSymbol)); 357191443Srwatson } 358191443Srwatson } 359191443Srwatson const NoteTag *T = nullptr; 360191443Srwatson if (!Notes.empty()) { 361191443Srwatson T = C.getNoteTag( 362191443Srwatson [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string { 363191443Srwatson if (&BR.getBugType() != &UseAfterReleaseBugType && 364191443Srwatson &BR.getBugType() != &LeakBugType && 36584102Sjlemon &BR.getBugType() != &DoubleReleaseBugType) 36684102Sjlemon return ""; 367191443Srwatson for (auto &Note : Notes) { 368194760Srwatson std::string Text = Note(BR); 369194760Srwatson if (!Text.empty()) 370194760Srwatson return Text; 37184102Sjlemon } 372191443Srwatson return ""; 373191443Srwatson }); 3741541Srgrimes } 375191500Srwatson C.addTransition(State, T); 3761541Srgrimes} 3771541Srgrimes 3781541Srgrimesvoid FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper, 379227958Sglebius CheckerContext &C) const { 380194760Srwatson ProgramStateRef State = C.getState(); 381194760Srwatson SmallVector<SymbolRef, 2> LeakedSyms; 382194951Srwatson HStateMapTy TrackedHandles = State->get<HStateMap>(); 38371999Sphk for (auto &CurItem : TrackedHandles) { 3848071Swollman if (!SymReaper.isDead(CurItem.first)) 3858071Swollman continue; 3868071Swollman if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated()) 3878071Swollman LeakedSyms.push_back(CurItem.first); 3888071Swollman State = State->remove<HStateMap>(CurItem.first); 389194760Srwatson } 390194760Srwatson 391194760Srwatson ExplodedNode *N = C.getPredecessor(); 392194760Srwatson if (!LeakedSyms.empty()) 393194951Srwatson N = reportLeaks(LeakedSyms, C, N); 3948876Srgrimes 3958071Swollman C.addTransition(State, N); 3968071Swollman} 3978071Swollman 398191500Srwatson// Acquiring a handle is not always successful. In Fuchsia most functions 399194760Srwatson// return a status code that determines the status of the handle. 4008071Swollman// When we split the path based on this status code we know that on one 4011541Srgrimes// path we do have the handle and on the other path the acquire failed. 402191500Srwatson// This method helps avoiding false positive leak warnings on paths where 403191500Srwatson// the function failed. 404194760Srwatson// Moreover, when a handle is known to be zero (the invalid handle), 405191500Srwatson// we no longer can follow the symbol on the path, becaue the constant 4061541Srgrimes// zero will be used instead of the symbol. We also do not need to release 4071541Srgrimes// an invalid handle, so we remove the corresponding symbol from the state. 4081541SrgrimesProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State, 4091541Srgrimes SVal Cond, 410184295Sbz bool Assumption) const { 41120407Swollman // TODO: add notes about successes/fails for APIs. 412191500Srwatson ConstraintManager &Cmr = State->getConstraintManager(); 413191500Srwatson HStateMapTy TrackedHandles = State->get<HStateMap>(); 414191500Srwatson for (auto &CurItem : TrackedHandles) { 415191500Srwatson ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first); 416194760Srwatson if (HandleVal.isConstrainedTrue()) { 417191500Srwatson // The handle is invalid. We can no longer follow the symbol on this path. 418191500Srwatson State = State->remove<HStateMap>(CurItem.first); 41920407Swollman } 420194602Srwatson SymbolRef ErrorSym = CurItem.second.getErrorSym(); 42120407Swollman if (!ErrorSym) 42220407Swollman continue; 42320407Swollman ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym); 424108033Shsu if (ErrorVal.isConstrainedTrue()) { 4251541Srgrimes // Allocation succeeded. 42685740Sdes if (CurItem.second.maybeAllocated()) 4271541Srgrimes State = State->set<HStateMap>( 4281541Srgrimes CurItem.first, HandleState::getAllocated(State, CurItem.second)); 4291541Srgrimes } else if (ErrorVal.isConstrainedFalse()) { 4301541Srgrimes // Allocation failed. 4311541Srgrimes if (CurItem.second.maybeAllocated()) 432151824Sglebius State = State->remove<HStateMap>(CurItem.first); 433194760Srwatson } 434194760Srwatson } 435191285Srwatson return State; 436194760Srwatson} 437194760Srwatson 438194951SrwatsonProgramStateRef FuchsiaHandleChecker::checkPointerEscape( 439181803Sbz ProgramStateRef State, const InvalidatedSymbols &Escaped, 440194951Srwatson const CallEvent *Call, PointerEscapeKind Kind) const { 44187124Sbrian const FunctionDecl *FuncDecl = 4421541Srgrimes Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr; 4431541Srgrimes 4441541Srgrimes llvm::DenseSet<SymbolRef> UnEscaped; 4451541Srgrimes // Not all calls should escape our symbols. 4461541Srgrimes if (FuncDecl && 4471541Srgrimes (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall || 4481541Srgrimes Kind == PSK_EscapeOutParameters)) { 4491541Srgrimes for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) { 450191500Srwatson if (Arg >= FuncDecl->getNumParams()) 451191500Srwatson break; 452194760Srwatson const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); 453191500Srwatson SymbolRef Handle = 4541541Srgrimes getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State); 4551541Srgrimes if (!Handle) 456191500Srwatson continue; 457191500Srwatson if (hasFuchsiaAttr<UseHandleAttr>(PVD) || 458194760Srwatson hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) 459194760Srwatson UnEscaped.insert(Handle); 460191500Srwatson } 4611541Srgrimes } 4621541Srgrimes 4631541Srgrimes // For out params, we have to deal with derived symbols. See 464194760Srwatson // MacOSKeychainAPIChecker for details. 4651541Srgrimes for (auto I : State->get<HStateMap>()) { 4661541Srgrimes if (Escaped.count(I.first) && !UnEscaped.count(I.first)) 467191500Srwatson State = State->set<HStateMap>(I.first, HandleState::getEscaped()); 468191500Srwatson if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) { 469194760Srwatson auto ParentSym = SD->getParentSymbol(); 470191500Srwatson if (Escaped.count(ParentSym)) 4711541Srgrimes State = State->set<HStateMap>(I.first, HandleState::getEscaped()); 472194760Srwatson } 4731541Srgrimes } 4741541Srgrimes 475191500Srwatson return State; 476191500Srwatson} 477194760Srwatson 478191500SrwatsonExplodedNode * 4791541SrgrimesFuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles, 480194760Srwatson CheckerContext &C, ExplodedNode *Pred) const { 4811541Srgrimes ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred); 4821541Srgrimes for (SymbolRef LeakedHandle : LeakedHandles) { 4831541Srgrimes reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType, 484194760Srwatson "Potential leak of handle"); 4851541Srgrimes } 4861541Srgrimes return ErrNode; 487191500Srwatson} 488191500Srwatson 489194760Srwatsonvoid FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym, 490191500Srwatson const SourceRange &Range, 4911541Srgrimes CheckerContext &C) const { 4921541Srgrimes ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); 493184295Sbz reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType, 494146883Siedowse "Releasing a previously released handle"); 495146883Siedowse} 496146883Siedowse 497146883Siedowsevoid FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym, 498194760Srwatson const SourceRange &Range, 499146883Siedowse CheckerContext &C) const { 5001541Srgrimes ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); 5011541Srgrimes reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType, 5021541Srgrimes "Using a previously released handle"); 5031541Srgrimes} 5041541Srgrimes 5051541Srgrimesvoid FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, 5061541Srgrimes CheckerContext &C, 5071541Srgrimes const SourceRange *Range, 508194760Srwatson const BugType &Type, StringRef Msg) const { 5091541Srgrimes if (!ErrorNode) 5101541Srgrimes return; 511191500Srwatson 512191500Srwatson std::unique_ptr<PathSensitiveBugReport> R; 513194760Srwatson if (Type.isSuppressOnSink()) { 514191500Srwatson const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C); 5151541Srgrimes if (AcquireNode) { 516194760Srwatson PathDiagnosticLocation LocUsedForUniqueing = 5171541Srgrimes PathDiagnosticLocation::createBegin( 5181541Srgrimes AcquireNode->getStmtForDiagnostics(), C.getSourceManager(), 51987124Sbrian AcquireNode->getLocationContext()); 520228313Sglebius 52187124Sbrian R = std::make_unique<PathSensitiveBugReport>( 52287124Sbrian Type, Msg, ErrorNode, LocUsedForUniqueing, 523168032Sbms AcquireNode->getLocationContext()->getDecl()); 524189603Sbms } 525189592Sbms } 526189592Sbms if (!R) 527189592Sbms R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode); 528189592Sbms if (Range) 529189592Sbms R->addRange(*Range); 530126264Smlaier R->markInteresting(Sym); 531168032Sbms C.emitReport(std::move(R)); 532194760Srwatson} 533194760Srwatson 5341541Srgrimesvoid ento::registerFuchsiaHandleChecker(CheckerManager &mgr) { 5351541Srgrimes mgr.registerChecker<FuchsiaHandleChecker>(); 536228062Sglebius} 537228062Sglebius 53885740Sdesbool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) { 539194760Srwatson return true; 5401541Srgrimes} 5411541Srgrimes 5421541Srgrimesvoid FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State, 5431541Srgrimes const char *NL, const char *Sep) const { 5441541Srgrimes 545227959Sglebius HStateMapTy StateMap = State->get<HStateMap>(); 546227791Sglebius 547227791Sglebius if (!StateMap.isEmpty()) { 5481541Srgrimes Out << Sep << "FuchsiaHandleChecker :" << NL; 549197210Sqingli for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E; 550197210Sqingli ++I) { 551197210Sqingli I.getKey()->dumpToStream(Out); 552197210Sqingli Out << " : "; 553197210Sqingli I.getData().dump(Out); 554197210Sqingli Out << NL; 555197210Sqingli } 556197210Sqingli } 557197210Sqingli} 558222438Sqingli