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

Reply via email to