Clang Project

clang_source_code/test/Analysis/new-ctor-recursive.cpp
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
3void clang_analyzer_eval(bool);
4void clang_analyzer_dump(int);
5
6typedef __typeof__(sizeof(int)) size_t;
7
8void *conjure();
9void exit(int);
10
11struct S;
12
13S *global_s;
14
15// Recursive operator kinda placement new.
16void *operator new(size_t size, S *place);
17
18enum class ConstructionKind : char {
19  Garbage,
20  Recursive
21};
22
23struct S {
24public:
25  int x;
26  S(): x(1) {}
27  S(int y): x(y) {}
28
29  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  }
42  ~S() {}
43};
44
45// Do not try this at home!
46void *operator new(size_t size, S *place) {
47  if (!place)
48    return new S();
49  return place;
50}
51
52void testThatCharConstructorIndeedYieldsGarbage() {
53  S *s = new S(ConstructionKind::Garbage);
54  clang_analyzer_eval(s->x == 0); // expected-warning{{UNKNOWN}}
55  clang_analyzer_eval(s->x == 1); // expected-warning{{UNKNOWN}}
56  // FIXME: This should warn, but MallocChecker doesn't default-bind regions
57  // returned by standard operator new to garbage.
58  s->x += 1; // no-warning
59  delete s;
60}
61
62
63void testChainedOperatorNew() {
64  S *s;
65  // * Evaluate standard new.
66  // * Evaluate constructor S(3).
67  // * Bind value for standard new.
68  // * Evaluate our custom new.
69  // * Evaluate constructor S(Garbage).
70  // * Bind value for our custom new.
71  s = new (new S(3)) S(ConstructionKind::Garbage);
72  clang_analyzer_eval(s->x == 3); // expected-warning{{TRUE}}
73  // expected-warning@+9{{Potential leak of memory pointed to by 's'}}
74
75  // * Evaluate standard new.
76  // * Evaluate constructor S(Garbage).
77  // * Bind value for standard new.
78  // * Evaluate our custom new.
79  // * Evaluate constructor S(4).
80  // * Bind value for our custom new.
81  s = new (new S(ConstructionKind::Garbage)) S(4);
82  clang_analyzer_eval(s->x == 4); // expected-warning{{TRUE}}
83  delete s;
84
85  // -> Enter our custom new (nullptr).
86  //   * Evaluate standard new.
87  //   * Inline constructor S().
88  //   * Bind value for standard new.
89  // <- Exit our custom new (nullptr).
90  // * Evaluate constructor S(Garbage).
91  // * Bind value for our custom new.
92  s = new (nullptr) S(ConstructionKind::Garbage);
93  clang_analyzer_eval(s->x == 1); // expected-warning{{TRUE}}
94  delete s;
95
96  // -> Enter our custom new (nullptr).
97  //   * Evaluate standard new.
98  //   * Inline constructor S().
99  //   * Bind value for standard new.
100  // <- Exit our custom new (nullptr).
101  // -> Enter constructor S(Recursive).
102  //   -> Enter our custom new (nullptr).
103  //     * Evaluate standard new.
104  //     * Inline constructor S().
105  //     * Bind value for standard new.
106  //   <- Exit our custom new (nullptr).
107  //   * Evaluate constructor S(5).
108  //   * Bind value for our custom new (nullptr).
109  //   * Assign that value to global_s.
110  // <- Exit constructor S(Recursive).
111  // * Bind value for our custom new (nullptr).
112  global_s = nullptr;
113  s = new (nullptr) S(ConstructionKind::Recursive);
114  clang_analyzer_eval(global_s); // expected-warning{{TRUE}}
115  clang_analyzer_eval(global_s->x == 5); // expected-warning{{TRUE}}
116  clang_analyzer_eval(s->x == 6); // expected-warning{{TRUE}}
117  delete s;
118}
119