Skip to content

Commit fc8c65b

Browse files
committed
[clang-tidy] Add a module for the Linux kernel.
Summary: Now that clang is going to be able to build the Linux kernel again on x86, and we have gen_compile_commands.py upstream for generating compile_commands.json, clang-tidy can be used on the Linux kernel source. To that end, this commit adds a new clang-tidy module to be used for checks specific to Linux kernel source. The Linux kernel follows its own style of C, and it will be useful to separate those checks into their own module. This also adds an initial check that makes sure that return values from the kernel error functions like PTR_ERR and ERR_PTR are checked. It also makes sure that any functions that directly return values from these functions are checked. Subscribers: xazax.hun, gribozavr, Eugene.Zelenko, lebedev.ri, mgorny, jdoerfert, cfe-commits Tags: #clang, #clang-tools-extra Reviewers: aaron.ballman, alexfh, hokein, JonasToth Differential Revision: https://reviews.llvm.org/D59963 llvm-svn: 367071
1 parent 3d21a3a commit fc8c65b

File tree

12 files changed

+238
-1
lines changed

12 files changed

+238
-1
lines changed

clang-tools-extra/clang-tidy/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ add_subdirectory(cppcoreguidelines)
4444
add_subdirectory(fuchsia)
4545
add_subdirectory(google)
4646
add_subdirectory(hicpp)
47+
add_subdirectory(linuxkernel)
4748
add_subdirectory(llvm)
4849
add_subdirectory(misc)
4950
add_subdirectory(modernize)

clang-tools-extra/clang-tidy/ClangTidyForceLinker.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ extern volatile int BugproneModuleAnchorSource;
3535
static int LLVM_ATTRIBUTE_UNUSED BugproneModuleAnchorDestination =
3636
BugproneModuleAnchorSource;
3737

38+
// This anchor is used to force the linker to link the LinuxKernelModule.
39+
extern volatile int LinuxKernelModuleAnchorSource;
40+
static int LLVM_ATTRIBUTE_UNUSED LinuxKernelModuleAnchorDestination =
41+
LinuxKernelModuleAnchorSource;
42+
3843
// This anchor is used to force the linker to link the LLVMModule.
3944
extern volatile int LLVMModuleAnchorSource;
4045
static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination =
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
set(LLVM_LINK_COMPONENTS support)
2+
3+
add_clang_library(clangTidyLinuxKernelModule
4+
LinuxKernelTidyModule.cpp
5+
MustCheckErrsCheck.cpp
6+
7+
LINK_LIBS
8+
clangAST
9+
clangASTMatchers
10+
clangBasic
11+
clangLex
12+
clangTidy
13+
clangTidyUtils
14+
)
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===--- LinuxKernelTidyModule.cpp - clang-tidy----------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "../ClangTidy.h"
10+
#include "../ClangTidyModule.h"
11+
#include "../ClangTidyModuleRegistry.h"
12+
#include "MustCheckErrsCheck.h"
13+
14+
namespace clang {
15+
namespace tidy {
16+
namespace linuxkernel {
17+
18+
/// This module is for checks specific to the Linux kernel.
19+
class LinuxKernelModule : public ClangTidyModule {
20+
public:
21+
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
22+
CheckFactories.registerCheck<MustCheckErrsCheck>(
23+
"linuxkernel-must-check-errs");
24+
}
25+
};
26+
// Register the LinuxKernelTidyModule using this statically initialized
27+
// variable.
28+
static ClangTidyModuleRegistry::Add<LinuxKernelModule>
29+
X("linux-module", "Adds checks specific to the Linux kernel.");
30+
} // namespace linuxkernel
31+
32+
// This anchor is used to force the linker to link in the generated object file
33+
// and thus register the LinuxKernelModule.
34+
volatile int LinuxKernelModuleAnchorSource = 0;
35+
36+
} // namespace tidy
37+
} // namespace clang
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===--- MustCheckErrsCheck.cpp - clang-tidy ------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "MustCheckErrsCheck.h"
10+
#include "clang/AST/ASTContext.h"
11+
#include "clang/ASTMatchers/ASTMatchFinder.h"
12+
13+
using namespace clang::ast_matchers;
14+
15+
namespace clang {
16+
namespace tidy {
17+
namespace linuxkernel {
18+
19+
void MustCheckErrsCheck::registerMatchers(MatchFinder *Finder) {
20+
auto ErrFn =
21+
functionDecl(hasAnyName("ERR_PTR", "PTR_ERR", "IS_ERR", "IS_ERR_OR_NULL",
22+
"ERR_CAST", "PTR_ERR_OR_ZERO"));
23+
auto NonCheckingStmts = stmt(anyOf(compoundStmt(), labelStmt()));
24+
Finder->addMatcher(
25+
callExpr(callee(ErrFn), hasParent(NonCheckingStmts)).bind("call"),
26+
this);
27+
28+
auto ReturnToCheck = returnStmt(hasReturnValue(callExpr(callee(ErrFn))));
29+
auto ReturnsErrFn = functionDecl(hasDescendant(ReturnToCheck));
30+
Finder->addMatcher(callExpr(callee(ReturnsErrFn), hasParent(NonCheckingStmts))
31+
.bind("transitive_call"),
32+
this);
33+
}
34+
35+
void MustCheckErrsCheck::check(const MatchFinder::MatchResult &Result) {
36+
const CallExpr *MatchedCallExpr = Result.Nodes.getNodeAs<CallExpr>("call");
37+
if (MatchedCallExpr) {
38+
diag(MatchedCallExpr->getExprLoc(), "result from function %0 is unused")
39+
<< MatchedCallExpr->getDirectCallee();
40+
}
41+
42+
const CallExpr *MatchedTransitiveCallExpr =
43+
Result.Nodes.getNodeAs<CallExpr>("transitive_call");
44+
if (MatchedTransitiveCallExpr) {
45+
diag(MatchedTransitiveCallExpr->getExprLoc(),
46+
"result from function %0 is unused but represents an error value")
47+
<< MatchedTransitiveCallExpr->getDirectCallee();
48+
}
49+
}
50+
51+
} // namespace linuxkernel
52+
} // namespace tidy
53+
} // namespace clang
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===--- MustCheckErrsCheck.h - clang-tidy ----------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_MUSTCHECKERRSCHECK_H
10+
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_MUSTCHECKERRSCHECK_H
11+
12+
#include "../ClangTidyCheck.h"
13+
14+
namespace clang {
15+
namespace tidy {
16+
namespace linuxkernel {
17+
18+
/// Checks Linux kernel code to see if it uses the results from the functions in
19+
/// linux/err.h. Also checks to see if code uses the results from functions that
20+
/// directly return a value from one of these error functions.
21+
///
22+
/// This is important in the Linux kernel because ERR_PTR, PTR_ERR, IS_ERR,
23+
/// IS_ERR_OR_NULL, ERR_CAST, and PTR_ERR_OR_ZERO return values must be checked,
24+
/// since positive pointers and negative error codes are being used in the same
25+
/// context. These functions are marked with
26+
/// __attribute__((warn_unused_result)), but some kernel versions do not have
27+
/// this warning enabled for clang.
28+
///
29+
/// For the user-facing documentation see:
30+
/// http://clang.llvm.org/extra/clang-tidy/checks/linuxkernel-must-use-errs.html
31+
class MustCheckErrsCheck : public ClangTidyCheck {
32+
public:
33+
MustCheckErrsCheck(StringRef Name, ClangTidyContext *Context)
34+
: ClangTidyCheck(Name, Context) {}
35+
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
36+
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
37+
};
38+
39+
} // namespace linuxkernel
40+
} // namespace tidy
41+
} // namespace clang
42+
43+
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LINUXKERNEL_MUSTCHECKERRSCHECK_H

clang-tools-extra/clang-tidy/plugin/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_clang_library(clangTidyPlugin
1717
clangTidyFuchsiaModule
1818
clangTidyGoogleModule
1919
clangTidyHICPPModule
20+
clangTidyLinuxKernelModule
2021
clangTidyLLVMModule
2122
clangTidyMiscModule
2223
clangTidyModernizeModule

clang-tools-extra/clang-tidy/tool/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ target_link_libraries(clang-tidy
2626
clangTidyFuchsiaModule
2727
clangTidyGoogleModule
2828
clangTidyHICPPModule
29+
clangTidyLinuxKernelModule
2930
clangTidyLLVMModule
3031
clangTidyMiscModule
3132
clangTidyModernizeModule

clang-tools-extra/docs/ReleaseNotes.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,19 @@ The improvements are...
6767
Improvements to clang-tidy
6868
--------------------------
6969

70-
The improvements are...
70+
- New :doc:`linuxkernel-must-use-errs
71+
<clang-tidy/checks/linuxkernel-must-use-errs>` check.
72+
73+
Checks Linux kernel code to see if it uses the results from the functions in
74+
``linux/err.h``. Also checks to see if code uses the results from functions that
75+
directly return a value from one of these error functions.
76+
77+
This is important in the Linux kernel because ``ERR_PTR``, ``PTR_ERR``,
78+
``IS_ERR``, ``IS_ERR_OR_NULL``, ``ERR_CAST``, and ``PTR_ERR_OR_ZERO`` return
79+
values must be checked, since positive pointers and negative error codes are
80+
being used in the same context. These functions are marked with
81+
``__attribute__((warn_unused_result))``, but some kernel versions do not have
82+
this warning enabled for clang.
7183

7284
Improvements to include-fixer
7385
-----------------------------
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.. title:: clang-tidy - linuxkernel-must-use-errs
2+
3+
linuxkernel-must-use-errs
4+
=========================
5+
6+
Checks for cases where the kernel error functions ``ERR_PTR``,
7+
``PTR_ERR``, ``IS_ERR``, ``IS_ERR_OR_NULL``, ``ERR_CAST``, and
8+
``PTR_ERR_OR_ZERO`` are called but the results are not used. These
9+
functions are marked with ``__attribute__((warn_unused_result))``, but
10+
the compiler warning for this attribute is not always enabled.
11+
12+
This also checks for unused values returned by functions that return
13+
``ERR_PTR``.
14+
15+
Examples:
16+
17+
.. code-block:: c
18+
19+
/* Trivial unused call to an ERR function */
20+
PTR_ERR_OR_ZERO(some_function_call());
21+
22+
/* A function that returns ERR_PTR. */
23+
void *fn() { ERR_PTR(-EINVAL); }
24+
25+
/* An invalid use of fn. */
26+
fn();

clang-tools-extra/docs/clang-tidy/checks/list.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Clang-Tidy Checks
183183
hicpp-use-nullptr (redirects to modernize-use-nullptr) <hicpp-use-nullptr>
184184
hicpp-use-override (redirects to modernize-use-override) <hicpp-use-override>
185185
hicpp-vararg (redirects to cppcoreguidelines-pro-type-vararg) <hicpp-vararg>
186+
linuxkernel-must-use-errs
186187
llvm-header-guard
187188
llvm-include-order
188189
llvm-namespace-comment
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %check_clang_tidy %s linuxkernel-must-check-errs %t
2+
3+
#define __must_check __attribute__((warn_unused_result))
4+
5+
// Prototypes of the error functions.
6+
void * __must_check ERR_PTR(long error);
7+
long __must_check PTR_ERR(const void *ptr);
8+
int __must_check IS_ERR(const void *ptr);
9+
int __must_check IS_ERR_OR_NULL(const void *ptr);
10+
void * __must_check ERR_CAST(const void *ptr);
11+
int __must_check PTR_ERR_OR_ZERO(const void *ptr);
12+
13+
void f() {
14+
ERR_PTR(0);
15+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'ERR_PTR' is unused
16+
PTR_ERR((void *)0);
17+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'PTR_ERR' is unused
18+
IS_ERR((void *)0);
19+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'IS_ERR' is unused
20+
ERR_CAST((void *)0);
21+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'ERR_CAST' is unused
22+
out:
23+
PTR_ERR_OR_ZERO((void *)0);
24+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'PTR_ERR_OR_ZERO' is unused
25+
}
26+
27+
void *f1() {
28+
return ERR_PTR(0);
29+
}
30+
31+
long f2() {
32+
if (IS_ERR((void *)0)) {
33+
return PTR_ERR((void *)0);
34+
}
35+
return -1;
36+
}
37+
38+
void f3() {
39+
f1();
40+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'f1' is unused but represents an error value
41+
f2();
42+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: result from function 'f2' is unused but represents an error value
43+
}

0 commit comments

Comments
 (0)