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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits