https://github.com/Flandini updated https://github.com/llvm/llvm-project/pull/127700
>From 2c094dc9d9eab60e94ea018a854a1eae48dd894b Mon Sep 17 00:00:00 2001 From: Michael Flanders <flanders.micha...@gmail.com> Date: Tue, 18 Feb 2025 12:27:18 -0600 Subject: [PATCH 1/2] [analyzer] Do list init for CXX new expr with initializer list --- clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 18 +- clang/test/Analysis/initializer.cpp | 185 ++++++++++++++++++ 2 files changed, 194 insertions(+), 9 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index d01b6ae55f611..e376b84f8219f 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -2425,6 +2425,15 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) { const MemRegion *R = MemRegVal->getRegion(); + // Binding directly to a symbolic region should be treated as binding + // to element 0. + if (const auto *SymReg = dyn_cast<SymbolicRegion>(R)) { + QualType Ty = SymReg->getPointeeStaticType(); + if (Ty->isVoidType()) + Ty = StateMgr.getContext().CharTy; + R = GetElementZeroRegion(SymReg, Ty); + } + // Check if the region is a struct region. if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) { QualType Ty = TR->getValueType(); @@ -2438,15 +2447,6 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) { return bindAggregate(B, TR, V); } - // Binding directly to a symbolic region should be treated as binding - // to element 0. - if (const auto *SymReg = dyn_cast<SymbolicRegion>(R)) { - QualType Ty = SymReg->getPointeeStaticType(); - if (Ty->isVoidType()) - Ty = StateMgr.getContext().CharTy; - R = GetElementZeroRegion(SymReg, Ty); - } - assert((!isa<CXXThisRegion>(R) || !B.lookup(R)) && "'this' pointer is not an l-value and is not assignable"); diff --git a/clang/test/Analysis/initializer.cpp b/clang/test/Analysis/initializer.cpp index f50afff25d245..2112c049f38f8 100644 --- a/clang/test/Analysis/initializer.cpp +++ b/clang/test/Analysis/initializer.cpp @@ -254,6 +254,191 @@ void foo() { } } // namespace CXX17_aggregate_construction +namespace newexpr_init_list_initialization { +struct S { + int foo; + int bar; +}; +void none_designated() { + S *s = new S{13,1}; + clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}} + delete s; +} +void none_designated_swapped() { + S *s = new S{1,13}; + clang_analyzer_eval(1 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(13 == s->bar); // expected-warning{{TRUE}} + delete s; +} +void one_designated_one_not() { + S *s = new S{ 1, .bar = 13 }; + clang_analyzer_eval(1 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(13 == s->bar); // expected-warning{{TRUE}} + delete s; +} +void all_designated() { + S *s = new S{ + .foo = 13, + .bar = 1, + }; + clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}} + delete s; +} +void non_designated_array_of_aggr_struct() { + S *s = new S[2] { {1, 2}, {3, 4} }; + clang_analyzer_eval(1 == s[0].foo); // expected-warning{{TRUE}} + clang_analyzer_eval(2 == s[0].bar); // expected-warning{{TRUE}} + clang_analyzer_eval(3 == s[1].foo); // expected-warning{{TRUE}} + clang_analyzer_eval(4 == s[1].bar); // expected-warning{{TRUE}} + delete[] s; +} + +struct WithGaps { + int foo; + int bar; + int baz; +}; +void out_of_order_designated_initializers_with_gaps() { + WithGaps *s = new WithGaps{ + .foo = 13, + .baz = 1, + }; + clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == s->bar); // expected-warning{{TRUE}} + clang_analyzer_eval(1 == s->baz); // expected-warning{{TRUE}} + delete s; +} + +// https://eel.is/c++draft/dcl.init.aggr#note-6: +// Static data members, non-static data members of anonymous +// union members, and unnamed bit-fields are not considered +// elements of the aggregate. +struct NonConsideredFields { + int i; + static int s; + int j; + int :17; + int k; +}; +void considered_fields_initd() { + auto S = new NonConsideredFields { 1, 2, 3 }; + clang_analyzer_eval(1 == S->i); // expected-warning{{TRUE}} + clang_analyzer_eval(2 == S->j); // expected-warning{{TRUE}} + clang_analyzer_eval(3 == S->k); // expected-warning{{TRUE}} + delete S; +} + +class PubClass { +public: + int foo; + int bar; +}; +void public_class_designated_initializers() { + S *s = new S{ + .foo = 13, + .bar = 1, + }; + clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}} + delete s; +} + +union UnionTestTy { + int x; + char y; +}; +void new_expr_aggr_init_union_no_designator() { + UnionTestTy *u = new UnionTestTy{}; + clang_analyzer_eval(0 == u->x); // expected-warning{{UNKNOWN}} TODO: should be TRUE + clang_analyzer_eval(u->y); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning + delete u; +} +void new_expr_aggr_init_union_designated_first_field() { + UnionTestTy *u = new UnionTestTy{ .x = 14 }; + clang_analyzer_eval(14 == u->x); // expected-warning{{UNKNOWN}} TODO: should be TRUE + clang_analyzer_eval(u->y); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning + delete u; +} +void new_expr_aggr_init_union_designated_non_first_field() { + UnionTestTy *u = new UnionTestTy{ .y = 3 }; + clang_analyzer_eval(3 == u->y); // expected-warning{{UNKNOWN}} TODO: should be TRUE + clang_analyzer_eval(u->x); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning + delete u; +} + +union UnionTestTyWithDefaultMemberInit { + int x; + char y = 14; +}; +void union_with_default_member_init_empty_init_list() { + auto U = new UnionTestTyWithDefaultMemberInit{}; + // clang_analyzer_eval(14 == U->y); // TODO: Should be true + clang_analyzer_eval(U->x); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning + delete U; +} + +struct Inner { + int bar; +}; +struct Nested { + int foo; + Inner inner; + int baz; +}; +void nested_aggregates() { + auto N = new Nested{}; + clang_analyzer_eval(0 == N->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N->inner.bar); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N->baz); // expected-warning{{TRUE}} + + auto N1 = new Nested{1}; + clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N1->baz); // expected-warning{{TRUE}} + + auto N2 = new Nested{.baz = 14}; + clang_analyzer_eval(0 == N->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N->inner.bar); // expected-warning{{TRUE}} + clang_analyzer_eval(14 == N->baz); // expected-warning{{FALSE}} TODO: Should be TRUE + + auto N3 = new Nested{1,2,3}; + clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE + clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE + + auto N4 = new Nested{1, {}, 3}; + clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}} + clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE + + auto N5 = new Nested{{},{},{}}; + clang_analyzer_eval(0 == N1->foo); // expected-warning{{FALSE}} TODO: Should be TRUE + clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}} + clang_analyzer_eval(0 == N1->baz); // expected-warning{{TRUE}} + + auto N6 = new Nested{1, {.bar = 2}, 3}; + clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE + clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE + + auto N7 = new Nested{1, {2}, 3}; + clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}} + clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE + clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE + + delete N; + delete N1; + delete N2; + delete N3; + delete N4; + delete N5; + delete N6; + delete N7; +} +} // namespace newexpr_init_list_initialization + namespace CXX17_transparent_init_list_exprs { class A {}; >From e56332bb4f71ab7aabdec0f16d7dff911b949e28 Mon Sep 17 00:00:00 2001 From: Michael Flanders <flanders.micha...@gmail.com> Date: Tue, 18 Feb 2025 15:22:28 -0600 Subject: [PATCH 2/2] Remove whitespace end of line --- clang/test/Analysis/initializer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Analysis/initializer.cpp b/clang/test/Analysis/initializer.cpp index 2112c049f38f8..edc41d29e1df1 100644 --- a/clang/test/Analysis/initializer.cpp +++ b/clang/test/Analysis/initializer.cpp @@ -311,9 +311,9 @@ void out_of_order_designated_initializers_with_gaps() { delete s; } -// https://eel.is/c++draft/dcl.init.aggr#note-6: -// Static data members, non-static data members of anonymous -// union members, and unnamed bit-fields are not considered +// https://eel.is/c++draft/dcl.init.aggr#note-6: +// Static data members, non-static data members of anonymous +// union members, and unnamed bit-fields are not considered // elements of the aggregate. struct NonConsideredFields { int i; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits