334 lines · cpp
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-CHECK4//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 suppress-dereferences-from-any-address-space=false\8// RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK9//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 suppress-dereferences-from-any-address-space=true\13// RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s -check-prefix=X86-CHECK14//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-CHECK18//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 suppress-dereferences-from-any-address-space=true\22// RUN: -analyzer-output=text -verify -DX86 -DSUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK-SUPPRESSED23//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 suppress-dereferences-from-any-address-space=false\27// RUN: -analyzer-output=text -verify -DX86 -DNOT_SUPPRESSED %s 2>&1 | FileCheck %s --check-prefix=X86-CHECK28//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>&132//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 suppress-dereferences-from-any-address-space=false\36// RUN: -analyzer-output=text -verify -DMIPS %s 2>&137//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 suppress-dereferences-from-any-address-space=true\41// RUN: -analyzer-output=text -verify -DMIPS_SUPPRESSED %s42 43#include "Inputs/llvm.h"44 45// The amggcn triple case uses an intentionally different address space.46// The core.NullDereference checker intentionally ignores checks47// 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 is51// different than Generic.52#define DEVICE __attribute__((address_space(3)))53 54namespace clang {55struct Shape {56 template <typename T>57 const T *castAs() const;58 59 template <typename T>60 const T *getAs() const;61};62class Triangle : public Shape {};63class Rectangle : public Shape {};64class Hexagon : public Shape {};65class Circle : public Shape {};66} // namespace clang67 68using namespace llvm;69using namespace clang;70 71void clang_analyzer_printState();72 73#if defined(X86)74void 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)85void 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 Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }90 (void)C;91}92#endif93#if defined(NOT_SUPPRESSED)94void 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 Shape & S>}", "dyn_type": "const __attribute__((address_space(3))) class clang::Circle &", "sub_classable": true }102 (void)C;103}104#endif105#elif defined(MIPS)106void 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)113void evalReferences_addrspace(const Shape &S) {114 const auto &C = dyn_cast<DEVICE Circle>(S);115 (void)C;116}117#endif118#endif119 120void 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 177void 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 235void 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 252void 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 262void 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 273void 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 283void 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 crash307// CastValueChecker was using QualType()->getPointeeCXXRecordDecl(), in308// getNoteTag which evaluated to nullptr, then crashed when attempting to309// deref an invocation to getNameAsString(). The fix is to use310// 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();320namespace llvm {321template <typename, typename a> void isa(a &);322template <typename> class PointerUnion {323public:324 template <typename T> T *getAs() {325 (void)isa<int>(*this);326 return nullptr;327 }328};329class LLVMContext {330 PointerUnion<LLVMContext> c;331 void d() { c.getAs<int>(); }332};333} // namespace llvm334