[clang-tools-extra] r253246 - Add a new clang-tidy checker that flags throw expressions whose thrown type is not nothrow copy constructible. While the compiler is free to elide copy constructor calls in some cases, it is under no obligation to do so, which makes the code a portability concern as well as a security concern.

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 16 11:17:43 PST 2015


Author: aaronballman
Date: Mon Nov 16 13:17:43 2015
New Revision: 253246

URL: http://llvm.org/viewvc/llvm-project?rev=253246&view=rev
Log:
Add a new clang-tidy checker that flags throw expressions whose thrown type is not nothrow copy constructible. While the compiler is free to elide copy constructor calls in some cases, it is under no obligation to do so, which makes the code a portability concern as well as a security concern.

This checker corresponds to the CERT secure coding rule: https://www.securecoding.cert.org/confluence/display/cplusplus/ERR60-CPP.+Exception+objects+must+be+nothrow+copy+constructible

Added:
    clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.cpp
    clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/cert-thrown-exception-type.rst
    clang-tools-extra/trunk/test/clang-tidy/cert-throw-exception-type.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/cert/CERTTidyModule.cpp
    clang-tools-extra/trunk/clang-tidy/cert/CMakeLists.txt
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/cert/CERTTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cert/CERTTidyModule.cpp?rev=253246&r1=253245&r2=253246&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cert/CERTTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/cert/CERTTidyModule.cpp Mon Nov 16 13:17:43 2015
@@ -17,6 +17,7 @@
 #include "../misc/StaticAssertCheck.h"
 #include "../misc/ThrowByValueCatchByReferenceCheck.h"
 #include "SetLongJmpCheck.h"
+#include "ThrownExceptionTypeCheck.h"
 #include "VariadicFunctionDefCheck.h"
 
 namespace clang {
@@ -40,6 +41,8 @@ public:
     // ERR
     CheckFactories.registerCheck<SetLongJmpCheck>(
         "cert-err52-cpp");
+    CheckFactories.registerCheck<ThrownExceptionTypeCheck>(
+        "cert-err60-cpp");
     CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
         "cert-err61-cpp");
 

Modified: clang-tools-extra/trunk/clang-tidy/cert/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cert/CMakeLists.txt?rev=253246&r1=253245&r2=253246&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cert/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/cert/CMakeLists.txt Mon Nov 16 13:17:43 2015
@@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS support)
 add_clang_library(clangTidyCERTModule
   CERTTidyModule.cpp
   SetLongJmpCheck.cpp
+  ThrownExceptionTypeCheck.cpp
   VariadicFunctionDefCheck.cpp
 
   LINK_LIBS

Added: clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.cpp?rev=253246&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.cpp Mon Nov 16 13:17:43 2015
@@ -0,0 +1,50 @@
+//===--- ThrownExceptionTypeCheck.cpp - clang-tidy-------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThrownExceptionTypeCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace {
+AST_MATCHER(CXXConstructorDecl, isNoThrowCopyConstructor) {
+  if (!Node.isCopyConstructor())
+    return false;
+
+  if (const auto *FnTy = Node.getType()->getAs<FunctionProtoType>())
+    return FnTy->isNothrow(Node.getASTContext());
+  llvm_unreachable("Copy constructor with no prototype");
+}
+} // end namespace
+
+namespace tidy {
+void ThrownExceptionTypeCheck::registerMatchers(MatchFinder *Finder) {
+  if (!getLangOpts().CPlusPlus)
+    return;
+
+  Finder->addMatcher(
+      cxxThrowExpr(
+          has(cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
+              isCopyConstructor(), unless(isNoThrowCopyConstructor()))))
+          .bind("expr"))),
+      this);
+
+}
+
+void ThrownExceptionTypeCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
+  diag(E->getExprLoc(),
+       "thrown exception type is not nothrow copy constructible");
+}
+
+} // namespace tidy
+} // namespace clang
+

Added: clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.h?rev=253246&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/cert/ThrownExceptionTypeCheck.h Mon Nov 16 13:17:43 2015
@@ -0,0 +1,34 @@
+//===--- ThrownExceptionTypeCheck.h - clang-tidy-----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// Checks whether a thrown object is nothrow copy constructible.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/cert-thrown-exception-type.html
+class ThrownExceptionTypeCheck : public ClangTidyCheck {
+public:
+  ThrownExceptionTypeCheck(StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_THROWNEXCEPTIONTYPECHECK_H
+

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/cert-thrown-exception-type.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/cert-thrown-exception-type.rst?rev=253246&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/cert-thrown-exception-type.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/cert-thrown-exception-type.rst Mon Nov 16 13:17:43 2015
@@ -0,0 +1,9 @@
+cert-err60-cpp
+==============
+
+This check flags all throw expressions where the exception object is not nothrow
+copy constructible.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR60-CPP. Exception objects must be nothrow copy constructible
+<https://www.securecoding.cert.org/confluence/display/cplusplus/ERR60-CPP.+Exception+objects+must+be+nothrow+copy+constructible>`_.

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=253246&r1=253245&r2=253246&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Mon Nov 16 13:17:43 2015
@@ -3,6 +3,7 @@ List of clang-tidy Checks
 
 .. toctree::
    cert-setlongjmp
+   cert-thrown-exception-type
    cert-variadic-function-def
    cppcoreguidelines-pro-bounds-array-to-pointer-decay
    cppcoreguidelines-pro-bounds-pointer-arithmetic

Added: clang-tools-extra/trunk/test/clang-tidy/cert-throw-exception-type.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/cert-throw-exception-type.cpp?rev=253246&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/cert-throw-exception-type.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/cert-throw-exception-type.cpp Mon Nov 16 13:17:43 2015
@@ -0,0 +1,112 @@
+// RUN: %check_clang_tidy %s cert-err60-cpp %t -- -- -std=c++11 -fcxx-exceptions
+
+struct S {};
+struct T : S {};
+struct U {
+  U() = default;
+  U(const U&) = default;
+};
+
+struct V {
+  V() = default;
+  V(const V&) noexcept;
+};
+
+struct W {
+  W() = default;
+  W(const W&) noexcept(false);
+};
+
+struct X {
+  X() = default;
+  X(const X&) {}
+};
+
+struct Y {
+  Y() = default;
+  Y(const Y&) throw();
+};
+
+struct Z {
+  Z() = default;
+  Z(const Z&) throw(int);
+};
+
+void g() noexcept(false);
+
+struct A {
+  A() = default;
+  A(const A&) noexcept(noexcept(g()));
+};
+
+struct B {
+  B() = default;
+  B(const B&) = default;
+  B(const A&) noexcept(false);
+};
+
+class C {
+  W M; // W is not no-throw copy constructible
+public:
+  C() = default;
+  C(const C&) = default;
+};
+
+struct D {
+  D() = default;
+  D(const D&) noexcept(false);
+  D(D&) noexcept(true);
+};
+
+struct E {
+  E() = default;
+  E(E&) noexcept(true);
+  E(const E&) noexcept(false);
+};
+
+struct Allocates {
+  int *x;
+  Allocates() : x(new int(0)) {}
+  Allocates(const Allocates &other) : x(new int(*other.x)) {}
+};
+
+struct OptionallyAllocates {
+  int *x;
+  OptionallyAllocates() : x(new int(0)) {}
+  OptionallyAllocates(const Allocates &other) noexcept(true) {
+    try {
+      x = new int(*other.x);
+    } catch (...) {
+      x = nullptr;
+    }
+  }
+};
+
+void f() {
+  throw 12; // ok
+  throw "test"; // ok
+  throw S(); // ok
+  throw T(); // ok
+  throw U(); // ok
+  throw V(); // ok
+  throw W(); // match, noexcept(false)
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible [cert-err60-cpp]
+  throw X(); // match, no noexcept clause, nontrivial
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw Y(); // ok
+  throw Z(); // match, throw(int)
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw A(); // match, noexcept(false)
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw B(); // ok
+  throw C(); // match, C has a member variable that makes it throwing on copy
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw D(); // match, has throwing copy constructor
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw E(); // match, has throwing copy constructor
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw Allocates(); // match, copy constructor throws
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: thrown exception type is not nothrow copy constructible
+  throw OptionallyAllocates(); // ok
+
+}




More information about the cfe-commits mailing list