Based on CERT-MSC54-CPP
Details
Diff Detail
- Repository
- rL LLVM
Event Timeline
clang-tidy/cert/CERTTidyModule.cpp | ||
---|---|---|
62–64 | checker -> check. | |
docs/ReleaseNotes.rst | ||
85 | Probably C++ should be mentioned for clarity. | |
docs/clang-tidy/checks/cert-msc54-cpp.rst | ||
8 | 'extern C' -> `extern "C"`. | |
22 | Unnecessary empty line. | |
33 | Unnecessary empty line. | |
35 | Please replace CPP with C++ as in similar checks documentation. |
This check is an interesting one. The rules around what is signal safe are changing for C++17 to be a bit more lenient than what the rules are for C++14. CERT's rule is written against C++14, and so the current behavior matches the rule wording. However, the *intent* of the rule is to ensure that only signal-safe functionality is used from a signal handler, and so from that perspective, I can imagine a user compiling for C++17 to want the relaxed rules to still comply with CERT's wording. What do you think?
clang-tidy/cert/SignalHandlerMustBePlainOldFunctionCheck.cpp | ||
---|---|---|
23 | Since this is only needed once and is quite succinct, I'd just lower it into its usage. | |
48 | Same here. | |
53 | And here. | |
84 | Don't use auto for this one, since the type is neither complex nor spelled out in the initialization. | |
85 | Can use isDefined() instead of getDefinition(). Then you can store off the FunctionDecl * for the definition and use it below in the call to hasCxxRepr(). | |
103–104 | These functions can be marked const. | |
142 | 'extern \"C\"'' instead of 'external C'. I'd probably reword it to: "signal handlers must be 'extern \"C\"" | |
150 | representations -> constructs (same below) | |
docs/clang-tidy/checks/cert-msc54-cpp.rst | ||
25 | Space between // and warning; indent the comment. | |
30 | Indent the code. |
I think your concerns are right. I've checked the upcoming changes in the C++17 standard draft and I'll add some logic to the code to have those relaxed rules at least partly fulfilled.
For now, I uploaded the changes required for this check.
docs/ReleaseNotes.rst | ||
---|---|---|
64 | You missed a conflict marker here (and below in line 149). |
Aside from a few small nits, this looks reasonable. Have you run it over any large code bases that use signals to test the quality of the check?
docs/clang-tidy/checks/cert-msc54-cpp.rst | ||
---|---|---|
23 | The warning text should match the actual warning. | |
test/clang-tidy/cert-signal-handler-must-be-plain-old-function.cpp | ||
56–57 | Can you move these to be closer to where the actual note appears? It makes it easier to ensure that the diagnostic appears on the proper line. |
I rebased the patch so it compiles with master version of LLVM/Clang. I did no other change, so I would like if this patch would be committed on behalf of @NorenaLeonetti if the patch is acceptable.
I would kindly ask the reviewers to give some comments if any additional modification is needed. I run this checker on DuckDB project and this checker gave two reports on functions which shouldn't be used as signal handler:
duckdb-0.2.0/third_party/sqlsmith/sqlsmith.cc:38:17: do not use C++ constructs in signal handlers [cert-msc54-cpp]
https://github.com/cwida/duckdb/blob/master/third_party/sqlsmith/sqlsmith.cc#L38
duckdb-0.2.0/tools/shell/shell.c:8828:13: signal handlers must be 'extern "C"' [cert-msc54-cpp]
https://github.com/cwida/duckdb/blob/master/tools/shell/shell.c#L8828
I haven't found other C++ projects which use signals. However, this checker reports on the non-compliant code fragments of the corresponding SEI-CERT rule: https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC54-CPP.+A+signal+handler+must+be+a+plain+old+function. The two findings above also seem to be true positive.
Please consider these changes, and whether this is relevant as implemented: http://wg21.link/p0270
clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp | ||
---|---|---|
22 ↗ | (On Diff #288617) | "C++ construct" isn't particularly useful. Here it needs to call out throwing exceptions. |
57 ↗ | (On Diff #288617) | Here too, I have no idea what this means given just this message. |
73 ↗ | (On Diff #288617) | This is also very confusing. |
Test file has been extended with the second line of the "note" diagnostic message which designates the location of the suspicious "C++ construct". The full clang-tidy output looks like this:
llvm-project/clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp:20:17: warning: do not use C++ constructs in signal handlers [cert-msc54-cpp]
extern "C" void cpp_signal_handler(int sig) {
^
llvm-project/clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp:23:3: note: C++ construct used here
throw "error message"; ^
clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp | ||
---|---|---|
22 ↗ | (On Diff #288617) | Thanks for the review! llvm-project/clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp:20:17: warning: do not use C++ constructs in signal handlers [cert-msc54-cpp] ^ llvm-project/clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp:23:3: note: C++ construct used here throw "error message"; ^ Do you think it's enough, or should the note text be different for all C++ constructs? |
Note texts are now describing what kind of C++ constructs were used. The warning message also explains better the reason of the issue: "signal handlers must be plain old functions, C++-only constructs are not allowed"
MSC54-CPP refers to POF, which as I pointed out above isn't relevant anymore. I'd much rather have a diagnostic which honors the state of things after http://wg21.link/p0270.
Additionally, lots of what MSC54-CPP intends is implementation-defined. We shouldn't diagnose for things that clang has defined as signal safe, at least not by default.
From the paper, I'd like to see tests for these:
- a call to any standard library function, except for plain lock-free atomic atomic operations and functions explicitly identified as signal-safe. [Note: This implicitly excludes the use of new and delete expressions that rely on a library-provided memory allocator. – end note]; -- here I'd like to explicitly see the list of signal-safe functions, and examples of ones that are not
- an access to an object with thread storage duration;
- a dynamic_cast expression;
- throwing of an exception;
- control entering a try-block or function-try-block; or
- initialization of a variable with static storage duration requiring dynamic initialization (3.6.3 [basic.start.dynamic], 6.7 [stmt.decl])). [ Note: Such initialization might occur because it is the first odr-use (3.2 [basic.def.odr]) of that variable. -- end note ]
- waiting for the completion of the initialization of a variable with static storage duration (6.7 [stmt.decl]).
clang-tools-extra/clang-tidy/cert/SignalHandlerMustBePlainOldFunctionCheck.cpp | ||
---|---|---|
84 ↗ | (On Diff #288777) | Most of the above are fine per p0270, and most don't have a test at the moment. |
clang-tools-extra/docs/clang-tidy/checks/cert-msc54-cpp.rst | ||
15 ↗ | (On Diff #288777) | 'extern', not 'external' |
23 ↗ | (On Diff #288777) | Update the example too. |
clang-tools-extra/test/clang-tidy/checkers/cert-signal-handler-must-be-plain-old-function.cpp | ||
74 ↗ | (On Diff #288777) | I don't think this should diagnose, it is signal safe for clang's implementation, and allowed by p0270. |
91 ↗ | (On Diff #288777) | _Thread_local isn't signal safe per p0270. |
114 ↗ | (On Diff #288777) | The atomic isn't used here, and atomic initialization isn't atomic, so the test isn't sufficient. |
I agree, and I've commented on that rule to remind the folks at CERT that the rule has largely gone stale.
Additionally, lots of what MSC54-CPP intends is implementation-defined. We shouldn't diagnose for things that clang has defined as signal safe, at least not by default.
Also agreed.
clang-tools-extra/clang-tidy/cert/SignalHandlerMustBePlainOldFunctionCheck.cpp | ||
---|---|---|
42 ↗ | (On Diff #288777) | I'm not super keen on this approach because as new C++ constructs are added, this will continually need to be updated, which is a maintenance burden I think we should try to avoid. I would rather use some generic wording or tie the wording automatically to something provided by the Stmt class. |
44 ↗ | (On Diff #288777) | Diagnostics in clang-tidy should start with a lowercase letter |
91 ↗ | (On Diff #288777) | Similar concerns here. |
checker -> check.