Index: clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -239,11 +239,9 @@ return true; } - SmallVector GetSymbols() { - return Symbols; - } + SmallVector GetSymbols() { return Symbols; } - private: +private: SmallVector Symbols; ProgramStateRef State; }; @@ -251,8 +249,8 @@ /// 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) { +static SmallVector +getFuchsiaHandleSymbols(QualType QT, SVal Arg, ProgramStateRef State) { int PtrToHandleLevel = 0; while (QT->isAnyPointerType() || QT->isReferenceType()) { ++PtrToHandleLevel; @@ -321,22 +319,18 @@ hasFuchsiaAttr(PVD)) continue; - for (SymbolRef Handle: Handles) { + for (SymbolRef Handle : Handles) { const HandleState *HState = State->get(Handle); if (!HState || HState->isEscaped()) continue; - if (hasFuchsiaAttr(PVD) || PVD->getType()->isIntegerType()) { + 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()); - } } } C.addTransition(State); @@ -348,6 +342,10 @@ if (!FuncDecl) return; + // If we analyzed the function body, then ignore the annotations. + if (C.wasInlined) + return; + ProgramStateRef State = C.getState(); std::vector> Notes; @@ -382,7 +380,7 @@ SmallVector Handles = getFuchsiaHandleSymbols(PVD->getType(), Call.getArgSVal(Arg), State); - for (SymbolRef Handle: Handles) { + for (SymbolRef Handle : Handles) { const HandleState *HState = State->get(Handle); if (HState && HState->isEscaped()) continue; @@ -418,6 +416,14 @@ }); State = State->set( Handle, HandleState::getMaybeAllocated(ResultSymbol)); + } else if (!hasFuchsiaAttr(PVD) && + PVD->getType()->isIntegerType()) { + // Working around integer by-value escapes. + // The by-value escape would not be captured in checkPointerEscape. + // If the function was not analyzed (otherwise wasInlined should be + // true) and there is no annotation on the handle, we assume the handle + // is escaped. + State = State->set(Handle, HandleState::getEscaped()); } } } @@ -425,17 +431,17 @@ 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 ""; - }); + 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); } @@ -523,7 +529,7 @@ const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); SmallVector Handles = getFuchsiaHandleSymbols(PVD->getType(), Call->getArgSVal(Arg), State); - for (SymbolRef Handle: Handles) { + for (SymbolRef Handle : Handles) { if (hasFuchsiaAttr(PVD) || hasFuchsiaAttr(PVD)) { UnEscaped.insert(Handle); Index: clang/test/Analysis/fuchsia_handle.cpp =================================================================== --- clang/test/Analysis/fuchsia_handle.cpp +++ clang/test/Analysis/fuchsia_handle.cpp @@ -315,6 +315,43 @@ // expected-note@-1 {{Potential leak of handle}} } +// Assume this function's declaration that has the release annotation is in one +// header file while its implementation is in another file. We have to annotate +// the declaration because it might be used outside the TU. +// We also want to make sure it is okay to call the function within the same TU. +zx_status_t test_release_handle(zx_handle_t handle ZX_HANDLE_RELEASE) { + return zx_handle_close(handle); +} + +void checkReleaseImplementedFunc() { + zx_handle_t a, b; + zx_channel_create(0, &a, &b); + zx_handle_close(a); + test_release_handle(b); +} + +void use_handle(zx_handle_t handle) { + // Do nothing. +} + +void test_call_by_value() { + zx_handle_t a, b; + zx_channel_create(0, &a, &b); + zx_handle_close(a); + use_handle(b); + zx_handle_close(b); +} + +void test_call_by_value_leak() { + zx_handle_t a, b; + zx_channel_create(0, &a, &b); // expected-note {{Handle allocated through 3rd parameter}} + zx_handle_close(a); + // Here we are passing handle as value to a function that could be analyzed + // by the analyzer, thus the handle should not be considered escaped. + use_handle(b); +} // expected-warning {{Potential leak of handle}} + // expected-note@-1 {{Potential leak of handle}} + // RAII template