xref: /llvm-project/clang/test/Analysis/new-ctor-recursive.cpp (revision a504ddc8bf9d5c406ea88b84b8495d7aae200d4c)
1 // RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-allocator-inlining=true -std=c++11 -verify -analyzer-config eagerly-assume=false %s
2 
3 void clang_analyzer_eval(bool);
4 void clang_analyzer_dump(int);
5 
6 typedef __typeof__(sizeof(int)) size_t;
7 
8 void *conjure();
9 void exit(int);
10 
11 struct S;
12 
13 S *global_s;
14 
15 // Recursive operator kinda placement new.
16 void *operator new(size_t size, S *place);
17 
18 enum class ConstructionKind : char {
19   Garbage,
20   Recursive
21 };
22 
23 struct S {
24 public:
25   int x;
SS26   S(): x(1) {}
SS27   S(int y): x(y) {}
28 
SS29   S(ConstructionKind k) {
30     switch (k) {
31     case ConstructionKind::Recursive: { // Call one more operator new 'r'ecursively.
32       S *s = new (nullptr) S(5);
33       x = s->x + 1;
34       global_s = s;
35       return;
36     }
37     case ConstructionKind::Garbage: {
38       // Leaves garbage in 'x'.
39     }
40     }
41   }
~SS42   ~S() {}
43 };
44 
45 // Do not try this at home!
operator new(size_t size,S * place)46 void *operator new(size_t size, S *place) {
47   if (!place)
48     return new S();
49   return place;
50 }
51 
testThatCharConstructorIndeedYieldsGarbage()52 void testThatCharConstructorIndeedYieldsGarbage() {
53   S *s = new S(ConstructionKind::Garbage);
54   clang_analyzer_eval(s->x == 0); // expected-warning{{The left operand of '==' is a garbage value [core.UndefinedBinaryOperatorResult]}}
55   clang_analyzer_eval(s->x == 1);
56   s->x += 1;
57   delete s;
58 }
59 
60 
testChainedOperatorNew()61 void testChainedOperatorNew() {
62   S *s;
63   // * Evaluate standard new.
64   // * Evaluate constructor S(3).
65   // * Bind value for standard new.
66   // * Evaluate our custom new.
67   // * Evaluate constructor S(Garbage).
68   // * Bind value for our custom new.
69   s = new (new S(3)) S(ConstructionKind::Garbage);
70   clang_analyzer_eval(s->x == 3); // expected-warning{{TRUE}}
71   // expected-warning@+9{{Potential leak of memory pointed to by 's'}}
72 
73   // * Evaluate standard new.
74   // * Evaluate constructor S(Garbage).
75   // * Bind value for standard new.
76   // * Evaluate our custom new.
77   // * Evaluate constructor S(4).
78   // * Bind value for our custom new.
79   s = new (new S(ConstructionKind::Garbage)) S(4);
80   clang_analyzer_eval(s->x == 4); // expected-warning{{TRUE}}
81   delete s;
82 
83   // -> Enter our custom new (nullptr).
84   //   * Evaluate standard new.
85   //   * Inline constructor S().
86   //   * Bind value for standard new.
87   // <- Exit our custom new (nullptr).
88   // * Evaluate constructor S(Garbage).
89   // * Bind value for our custom new.
90   s = new (nullptr) S(ConstructionKind::Garbage);
91   clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}}
92   delete s;
93 
94   // -> Enter our custom new (nullptr).
95   //   * Evaluate standard new.
96   //   * Inline constructor S().
97   //   * Bind value for standard new.
98   // <- Exit our custom new (nullptr).
99   // -> Enter constructor S(Recursive).
100   //   -> Enter our custom new (nullptr).
101   //     * Evaluate standard new.
102   //     * Inline constructor S().
103   //     * Bind value for standard new.
104   //   <- Exit our custom new (nullptr).
105   //   * Evaluate constructor S(5).
106   //   * Bind value for our custom new (nullptr).
107   //   * Assign that value to global_s.
108   // <- Exit constructor S(Recursive).
109   // * Bind value for our custom new (nullptr).
110   global_s = nullptr;
111   s = new (nullptr) S(ConstructionKind::Recursive);
112   clang_analyzer_eval(global_s); // expected-warning{{TRUE}}
113   clang_analyzer_eval(global_s->x == 5); // expected-warning{{TRUE}}
114   clang_analyzer_eval(s->x == 6); // expected-warning{{TRUE}}
115   delete s;
116 }
117