]> granicus.if.org Git - clang/commitdiff
[analyzer] CastValueChecker: Avoid modeling casts between objects.
authorArtem Dergachev <artem.dergachev@gmail.com>
Fri, 23 Aug 2019 03:23:58 +0000 (03:23 +0000)
committerArtem Dergachev <artem.dergachev@gmail.com>
Fri, 23 Aug 2019 03:23:58 +0000 (03:23 +0000)
Our method only works correctly when casting a pointer to a pointer
or a reference to a reference.

Fixes a crash.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@369727 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/CastValueChecker.cpp
test/Analysis/Inputs/llvm.h
test/Analysis/cast-value-logic.cpp
test/Analysis/cast-value-notes.cpp
test/Analysis/cast-value-state-dump.cpp

index 8724e4acbc4ce971870330885d072684e24d7f63..cd3b70db9a5f4bf991f02d8334f9b462f31f3936 100644 (file)
@@ -382,8 +382,13 @@ bool CastValueChecker::evalCall(const CallEvent &Call,
 
   switch (Kind) {
   case CallKind::Function: {
-    // We need to obtain the record type of the call's parameter to model it.
-    if (!getRecordType(Call.parameters()[0]->getType())->isRecordType())
+    // We only model casts from pointers to pointers or from references
+    // to references. Other casts are most likely specialized and we
+    // cannot model them.
+    QualType ParamT = Call.parameters()[0]->getType();
+    QualType ResultT = Call.getResultType();
+    if (!(ParamT->isPointerType() && ResultT->isPointerType()) &&
+        !(ParamT->isReferenceType() && ResultT->isReferenceType()))
       return false;
 
     DV = Call.getArgSVal(0).getAs<DefinedOrUnknownSVal>();
index d77b4648107d233aef728c2d584b486fb084d0d9..c9d66ba2374d3755f76f35338eee8bc75a2d76aa 100644 (file)
@@ -1,5 +1,7 @@
 #pragma clang system_header
 
+#include "system-header-simulator-cxx.h"
+
 namespace llvm {
 template <class X, class Y>
 const X *cast(Y Value);
@@ -22,4 +24,7 @@ bool isa(Y Value);
 
 template <class X, class Y>
 bool isa_and_nonnull(Y Value);
+
+template <typename X, typename Y>
+std::unique_ptr<X> cast(std::unique_ptr<Y> &&Value);
 } // namespace llvm
index 0d2255a3aba2688a28c3dda101fbe612ee015150..c5083ef57c9cfc80fe040297e0f621c07f7c7fb0 100644 (file)
@@ -135,4 +135,10 @@ namespace crashes {
 void test_non_reference_null_region_crash(Shape s) {
   cast<Circle>(s); // no-crash
 }
+
+void test_non_reference_temporary_crash() {
+  extern std::unique_ptr<Shape> foo();
+  auto P = foo();
+  auto Q = cast<Circle>(std::move(P)); // no-crash
+}
 } // namespace crashes
index 6e7f6b01af7b7a7942405631e0088fa8e9637757..f92ba90336a7a6df6e1bc9566c44e7a34ec15dfb 100644 (file)
@@ -27,9 +27,9 @@ void evalReferences(const Shape &S) {
 }
 
 void evalNonNullParamNonNullReturnReference(const Shape &S) {
+  // Unmodeled cast from reference to pointer.
   const auto *C = dyn_cast_or_null<Circle>(S);
-  // expected-note@-1 {{Assuming 'S' is a 'Circle'}}
-  // expected-note@-2 {{'C' initialized here}}
+  // expected-note@-1 {{'C' initialized here}}
 
   if (!dyn_cast_or_null<Circle>(C)) {
     // expected-note@-1 {{'C' is a 'Circle'}}
@@ -132,10 +132,11 @@ void evalZeroParamNonNullReturn(const Shape &S) {
   // expected-warning@-3 {{Division by zero}}
 }
 
-void evalZeroParamNullReturn(const Shape &S) {
-  const auto *C = S.getAs<Circle>();
+void evalZeroParamNullReturn(const Shape *S) {
+  const auto &C = S->getAs<Circle>();
   // expected-note@-1 {{Assuming 'S' is not a 'Circle'}}
-  // expected-note@-2 {{'C' initialized to a null pointer value}}
+  // expected-note@-2 {{Storing null pointer value}}
+  // expected-note@-3 {{'C' initialized here}}
 
   if (!dyn_cast_or_null<Triangle>(S)) {
     // expected-note@-1 {{Assuming 'S' is a 'Triangle'}}
index fd679984d6b2be70e6362fb589f096987469ad04..890fa189335614893befc1d73735133a447977c8 100644 (file)
@@ -16,7 +16,7 @@ class Square : public Shape {};
 using namespace llvm;
 using namespace clang;
 
-void evalNonNullParamNonNullReturnReference(const Shape &S) {
+void evalNonNullParamNonNullReturn(const Shape *S) {
   const auto *C = dyn_cast_or_null<Circle>(S);
   // expected-note@-1 {{Assuming 'S' is a 'Circle'}}
   // expected-note@-2 {{'C' initialized here}}
@@ -31,10 +31,10 @@ void evalNonNullParamNonNullReturnReference(const Shape &S) {
   clang_analyzer_printState();
 
   // CHECK:      "dynamic_types": [
-  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "dyn_type": "const class clang::Circle", "sub_classable": true }
+  // CHECK-NEXT:   { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "dyn_type": "const class clang::Circle", "sub_classable": true }
   // CHECK-NEXT: ],
   // CHECK-NEXT: "dynamic_casts": [
-  // CHECK:        { "region": "SymRegion{reg_$0<const struct clang::Shape & S>}", "casts": [
+  // CHECK:        { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "casts": [
   // CHECK-NEXT:     { "from": "struct clang::Shape", "to": "class clang::Circle", "kind": "success" },
   // CHECK-NEXT:     { "from": "struct clang::Shape", "to": "class clang::Square", "kind": "fail" }
   // CHECK-NEXT:   ]}