mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 15:56:06 +00:00

If an object has a trivial copy/move constructor, it's not inlined on invocation but a trivial copy is performed instead. This patch handles trivial copies in the bug reporter by matching the field regions of the 2 objects involved in the copy/move construction, and tracking the appropriate region further. This patch also introduces some support for tracking values in initializer lists. Differential Revision: https://reviews.llvm.org/D131262
272 lines
8.2 KiB
C++
272 lines
8.2 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-output=text -std=c++11 -verify %s
|
|
// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-output=text -std=c++17 -verify %s
|
|
|
|
#include "Inputs/system-header-simulator-cxx.h"
|
|
|
|
namespace copyMoveTrackCtor {
|
|
struct S {
|
|
int *p1, *p2;
|
|
S(int *a, int *b) : p1(a), p2(b) {} // expected-note{{Null pointer value stored to 's.p1'}}
|
|
};
|
|
|
|
void CtorDirect() {
|
|
int *x = nullptr, *y = nullptr;
|
|
// expected-note@-1{{'x' initialized to a null pointer value}}
|
|
|
|
S s(x, y);
|
|
// expected-note@-1{{Passing null pointer value via 1st parameter 'a'}}
|
|
// expected-note@-2{{Calling constructor for 'S'}}
|
|
// expected-note@-3{{Returning from constructor for 'S'}}
|
|
// expected-note@-4{{'s' initialized here}}
|
|
S s2 = s; // expected-note{{Null pointer value stored to 's2.p1'}}
|
|
// expected-note@-1{{'s2' initialized here}}
|
|
S s3 = s2; // expected-note{{Null pointer value stored to 's3.p1'}}
|
|
// expected-note@-1{{'s3' initialized here}}
|
|
S s4 = std::move(s3); // expected-note{{Null pointer value stored to 's4.p1'}}
|
|
// expected-note@-1{{'s4' initialized here}}
|
|
S s5 = s4; // expected-note{{Null pointer value stored to 's5.p1'}}
|
|
|
|
int i = *s5.p1; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer (loaded from field 'p1')}}
|
|
|
|
(void) i;
|
|
}
|
|
} // namespace copyMoveTrackCtor
|
|
|
|
namespace copyMoveTrackInitList {
|
|
struct S {
|
|
int *p1, *p2;
|
|
};
|
|
|
|
void InitListDirect() {
|
|
int *x = nullptr, *y = nullptr; //expected-note{{'x' initialized to a null pointer value}}
|
|
|
|
S s{x, y}; //expected-note{{'s.p1' initialized to a null pointer value}}
|
|
//expected-note@-1{{'s' initialized here}}
|
|
S s2 = s; // expected-note{{Null pointer value stored to 's2.p1'}}
|
|
// expected-note@-1{{'s2' initialized here}}
|
|
S s3 = s2; // expected-note{{Null pointer value stored to 's3.p1'}}
|
|
// expected-note@-1{{'s3' initialized here}}
|
|
S s4 = std::move(s3); // expected-note{{Null pointer value stored to 's4.p1'}}
|
|
// expected-note@-1{{'s4' initialized here}}
|
|
S s5 = s4; // expected-note{{Null pointer value stored to 's5.p1'}}
|
|
|
|
int i = *s5.p1; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer (loaded from field 'p1')}}
|
|
|
|
(void) i;
|
|
}
|
|
|
|
void InitListAssign() {
|
|
int *x = nullptr, *y = nullptr; //expected-note{{'x' initialized to a null pointer value}}
|
|
|
|
S s = {x, y}; //expected-note{{'s.p1' initialized to a null pointer value}}
|
|
//expected-note@-1{{'s' initialized here}}
|
|
S s2 = s; // expected-note{{Null pointer value stored to 's2.p1'}}
|
|
// expected-note@-1{{'s2' initialized here}}
|
|
S s3 = s2; // expected-note{{Null pointer value stored to 's3.p1'}}
|
|
// expected-note@-1{{'s3' initialized here}}
|
|
S s4 = std::move(s3); // expected-note{{Null pointer value stored to 's4.p1'}}
|
|
// expected-note@-1{{'s4' initialized here}}
|
|
S s5 = s4; // expected-note{{Null pointer value stored to 's5.p1'}}
|
|
|
|
int i = *s5.p1; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer (loaded from field 'p1')}}
|
|
|
|
(void) i;
|
|
}
|
|
|
|
} // namespace copyMoveTrackInitList
|
|
|
|
namespace copyMoveTrackCtorMemberInitList {
|
|
struct S {
|
|
int *p1, *p2;
|
|
S(int *a, int *b) : p1{a}, p2{b} {} // expected-note{{Null pointer value stored to 's.p1'}}
|
|
};
|
|
|
|
void CtorDirect() {
|
|
int *x = nullptr, *y = nullptr;
|
|
// expected-note@-1{{'x' initialized to a null pointer value}}
|
|
|
|
S s{x, y};
|
|
// expected-note@-1{{Passing null pointer value via 1st parameter 'a'}}
|
|
// expected-note@-2{{Calling constructor for 'S'}}
|
|
// expected-note@-3{{Returning from constructor for 'S'}}
|
|
// expected-note@-4{{'s' initialized here}}
|
|
S s2 = s; // expected-note{{Null pointer value stored to 's2.p1'}}
|
|
// expected-note@-1{{'s2' initialized here}}
|
|
S s3 = s2; // expected-note{{Null pointer value stored to 's3.p1'}}
|
|
// expected-note@-1{{'s3' initialized here}}
|
|
S s4 = std::move(s3); // expected-note{{Null pointer value stored to 's4.p1'}}
|
|
// expected-note@-1{{'s4' initialized here}}
|
|
S s5 = s4; // expected-note{{Null pointer value stored to 's5.p1'}}
|
|
|
|
int i = *s5.p1; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer (loaded from field 'p1')}}
|
|
|
|
(void) i;
|
|
}
|
|
} // namespace copyMoveTrackCtorMemberInitList
|
|
|
|
namespace directInitList {
|
|
struct S {
|
|
int *p1, *p2;
|
|
};
|
|
|
|
void InitListDirect() {
|
|
int *x = nullptr, *y = nullptr; //expected-note{{'y' initialized to a null pointer value}}
|
|
|
|
S s{x, y}; //expected-note{{'s.p2' initialized to a null pointer value}}
|
|
|
|
int i = *s.p2; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer}}
|
|
(void) i;
|
|
}
|
|
} // namespace directInitList
|
|
|
|
namespace directNestedInitList {
|
|
struct S2 {
|
|
int *p1, *p2;
|
|
};
|
|
|
|
struct S {
|
|
S2 s;
|
|
};
|
|
|
|
void InitListNestedDirect() {
|
|
int *x = nullptr, *y = nullptr; //expected-note{{'y' initialized to a null pointer value}}
|
|
|
|
//FIXME: Put more information to the notes.
|
|
S s{x, y}; //expected-note{{'s.s.p2' initialized to a null pointer value}}
|
|
|
|
int i = *s.s.p2; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer}}
|
|
(void) i;
|
|
}
|
|
} // namespace directNestedInitList
|
|
|
|
#if __cplusplus >= 201703L
|
|
|
|
namespace structuredBinding {
|
|
struct S {
|
|
int *p1, *p2;
|
|
};
|
|
|
|
void StructuredBinding() {
|
|
int *x = nullptr, *y = nullptr;
|
|
//expected-note@-1{{'y' initialized to a null pointer value}}
|
|
|
|
S s{x, y};
|
|
//expected-note@-1{{'s.p2' initialized to a null pointer value}}
|
|
//expected-note@-2{{'s' initialized here}}
|
|
|
|
auto [a, b] = s; //expected-note{{Null pointer value stored to '.p2'}}
|
|
|
|
int i = *b; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer}}
|
|
(void) i;
|
|
}
|
|
} // namespace structuredBinding
|
|
|
|
#endif
|
|
|
|
namespace nestedCtorInitializer {
|
|
struct S5{
|
|
int *x, *y;
|
|
};
|
|
|
|
struct S4 {
|
|
S5 s5;
|
|
};
|
|
|
|
struct S3 {
|
|
S4 s4;
|
|
};
|
|
|
|
struct S2 {
|
|
S3 s3;
|
|
};
|
|
|
|
struct S {
|
|
S2 s2;
|
|
|
|
//FIXME: Put more information to the notes.
|
|
S(int *x, int *y) : s2{x, y} {};
|
|
// expected-note@-1{{Null pointer value stored to 's.s2.s3.s4.s5.y'}}
|
|
};
|
|
|
|
void nestedCtorInit(){
|
|
int *x = nullptr, *y = nullptr; // expected-note{{'y' initialized to a null pointer value}}
|
|
|
|
S s{x,y};
|
|
// expected-note@-1{{Passing null pointer value via 2nd parameter}}
|
|
// expected-note@-2{{Calling constructor for 'S'}}
|
|
// expected-note@-3{{Returning from constructor for 'S'}}
|
|
|
|
int i = *s.s2.s3.s4.s5.y; // expected-warning{{Dereference of null pointer}}
|
|
// expected-note@-1{{Dereference of null pointer}}
|
|
(void) i;
|
|
}
|
|
} // namespace nestedCtorInitializer
|
|
|
|
namespace NestedRegionTrack {
|
|
struct N {
|
|
int *e;
|
|
};
|
|
|
|
struct S {
|
|
N y;
|
|
};
|
|
|
|
void NestedRegionTrack() {
|
|
int *x = nullptr, *y = nullptr;
|
|
// expected-note@-1{{'y' initialized to a null pointer value}}
|
|
|
|
// Test for nested single element initializer list here.
|
|
S a{{{{{{{{y}}}}}}}};
|
|
// expected-note@-1{{'a.y.e' initialized to a null pointer value}}
|
|
// expected-note@-2{{'a' initialized here}}
|
|
// expected-warning@-3{{too many braces around scalar initializer}}
|
|
// expected-warning@-4{{too many braces around scalar initializer}}
|
|
// expected-warning@-5{{too many braces around scalar initializer}}
|
|
// expected-warning@-6{{too many braces around scalar initializer}}
|
|
// expected-warning@-7{{too many braces around scalar initializer}}
|
|
|
|
S b = a; // expected-note{{Null pointer value stored to 'b.y.e'}}
|
|
|
|
int i = *b.y.e;
|
|
// expected-warning@-1{{Dereference of null pointer}}
|
|
// expected-note@-2{{Dereference of null pointer}}
|
|
(void) i;
|
|
(void) x;
|
|
}
|
|
|
|
} // namespace NestedRegionTrack
|
|
|
|
namespace NestedElementRegionTrack {
|
|
struct N {
|
|
int *arr[2];
|
|
};
|
|
|
|
struct S {
|
|
N n;
|
|
};
|
|
|
|
void NestedElementRegionTrack() {
|
|
int *x = nullptr, *y = nullptr;
|
|
// expected-note@-1{{'y' initialized to a null pointer value}}
|
|
|
|
S a{{x, y}};
|
|
// expected-note@-1{{Initializing to a null pointer value}}
|
|
// expected-note@-2{{'a' initialized here}}
|
|
|
|
S b = a; // expected-note{{Storing null pointer value}}
|
|
|
|
int i = *b.n.arr[1];
|
|
// expected-warning@-1{{Dereference of null pointer}}
|
|
// expected-note@-2{{Dereference of null pointer}}
|
|
(void) i;
|
|
}
|
|
|
|
} // namespace NestedElementRegionTrack
|