Nathan-Huckleberry created this revision.
Herald added subscribers: cfe-commits, xazax.hun, mgorny.
Herald added a project: clang.

Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65828

Files:
  clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt
  clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.cpp
  clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.h
  clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/linuxkernel-irq-unbalanced.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/test/clang-tidy/linuxkernel-irq-unbalanced.cpp

Index: clang-tools-extra/test/clang-tidy/linuxkernel-irq-unbalanced.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/linuxkernel-irq-unbalanced.cpp
@@ -0,0 +1,49 @@
+// RUN: %check_clang_tidy %s linuxkernel-irq-unbalanced %t
+
+extern void arch_local_irq_disable();
+extern void arch_local_irq_enable();
+
+#define raw_local_irq_disable() arch_local_irq_disable()
+#define raw_local_irq_enable() arch_local_irq_enable()
+
+#define local_irq_enable()  \
+  do {                      \
+    raw_local_irq_enable(); \
+  } while (0)
+#define local_irq_disable()  \
+  do {                       \
+    raw_local_irq_disable(); \
+  } while (0)
+
+void foo() {
+  local_irq_disable();
+  local_irq_enable();
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: call to 'enable_local_irq' without 'disable_local_irq' in 'bar'  [linuxkernel-irq-unbalanced]
+void bar() {
+  local_irq_enable();
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: call to 'disable_local_irq' without 'enable_local_irq' in 'baz'  [linuxkernel-irq-unbalanced]
+void baz() {
+  local_irq_disable();
+}
+
+void f() {
+  if (1) {
+    local_irq_disable();
+    local_irq_enable();
+  }
+}
+
+// CHECK-MESSAGES: :[[@LINE+1]]:6: warning: call to 'disable_local_irq' without 'enable_local_irq' in 'f2'  [linuxkernel-irq-unbalanced]
+void f2() {
+  if (1) {
+    local_irq_disable();
+  }
+}
+
+__attribute__((annotate("ignore_irq_balancing"))) void g() {
+  local_irq_enable();
+}
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -269,6 +269,7 @@
    hicpp-use-nullptr (redirects to modernize-use-nullptr) <hicpp-use-nullptr>
    hicpp-use-override (redirects to modernize-use-override) <hicpp-use-override>
    hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) <hicpp-vararg>
+   linuxkernel-irq-unbalanced
    linuxkernel-must-use-errs
    llvm-header-guard
    llvm-include-order
Index: clang-tools-extra/docs/clang-tidy/checks/linuxkernel-irq-unbalanced.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/linuxkernel-irq-unbalanced.rst
@@ -0,0 +1,18 @@
+.. title:: clang-tidy - linuxkernel-irq-unbalanced
+
+linuxkernel-irq-unbalanced
+==========================
+
+Checks for calls to ``local_irq_disable`` without matching calls to ``local_irq_enable``
+and vice-versa. In most cases these functions must be called in pairs to avoid indefinite
+hanging in the kernel. Functions marked with ``__attribute__((annotate("ignore_irq_balancing")))``
+are ignored for analysis. This is common when the machine is powering down.
+
+Example:
+
+.. code-block:: c
+
+   void bar() {
+      local_irq_disable();
+      // No call to local_irq_enable();
+   }
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -73,6 +73,11 @@
   Checks Linux kernel code to see if it uses the results from the functions in
   ``linux/err.h``.
 
+- New :doc:`linuxkernel-irq-unbalanced
+  <clang-tidy/checks/linuxkernel-irq-unbalanced>` check.
+
+  Checks Linux kernel for dangerous uses of ``local_irq_disable`` and ``local_irq_enable``
+
 - New :doc:`google-upgrade-googletest-case
   <clang-tidy/checks/google-upgrade-googletest-case>` check.
 
@@ -80,6 +85,7 @@
   replaces them with equivalent APIs with ``suite``.
 
 
+
 Improvements to include-fixer
 -----------------------------
 
Index: clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp
+++ clang-tools-extra/clang-tidy/linuxkernel/LinuxKernelTidyModule.cpp
@@ -9,6 +9,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "IrqUnbalancedCheck.h"
 #include "MustCheckErrsCheck.h"
 
 namespace clang {
@@ -19,6 +20,8 @@
 class LinuxKernelModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<IrqUnbalancedCheck>(
+        "linuxkernel-irq-unbalanced");
     CheckFactories.registerCheck<MustCheckErrsCheck>(
         "linuxkernel-must-check-errs");
   }
Index: clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.h
@@ -0,0 +1,34 @@
+//===--- IrqUnbalancedCheck.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_LINUXKERNEL_IRQUNBALANCEDCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_IRQUNBALANCEDCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace linuxkernel {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/linuxkernel-irq-unbalanced.html
+class IrqUnbalancedCheck : public ClangTidyCheck {
+public:
+  IrqUnbalancedCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace linuxkernel
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_IRQUNBALANCEDCHECK_H
Index: clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/linuxkernel/IrqUnbalancedCheck.cpp
@@ -0,0 +1,70 @@
+//===--- IrqUnbalancedCheck.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 "IrqUnbalancedCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+std::string annotation = "ignore_irq_balancing";
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace linuxkernel {
+
+void IrqUnbalancedCheck::registerMatchers(MatchFinder *Finder) {
+  // FIXME: Add matchers.
+  auto disable = forEachDescendant(
+      callExpr(hasDeclaration(namedDecl(hasName("arch_local_irq_disable"))))
+          .bind("disable"));
+  auto enable = forEachDescendant(
+      callExpr(hasDeclaration(namedDecl(hasName("arch_local_irq_enable"))))
+          .bind("enable"));
+  auto matcher = functionDecl(
+      anyOf(allOf(disable, unless(enable)), allOf(enable, unless(disable))));
+
+  Finder->addMatcher(matcher.bind("func"), this);
+}
+
+void IrqUnbalancedCheck::check(const MatchFinder::MatchResult &Result) {
+  // FIXME: Add callback implementation.
+  const auto *MatchedDecl = Result.Nodes.getNodeAs<FunctionDecl>("func");
+  const auto *DisableCall = Result.Nodes.getNodeAs<CallExpr>("disable");
+  const auto *EnableCall = Result.Nodes.getNodeAs<CallExpr>("enable");
+
+  for (const auto *Attr : MatchedDecl->attrs()) {
+    if (Attr->getKind() == clang::attr::Annotate) {
+      if (dyn_cast<AnnotateAttr>(Attr)->getAnnotation().str() == annotation) {
+        return;
+      }
+    }
+  }
+
+  if (EnableCall) {
+    diag(MatchedDecl->getLocation(),
+         "call to 'enable_local_irq' without 'disable_local_irq' in %0 ")
+        << MatchedDecl;
+    diag(EnableCall->getBeginLoc(), "call to 'enable_local_irq'",
+         DiagnosticIDs::Note)
+        << MatchedDecl;
+  }
+
+  if (DisableCall) {
+    diag(MatchedDecl->getLocation(),
+         "call to 'disable_local_irq' without 'enable_local_irq' in %0 ")
+        << MatchedDecl;
+    diag(DisableCall->getBeginLoc(), "call to 'disable_local_irq'",
+         DiagnosticIDs::Note)
+        << MatchedDecl;
+  }
+}
+
+} // namespace linuxkernel
+} // namespace tidy
+} // namespace clang
Index: clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/linuxkernel/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(LLVM_LINK_COMPONENTS support)
 
 add_clang_library(clangTidyLinuxKernelModule
+  IrqUnbalancedCheck.cpp
   LinuxKernelTidyModule.cpp
   MustCheckErrsCheck.cpp
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D65828: [clang-... Nathan Huckleberry via Phabricator via cfe-commits

Reply via email to