1 // RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \ 2 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 3 // RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-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-config core.NullDereference:SuppressAddressSpaces=false\ 8 // RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK 9 // 10 // RUN: %clang_analyze_cc1 -std=c++14 -triple amdgcn-unknown-unknown \ 11 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 12 // RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\ 13 // RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK 14 // 15 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \ 16 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 17 // RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK 18 // 19 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \ 20 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 21 // RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\ 22 // RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK-SUPPRESSED 23 // 24 // RUN: %clang_analyze_cc1 -std=c++14 -triple x86_64-unknown-unknown \ 25 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 26 // RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\ 27 // RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK 28 // 29 // RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \ 30 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 31 // RUN: -analyzer-output=text -verify -DMIPS %s 2>&1 32 // 33 // RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \ 34 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 35 // RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=false\ 36 // RUN: -analyzer-output=text -verify -DMIPS %s 2>&1 37 // 38 // RUN: %clang_analyze_cc1 -std=c++14 -triple mips-unknown-unknown \ 39 // RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\ 40 // RUN: -analyzer-config core.NullDereference:SuppressAddressSpaces=true\ 41 // RUN: -analyzer-output=text -verify -DMIPS_SUPPRESSED %s 42 43 #include "Inputs/llvm.h" 44 45 // The amggcn triple case uses an intentionally different address space. 46 // The core.NullDereference checker intentionally ignores checks 47 // that use address spaces, so the case is differentiated here. 48 // 49 // From https://llvm.org/docs/AMDGPUUsage.html#address-spaces, 50 // select address space 3 (local), since the pointer size is 51 // different than Generic. 52 #define DEVICE __attribute__((address_space(3))) 53 54 namespace clang { 55 struct Shape { 56 template <typename T> 57 const T *castAs() const; 58 59 template <typename T> 60 const T *getAs() const; 61 }; 62 class Triangle : public Shape {}; 63 class Rectangle : public Shape {}; 64 class Hexagon : public Shape {}; 65 class Circle : public Shape {}; 66 } // namespace clang 67 68 using namespace llvm; 69 using namespace clang; 70 71 void clang_analyzer_printState(); 72 73 #if defined(X86) 74 void evalReferences(const Shape &S) { 75 const auto &C = dyn_cast<Circle>(S); 76 // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} 77 // expected-note@-2 {{Dereference of null pointer}} 78 // expected-warning@-3 {{Dereference of null pointer}} 79 clang_analyzer_printState(); 80 // XX86-CHECK: "dynamic_types": [ 81 // XX86-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle &", "sub_classable": true } 82 (void)C; 83 } 84 #if defined(SUPPRESSED) 85 void evalReferences_addrspace(const Shape &S) { 86 const auto &C = dyn_cast<DEVICE Circle>(S); 87 clang_analyzer_printState(); 88 // X86-CHECK-SUPPRESSED: "dynamic_types": [ 89 // X86-CHECK-SUPPRESSED-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } 90 (void)C; 91 } 92 #endif 93 #if defined(NOT_SUPPRESSED) 94 void evalReferences_addrspace(const Shape &S) { 95 const auto &C = dyn_cast<DEVICE Circle>(S); 96 // expected-note@-1 {{Assuming 'S' is not a 'const __attribute__((address_space(3))) class clang::Circle &'}} 97 // expected-note@-2 {{Dereference of null pointer}} 98 // expected-warning@-3 {{Dereference of null pointer}} 99 clang_analyzer_printState(); 100 // X86-CHECK: "dynamic_types": [ 101 // X86-CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true } 102 (void)C; 103 } 104 #endif 105 #elif defined(MIPS) 106 void evalReferences(const Shape &S) { 107 const auto &C = dyn_cast<Circle>(S); 108 // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle &'}} 109 // expected-note@-2 {{Dereference of null pointer}} 110 // expected-warning@-3 {{Dereference of null pointer}} 111 } 112 #if defined(MIPS_SUPPRESSED) 113 void evalReferences_addrspace(const Shape &S) { 114 const auto &C = dyn_cast<DEVICE Circle>(S); 115 (void)C; 116 } 117 #endif 118 #endif 119 120 void evalNonNullParamNonNullReturnReference(const Shape &S) { 121 const auto *C = dyn_cast_or_null<Circle>(S); 122 // expected-note@-1 {{'C' initialized here}} 123 124 if (!dyn_cast_or_null<Circle>(C)) { 125 // expected-note@-1 {{Assuming 'C' is a 'const class clang::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 'const class clang::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 'const class clang::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 'const class clang::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 evalNonNullParamNonNullReturn(const Shape *S) { 178 const auto *C = cast<Circle>(S); 179 // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} 180 // expected-note@-2 {{'C' initialized here}} 181 182 if (!dyn_cast_or_null<Circle>(C)) { 183 // expected-note@-1 {{Assuming 'C' is a 'const class clang::Circle *'}} 184 // expected-note@-2 {{Taking false branch}} 185 return; 186 } 187 188 if (dyn_cast_or_null<Triangle>(C)) { 189 // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Triangle *'}} 190 // expected-note@-2 {{Taking false branch}} 191 return; 192 } 193 194 if (dyn_cast_or_null<Rectangle>(C)) { 195 // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Rectangle *'}} 196 // expected-note@-2 {{Taking false branch}} 197 return; 198 } 199 200 if (dyn_cast_or_null<Hexagon>(C)) { 201 // expected-note@-1 {{Assuming 'C' is not a 'const class clang::Hexagon *'}} 202 // expected-note@-2 {{Taking false branch}} 203 return; 204 } 205 206 if (isa<Triangle>(C)) { 207 // expected-note@-1 {{'C' is not a 'Triangle'}} 208 // expected-note@-2 {{Taking false branch}} 209 return; 210 } 211 212 if (isa<Triangle, Rectangle>(C)) { 213 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle'}} 214 // expected-note@-2 {{Taking false branch}} 215 return; 216 } 217 218 if (isa<Triangle, Rectangle, Hexagon>(C)) { 219 // expected-note@-1 {{'C' is neither a 'Triangle' nor a 'Rectangle' nor a 'Hexagon'}} 220 // expected-note@-2 {{Taking false branch}} 221 return; 222 } 223 224 if (isa<Circle, Rectangle, Hexagon>(C)) { 225 // expected-note@-1 {{'C' is a 'Circle'}} 226 // expected-note@-2 {{Taking true branch}} 227 228 (void)(1 / !C); 229 // expected-note@-1 {{'C' is non-null}} 230 // expected-note@-2 {{Division by zero}} 231 // expected-warning@-3 {{Division by zero}} 232 } 233 } 234 235 void evalNonNullParamNullReturn(const Shape *S) { 236 const auto *C = dyn_cast_or_null<Circle>(S); 237 // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} 238 239 if (const auto *T = dyn_cast_or_null<Triangle>(S)) { 240 // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} 241 // expected-note@-2 {{'T' initialized here}} 242 // expected-note@-3 {{'T' is non-null}} 243 // expected-note@-4 {{Taking true branch}} 244 245 (void)(1 / !T); 246 // expected-note@-1 {{'T' is non-null}} 247 // expected-note@-2 {{Division by zero}} 248 // expected-warning@-3 {{Division by zero}} 249 } 250 } 251 252 void evalNullParamNullReturn(const Shape *S) { 253 const auto *C = dyn_cast_or_null<Circle>(S); 254 // expected-note@-1 {{Assuming null pointer is passed into cast}} 255 // expected-note@-2 {{'C' initialized to a null pointer value}} 256 257 (void)(1 / (bool)C); 258 // expected-note@-1 {{Division by zero}} 259 // expected-warning@-2 {{Division by zero}} 260 } 261 262 void evalZeroParamNonNullReturnPointer(const Shape *S) { 263 const auto *C = S->castAs<Circle>(); 264 // expected-note@-1 {{'S' is a 'const class clang::Circle *'}} 265 // expected-note@-2 {{'C' initialized here}} 266 267 (void)(1 / !C); 268 // expected-note@-1 {{'C' is non-null}} 269 // expected-note@-2 {{Division by zero}} 270 // expected-warning@-3 {{Division by zero}} 271 } 272 273 void evalZeroParamNonNullReturn(const Shape &S) { 274 const auto *C = S.castAs<Circle>(); 275 // expected-note@-1 {{'C' initialized here}} 276 277 (void)(1 / !C); 278 // expected-note@-1 {{'C' is non-null}} 279 // expected-note@-2 {{Division by zero}} 280 // expected-warning@-3 {{Division by zero}} 281 } 282 283 void evalZeroParamNullReturn(const Shape *S) { 284 const auto &C = S->getAs<Circle>(); 285 // expected-note@-1 {{Assuming 'S' is not a 'const class clang::Circle *'}} 286 // expected-note@-2 {{Storing null pointer value}} 287 // expected-note@-3 {{'C' initialized here}} 288 289 if (!dyn_cast_or_null<Triangle>(S)) { 290 // expected-note@-1 {{Assuming 'S' is a 'const class clang::Triangle *'}} 291 // expected-note@-2 {{Taking false branch}} 292 return; 293 } 294 295 if (!dyn_cast_or_null<Triangle>(S)) { 296 // expected-note@-1 {{'S' is a 'Triangle'}} 297 // expected-note@-2 {{Taking false branch}} 298 return; 299 } 300 301 (void)(1 / (bool)C); 302 // expected-note@-1 {{Division by zero}} 303 // expected-warning@-2 {{Division by zero}} 304 } 305 306 // don't crash 307 // CastValueChecker was using QualType()->getPointeeCXXRecordDecl(), in 308 // getNoteTag which evaluated to nullptr, then crashed when attempting to 309 // deref an invocation to getNameAsString(). The fix is to use 310 // QualType().getAsString(). 311 // 312 // Example: 313 // std::string CastToName = 314 // CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString() 315 // : CastToTy->getPointeeCXXRecordDecl()->getNameAsString(); 316 // Changed to: 317 // std::string CastToName = 318 // CastInfo ? CastInfo->to()->getAsCXXRecordDecl()->getNameAsString() 319 // : CastToTy.getAsString(); 320 namespace llvm { 321 template <typename, typename a> void isa(a &); 322 template <typename> class PointerUnion { 323 public: 324 template <typename T> T *getAs() { 325 (void)isa<int>(*this); 326 return nullptr; 327 } 328 }; 329 class LLVMContext { 330 PointerUnion<LLVMContext> c; 331 void d() { c.getAs<int>(); } 332 }; 333 } // namespace llvm 334