isuckatcs created this revision.
isuckatcs added reviewers: njames93, baloghadamsoftware, aaron.ballman, 
LegalizeAdulthood.
Herald added subscribers: carlosgalvezp, manas, ASDenysPetrov, dkrupp, 
donat.nagy, Szelethus, a.sidorin, rnkovacs, xazax.hun.
Herald added a project: All.
isuckatcs requested review of this revision.
Herald added a project: clang-tools-extra.
Herald added a subscriber: cfe-commits.

`ExceptionAnalyzer` only compared exact types in case of pointer,
which is incorrect. An `int *` can be caught by a `const int *` handler,
but `ExceptionAnalyzer` falsely reported it an escaping exception.

For example:

  void foo() noexcept {
    try {
      int a = 1;
      throw &a;
    } catch (const int *) {
    }
  }

In function `foo()` the `&a` is caught by the handler, but clang-tidy 
reports the following warning:

  warning: an exception may be thrown in function 'foo' which should not throw 
exceptions [bugprone-exception-escape]


https://reviews.llvm.org/D135495

Files:
  clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
  clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
===================================================================
--- clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
+++ clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
@@ -101,6 +101,84 @@
   }
 }
 
+void throw_catch_pointer_c() noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_pointer_c' which should not throw exceptions
+  try {
+    int a = 1;
+    throw &a;
+  } catch(const int *) {}
+}
+
+void throw_catch_pointer_v() noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_pointer_v' which should not throw exceptions
+  try {
+    int a = 1;
+    throw &a;
+  } catch(volatile int *) {}
+}
+
+void throw_catch_pointer_cv() noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_catch_pointer_cv' which should not throw exceptions
+  try {
+    int a = 1;
+    throw &a;
+  } catch(const volatile int *) {}
+}
+
+void throw_c_catch_pointer() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_c_catch_pointer' which should not throw exceptions
+  try {
+    int a = 1;
+    const int *p = &a;
+    throw p;
+  } catch(int *) {}
+}
+
+void throw_c_catch_pointer_v() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_c_catch_pointer_v' which should not throw exceptions
+  try {
+    int a = 1;
+    const int *p = &a;
+    throw p;
+  } catch(volatile int *) {}
+}
+
+void throw_v_catch_pointer() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_v_catch_pointer' which should not throw exceptions
+  try {
+    int a = 1;
+    volatile int *p = &a;
+    throw p;
+  } catch(int *) {}
+}
+
+void throw_v_catch_pointer_c() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_v_catch_pointer_c' which should not throw exceptions
+  try {
+    int a = 1;
+    volatile int *p = &a;
+    throw p;
+  } catch(const int *) {}
+}
+
+void throw_cv_catch_pointer_c() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_cv_catch_pointer_c' which should not throw exceptions
+  try {
+    int a = 1;
+    const volatile int *p = &a;
+    throw p;
+  } catch(const int *) {}
+}
+
+void throw_cv_catch_pointer_v() noexcept {
+  // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'throw_cv_catch_pointer_v' which should not throw exceptions
+  try {
+    int a = 1;
+    const volatile int *p = &a;
+    throw p;
+  } catch(volatile int *) {}
+}
+
 class base {};
 class derived: public base {};
 
Index: clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
===================================================================
--- clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -61,6 +61,24 @@
   for (const Type *T : ThrownExceptions) {
     if (T == BaseClass || isBaseOf(T, BaseClass))
       TypesToDelete.push_back(T);
+    else if (T->isPointerType() && BaseClass->isPointerType()) {
+      auto BPointeeTy = BaseClass->getAs<PointerType>()->getPointeeType();
+      auto TPointeeTy = T->getAs<PointerType>()->getPointeeType();
+
+      auto BCVR = BPointeeTy.getCVRQualifiers();
+      auto TCVR = TPointeeTy.getCVRQualifiers();
+
+      // In case the unqualified types are the same, the exception will be
+      // caught if
+      //  1.) the thrown type doesn't have qualifiers
+      //  2.) the handler has the same qualifiers as the thrown type
+      //  3.) the handle has more qualifiers than the thrown type
+      if (BPointeeTy->getUnqualifiedDesugaredType() ==
+              TPointeeTy->getUnqualifiedDesugaredType() &&
+          (TCVR == 0 || (BCVR ^ TCVR) == 0 || (BCVR & TCVR) > BCVR)) {
+        TypesToDelete.push_back(T);
+      }
+    }
   }
 
   for (const Type *T : TypesToDelete)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to