Skip to content

[clang-tidy] bugprone-exception-escape didn't detech catching of an exception with pointer type by void * exception handler #99773

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 22, 2024

Conversation

hanickadot
Copy link
Contributor

@hanickadot hanickadot commented Jul 20, 2024

As in title, code which checks eligibility of exceptions with pointer types to be handled by exception handler of type void * disallowed this case. It was working like this:

if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy) &&
          isUnambiguousPublicBaseClass(
              ExceptionCanTy->getTypePtr()->getPointeeType().getTypePtr(),
              HandlerCanTy->getTypePtr()->getPointeeType().getTypePtr())) {

but in isUnambiguousPublicBaseClass there was code which looked for definitions:

bool isUnambiguousPublicBaseClass(const Type *DerivedType,
                                  const Type *BaseType) {
  const auto *DerivedClass =
      DerivedType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  const auto *BaseClass =
      BaseType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  if (!DerivedClass || !BaseClass)
    return false;

This code disallowed usage of void * type which was already correctly detected in isStandardPointerConvertible.

AFAIK this seems like misinterpretation of specification:

14.4 Handling an exception
a standard pointer conversion not involving conversions to pointers to private or protected or ambiguous classes
(https://eel.is/c++draft/except.handle#3.3.1)

and

7.3.12 Pointer conversions
... If B is an inaccessible ([class.access]) or ambiguous ([class.member.lookup]) base class of D, a program that necessitates this conversion is ill-formed. ...
(https://eel.is/c++draft/conv.ptr#3)

14.4 is carving out private, protected, and ambiguous base classes, but they are already carved out in 7.3.12 and implemented in isStandardPointerConvertible

@llvmbot
Copy link
Member

llvmbot commented Jul 20, 2024

@llvm/pr-subscribers-clang-tidy

@llvm/pr-subscribers-clang-tools-extra

Author: Hana Dusíková (hanickadot)

Changes

As in title, code which check eligibility of exceptions with pointer types to be handled by exception handler of type void * disallowed this case. It was check:

if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy) &&
          isUnambiguousPublicBaseClass(
              ExceptionCanTy->getTypePtr()->getPointeeType().getTypePtr(),
              HandlerCanTy->getTypePtr()->getPointeeType().getTypePtr())) {

but in isUnambiguousPublicBaseClass there was code which looked for definitions:

bool isUnambiguousPublicBaseClass(const Type *DerivedType,
                                  const Type *BaseType) {
  const auto *DerivedClass =
      DerivedType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  const auto *BaseClass =
      BaseType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  if (!DerivedClass || !BaseClass)
    return false;

This code disallowed usage of void * type which was correctly detected in isStandardPointerConvertible.

AFAIK this seems like misinterpretation of specification:

> 14.4 Handling an exception
> a standard pointer conversion not involving conversions to pointers to private or protected or ambiguous classes
(https://eel.is/c++draft/except.handle#3.3.1)

and

> 7.3.12 Pointer conversions
> ... If B is an inaccessible ([class.access]) or ambiguous ([class.member.lookup]) base class of D, a program that necessitates this conversion is ill-formed[.](https://eel.is/c++draft/conv.ptr#3.sentence-2) ...
(https://eel.is/c++draft/conv.ptr#3)

14.4 is carving out private, protected, and ambiguous base classes, but they are already carved out in 7.3.12 and implemented in isStandardPointerConvertible


Full diff: https://github.com/llvm/llvm-project/pull/99773.diff

3 Files Affected:

  • (modified) clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp (+5-5)
  • (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4)
  • (modified) clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp (+18)
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
index 6ae46e2b1262a..9bfb7e2677533 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionAnalyzer.cpp
@@ -141,7 +141,10 @@ bool isStandardPointerConvertible(QualType From, QualType To) {
     if (RD->isCompleteDefinition() &&
         isBaseOf(From->getPointeeType().getTypePtr(),
                  To->getPointeeType().getTypePtr())) {
-      return true;
+      // If B is an inaccessible or ambiguous base class of D, a program
+      // that necessitates this conversion is ill-formed
+      return isUnambiguousPublicBaseClass(From->getPointeeType().getTypePtr(),
+                                          To->getPointeeType().getTypePtr());
     }
   }
 
@@ -375,10 +378,7 @@ bool ExceptionAnalyzer::ExceptionInfo::filterByCatch(
         isPointerOrPointerToMember(ExceptionCanTy->getTypePtr())) {
       // A standard pointer conversion not involving conversions to pointers to
       // private or protected or ambiguous classes ...
-      if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy) &&
-          isUnambiguousPublicBaseClass(
-              ExceptionCanTy->getTypePtr()->getPointeeType().getTypePtr(),
-              HandlerCanTy->getTypePtr()->getPointeeType().getTypePtr())) {
+      if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy)) {
         TypesToDelete.push_back(ExceptionTy);
       }
       // A function pointer conversion ...
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a23483e6df6d2..8e8c0cd0cc3d8 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -518,6 +518,10 @@ Changes in existing checks
   usages of ``std::string_view::compare``. Added a `StringLikeClasses` option
   to detect usages of ``compare`` method in custom string-like classes.
 
+- Improved :doc:`exception-escape <clang-tidy/checks/bugprone/exception-escape>`
+  check to correctly detect exception handler of type `CV void *` as catching all 
+  `CV` compatible pointer types.
+
 Removed checks
 ^^^^^^^^^^^^^^
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
index f5e74df1621ce..26c443b139629 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/exception-escape.cpp
@@ -756,3 +756,21 @@ struct test_implicit_throw {
 };
 
 }}
+
+void pointer_exception_can_not_escape_with_const_void_handler() noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'pointer_exception_can_not_escape_with_const_void_handler' which should not throw exceptions
+  const int value = 42;
+  try {
+    throw &value;
+  } catch (const void *) {
+  }
+}
+
+void pointer_exception_can_not_escape_with_void_handler() noexcept {
+  // CHECK-MESSAGES-NOT: :[[@LINE-1]]:6: warning: an exception may be thrown in function 'pointer_exception_can_not_escape_with_void_handler' which should not throw exceptions
+  int value = 42;
+  try {
+    throw &value;
+  } catch (void *) {
+  }
+}

… exception with pointer type by `void *` exception handler
@hanickadot hanickadot force-pushed the bugprone-exception-escape-with-void branch from 3ea4f5d to ebf1c69 Compare July 21, 2024 15:11
@hanickadot hanickadot requested a review from EugeneZelenko July 21, 2024 18:41
Copy link
Member

@PiotrZSL PiotrZSL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Except bug in release notes looks fine for me.

@hanickadot hanickadot merged commit 52dd4db into llvm:main Jul 22, 2024
5 of 6 checks passed
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
… exception with pointer type by `void *` exception handler (#99773)

Summary:
As in title, code which checks eligibility of exceptions with pointer
types to be handled by exception handler of type `void *` disallowed
this case. It was working like this:

```c++
if (isStandardPointerConvertible(ExceptionCanTy, HandlerCanTy) &&
          isUnambiguousPublicBaseClass(
              ExceptionCanTy->getTypePtr()->getPointeeType().getTypePtr(),
              HandlerCanTy->getTypePtr()->getPointeeType().getTypePtr())) {
```

but in `isUnambiguousPublicBaseClass` there was code which looked for
definitions:

```c++
bool isUnambiguousPublicBaseClass(const Type *DerivedType,
                                  const Type *BaseType) {
  const auto *DerivedClass =
      DerivedType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  const auto *BaseClass =
      BaseType->getCanonicalTypeUnqualified()->getAsCXXRecordDecl();
  if (!DerivedClass || !BaseClass)
    return false;
```

This code disallowed usage of `void *` type which was already correctly
detected in `isStandardPointerConvertible`.

AFAIK this seems like misinterpretation of specification:

> 14.4 Handling an exception
> a standard [pointer conversion](https://eel.is/c++draft/conv.ptr) not
involving conversions to pointers to private or protected or ambiguous
classes
(https://eel.is/c++draft/except.handle#3.3.1)

and 

> 7.3.12 Pointer conversions
> ... If B is an inaccessible
([[class.access]](https://eel.is/c++draft/class.access)) or ambiguous
([[class.member.lookup]](https://eel.is/c++draft/class.member.lookup))
base class of D, a program that necessitates this conversion is
ill-formed[.](https://eel.is/c++draft/conv.ptr#3.sentence-2) ...
(https://eel.is/c++draft/conv.ptr#3)

14.4 is carving out private, protected, and ambiguous base classes, but
they are already carved out in 7.3.12 and implemented in
`isStandardPointerConvertible`

---------

Co-authored-by: Piotr Zegar <[email protected]>

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251102
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants