https://github.com/benedekaibas updated https://github.com/llvm/llvm-project/pull/211818
>From 1025b0c91d2bf411a5fa27357ee61cd2e6c7b31e Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Fri, 24 Jul 2026 16:53:31 +0200 Subject: [PATCH 1/2] [analyzer] Improve dangling value tracking in DanglingPtrDeref --- .../Checkers/DanglingPtrDeref.cpp | 11 ++++++----- clang/test/Analysis/dangling-ptr-deref.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp index 9b4b1056c8ee6..51a1cb891f6cc 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DanglingPtrDeref.cpp @@ -15,8 +15,8 @@ class DanglingPtrDeref : public Checker<check::Location, check::PostCall> { void checkLocation(SVal Loc, bool IsLoad, const Stmt *S, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; - void reportUseAfterScope(const MemRegion *Region, ExplodedNode *N, - CheckerContext &C) const; + void reportUseAfterScope(const MemRegion *Region, const Stmt *S, + ExplodedNode *N, CheckerContext &C) const; const BugType BugMsg{this, "ReportDanglingPtrDeref", "LifetimeBound"}; }; @@ -45,7 +45,7 @@ void DanglingPtrDeref::checkLocation(SVal Loc, bool IsLoad, const Stmt *S, if (const MemRegion *LocRegion = Loc.getAsRegion()) { if (lifetime_modeling::isDeallocated(State, LocRegion)) { if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) - reportUseAfterScope(LocRegion, N, C); + reportUseAfterScope(LocRegion, S, N, C); } } } @@ -62,7 +62,7 @@ void DanglingPtrDeref::checkPostCall(const CallEvent &Call, if (const MemRegion *ArgRegion = Call.getArgSVal(Idx).getAsRegion()) if (lifetime_modeling::isDeallocated(State, ArgRegion)) if (ExplodedNode *N = C.generateNonFatalErrorNode()) - reportUseAfterScope(ArgRegion, N, C); + reportUseAfterScope(ArgRegion, Call.getArgExpr(Idx), N, C); } } @@ -75,7 +75,7 @@ static std::string getRegionName(const MemRegion *Reg) { } void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region, - ExplodedNode *N, + const Stmt *S, ExplodedNode *N, CheckerContext &C) const { auto BR = std::make_unique<PathSensitiveBugReport>( BugMsg, @@ -83,6 +83,7 @@ void DanglingPtrDeref::reportUseAfterScope(const MemRegion *Region, " after its lifetime ended."), N); BR->addVisitor<DanglingPtrDerefBRVisitor>(Region); + bugreporter::trackExpressionValue(N, bugreporter::getDerefExpr(S), *BR); C.emitReport(std::move(BR)); } diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp index fa9dae41421bc..652accd1f359a 100644 --- a/clang/test/Analysis/dangling-ptr-deref.cpp +++ b/clang/test/Analysis/dangling-ptr-deref.cpp @@ -4,8 +4,8 @@ void test_case_one() { int *ptr = nullptr; { - int num = 5; - ptr = # + int num = 5; // expected-note {{'num' initialized to 5}} + ptr = # // expected-note {{Value assigned to 'ptr'}} } // expected-note@-1 {{'num' is destroyed here}} *ptr = 6; @@ -17,10 +17,10 @@ void test_case_two() { int *ptr_one = nullptr; int *ptr_two = nullptr; { - int n = 1; - int m = 2; - ptr_one = &n; - ptr_two = &m; + int n = 1; // expected-note {{'n' initialized to 1}} + int m = 2; // expected-note {{'m' initialized to 2}} + ptr_one = &n; // expected-note {{Value assigned to 'ptr_one'}} + ptr_two = &m; // expected-note {{Value assigned to 'ptr_two'}} } // expected-note@-1 {{'n' is destroyed here}} // expected-note@-2 {{'m' is destroyed here}} @@ -45,7 +45,7 @@ void test_case_three() { void test_case_four() { int *ptr = nullptr; { - int num = 5; + int num = 5; // expected-note {{'num' initialized to 5}} ptr = # } // expected-note@-1 {{'num' is destroyed here}} @@ -75,8 +75,8 @@ void test_case_seven() { // expected-note@+3 {{Loop condition is true. Entering loop body}} // expected-note@+2 {{Assuming 'i' is >= 10}} // expected-note@+1 {{Loop condition is false. Execution continues on line}} - for (int i = 0; i < 10; ++i) { - ptr = &i; + for (int i = 0; i < 10; ++i) { // expected-note {{'i' initialized to 0}} + ptr = &i; // expected-note {{Value assigned to 'ptr'}} escape(ptr); } // expected-note@-1 {{'i' is destroyed here}} >From 415befa8f27112f0152f0adf4340d1cd6fd1a321 Mon Sep 17 00:00:00 2001 From: benedekaibas <[email protected]> Date: Sun, 26 Jul 2026 18:36:34 +0200 Subject: [PATCH 2/2] Add notes to the test suite. --- clang/test/Analysis/dangling-ptr-deref.cpp | 28 +++++++++++----------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/clang/test/Analysis/dangling-ptr-deref.cpp b/clang/test/Analysis/dangling-ptr-deref.cpp index 652accd1f359a..d7cdae75a1d95 100644 --- a/clang/test/Analysis/dangling-ptr-deref.cpp +++ b/clang/test/Analysis/dangling-ptr-deref.cpp @@ -88,8 +88,8 @@ void test_case_seven() { void passing_dangling_ptr_to_opaque_func() { int *ptr = nullptr; { - int num = 5; - ptr = # + int num = 5; // expected-note {{'num' initialized to 5}} + ptr = # // expected-note {{Value assigned to 'ptr'}} } // expected-note@-1 {{'num' is destroyed here}} escape(ptr); @@ -104,7 +104,7 @@ int deref_param(int *p) { return *p; } void inlined_callee_single_report() { int *ptr = nullptr; { - int num = 5; + int num = 5; // expected-note {{'num' initialized to 5}} ptr = # } // expected-note@-1 {{'num' is destroyed here}} @@ -131,7 +131,7 @@ struct A { char member_subregion_dangling_deref() { const char *p = nullptr; { - MyBuffer tmp_buffer = {}; + MyBuffer tmp_buffer = {}; // expected-note {{Initializing to 0}} p = tmp_buffer.buffer; } // expected-note@-1 {{'tmp_buffer.buffer[0]' is destroyed here}} @@ -147,7 +147,7 @@ void passing_dangling_to_call() { const char *p = nullptr; { MyBuffer tmp_buffer = {}; - p = tmp_buffer.buffer; + p = tmp_buffer.buffer; // expected-note {{Value assigned to 'p'}} } // expected-note@-1 {{'tmp_buffer.buffer[0]' is destroyed here}} opaque(p); @@ -178,8 +178,8 @@ char member_subregion_alive_deref_pp() { void arr_elem_subreg_dangling_deref() { int *ptr = nullptr; { - int local_arr[4]; - ptr = &local_arr[1]; + int local_arr[4]; // expected-note {{'local_arr' declared without an initial value}} + ptr = &local_arr[1]; // expected-note {{Value assigned to 'ptr'}} } // expected-note@-1 {{'local_arr[1]' is destroyed here}} *ptr = 7; @@ -190,7 +190,7 @@ void arr_elem_subreg_dangling_deref() { char member_array_elem_dangling_deref() { const char *p = nullptr; { - MyBuffer tmp_buffer = {}; + MyBuffer tmp_buffer = {}; // expected-note {{Initializing to 0}} p = tmp_buffer.buffer + 3; } // expected-note@-1 {{'tmp_buffer.buffer[3]' is destroyed here}} @@ -202,7 +202,7 @@ char member_array_elem_dangling_deref() { char member_array_out_of_bounds_dangling_deref() { const char *p = nullptr; { - MyBuffer tmp_buffer = {}; + MyBuffer tmp_buffer = {}; // expected-note {{Initializing to 0}} p = tmp_buffer.buffer + 10; } // expected-note@-1 {{'tmp_buffer.buffer[10]' is destroyed here}} @@ -214,7 +214,7 @@ char member_array_out_of_bounds_dangling_deref() { int struct_field_dangling_deref() { int *p = nullptr; { - MyStruct s = {}; + MyStruct s = {}; // expected-note {{'s.x' initialized to 0}} p = &s.x; } // expected-note@-1 {{'s.x' is destroyed here}} @@ -226,7 +226,7 @@ int struct_field_dangling_deref() { int struct_array_element_dangling_deref() { int *p = nullptr; { - MyStruct arr[4] = {}; + MyStruct arr[4] = {}; // expected-note {{field 'x' initialized to 0}} p = &arr[2].x; } // expected-note@-1 {{'arr[2].x' is destroyed here}} @@ -238,7 +238,7 @@ int struct_array_element_dangling_deref() { int nested_field_dangling_deref() { int *p = nullptr; { - Outer o = {}; + Outer o = {}; // expected-note {{'o.inner.x' initialized to 0}} p = &o.inner.x; } // expected-note@-1 {{'o.inner.x' is destroyed here}} @@ -250,7 +250,7 @@ int nested_field_dangling_deref() { int nested_type_field_dangling_deref() { int *p = nullptr; { - A a = {}; + A a = {}; // expected-note {{'a.b.x' initialized to 0}} p = &a.b.x; } // expected-note@-1 {{'a.b.x' is destroyed here}} @@ -262,7 +262,7 @@ int nested_type_field_dangling_deref() { char member_subregion_dangling_deref_increment() { const char *p = nullptr; { - MyBuffer tmp_buffer = {}; + MyBuffer tmp_buffer = {}; // expected-note {{Initializing to 0}} p = tmp_buffer.buffer; } // expected-note@-1 {{'tmp_buffer.buffer[1]' is destroyed here}} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
