aaron.ballman created this revision.
aaron.ballman added reviewers: alexfh, sbenza.
aaron.ballman added a subscriber: cfe-commits.
Throwing an exception from the constructor of an object being used with static
or thread_local storage duration is a dangerous operation. The exception thrown
for an object with static storage duration cannot be caught, even by
function-try-blocks in main, and the exception thrown for an object with
thread_local storage duration cannot be caught by a function-try-block of the
initial thread. This patch adds a checker to flag such constructs.
This check corresponds to the CERT secure coding rule:
https://www.securecoding.cert.org/confluence/display/cplusplus/ERR58-CPP.+Constructors+of+objects+with+static+or+thread+storage+duration+must+not+throw+exceptions
http://reviews.llvm.org/D14824
Files:
clang-tidy/cert/CERTTidyModule.cpp
clang-tidy/cert/CMakeLists.txt
clang-tidy/cert/StaticObjectExceptionCheck.cpp
clang-tidy/cert/StaticObjectExceptionCheck.h
docs/clang-tidy/checks/cert-static-object-exception.rst
docs/clang-tidy/checks/list.rst
test/clang-tidy/cert-static-object-exception.cpp
Index: test/clang-tidy/cert-static-object-exception.cpp
===================================================================
--- test/clang-tidy/cert-static-object-exception.cpp
+++ test/clang-tidy/cert-static-object-exception.cpp
@@ -0,0 +1,52 @@
+// RUN: %check_clang_tidy %s cert-err58-cpp %t
+
+struct S {
+ S() noexcept(false);
+};
+
+struct T {
+ T() noexcept;
+};
+
+struct U {
+ U() {}
+};
+
+struct V {
+ explicit V(const char *) {} // Can throw
+};
+
+
+S s;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 's' with static storage duration may throw an exception that cannot be caught [cert-err58-cpp]
+// CHECK-MESSAGES: 4:3: note: possibly throwing constructor declared here
+T t; // ok
+U u;
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'u' with static storage duration may throw an exception that cannot be caught
+// CHECK-MESSAGES: 12:3: note: possibly throwing constructor declared here
+V v("v");
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: construction of 'v' with static storage duration may throw an exception that cannot be caught
+// CHECK-MESSAGES: 16:12: note: possibly throwing constructor declared here
+
+void f(S s1, T t1, U u1, V v1) { // ok, ok, ok, ok
+ S s2; // ok
+ T t2; // ok
+ U u2; // ok
+ V v2("v"); // ok
+
+ thread_local S s3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: construction of 's3' with thread_local storage duration may throw an exception that cannot be caught
+ thread_local T t3; // ok
+ thread_local U u3;
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: construction of 'u3' with thread_local storage duration may throw an exception that cannot be caught
+ thread_local V v3("v");
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: construction of 'v3' with thread_local storage duration may throw an exception that cannot be caught
+
+ static S s4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 's4' with static storage duration may throw an exception that cannot be caught
+ static T t4; // ok
+ static U u4;
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'u4' with static storage duration may throw an exception that cannot be caught
+ static V v4("v");
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: construction of 'v4' with static storage duration may throw an exception that cannot be caught
+}
Index: docs/clang-tidy/checks/list.rst
===================================================================
--- docs/clang-tidy/checks/list.rst
+++ docs/clang-tidy/checks/list.rst
@@ -1,8 +1,9 @@
List of clang-tidy Checks
=========================
-.. toctree::
+.. toctree::
cert-setlongjmp
+ cert-static-object-exception
cert-thrown-exception-type
cert-variadic-function-def
cppcoreguidelines-pro-bounds-array-to-pointer-decay
Index: docs/clang-tidy/checks/cert-static-object-exception.rst
===================================================================
--- docs/clang-tidy/checks/cert-static-object-exception.rst
+++ docs/clang-tidy/checks/cert-static-object-exception.rst
@@ -0,0 +1,9 @@
+cert-err58-cpp
+==============
+
+This check flags all static or thread_local variable declarations where the
+constructor for the object may throw an exception.
+
+This check corresponds to the CERT C++ Coding Standard rule
+`ERR58-CPP. Constructors of objects with static or thread storage duration must not throw exceptions
+<https://www.securecoding.cert.org/confluence/display/cplusplus/ERR58-CPP.+Constructors+of+objects+with+static+or+thread+storage+duration+must+not+throw+exceptions>`_.
Index: clang-tidy/cert/StaticObjectExceptionCheck.h
===================================================================
--- clang-tidy/cert/StaticObjectExceptionCheck.h
+++ clang-tidy/cert/StaticObjectExceptionCheck.h
@@ -0,0 +1,34 @@
+//===--- StaticObjectExceptionCheck.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_ERR58_CPP_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_CERT_ERR58_CPP_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/CERT-err58-cpp.html
+class StaticObjectExceptionCheck : public ClangTidyCheck {
+public:
+ StaticObjectExceptionCheck(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_ERR58_CPP_H
+
Index: clang-tidy/cert/StaticObjectExceptionCheck.cpp
===================================================================
--- clang-tidy/cert/StaticObjectExceptionCheck.cpp
+++ clang-tidy/cert/StaticObjectExceptionCheck.cpp
@@ -0,0 +1,55 @@
+//===--- StaticObjectExceptionCheck.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 "StaticObjectExceptionCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace {
+AST_MATCHER(CXXConstructorDecl, isNoThrowConstructor) {
+ const auto *FnTy = Node.getType()->getAs<FunctionProtoType>();
+ return FnTy->isNothrow(Node.getASTContext());
+}
+} // end namespace
+
+namespace tidy {
+
+void StaticObjectExceptionCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus)
+ return;
+
+ // Match any static or thread_local variable declaration that is initialized
+ // with a constructor that can throw.
+ Finder->addMatcher(
+ varDecl(anyOf(hasThreadStorageDuration(), hasStaticStorageDuration()),
+ hasInitializer(cxxConstructExpr(hasDeclaration(
+ cxxConstructorDecl(unless(isNoThrowConstructor()))
+ .bind("ctor")))))
+ .bind("var"),
+ this);
+}
+
+void StaticObjectExceptionCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
+ const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor");
+
+ diag(VD->getLocation(),
+ "construction of %0 with %select{static|thread_local}1 storage "
+ "duration may throw an exception that cannot be caught")
+ << VD << (VD->getStorageDuration() == SD_Static ? 0 : 1);
+ diag(Ctor->getLocation(), "possibly throwing constructor declared here",
+ DiagnosticIDs::Note);
+}
+
+} // namespace tidy
+} // namespace clang
+
Index: clang-tidy/cert/CMakeLists.txt
===================================================================
--- clang-tidy/cert/CMakeLists.txt
+++ clang-tidy/cert/CMakeLists.txt
@@ -3,6 +3,7 @@
add_clang_library(clangTidyCERTModule
CERTTidyModule.cpp
SetLongJmpCheck.cpp
+ StaticObjectExceptionCheck.cpp
ThrownExceptionTypeCheck.cpp
VariadicFunctionDefCheck.cpp
Index: clang-tidy/cert/CERTTidyModule.cpp
===================================================================
--- clang-tidy/cert/CERTTidyModule.cpp
+++ clang-tidy/cert/CERTTidyModule.cpp
@@ -16,6 +16,7 @@
#include "../misc/NonCopyableObjects.h"
#include "../misc/StaticAssertCheck.h"
#include "../misc/ThrowByValueCatchByReferenceCheck.h"
+#include "StaticObjectExceptionCheck.h"
#include "SetLongJmpCheck.h"
#include "ThrownExceptionTypeCheck.h"
#include "VariadicFunctionDefCheck.h"
@@ -41,6 +42,8 @@
// ERR
CheckFactories.registerCheck<SetLongJmpCheck>(
"cert-err52-cpp");
+ CheckFactories.registerCheck<StaticObjectExceptionCheck>(
+ "cert-err58-cpp");
CheckFactories.registerCheck<ThrownExceptionTypeCheck>(
"cert-err60-cpp");
CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits