Index: clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -53,7 +53,7 @@ // // 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. +// Thus, the diagram 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' @@ -226,32 +226,71 @@ 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) { +namespace { +class FuchsiaHandleSymbolVisitor final : public SymbolVisitor { +public: + FuchsiaHandleSymbolVisitor(ProgramStateRef State) : State(std::move(State)) {} + ProgramStateRef getState() const { return State; } + + bool VisitSymbol(SymbolRef S) override { + if (const auto *HandleType = S->getType()->getAs()) + if (HandleType->getDecl()->getName() == HandleTypeName) + Symbols.push_back(S); + return true; + } + + SmallVector GetSymbols() { + return Symbols; + } + + private: + SmallVector Symbols; + ProgramStateRef State; +}; +} // end anonymous namespace + +/// Returns the symbols extracted from the argument or empty vector if it cannot +/// be found. It is unlikely to have over 1024 symbols in one argument. +static SmallVector getFuchsiaHandleSymbols( + QualType QT, SVal Arg, ProgramStateRef State) { int PtrToHandleLevel = 0; while (QT->isAnyPointerType() || QT->isReferenceType()) { ++PtrToHandleLevel; QT = QT->getPointeeType(); } + if (QT->isStructureType()) { + // If we see a structure, see if there is any handle inside the structure. + FuchsiaHandleSymbolVisitor Visitor(State); + State->scanReachableSymbols(Arg, Visitor); + return Visitor.GetSymbols(); + } if (const auto *HandleType = QT->getAs()) { if (HandleType->getDecl()->getName() != HandleTypeName) - return nullptr; - if (PtrToHandleLevel > 1) { + return {}; + if (PtrToHandleLevel > 1) // Not supported yet. - return nullptr; - } + return {}; if (PtrToHandleLevel == 0) { - return Arg.getAsSymbol(); + SymbolRef Sym = Arg.getAsSymbol(); + if (Sym) { + return {Sym}; + } else { + return {}; + } } else { assert(PtrToHandleLevel == 1); - if (Optional ArgLoc = Arg.getAs()) - return State->getSVal(*ArgLoc).getAsSymbol(); + if (Optional ArgLoc = Arg.getAs()) { + SymbolRef Sym = State->getSVal(*ArgLoc).getAsSymbol(); + if (Sym) { + return {Sym}; + } else { + return {}; + } + } } } - return nullptr; + return {}; } void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call, @@ -273,30 +312,30 @@ if (Arg >= FuncDecl->getNumParams()) break; const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); - SymbolRef Handle = - getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); - if (!Handle) - continue; + SmallVector Handles = + getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State); // Handled in checkPostCall. if (hasFuchsiaAttr(PVD) || hasFuchsiaAttr(PVD)) continue; - const HandleState *HState = State->get(Handle); - if (!HState || HState->isEscaped()) - continue; + for (SymbolRef Handle: Handles) { + const HandleState *HState = State->get(Handle); + if (!HState || HState->isEscaped()) + continue; - if (hasFuchsiaAttr(PVD) || PVD->getType()->isIntegerType()) { - if (HState->isReleased()) { - reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C); - return; + if (hasFuchsiaAttr(PVD) || PVD->getType()->isIntegerType()) { + if (HState->isReleased()) { + reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C); + return; + } + } + if (!hasFuchsiaAttr(PVD) && + PVD->getType()->isIntegerType()) { + // Working around integer by-value escapes. + State = State->set(Handle, HandleState::getEscaped()); } - } - if (!hasFuchsiaAttr(PVD) && - PVD->getType()->isIntegerType()) { - // Working around integer by-value escapes. - State = State->set(Handle, HandleState::getEscaped()); } } C.addTransition(State); @@ -339,46 +378,46 @@ break; const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); unsigned ParamDiagIdx = PVD->getFunctionScopeIndex() + 1; - SymbolRef Handle = - getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); - if (!Handle) - continue; + SmallVector Handles = + getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State); - const HandleState *HState = State->get(Handle); - if (HState && HState->isEscaped()) - continue; - if (hasFuchsiaAttr(PVD)) { - if (HState && HState->isReleased()) { - reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C); - return; - } else { + for (SymbolRef Handle: Handles) { + const HandleState *HState = State->get(Handle); + if (HState && HState->isEscaped()) + continue; + if (hasFuchsiaAttr(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(&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(Handle, HandleState::getReleased()); + } + } else if (hasFuchsiaAttr(PVD)) { Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); - OS << "Handle released through " << ParamDiagIdx + OS << "Handle allocated through " << ParamDiagIdx << llvm::getOrdinalSuffix(ParamDiagIdx) << " parameter"; return OS.str(); } else return ""; }); - State = State->set(Handle, HandleState::getReleased()); + State = State->set( + Handle, HandleState::getMaybeAllocated(ResultSymbol)); } - } else if (hasFuchsiaAttr(PVD)) { - Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { - auto *PathBR = static_cast(&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( - Handle, HandleState::getMaybeAllocated(ResultSymbol)); } } const NoteTag *T = nullptr; @@ -481,13 +520,14 @@ 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(PVD) || - hasFuchsiaAttr(PVD)) - UnEscaped.insert(Handle); + SmallVector Handles = + getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State); + for (SymbolRef Handle: Handles) { + if (hasFuchsiaAttr(PVD) || + hasFuchsiaAttr(PVD)) { + UnEscaped.insert(Handle); + } + } } }