llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-static-analyzer-1 Author: Benedek Kaibas (benedekaibas) <details> <summary>Changes</summary> Currently the `DanglingPtrDeref` checker only records the whole object's region as deallocated. However, dangling pointers often refer to subobjects (e.g., a struct field or an element of an array). With the change in this PR, `isDeallocated` now checks whether a region's base region is in the `DeallocatedSourceSet`. --- Full diff: https://github.com/llvm/llvm-project/pull/211552.diff 3 Files Affected: - (modified) clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp (+11-3) - (modified) clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp (+1-1) - (modified) clang/test/Analysis/dangling-ptr-deref.cpp (+53) ``````````diff diff --git a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp index ff2087e1db933..41fcc68f8f109 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp @@ -66,13 +66,21 @@ void DanglingPtrDeref::checkPostCall(const CallEvent &Call, } } +static std::string getRegionName(const MemRegion *Reg) { + // FIXME: Once the checker supports heap allocation, more region kinds + // should be handled to produce the correct descriptive name. + if (const std::string RegName = Reg->getDescriptiveName(); !RegName.empty()) + return RegName; + return "the region"; +} + void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region, ExplodedNode *N, CheckerContext &C) const { auto BR = std::make_unique<PathSensitiveBugReport>( BugMsg, - (llvm::Twine("Use of '") + Region->getString() + - "' after its lifetime ended."), + (llvm::Twine("Use of ") + getRegionName(Region) + + " after its lifetime ended."), N); BR->addVisitor<DanglingPtrDerefBRVisitor>(Region); C.emitReport(std::move(BR)); @@ -99,7 +107,7 @@ DanglingPtrDerefBRVisitor::VisitNode(const ExplodedNode *N, S, BRC.getSourceManager(), N->getStackFrame()); return std::make_shared<PathDiagnosticEventPiece>( Pos, - (llvm::Twine("'") + SourceRegion->getString() + "' is destroyed here") + (llvm::Twine() + getRegionName(SourceRegion) + " is destroyed here") .str(), true); } diff --git a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp index 2b6f5dae4243f..ef0b1cb264b18 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LifetimeModeling.cpp @@ -73,7 +73,7 @@ std::vector<const MemRegion *> lifetime_modeling::getDanglingRegionsAfterReturn( bool lifetime_modeling::isDeallocated(ProgramStateRef State, const MemRegion *Region) { - return State->contains<DeallocatedSourceSet>(Region); + return State->contains<DeallocatedSourceSet>(Region->getBaseRegion()); } static ProgramStateRef bindSource(ProgramStateRef State, SVal RetVal, diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp index e661eff9ccbb6..9deda4b2502a4 100644 --- a/clang/test/Analysis/dangling-ptr-deref.cpp +++ b/clang/test/Analysis/dangling-ptr-deref.cpp @@ -112,3 +112,56 @@ void inlined_callee_single_report() { // expected-note@-1 {{Calling 'deref_param'}} (void)r; } + +struct MyBuffer { + char buffer[8]; +}; + +void member_subregion_dangling_deref() { + const char *p = nullptr; + { + struct MyBuffer tmp_buffer = {}; + p = tmp_buffer.buffer; + } + // expected-note@-1 {{'tmp_buffer.buffer[0]' is destroyed here}} + char c = *p; + // expected-warning@-1 {{Use of 'tmp_buffer.buffer[0]' after its lifetime ended}} + // expected-note@-2 {{Use of 'tmp_buffer.buffer[0]' after its lifetime ended}} + (void)c; +} + +void opaque(const char *); + +void passing_dangling_to_call() { + const char *p = nullptr; + { + struct MyBuffer tmp_buffer = {}; + p = tmp_buffer.buffer; + } + // expected-note@-1 {{'tmp_buffer.buffer[0]' is destroyed here}} + opaque(p); + // expected-warning@-1 {{Use of 'tmp_buffer.buffer[0]' after its lifetime ended}} + // expected-note@-2 {{Use of 'tmp_buffer.buffer[0]' after its lifetime ended}} +} + +void member_subregion_alive_deref() { + { + struct MyBuffer tmp_buffer = {}; + const char *p = tmp_buffer.buffer; + opaque(p); // no-warning + char c = *p; // no-warning + (void)c; + } +} + +void arr_elem_subreg_dangling_deref() { + int *ptr = nullptr; + { + int local_arr[5]; + ptr = &local_arr[1]; + } + // expected-note@-1 {{'local_arr[1]' is destroyed here}} + *ptr = 7; + // expected-warning@-1 {{Use of 'local_arr[1]' after its lifetime ended}} + // expected-note@-2 {{Use of 'local_arr[1]' after its lifetime ended}} +} `````````` </details> https://github.com/llvm/llvm-project/pull/211552 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
