[clang-tools-extra] r369568 - [clang-tidy] Check for dynamically initialized statics in headers.
Yuanfang Chen via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 21 13:00:01 PDT 2019
Author: yuanfang
Date: Wed Aug 21 13:00:01 2019
New Revision: 369568
URL: http://llvm.org/viewvc/llvm-project?rev=369568&view=rev
Log:
[clang-tidy] Check for dynamically initialized statics in headers.
Finds instances where variables with static storage are initialized dynamically in header files.
Reviewed By: aaron.ballman, alexfh
Patch by Charles Zhang!
Differential Revision: https://reviews.llvm.org/D62829
Added:
clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-dynamic-static-initializers.rst
clang-tools-extra/trunk/test/clang-tidy/bugprone-dynamic-static-initializers.hpp
Modified:
clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
clang-tools-extra/trunk/docs/ReleaseNotes.rst
clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
Modified: clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp?rev=369568&r1=369567&r2=369568&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/BugproneTidyModule.cpp Wed Aug 21 13:00:01 2019
@@ -16,6 +16,7 @@
#include "BranchCloneCheck.h"
#include "CopyConstructorInitCheck.h"
#include "DanglingHandleCheck.h"
+#include "DynamicStaticInitializersCheck.h"
#include "ExceptionEscapeCheck.h"
#include "FoldInitTypeCheck.h"
#include "ForwardDeclarationNamespaceCheck.h"
@@ -73,6 +74,8 @@ public:
"bugprone-copy-constructor-init");
CheckFactories.registerCheck<DanglingHandleCheck>(
"bugprone-dangling-handle");
+ CheckFactories.registerCheck<DynamicStaticInitializersCheck>(
+ "bugprone-dynamic-static-initializers");
CheckFactories.registerCheck<ExceptionEscapeCheck>(
"bugprone-exception-escape");
CheckFactories.registerCheck<FoldInitTypeCheck>(
Modified: clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt?rev=369568&r1=369567&r2=369568&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/CMakeLists.txt Wed Aug 21 13:00:01 2019
@@ -8,6 +8,7 @@ add_clang_library(clangTidyBugproneModul
BugproneTidyModule.cpp
CopyConstructorInitCheck.cpp
DanglingHandleCheck.cpp
+ DynamicStaticInitializersCheck.cpp
ExceptionEscapeCheck.cpp
FoldInitTypeCheck.cpp
ForwardDeclarationNamespaceCheck.cpp
Added: clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp?rev=369568&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.cpp Wed Aug 21 13:00:01 2019
@@ -0,0 +1,68 @@
+//===--- DynamicStaticInitializersCheck.cpp - clang-tidy ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicStaticInitializersCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+AST_MATCHER(clang::VarDecl, hasConstantDeclaration) {
+ const Expr *Init = Node.getInit();
+ if (Init && !Init->isValueDependent()) {
+ if (Node.isConstexpr())
+ return true;
+ return Node.checkInitIsICE();
+ }
+ return false;
+}
+
+DynamicStaticInitializersCheck::DynamicStaticInitializersCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ RawStringHeaderFileExtensions(Options.getLocalOrGlobal(
+ "HeaderFileExtensions", utils::defaultHeaderFileExtensions())) {
+ if (!utils::parseHeaderFileExtensions(RawStringHeaderFileExtensions,
+ HeaderFileExtensions, ',')) {
+ llvm::errs() << "Invalid header file extension: "
+ << RawStringHeaderFileExtensions << "\n";
+ }
+}
+
+void DynamicStaticInitializersCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "HeaderFileExtensions", RawStringHeaderFileExtensions);
+}
+
+void DynamicStaticInitializersCheck::registerMatchers(MatchFinder *Finder) {
+ if (!getLangOpts().CPlusPlus || getLangOpts().ThreadsafeStatics)
+ return;
+ Finder->addMatcher(
+ varDecl(hasGlobalStorage(), unless(hasConstantDeclaration())).bind("var"),
+ this);
+}
+
+void DynamicStaticInitializersCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var");
+ SourceLocation Loc = Var->getLocation();
+ if (!Loc.isValid() || !utils::isPresumedLocInHeaderFile(Loc, *Result.SourceManager,
+ HeaderFileExtensions))
+ return;
+ // If the initializer is a constant expression, then the compiler
+ // doesn't have to dynamically initialize it.
+ diag(Loc, "static variable %0 may be dynamically initialized in this header file")
+ << Var;
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
Added: clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.h?rev=369568&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/bugprone/DynamicStaticInitializersCheck.h Wed Aug 21 13:00:01 2019
@@ -0,0 +1,43 @@
+//===--- DynamicStaticInitializersCheck.h - clang-tidy ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DYNAMIC_STATIC_INITIALIZERS_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DYNAMIC_STATIC_INITIALIZERS_CHECK_H
+
+#include "../ClangTidyCheck.h"
+#include "../utils/HeaderFileExtensionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds dynamically initialized static variables in header files.
+///
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a comma-separated list of filename extensions of
+/// header files (The filename extensions should not contain "." prefix).
+/// "h,hh,hpp,hxx" by default.
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between "," if there are other filename extensions.
+class DynamicStaticInitializersCheck : public ClangTidyCheck {
+public:
+ DynamicStaticInitializersCheck(StringRef Name, ClangTidyContext *Context);
+ void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+ const std::string RawStringHeaderFileExtensions;
+ utils::HeaderFileExtensionsSet HeaderFileExtensions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DYNAMIC_STATIC_INITIALIZERS_CHECK_H
Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=369568&r1=369567&r2=369568&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Wed Aug 21 13:00:01 2019
@@ -67,6 +67,12 @@ The improvements are...
Improvements to clang-tidy
--------------------------
+- New :doc:`bugprone-dynamic-static-initializers
+ <clang-tidy/checks/bugprone-dynamic-static-initializers>` check.
+
+ Finds instances where variables with static storage are initialized
+ dynamically in header files.
+
- New :doc:`linuxkernel-must-use-errs
<clang-tidy/checks/linuxkernel-must-use-errs>` check.
@@ -79,7 +85,6 @@ Improvements to clang-tidy
Finds uses of deprecated Googletest APIs with names containing ``case`` and
replaces them with equivalent APIs with ``suite``.
-
Improvements to include-fixer
-----------------------------
Added: clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-dynamic-static-initializers.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-dynamic-static-initializers.rst?rev=369568&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-dynamic-static-initializers.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/bugprone-dynamic-static-initializers.rst Wed Aug 21 13:00:01 2019
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - bugprone-dynamic-static-initializers
+
+bugprone-dynamic-static-initializers
+====================================
+
+Finds instances of static variables that are dynamically initialized
+in header files.
+
+This can pose problems in certain multithreaded contexts. For example,
+when disabling compiler generated synchronization instructions for
+static variables initialized at runtime (e.g. by ``-fno-threadsafe-statics``), even if a particular project
+takes the necessary precautions to prevent race conditions during
+initialization by providing their own synchronization, header files included from other projects may
+not. Therefore, such a check is helpful for ensuring that disabling
+compiler generated synchronization for static variable initialization will not cause
+problems.
+
+Consider the following code:
+
+-- code-block:: c
+
+int foo() {
+ static int k = bar();
+ return k;
+}
+
+When synchronization of static initialization is disabled, if two threads both call `foo` for the first time, there is the possibility that `k` will be double initialized, creating a race condition.
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=369568&r1=369567&r2=369568&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Wed Aug 21 13:00:01 2019
@@ -44,6 +44,7 @@ Clang-Tidy Checks
bugprone-branch-clone
bugprone-copy-constructor-init
bugprone-dangling-handle
+ bugprone-dynamic-static-initializers
bugprone-exception-escape
bugprone-fold-init-type
bugprone-forward-declaration-namespace
Added: clang-tools-extra/trunk/test/clang-tidy/bugprone-dynamic-static-initializers.hpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/bugprone-dynamic-static-initializers.hpp?rev=369568&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/bugprone-dynamic-static-initializers.hpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/bugprone-dynamic-static-initializers.hpp Wed Aug 21 13:00:01 2019
@@ -0,0 +1,44 @@
+// RUN: %check_clang_tidy %s bugprone-dynamic-static-initializers %t -- -- -fno-threadsafe-statics
+
+int fact(int n) {
+ return (n == 0) ? 1 : n * fact(n - 1);
+}
+
+int static_thing = fact(5);
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static variable 'static_thing' may be dynamically initialized in this header file [bugprone-dynamic-static-initializers]
+
+int sample() {
+ int x;
+ return x;
+}
+
+int dynamic_thing = sample();
+// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static variable 'dynamic_thing' may be dynamically initialized in this header file [bugprone-dynamic-static-initializers]
+
+int not_so_bad = 12 + 4942; // no warning
+
+extern int bar();
+
+int foo() {
+ static int k = bar();
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static variable 'k' may be dynamically initialized in this header file [bugprone-dynamic-static-initializers]
+ return k;
+}
+
+int bar2() {
+ return 7;
+}
+
+int foo2() {
+ // This may work fine when optimization is enabled because bar() can
+ // be turned into a constant 7. But without optimization, it can
+ // cause problems. Therefore, we must err on the side of conservatism.
+ static int x = bar2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static variable 'x' may be dynamically initialized in this header file [bugprone-dynamic-static-initializers]
+ return x;
+}
+
+int foo3() {
+ static int p = 7 + 83; // no warning
+ return p;
+}
More information about the cfe-commits
mailing list