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 + +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits