1 // RUN: %clang_analyze_cc1 -std=c++14 \ 2 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 3 // RUN: -analyzer-output=text -verify -DDEFAULT_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=DEFAULT-CHECK 4 // 5 // RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \ 6 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 7 // RUN: -analyzer-output=text -verify -DAMDGCN_TRIPLE %s 2>&1 | FileCheck %s -check-prefix=AMDGCN-CHECK 8 9 #include "Inputs/llvm.h" 10 11 // The amggcn triple case uses an intentionally different address space. 12 // The core.NullDereference checker intentionally ignores checks 13 // that use address spaces, so the case is differentiated here. 14 // 15 // From https://llvm.org/docs/AMDGPUUsage.html#address-spaces, 16 // select address space 3 (local), since the pointer size is 17 // different than Generic. 18 #define DEVICE __attribute__((address_space(3))) 19 20 namespace clang { 21 struct Shape { 22 template <typename T> 23 const T *castAs() const; 24 25 template <typename T> 26 const T *getAs() const; 27 }; 28 class Triangle : public Shape {}; 29 class Rectangle : public Shape {}; 30 class Hexagon : public Shape {}; 31 class Circle : public Shape {}; 32 } // namespace clang 33 34 using namespace llvm; 35 using namespace clang; 36 37 void clang_analyzer_printState(); 38 39 #if defined(DEFAULT_TRIPLE) 40 void evalReferences(const Shape &S) { 41 const auto &C = dyn_cast<Circle>(S); 42 // expected-note@-1 {{Assuming 'S' is not a 'Circle'}} 43 // expected-note@-2 {{Dereference of null pointer}} 44 // expected-warning@-3 {{Dereference of null pointer}} 45 clang_analyzer_printState(); 46 // DEFAULT-CHECK: "dynamic_types": [ 47 // DEFAULT-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle &", "sub_classable": true } 48 (void)C; 49 } 50 #elif defined(AMDGCN_TRIPLE) 51 void evalReferences(const Shape &S) { 52 const auto &C = dyn_cast<DEVICE Circle>(S); 53 clang_analyzer_printState(); 54 // AMDGCN-CHECK: "dynamic_types": [ 55 // AMDGCN-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } 56 (void)C; 57 } 58 #else 59 #error Target must be specified, and must be pinned 60 #endif 61 62 void evalNonNullParamNonNullReturnReference(const Shape &S) { 63 const auto *C = dyn_cast_or_null<Circle>(S); 64 // expected-note@-1 {{'C' initialized here}} 65 66 if (!dyn_cast_or_null<Circle>(C)) { 67 // expected-note@-1 {{'C' is a 'Circle'}} 68 // expected-note@-2 {{Taking false branch}} 69 return; 70 } 71 72 if (dyn_cast_or_null<Triangle>(C)) { 73 // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}} 74 // expected-note@-2 {{Taking false branch}} 75 return; 76 } 77 78 if (dyn_cast_or_null<Rectangle>(C)) { 79 // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}} 80 // expected-note@-2 {{Taking false branch}} 81 return; 82 } 83 84 if (dyn_cast_or_null<Hexagon>(C)) { 85 // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}} 86 // expected-note@-2 {{Taking false branch}} 87 return; 88 } 89 90 if (isa<Triangle>(C)) { 91 // expected-note@-1 {{'C' is not a 'Triangle'}} 92 // expected-note@-2 {{Taking false branch}} 93 return; 94 } 95 96 if (isa<Triangle, Rectangle>(C)) { 97 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}} 98 // expected-note@-2 {{Taking false branch}} 99 return; 100 } 101 102 if (isa<Triangle, Rectangle, Hexagon>(C)) { 103 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}} 104 // expected-note@-2 {{Taking false branch}} 105 return; 106 } 107 108 if (isa<Circle, Rectangle, Hexagon>(C)) { 109 // expected-note@-1 {{'C' is a 'Circle'}} 110 // expected-note@-2 {{Taking true branch}} 111 112 (void)(1 / !C); 113 // expected-note@-1 {{'C' is non-null}} 114 // expected-note@-2 {{Division by zero}} 115 // expected-warning@-3 {{Division by zero}} 116 } 117 } 118 119 void evalNonNullParamNonNullReturn(const Shape *S) { 120 const auto *C = cast<Circle>(S); 121 // expected-note@-1 {{'S' is a 'Circle'}} 122 // expected-note@-2 {{'C' initialized here}} 123 124 if (!dyn_cast_or_null<Circle>(C)) { 125 // expected-note@-1 {{'C' is a 'Circle'}} 126 // expected-note@-2 {{Taking false branch}} 127 return; 128 } 129 130 if (dyn_cast_or_null<Triangle>(C)) { 131 // expected-note@-1 {{Assuming 'C' is not a 'Triangle'}} 132 // expected-note@-2 {{Taking false branch}} 133 return; 134 } 135 136 if (dyn_cast_or_null<Rectangle>(C)) { 137 // expected-note@-1 {{Assuming 'C' is not a 'Rectangle'}} 138 // expected-note@-2 {{Taking false branch}} 139 return; 140 } 141 142 if (dyn_cast_or_null<Hexagon>(C)) { 143 // expected-note@-1 {{Assuming 'C' is not a 'Hexagon'}} 144 // expected-note@-2 {{Taking false branch}} 145 return; 146 } 147 148 if (isa<Triangle>(C)) { 149 // expected-note@-1 {{'C' is not a 'Triangle'}} 150 // expected-note@-2 {{Taking false branch}} 151 return; 152 } 153 154 if (isa<Triangle, Rectangle>(C)) { 155 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}} 156 // expected-note@-2 {{Taking false branch}} 157 return; 158 } 159 160 if (isa<Triangle, Rectangle, Hexagon>(C)) { 161 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}} 162 // expected-note@-2 {{Taking false branch}} 163 return; 164 } 165 166 if (isa<Circle, Rectangle, Hexagon>(C)) { 167 // expected-note@-1 {{'C' is a 'Circle'}} 168 // expected-note@-2 {{Taking true branch}} 169 170 (void)(1 / !C); 171 // expected-note@-1 {{'C' is non-null}} 172 // expected-note@-2 {{Division by zero}} 173 // expected-warning@-3 {{Division by zero}} 174 } 175 } 176 177 void evalNonNullParamNullReturn(const Shape *S) { 178 const auto *C = dyn_cast_or_null<Circle>(S); 179 // expected-note@-1 {{Assuming 'S' is not a 'Circle'}} 180 181 if (const auto *T = dyn_cast_or_null<Triangle>(S)) { 182 // expected-note@-1 {{Assuming 'S' is a 'Triangle'}} 183 // expected-note@-2 {{'T' initialized here}} 184 // expected-note@-3 {{'T' is non-null}} 185 // expected-note@-4 {{Taking true branch}} 186 187 (void)(1 / !T); 188 // expected-note@-1 {{'T' is non-null}} 189 // expected-note@-2 {{Division by zero}} 190 // expected-warning@-3 {{Division by zero}} 191 } 192 } 193 194 void evalNullParamNullReturn(const Shape *S) { 195 const auto *C = dyn_cast_or_null<Circle>(S); 196 // expected-note@-1 {{Assuming null pointer is passed into cast}} 197 // expected-note@-2 {{'C' initialized to a null pointer value}} 198 199 (void)(1 / (bool)C); 200 // expected-note@-1 {{Division by zero}} 201 // expected-warning@-2 {{Division by zero}} 202 } 203 204 void evalZeroParamNonNullReturnPointer(const Shape *S) { 205 const auto *C = S->castAs<Circle>(); 206 // expected-note@-1 {{'S' is a 'Circle'}} 207 // expected-note@-2 {{'C' initialized here}} 208 209 (void)(1 / !C); 210 // expected-note@-1 {{'C' is non-null}} 211 // expected-note@-2 {{Division by zero}} 212 // expected-warning@-3 {{Division by zero}} 213 } 214 215 void evalZeroParamNonNullReturn(const Shape &S) { 216 const auto *C = S.castAs<Circle>(); 217 // expected-note@-1 {{'C' initialized here}} 218 219 (void)(1 / !C); 220 // expected-note@-1 {{'C' is non-null}} 221 // expected-note@-2 {{Division by zero}} 222 // expected-warning@-3 {{Division by zero}} 223 } 224 225 void evalZeroParamNullReturn(const Shape *S) { 226 const auto &C = S->getAs<Circle>(); 227 // expected-note@-1 {{Assuming 'S' is not a 'Circle'}} 228 // expected-note@-2 {{Storing null pointer value}} 229 // expected-note@-3 {{'C' initialized here}} 230 231 if (!dyn_cast_or_null<Triangle>(S)) { 232 // expected-note@-1 {{Assuming 'S' is a 'Triangle'}} 233 // expected-note@-2 {{Taking false branch}} 234 return; 235 } 236 237 if (!dyn_cast_or_null<Triangle>(S)) { 238 // expected-note@-1 {{'S' is a 'Triangle'}} 239 // expected-note@-2 {{Taking false branch}} 240 return; 241 } 242 243 (void)(1 / (bool)C); 244 // expected-note@-1 {{Division by zero}} 245 // expected-warning@-2 {{Division by zero}} 246 } 247