Skip to content

Commit 12791f2

Browse files
committed
[analyzer] Do list initialization for CXXNewExpr with initializer list arg
1 parent 88e72c4 commit 12791f2

File tree

2 files changed

+194
-9
lines changed

2 files changed

+194
-9
lines changed

clang/lib/StaticAnalyzer/Core/RegionStore.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2425,6 +2425,15 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
24252425

24262426
const MemRegion *R = MemRegVal->getRegion();
24272427

2428+
// Binding directly to a symbolic region should be treated as binding
2429+
// to element 0.
2430+
if (const auto *SymReg = dyn_cast<SymbolicRegion>(R)) {
2431+
QualType Ty = SymReg->getPointeeStaticType();
2432+
if (Ty->isVoidType())
2433+
Ty = StateMgr.getContext().CharTy;
2434+
R = GetElementZeroRegion(SymReg, Ty);
2435+
}
2436+
24282437
// Check if the region is a struct region.
24292438
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
24302439
QualType Ty = TR->getValueType();
@@ -2438,15 +2447,6 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
24382447
return bindAggregate(B, TR, V);
24392448
}
24402449

2441-
// Binding directly to a symbolic region should be treated as binding
2442-
// to element 0.
2443-
if (const auto *SymReg = dyn_cast<SymbolicRegion>(R)) {
2444-
QualType Ty = SymReg->getPointeeStaticType();
2445-
if (Ty->isVoidType())
2446-
Ty = StateMgr.getContext().CharTy;
2447-
R = GetElementZeroRegion(SymReg, Ty);
2448-
}
2449-
24502450
assert((!isa<CXXThisRegion>(R) || !B.lookup(R)) &&
24512451
"'this' pointer is not an l-value and is not assignable");
24522452

clang/test/Analysis/initializer.cpp

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,191 @@ void foo() {
254254
}
255255
} // namespace CXX17_aggregate_construction
256256

257+
namespace newexpr_init_list_initialization {
258+
struct S {
259+
int foo;
260+
int bar;
261+
};
262+
void none_designated() {
263+
S *s = new S{13,1};
264+
clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}}
265+
clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}}
266+
delete s;
267+
}
268+
void none_designated_swapped() {
269+
S *s = new S{1,13};
270+
clang_analyzer_eval(1 == s->foo); // expected-warning{{TRUE}}
271+
clang_analyzer_eval(13 == s->bar); // expected-warning{{TRUE}}
272+
delete s;
273+
}
274+
void one_designated_one_not() {
275+
S *s = new S{ 1, .bar = 13 };
276+
clang_analyzer_eval(1 == s->foo); // expected-warning{{TRUE}}
277+
clang_analyzer_eval(13 == s->bar); // expected-warning{{TRUE}}
278+
delete s;
279+
}
280+
void all_designated() {
281+
S *s = new S{
282+
.foo = 13,
283+
.bar = 1,
284+
};
285+
clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}}
286+
clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}}
287+
delete s;
288+
}
289+
void non_designated_array_of_aggr_struct() {
290+
S *s = new S[2] { {1, 2}, {3, 4} };
291+
clang_analyzer_eval(1 == s[0].foo); // expected-warning{{TRUE}}
292+
clang_analyzer_eval(2 == s[0].bar); // expected-warning{{TRUE}}
293+
clang_analyzer_eval(3 == s[1].foo); // expected-warning{{TRUE}}
294+
clang_analyzer_eval(4 == s[1].bar); // expected-warning{{TRUE}}
295+
delete[] s;
296+
}
297+
298+
struct WithGaps {
299+
int foo;
300+
int bar;
301+
int baz;
302+
};
303+
void out_of_order_designated_initializers_with_gaps() {
304+
WithGaps *s = new WithGaps{
305+
.foo = 13,
306+
.baz = 1,
307+
};
308+
clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}}
309+
clang_analyzer_eval(0 == s->bar); // expected-warning{{TRUE}}
310+
clang_analyzer_eval(1 == s->baz); // expected-warning{{TRUE}}
311+
delete s;
312+
}
313+
314+
// https://eel.is/c++draft/dcl.init.aggr#note-6:
315+
// Static data members, non-static data members of anonymous
316+
// union members, and unnamed bit-fields are not considered
317+
// elements of the aggregate.
318+
struct NonConsideredFields {
319+
int i;
320+
static int s;
321+
int j;
322+
int :17;
323+
int k;
324+
};
325+
void considered_fields_initd() {
326+
auto S = new NonConsideredFields { 1, 2, 3 };
327+
clang_analyzer_eval(1 == S->i); // expected-warning{{TRUE}}
328+
clang_analyzer_eval(2 == S->j); // expected-warning{{TRUE}}
329+
clang_analyzer_eval(3 == S->k); // expected-warning{{TRUE}}
330+
delete S;
331+
}
332+
333+
class PubClass {
334+
public:
335+
int foo;
336+
int bar;
337+
};
338+
void public_class_designated_initializers() {
339+
S *s = new S{
340+
.foo = 13,
341+
.bar = 1,
342+
};
343+
clang_analyzer_eval(13 == s->foo); // expected-warning{{TRUE}}
344+
clang_analyzer_eval(1 == s->bar); // expected-warning{{TRUE}}
345+
delete s;
346+
}
347+
348+
union UnionTestTy {
349+
int x;
350+
char y;
351+
};
352+
void new_expr_aggr_init_union_no_designator() {
353+
UnionTestTy *u = new UnionTestTy{};
354+
clang_analyzer_eval(0 == u->x); // expected-warning{{UNKNOWN}} TODO: should be TRUE
355+
clang_analyzer_eval(u->y); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning
356+
delete u;
357+
}
358+
void new_expr_aggr_init_union_designated_first_field() {
359+
UnionTestTy *u = new UnionTestTy{ .x = 14 };
360+
clang_analyzer_eval(14 == u->x); // expected-warning{{UNKNOWN}} TODO: should be TRUE
361+
clang_analyzer_eval(u->y); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning
362+
delete u;
363+
}
364+
void new_expr_aggr_init_union_designated_non_first_field() {
365+
UnionTestTy *u = new UnionTestTy{ .y = 3 };
366+
clang_analyzer_eval(3 == u->y); // expected-warning{{UNKNOWN}} TODO: should be TRUE
367+
clang_analyzer_eval(u->x); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning
368+
delete u;
369+
}
370+
371+
union UnionTestTyWithDefaultMemberInit {
372+
int x;
373+
char y = 14;
374+
};
375+
void union_with_default_member_init_empty_init_list() {
376+
auto U = new UnionTestTyWithDefaultMemberInit{};
377+
// clang_analyzer_eval(14 == U->y); // TODO: Should be true
378+
clang_analyzer_eval(U->x); // expected-warning{{UNKNOWN}} TODO: should be undefined, warning
379+
delete U;
380+
}
381+
382+
struct Inner {
383+
int bar;
384+
};
385+
struct Nested {
386+
int foo;
387+
Inner inner;
388+
int baz;
389+
};
390+
void nested_aggregates() {
391+
auto N = new Nested{};
392+
clang_analyzer_eval(0 == N->foo); // expected-warning{{TRUE}}
393+
clang_analyzer_eval(0 == N->inner.bar); // expected-warning{{TRUE}}
394+
clang_analyzer_eval(0 == N->baz); // expected-warning{{TRUE}}
395+
396+
auto N1 = new Nested{1};
397+
clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}}
398+
clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}}
399+
clang_analyzer_eval(0 == N1->baz); // expected-warning{{TRUE}}
400+
401+
auto N2 = new Nested{.baz = 14};
402+
clang_analyzer_eval(0 == N->foo); // expected-warning{{TRUE}}
403+
clang_analyzer_eval(0 == N->inner.bar); // expected-warning{{TRUE}}
404+
clang_analyzer_eval(14 == N->baz); // expected-warning{{FALSE}} TODO: Should be TRUE
405+
406+
auto N3 = new Nested{1,2,3};
407+
clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}}
408+
clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE
409+
clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE
410+
411+
auto N4 = new Nested{1, {}, 3};
412+
clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}}
413+
clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}}
414+
clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE
415+
416+
auto N5 = new Nested{{},{},{}};
417+
clang_analyzer_eval(0 == N1->foo); // expected-warning{{FALSE}} TODO: Should be TRUE
418+
clang_analyzer_eval(0 == N1->inner.bar); // expected-warning{{TRUE}}
419+
clang_analyzer_eval(0 == N1->baz); // expected-warning{{TRUE}}
420+
421+
auto N6 = new Nested{1, {.bar = 2}, 3};
422+
clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}}
423+
clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE
424+
clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE
425+
426+
auto N7 = new Nested{1, {2}, 3};
427+
clang_analyzer_eval(1 == N1->foo); // expected-warning{{TRUE}}
428+
clang_analyzer_eval(2 == N1->inner.bar); // expected-warning{{FALSE}} TODO: Should be TRUE
429+
clang_analyzer_eval(3 == N1->baz); // expected-warning{{FALSE}} TODO: Should be TRUE
430+
431+
delete N;
432+
delete N1;
433+
delete N2;
434+
delete N3;
435+
delete N4;
436+
delete N5;
437+
delete N6;
438+
delete N7;
439+
}
440+
} // namespace newexpr_init_list_initialization
441+
257442
namespace CXX17_transparent_init_list_exprs {
258443
class A {};
259444

0 commit comments

Comments
 (0)