[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
dyung added a comment. This appears to be failing on the PS4 linux bot likely due to the PS4 target has exceptions disabled by default. Can you take a look? https://lab.llvm.org/buildbot/#/builders/139/builds/2441 Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
This revision was landed with ongoing or failed builds. This revision was automatically updated to reflect the committed changes. Closed by commit rG530456caf908: [clang-tidy] Add new check bugprone-unhandled-exception-at-new. (authored by balazske). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,208 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +class bad_array_new_length : public bad_alloc {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (const std::bad_array_new_length &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES:
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 337344. balazske added a comment. Add another test. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,208 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +class bad_array_new_length : public bad_alloc {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (const std::bad_array_new_length &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_none() throw() { + int *I = new int; + //
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
aaron.ballman accepted this revision. aaron.ballman added a comment. This revision is now accepted and ready to land. LGTM! Comment at: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst:7 +Finds calls to ``new`` that may throw ``std::bad_alloc`` exception and +the exception handler is missing. + balazske wrote: > aaron.ballman wrote: > > This isn't quite accurate -- if the exception handler is missing or doesn't > > handle either `std::bad_alloc` or `std::exception`. > I restructure the text, but do not want to mention `std::exception` because > it is a base class (handling of `std::exception` means handling of > `std::bad_alloc`), and then why not mention generic exception handler > (`catch(...)`). I think this text is for introduction only, should not be > totally precise. The restructured text is good -- I just wanted the information *somewhere* so that users weren't surprised by the behavior. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:20 +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); balazske wrote: > aaron.ballman wrote: > > Another interesting test case would be when the user subclasses > > `std::bad_alloc` and throws errors of the subclass type from the allocation > > function which are in/correctly caught. > In this case the check must find every (visible) subclass of `std::bad_alloc` > check if there is a catch block for every case. Even then a custom allocation > function may throw other classes (not derived from `std::bad_alloc`) or > classes (may be inherited from `std::bad_alloc` but not visible in the TU) > that are not checked. So this is still a partial solution, probably not > better than the rule that a handler for `bad_alloc` (or more generic) should > exist. > So this is still a partial solution, probably not better than the rule that a > handler for bad_alloc (or more generic) should exist. Okay, that's fair -- we can always address it in follow-up if it turns out to be an issue in practice. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added inline comments. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:20 +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); aaron.ballman wrote: > Another interesting test case would be when the user subclasses > `std::bad_alloc` and throws errors of the subclass type from the allocation > function which are in/correctly caught. In this case the check must find every (visible) subclass of `std::bad_alloc` check if there is a catch block for every case. Even then a custom allocation function may throw other classes (not derived from `std::bad_alloc`) or classes (may be inherited from `std::bad_alloc` but not visible in the TU) that are not checked. So this is still a partial solution, probably not better than the rule that a handler for `bad_alloc` (or more generic) should exist. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added inline comments. Comment at: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst:7 +Finds calls to ``new`` that may throw ``std::bad_alloc`` exception and +the exception handler is missing. + aaron.ballman wrote: > This isn't quite accurate -- if the exception handler is missing or doesn't > handle either `std::bad_alloc` or `std::exception`. I restructure the text, but do not want to mention `std::exception` because it is a base class (handling of `std::exception` means handling of `std::bad_alloc`), and then why not mention generic exception handler (`catch(...)`). I think this text is for introduction only, should not be totally precise. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 337078. balazske marked 8 inline comments as done. balazske added a comment. Rebase, changed documentation, small fix in the code, more tests added. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,196 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +class bad_array_new_length : public bad_alloc {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (const std::bad_array_new_length &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
aaron.ballman added inline comments. Comment at: clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp:28-30 +// Generic catch handler should match anything. +if (CatchS->getCaughtType().isNull()) + return true; I think this should move above the call to `InnertMatcher.matches()` so that the inner matcher doesn't have to worry quite as much about getting null types. Comment at: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst:7 +Finds calls to ``new`` that may throw ``std::bad_alloc`` exception and +the exception handler is missing. + This isn't quite accurate -- if the exception handler is missing or doesn't handle either `std::bad_alloc` or `std::exception`. Comment at: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst:17 + +Calls to ``new`` can throw exception of type ``bad_alloc`` that should be +handled by the code. Alternatively the nonthrowing form of ``new`` can be Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:20 +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); Another interesting test case would be when the user subclasses `std::bad_alloc` and throws errors of the subclass type from the allocation function which are in/correctly caught. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:20 + +void f1() noexcept { + int *I1 = new int; aaron.ballman wrote: > It would be useful to also have a test with a function-try-block to ensure > those are handled properly. Still missing this test -- you should add one like: ``` void func() try { int *i = new int; } catch (const std::bad_alloc &) { } ``` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added a comment. Ping. The check now handles only check of allocation failure at `new`. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 335767. balazske added a comment. Fix a crash, update documentation. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,180 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_none() throw() { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_1() throw(std::bad_alloc) { + int *I = new int; +} + +void f_est_dynamic_2() throw(A) { + // the exception
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added a comment. Rename the check to "unhandled-bad_alloc" (or similar")? And the error message to " missing exception handler 'std::bad_alloc' "? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 335505. balazske added a comment. Removed check of possible exceptions from constructor call. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,175 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_none() throw() { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_1() throw(std::bad_alloc) { + int *I = new int; +} + +void f_est_dynamic_2() throw(A) {
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
aaron.ballman added inline comments. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:143 + f_est_noexcept_dependent_used(); +} balazske wrote: > balazske wrote: > > aaron.ballman wrote: > > > You have tests for placement new with `nothrow_t`, but I think other > > > forms of placement new are also very interesting to test as those > > > typically don't throw. > > > > > > Additionally, perhaps tests where the allocation functions have been > > > replaced by the user (such as a class allocation function)? > > I realized that the case of user-defined constructor or allocation function > > allows to throw any kind of exception. So the check should be improved to > > handle this case: Not rely on the syntax of new expression, instead check > > if the called allocation function or the called constructor may throw, and > > if yes, check what exceptions are possible. What is your opinion, is it a > > better approach? > > (And a function to collect all possible exceptions called from a function > > is needed, `ExceptionAnalyzer` seems usable.) > It looks like that the user is free to define custom `operator new` and any > constructor called that may throw any exception. Even in the "nothrow" case > it is possible to use a constructor that may throw? If we would analyze every > possible throwable exception that may come out from a new-expression, the > checker would end up almost in a general checker that checks for uncaught > exceptions. At least it is easy to extend. > Not rely on the syntax of new expression, instead check if the called > allocation function or the called constructor may throw, and if yes, check > what exceptions are possible. What is your opinion, is it a better approach? I think that's a better approach. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:143 + f_est_noexcept_dependent_used(); +} aaron.ballman wrote: > balazske wrote: > > balazske wrote: > > > aaron.ballman wrote: > > > > You have tests for placement new with `nothrow_t`, but I think other > > > > forms of placement new are also very interesting to test as those > > > > typically don't throw. > > > > > > > > Additionally, perhaps tests where the allocation functions have been > > > > replaced by the user (such as a class allocation function)? > > > I realized that the case of user-defined constructor or allocation > > > function allows to throw any kind of exception. So the check should be > > > improved to handle this case: Not rely on the syntax of new expression, > > > instead check if the called allocation function or the called constructor > > > may throw, and if yes, check what exceptions are possible. What is your > > > opinion, is it a better approach? > > > (And a function to collect all possible exceptions called from a function > > > is needed, `ExceptionAnalyzer` seems usable.) > > It looks like that the user is free to define custom `operator new` and any > > constructor called that may throw any exception. Even in the "nothrow" case > > it is possible to use a constructor that may throw? If we would analyze > > every possible throwable exception that may come out from a new-expression, > > the checker would end up almost in a general checker that checks for > > uncaught exceptions. At least it is easy to extend. > > Not rely on the syntax of new expression, instead check if the called > > allocation function or the called constructor may throw, and if yes, check > > what exceptions are possible. What is your opinion, is it a better approach? > > I think that's a better approach. > Even in the "nothrow" case it is possible to use a constructor that may throw? Certainly -- the `nothrow` syntax is specifying that the allocation cannot throw (it either returns a valid pointer to the allocated memory or null), not that the constructor cannot throw if the allocation succeeds. Is the check intended to care about *allocations* that fail or just exceptions in general around `new` expressions? If it's allocations that fail, then I wouldn't worry about the ctor's exception specification. If exceptions in general, then I agree that we're talking about a general checker for all uncaught exceptions in some ways. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 334156. balazske added a comment. Use `mayThrow`, improve test (user and class-specific cases). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,194 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &) noexcept; +void *operator new(std::size_t, void *) noexcept; + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void *operator new(std::size_t, int, int); +void *operator new(std::size_t, int, int, int) noexcept; + +struct ClassSpecificNew { + void *operator new(std::size_t); + void *operator new(std::size_t, std::align_val_t); + void *operator new(std::size_t, int, int) noexcept; + void *operator new(std::size_t, int, int, int); +}; + +struct ConstructorTest { + ConstructorTest(); + ConstructorTest(int) noexcept; +}; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } +} + +void f_new_nothrow() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_new_placement() noexcept { + char buf[100]; + int *I = new (buf) int; +} + +void f_new_user_defined() noexcept { + int *I1 = new (1, 2) int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + int *I2 = new (1, 2, 3) int; +} + +void f_class_specific() noexcept { + ClassSpecificNew *N1 = new ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N2 = new (static_cast(1)) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' + ClassSpecificNew *N3 = new (1, 2) ClassSpecificNew; + ClassSpecificNew *N4 = new (1, 2, 3) ClassSpecificNew; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: missing exception handler for allocation failure at 'new' +} + +void f_constructor() noexcept { + ConstructorTest *T1 = new ConstructorTest; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: missing exception handler for allocation failure at 'new' + ConstructorTest *T2 = new ConstructorTest{1}; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: missing exception handler for allocation failure at 'new' + ConstructorTest *T3 = new (std::nothrow) ConstructorTest; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: missing exception handler for
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added inline comments. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:143 + f_est_noexcept_dependent_used(); +} balazske wrote: > aaron.ballman wrote: > > You have tests for placement new with `nothrow_t`, but I think other forms > > of placement new are also very interesting to test as those typically don't > > throw. > > > > Additionally, perhaps tests where the allocation functions have been > > replaced by the user (such as a class allocation function)? > I realized that the case of user-defined constructor or allocation function > allows to throw any kind of exception. So the check should be improved to > handle this case: Not rely on the syntax of new expression, instead check if > the called allocation function or the called constructor may throw, and if > yes, check what exceptions are possible. What is your opinion, is it a better > approach? > (And a function to collect all possible exceptions called from a function is > needed, `ExceptionAnalyzer` seems usable.) It looks like that the user is free to define custom `operator new` and any constructor called that may throw any exception. Even in the "nothrow" case it is possible to use a constructor that may throw? If we would analyze every possible throwable exception that may come out from a new-expression, the checker would end up almost in a general checker that checks for uncaught exceptions. At least it is easy to extend. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added inline comments. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:143 + f_est_noexcept_dependent_used(); +} aaron.ballman wrote: > You have tests for placement new with `nothrow_t`, but I think other forms of > placement new are also very interesting to test as those typically don't > throw. > > Additionally, perhaps tests where the allocation functions have been replaced > by the user (such as a class allocation function)? I realized that the case of user-defined constructor or allocation function allows to throw any kind of exception. So the check should be improved to handle this case: Not rely on the syntax of new expression, instead check if the called allocation function or the called constructor may throw, and if yes, check what exceptions are possible. What is your opinion, is it a better approach? (And a function to collect all possible exceptions called from a function is needed, `ExceptionAnalyzer` seems usable.) Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
aaron.ballman added inline comments. Comment at: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst:17 +Calls to ``new`` can throw exception of type ``bad_alloc`` that should be +handled by the code. Alternatively the nonthrowing form of ``new`` can be +used. The check verifies that the exception is handled in the function Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:20 + +void f1() noexcept { + int *I1 = new int; It would be useful to also have a test with a function-try-block to ensure those are handled properly. Comment at: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp:143 + f_est_noexcept_dependent_used(); +} You have tests for placement new with `nothrow_t`, but I think other forms of placement new are also very interesting to test as those typically don't throw. Additionally, perhaps tests where the allocation functions have been replaced by the user (such as a class allocation function)? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske added a comment. Ping. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske updated this revision to Diff 326642. balazske added a comment. Rebase, fixes according to review comments. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,143 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &); +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &); + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } +} + +void f3() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_none() throw() { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_1() throw(std::bad_alloc) { + int *I = new int; +} + +void f_est_dynamic_2() throw(A) { + // the exception specification list is not checked + int *I = new int; +} + +template +void f_est_noexcept_dependent_unused() noexcept(P) { + int *I = new int; +} + +template +void f_est_noexcept_dependent_used() noexcept(P) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_1() { + f_est_noexcept_dependent_used(); +} Index: clang-tools-extra/docs/clang-tidy/checks/list.rst === --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -99,6 +99,7 @@ `bugprone-too-small-loop-variable `_, `bugprone-undefined-memory-manipulation `_, `bugprone-undelegated-constructor `_, + `bugprone-unhandled-exception-at-new `_, `bugprone-unhandled-self-assignment `_, `bugprone-unused-raii `_, "Yes" `bugprone-unused-return-value `_, Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst === --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - bugprone-unhandled-exception-at-new +
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
njames93 added inline comments. Comment at: clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp:23-24 +const CXXCatchStmt *CatchS = Node.getHandler(I); +if (InnerMatcher.matches(CatchS->getCaughtType(), Finder, Builder)) + return true; +// Generic catch handler should match anything. This can leak bound nodes If it doesn't match. Comment at: clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h:28 + bool isLanguageVersionSupported(const LangOptions ) const override { +return LangOpts.CPlusPlus; + } I'd suggest this check is only ran when exceptions are enabled. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
Eugene.Zelenko added inline comments. Comment at: clang-tools-extra/docs/ReleaseNotes.rst:73 + +New checks +^^ Please rebase from trunk. Comment at: clang-tools-extra/docs/ReleaseNotes.rst:79 + +Finds calls to ``new`` that may throw exception that is not handled. Please indent. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D97196/new/ https://reviews.llvm.org/D97196 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D97196: [clang-tidy] Add new check 'bugprone-unhandled-exception-at-new'.
balazske created this revision. Herald added subscribers: martong, gamesh411, Szelethus, dkrupp, xazax.hun, whisperity, mgorny. balazske requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D97196 Files: clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.cpp clang-tools-extra/clang-tidy/bugprone/UnhandledExceptionAtNewCheck.h clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst clang-tools-extra/docs/clang-tidy/checks/list.rst clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp === --- /dev/null +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-unhandled-exception-at-new.cpp @@ -0,0 +1,133 @@ +// RUN: %check_clang_tidy -std=c++14 %s bugprone-unhandled-exception-at-new %t + +namespace std { +typedef __typeof__(sizeof(0)) size_t; +enum class align_val_t : std::size_t {}; +class exception {}; +class bad_alloc : public exception {}; +struct nothrow_t {}; +extern const nothrow_t nothrow; +} // namespace std + +void *operator new(std::size_t, const std::nothrow_t &); +void *operator new(std::size_t, std::align_val_t, const std::nothrow_t &); + +class A {}; +typedef std::bad_alloc badalloc1; +using badalloc2 = std::bad_alloc; +using badalloc3 = std::bad_alloc &; + +void f1() noexcept { + int *I1 = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: missing exception handler for allocation failure at 'new' + try { +int *I2 = new int; +try { + int *I3 = new int; +} catch (A) { +} + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (const std::bad_alloc &) { + } + + try { +int *I = new int; + } catch (badalloc1) { + } + + try { +int *I = new int; + } catch (badalloc1 &) { + } + + try { +int *I = new int; + } catch (const badalloc1 &) { + } + + try { +int *I = new int; + } catch (badalloc2) { + } + + try { +int *I = new int; + } catch (badalloc3) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (std::bad_alloc *) { + } + + try { +int *I = new int; +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: missing exception handler for allocation failure at 'new' + } catch (A) { + } +} + +void f2() noexcept { + try { +int *I = new int; + } catch (A) { + } catch (std::bad_alloc) { + } + + try { +int *I = new int; + } catch (...) { + } + + try { +int *I = new int; + } catch (const std::exception &) { + } +} + +void f3() noexcept { + int *I1 = new (std::nothrow) int; + int *I2 = new (static_cast(1), std::nothrow) int; +} + +void f_est_none() { + int *I = new int; +} + +void f_est_noexcept_false() noexcept(false) { + int *I = new int; +} + +void f_est_noexcept_true() noexcept(true) { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_none() throw() { + int *I = new int; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: missing exception handler for allocation failure at 'new' +} + +void f_est_dynamic_1() throw(std::bad_alloc) { + int *I = new int; +} + +void f_est_dynamic_2() throw(A) { + // the exception specification list is not checked + int *I = new int; +} + +template +void f_est_noexcept_dependent() noexcept(P) { + int *I = new int; +} Index: clang-tools-extra/docs/clang-tidy/checks/list.rst === --- clang-tools-extra/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -99,6 +99,7 @@ `bugprone-too-small-loop-variable `_, `bugprone-undefined-memory-manipulation `_, `bugprone-undelegated-constructor `_, + `bugprone-unhandled-exception-at-new `_, `bugprone-unhandled-self-assignment `_, `bugprone-unused-raii `_, "Yes" `bugprone-unused-return-value `_, Index: clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst === --- /dev/null +++ clang-tools-extra/docs/clang-tidy/checks/bugprone-unhandled-exception-at-new.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - bugprone-unhandled-exception-at-new + +bugprone-unhandled-exception-at-new +=== + +Finds calls to ``new`` that may throw exception that is not handled. + +.. code-block:: c++ + + int *f() noexcept { +int *p