forked from OSchip/llvm-project
[clang-tidy] Support C++14 in bugprone-signal-handler.
Check `bugprone-signal-handler` is improved to check for C++-specific constructs in signal handlers. This check is valid until C++17. Reviewed By: whisperity Differential Revision: https://reviews.llvm.org/D118996
This commit is contained in:
parent
5eeef48ed1
commit
6e75ec5e38
|
@ -22,6 +22,7 @@ constexpr llvm::StringLiteral MinimalConformingFunctions[] = {
|
|||
// mentioned POSIX specification was not updated after 'quick_exit' appeared
|
||||
// in the C11 standard.
|
||||
// Also, we want to keep the "minimal set" a subset of the "POSIX set".
|
||||
// The list is repeated in bugprone-signal-handler.rst and should be kept up to date.
|
||||
constexpr llvm::StringLiteral POSIXConformingFunctions[] = {
|
||||
"_Exit",
|
||||
"_exit",
|
||||
|
@ -277,6 +278,25 @@ bool isStandardFunction(const FunctionDecl *FD) {
|
|||
FD->getCanonicalDecl()->getLocation());
|
||||
}
|
||||
|
||||
/// Check if a statement is "C++-only".
|
||||
/// This includes all statements that have a class name with "CXX" prefix
|
||||
/// and every other statement that is declared in file ExprCXX.h.
|
||||
bool isCXXOnlyStmt(const Stmt *S) {
|
||||
StringRef Name = S->getStmtClassName();
|
||||
if (Name.startswith("CXX"))
|
||||
return true;
|
||||
// Check for all other class names in ExprCXX.h that have no 'CXX' prefix.
|
||||
return isa<ArrayTypeTraitExpr, BuiltinBitCastExpr, CUDAKernelCallExpr,
|
||||
CoawaitExpr, CoreturnStmt, CoroutineBodyStmt, CoroutineSuspendExpr,
|
||||
CoyieldExpr, DependentCoawaitExpr, DependentScopeDeclRefExpr,
|
||||
ExprWithCleanups, ExpressionTraitExpr, FunctionParmPackExpr,
|
||||
LambdaExpr, MSDependentExistsStmt, MSPropertyRefExpr,
|
||||
MSPropertySubscriptExpr, MaterializeTemporaryExpr, OverloadExpr,
|
||||
PackExpansionExpr, SizeOfPackExpr, SubstNonTypeTemplateParmExpr,
|
||||
SubstNonTypeTemplateParmPackExpr, TypeTraitExpr,
|
||||
UserDefinedLiteral>(S);
|
||||
}
|
||||
|
||||
/// Given a call graph node of a \p Caller function and a \p Callee that is
|
||||
/// called from \p Caller, get a \c CallExpr of the corresponding function call.
|
||||
/// It is unspecified which call is found if multiple calls exist, but the order
|
||||
|
@ -291,6 +311,18 @@ Expr *findCallExpr(const CallGraphNode *Caller, const CallGraphNode *Callee) {
|
|||
return FoundCallee->CallExpr;
|
||||
}
|
||||
|
||||
SourceRange getSourceRangeOfStmt(const Stmt *S, ASTContext &Ctx) {
|
||||
ParentMapContext &PM = Ctx.getParentMapContext();
|
||||
DynTypedNode P = DynTypedNode::create(*S);
|
||||
while (P.getSourceRange().isInvalid()) {
|
||||
DynTypedNodeList PL = PM.getParents(P);
|
||||
if (PL.size() != 1)
|
||||
return {};
|
||||
P = PL[0];
|
||||
}
|
||||
return P.getSourceRange();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
AST_MATCHER(FunctionDecl, isStandardFunction) {
|
||||
|
@ -317,11 +349,7 @@ void SignalHandlerCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
|
|||
|
||||
bool SignalHandlerCheck::isLanguageVersionSupported(
|
||||
const LangOptions &LangOpts) const {
|
||||
// FIXME: Make the checker useful on C++ code.
|
||||
if (LangOpts.CPlusPlus)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return !LangOpts.CPlusPlus17;
|
||||
}
|
||||
|
||||
void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) {
|
||||
|
@ -332,13 +360,23 @@ void SignalHandlerCheck::registerMatchers(MatchFinder *Finder) {
|
|||
unless(isExpandedFromMacro("SIG_IGN")),
|
||||
unless(isExpandedFromMacro("SIG_DFL")))
|
||||
.bind("handler_expr");
|
||||
Finder->addMatcher(
|
||||
callExpr(callee(SignalFunction), hasArgument(1, HandlerExpr))
|
||||
.bind("register_call"),
|
||||
this);
|
||||
auto HandlerLambda = cxxMemberCallExpr(
|
||||
on(expr(ignoringParenImpCasts(lambdaExpr().bind("handler_lambda")))));
|
||||
Finder->addMatcher(callExpr(callee(SignalFunction),
|
||||
hasArgument(1, anyOf(HandlerExpr, HandlerLambda)))
|
||||
.bind("register_call"),
|
||||
this);
|
||||
}
|
||||
|
||||
void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
if (const auto *HandlerLambda =
|
||||
Result.Nodes.getNodeAs<LambdaExpr>("handler_lambda")) {
|
||||
diag(HandlerLambda->getBeginLoc(),
|
||||
"lambda function is not allowed as signal handler (until C++17)")
|
||||
<< HandlerLambda->getSourceRange();
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *HandlerDecl =
|
||||
Result.Nodes.getNodeAs<FunctionDecl>("handler_decl");
|
||||
const auto *HandlerExpr = Result.Nodes.getNodeAs<DeclRefExpr>("handler_expr");
|
||||
|
@ -356,32 +394,48 @@ void SignalHandlerCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
}
|
||||
|
||||
if (!HandlerDecl->hasBody()) {
|
||||
(void)checkFunction(HandlerDecl, HandlerExpr);
|
||||
// Here checkFunction will put the messages to HandlerExpr.
|
||||
// No need to show a call chain.
|
||||
// Without code body there is nothing more to check.
|
||||
// Check the handler function.
|
||||
// The warning is placed to the signal handler registration.
|
||||
// No need to display a call chain and no need for more checks.
|
||||
(void)checkFunction(HandlerDecl, HandlerExpr, {});
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Update CallGraph::getNode to use canonical decl?
|
||||
CallGraphNode *HandlerNode = CG.getNode(HandlerDecl->getCanonicalDecl());
|
||||
assert(HandlerNode &&
|
||||
"Handler with body should be present in the call graph.");
|
||||
// Start from signal handler and visit every function call.
|
||||
for (auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode);
|
||||
Itr != ItrE; ++Itr) {
|
||||
if (const auto *CallF = dyn_cast<FunctionDecl>((*Itr)->getDecl())) {
|
||||
unsigned int PathL = Itr.getPathLength();
|
||||
const Expr *CallOrRef = (PathL == 1)
|
||||
? HandlerExpr
|
||||
: findCallExpr(Itr.getPath(PathL - 2), *Itr);
|
||||
if (checkFunction(CallF, CallOrRef))
|
||||
reportHandlerChain(Itr, HandlerExpr);
|
||||
auto Itr = llvm::df_begin(HandlerNode), ItrE = llvm::df_end(HandlerNode);
|
||||
while (Itr != ItrE) {
|
||||
const auto *CallF = dyn_cast<FunctionDecl>((*Itr)->getDecl());
|
||||
unsigned int PathL = Itr.getPathLength();
|
||||
if (CallF) {
|
||||
// A signal handler or a function transitively reachable from the signal
|
||||
// handler was found to be unsafe.
|
||||
// Generate notes for the whole call chain (including the signal handler
|
||||
// registration).
|
||||
const Expr *CallOrRef = (PathL > 1)
|
||||
? findCallExpr(Itr.getPath(PathL - 2), *Itr)
|
||||
: HandlerExpr;
|
||||
auto ChainReporter = [this, &Itr, HandlerExpr](bool SkipPathEnd) {
|
||||
reportHandlerChain(Itr, HandlerExpr, SkipPathEnd);
|
||||
};
|
||||
// If problems were found in a function (`CallF`), skip the analysis of
|
||||
// functions that are called from it.
|
||||
if (checkFunction(CallF, CallOrRef, ChainReporter))
|
||||
Itr.skipChildren();
|
||||
else
|
||||
++Itr;
|
||||
} else {
|
||||
++Itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SignalHandlerCheck::checkFunction(const FunctionDecl *FD,
|
||||
const Expr *CallOrRef) {
|
||||
bool SignalHandlerCheck::checkFunction(
|
||||
const FunctionDecl *FD, const Expr *CallOrRef,
|
||||
std::function<void(bool)> ChainReporter) {
|
||||
bool FunctionIsCalled = isa<CallExpr>(CallOrRef);
|
||||
|
||||
if (isStandardFunction(FD)) {
|
||||
|
@ -390,7 +444,9 @@ bool SignalHandlerCheck::checkFunction(const FunctionDecl *FD,
|
|||
"asynchronous-safe; "
|
||||
"%select{using it as|calling it from}1 "
|
||||
"a signal handler may be dangerous")
|
||||
<< FD << FunctionIsCalled;
|
||||
<< FD << FunctionIsCalled << CallOrRef->getSourceRange();
|
||||
if (ChainReporter)
|
||||
ChainReporter(/*SkipPathEnd=*/true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -401,23 +457,74 @@ bool SignalHandlerCheck::checkFunction(const FunctionDecl *FD,
|
|||
"asynchronous-safe; "
|
||||
"%select{using it as|calling it from}1 "
|
||||
"a signal handler may be dangerous")
|
||||
<< FD << FunctionIsCalled;
|
||||
<< FD << FunctionIsCalled << CallOrRef->getSourceRange();
|
||||
if (ChainReporter)
|
||||
ChainReporter(/*SkipPathEnd=*/true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getLangOpts().CPlusPlus)
|
||||
return checkFunctionCPP14(FD, CallOrRef, ChainReporter);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SignalHandlerCheck::checkFunctionCPP14(
|
||||
const FunctionDecl *FD, const Expr *CallOrRef,
|
||||
std::function<void(bool)> ChainReporter) {
|
||||
if (!FD->isExternC()) {
|
||||
diag(CallOrRef->getBeginLoc(),
|
||||
"functions without C linkage are not allowed as signal "
|
||||
"handler (until C++17)");
|
||||
if (ChainReporter)
|
||||
ChainReporter(/*SkipPathEnd=*/true);
|
||||
return true;
|
||||
}
|
||||
|
||||
const FunctionDecl *FBody;
|
||||
const Stmt *BodyS = FD->getBody(FBody);
|
||||
if (!BodyS)
|
||||
return false;
|
||||
|
||||
bool StmtProblemsFound = false;
|
||||
ASTContext &Ctx = FBody->getASTContext();
|
||||
auto Matches =
|
||||
match(decl(forEachDescendant(stmt().bind("stmt"))), *FBody, Ctx);
|
||||
for (const auto &Match : Matches) {
|
||||
const auto *FoundS = Match.getNodeAs<Stmt>("stmt");
|
||||
if (isCXXOnlyStmt(FoundS)) {
|
||||
SourceRange R = getSourceRangeOfStmt(FoundS, Ctx);
|
||||
if (R.isInvalid())
|
||||
continue;
|
||||
diag(R.getBegin(),
|
||||
"C++-only construct is not allowed in signal handler (until C++17)")
|
||||
<< R;
|
||||
diag(R.getBegin(), "internally, the statement is parsed as a '%0'",
|
||||
DiagnosticIDs::Remark)
|
||||
<< FoundS->getStmtClassName();
|
||||
if (ChainReporter)
|
||||
ChainReporter(/*SkipPathEnd=*/false);
|
||||
StmtProblemsFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
return StmtProblemsFound;
|
||||
}
|
||||
|
||||
bool SignalHandlerCheck::isStandardFunctionAsyncSafe(
|
||||
const FunctionDecl *FD) const {
|
||||
assert(isStandardFunction(FD));
|
||||
|
||||
const IdentifierInfo *II = FD->getIdentifier();
|
||||
// Unnamed functions are not explicitly allowed.
|
||||
// C++ std operators may be unsafe and not within the
|
||||
// "common subset of C and C++".
|
||||
if (!II)
|
||||
return false;
|
||||
|
||||
// FIXME: Improve for C++ (check for namespace).
|
||||
if (!FD->isInStdNamespace() && !FD->isGlobal())
|
||||
return false;
|
||||
|
||||
if (ConformingFunctions.count(II->getName()))
|
||||
return true;
|
||||
|
||||
|
@ -426,7 +533,7 @@ bool SignalHandlerCheck::isStandardFunctionAsyncSafe(
|
|||
|
||||
void SignalHandlerCheck::reportHandlerChain(
|
||||
const llvm::df_iterator<clang::CallGraphNode *> &Itr,
|
||||
const DeclRefExpr *HandlerRef) {
|
||||
const DeclRefExpr *HandlerRef, bool SkipPathEnd) {
|
||||
int CallLevel = Itr.getPathLength() - 2;
|
||||
assert(CallLevel >= -1 && "Empty iterator?");
|
||||
|
||||
|
@ -435,16 +542,21 @@ void SignalHandlerCheck::reportHandlerChain(
|
|||
Callee = Caller;
|
||||
Caller = Itr.getPath(CallLevel);
|
||||
const Expr *CE = findCallExpr(Caller, Callee);
|
||||
diag(CE->getBeginLoc(), "function %0 called here from %1",
|
||||
DiagnosticIDs::Note)
|
||||
<< cast<FunctionDecl>(Callee->getDecl())
|
||||
<< cast<FunctionDecl>(Caller->getDecl());
|
||||
if (SkipPathEnd)
|
||||
SkipPathEnd = false;
|
||||
else
|
||||
diag(CE->getBeginLoc(), "function %0 called here from %1",
|
||||
DiagnosticIDs::Note)
|
||||
<< cast<FunctionDecl>(Callee->getDecl())
|
||||
<< cast<FunctionDecl>(Caller->getDecl());
|
||||
--CallLevel;
|
||||
}
|
||||
|
||||
diag(HandlerRef->getBeginLoc(),
|
||||
"function %0 registered here as signal handler", DiagnosticIDs::Note)
|
||||
<< cast<FunctionDecl>(Caller->getDecl()) << HandlerRef->getSourceRange();
|
||||
if (!SkipPathEnd)
|
||||
diag(HandlerRef->getBeginLoc(),
|
||||
"function %0 registered here as signal handler", DiagnosticIDs::Note)
|
||||
<< cast<FunctionDecl>(Caller->getDecl())
|
||||
<< HandlerRef->getSourceRange();
|
||||
}
|
||||
|
||||
} // namespace bugprone
|
||||
|
|
|
@ -37,13 +37,24 @@ private:
|
|||
/// Should test the properties of the function, and check in the code body.
|
||||
/// Should not check function calls in the code (this part is done by the call
|
||||
/// graph scan).
|
||||
/// @param FD The function to check. It may or may not have a definition.
|
||||
/// @param CallOrRef Location of the call to this function (in another
|
||||
/// Bug reports are generated for the whole code body (no stop at the first
|
||||
/// found issue). For issues that are not in the code body, only one
|
||||
/// bug report is generated.
|
||||
/// \param FD The function to check. It may or may not have a definition.
|
||||
/// \param CallOrRef Location of the call to this function (in another
|
||||
/// function) or the reference to the function (if it is used as a registered
|
||||
/// signal handler). This is the location where diagnostics are to be placed.
|
||||
/// @return Returns true if a diagnostic was emitted for this function.
|
||||
bool checkFunction(const FunctionDecl *FD, const Expr *CallOrRef);
|
||||
/// Returns true if a standard library function is considered as
|
||||
/// \param ChainReporter A function that adds bug report notes to display the
|
||||
/// chain of called functions from signal handler registration to the current
|
||||
/// function. This is called at every generated bug report.
|
||||
/// The bool parameter is used like \c SkipPathEnd in \c reportHandlerChain .
|
||||
/// \return Returns true if a diagnostic was emitted for this function.
|
||||
bool checkFunction(const FunctionDecl *FD, const Expr *CallOrRef,
|
||||
std::function<void(bool)> ChainReporter);
|
||||
/// Similar as \c checkFunction but only check for C++14 rules.
|
||||
bool checkFunctionCPP14(const FunctionDecl *FD, const Expr *CallOrRef,
|
||||
std::function<void(bool)> ChainReporter);
|
||||
/// Returns true if a standard library function is considered
|
||||
/// asynchronous-safe.
|
||||
bool isStandardFunctionAsyncSafe(const FunctionDecl *FD) const;
|
||||
/// Add diagnostic notes to show the call chain of functions from a signal
|
||||
|
@ -54,8 +65,10 @@ private:
|
|||
/// function call.
|
||||
/// @param HandlerRef Reference to the signal handler function where it is
|
||||
/// registered as signal handler.
|
||||
/// @param SkipPathEnd If true the last item of the call chain (farthest away
|
||||
/// from the \c signal call) is omitted from note generation.
|
||||
void reportHandlerChain(const llvm::df_iterator<clang::CallGraphNode *> &Itr,
|
||||
const DeclRefExpr *HandlerRef);
|
||||
const DeclRefExpr *HandlerRef, bool SkipPathEnd);
|
||||
|
||||
clang::CallGraph CG;
|
||||
|
||||
|
|
|
@ -265,6 +265,8 @@ public:
|
|||
CheckFactories.registerCheck<LimitedRandomnessCheck>("cert-msc50-cpp");
|
||||
CheckFactories.registerCheck<ProperlySeededRandomGeneratorCheck>(
|
||||
"cert-msc51-cpp");
|
||||
CheckFactories.registerCheck<bugprone::SignalHandlerCheck>(
|
||||
"cert-msc54-cpp");
|
||||
// OOP
|
||||
CheckFactories.registerCheck<performance::MoveConstructorInitCheck>(
|
||||
"cert-oop11-cpp");
|
||||
|
|
|
@ -107,9 +107,20 @@ New checks
|
|||
New check aliases
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
- New alias :doc:`cert-msc54-cpp
|
||||
<clang-tidy/checks/cert/msc54-cpp>` to
|
||||
:doc:`bugprone-signal-handler
|
||||
<clang-tidy/checks/bugprone/signal-handler>` was added.
|
||||
|
||||
|
||||
Changes in existing checks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Improved :doc:`bugprone-signal-handler
|
||||
<clang-tidy/checks/bugprone/signal-handler>` check. Partial
|
||||
support for C++14 signal handler rules was added. Bug report generation was
|
||||
improved.
|
||||
|
||||
Removed checks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
|
|
|
@ -3,34 +3,95 @@
|
|||
bugprone-signal-handler
|
||||
=======================
|
||||
|
||||
Finds functions registered as signal handlers that call non asynchronous-safe
|
||||
functions. Any function that cannot be determined to be an asynchronous-safe
|
||||
function call is assumed to be non-asynchronous-safe by the checker,
|
||||
including user functions for which only the declaration is visible.
|
||||
User function calls with visible definition are checked recursively.
|
||||
The check handles only C code. Only the function names are considered and the
|
||||
fact that the function is a system-call, but no other restrictions on the
|
||||
arguments passed to the functions (the ``signal`` call is allowed without
|
||||
restrictions).
|
||||
Finds specific constructs in signal handler functions that can cause undefined
|
||||
behavior. The rules for what is allowed differ between C++ language versions.
|
||||
|
||||
This check corresponds to the CERT C Coding Standard rule
|
||||
Checked signal handler rules for C:
|
||||
|
||||
- Calls to non-asynchronous-safe functions are not allowed.
|
||||
|
||||
Checked signal handler rules for up to and including C++14:
|
||||
|
||||
- Calls to non-asynchronous-safe functions are not allowed.
|
||||
- C++-specific code constructs are not allowed in signal handlers.
|
||||
In other words, only the common subset of C and C++ is allowed to be used.
|
||||
- Calls to functions with non-C linkage are not allowed (including the signal
|
||||
handler itself).
|
||||
|
||||
The check is disabled on C++17 and later.
|
||||
|
||||
Asnychronous-safety is determined by comparing the function's name against a set
|
||||
of known functions. In addition, the function must come from a system header
|
||||
include and in a global namespace. The (possible) arguments passed to the
|
||||
function are not checked. Any function that cannot be determined to be
|
||||
asynchronous-safe is assumed to be non-asynchronous-safe by the check,
|
||||
including user functions for which only the declaration is visible.
|
||||
Calls to user-defined functions with visible definitions are checked
|
||||
recursively.
|
||||
|
||||
This check implements the CERT C Coding Standard rule
|
||||
`SIG30-C. Call only asynchronous-safe functions within signal handlers
|
||||
<https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers>`_
|
||||
and has an alias name ``cert-sig30-c``.
|
||||
and the rule
|
||||
`MSC54-CPP. A signal handler must be a plain old function
|
||||
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/MSC54-CPP.+A+signal+handler+must+be+a+plain+old+function>`_.
|
||||
It has the alias names ``cert-sig30-c`` and ``cert-msc54-cpp``.
|
||||
|
||||
Options
|
||||
-------
|
||||
|
||||
.. option:: AsyncSafeFunctionSet
|
||||
|
||||
Selects which set of functions is considered as asynchronous-safe
|
||||
(and therefore allowed in signal handlers). Value ``minimal`` selects
|
||||
a minimal set that is defined in the CERT SIG30-C rule and includes functions
|
||||
``abort()``, ``_Exit()``, ``quick_exit()`` and ``signal()``. Value ``POSIX``
|
||||
selects a larger set of functions that is listed in POSIX.1-2017 (see `this
|
||||
link
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03>`_
|
||||
for more information).
|
||||
The function ``quick_exit`` is not included in the shown list. It is
|
||||
assumable that the reason is that the list was not updated for C11.
|
||||
The checker includes ``quick_exit`` in the set of safe functions.
|
||||
Functions registered as exit handlers are not checked.
|
||||
(and therefore allowed in signal handlers). It can be set to the following values:
|
||||
|
||||
``minimal``
|
||||
Selects a minimal set that is defined in the CERT SIG30-C rule.
|
||||
and includes functions ``abort()``, ``_Exit()``, ``quick_exit()`` and
|
||||
``signal()``.
|
||||
``POSIX``
|
||||
Selects a larger set of functions that is listed in POSIX.1-2017 (see `this
|
||||
link
|
||||
<https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_04_03>`_
|
||||
for more information). The following functions are included:
|
||||
``_Exit``, ``_exit``, ``abort``, ``accept``, ``access``, ``aio_error``,
|
||||
``aio_return``, ``aio_suspend``, ``alarm``, ``bind``, ``cfgetispeed``,
|
||||
``cfgetospeed``, ``cfsetispeed``, ``cfsetospeed``, ``chdir``, ``chmod``,
|
||||
``chown``, ``clock_gettime``, ``close``, ``connect``, ``creat``, ``dup``,
|
||||
``dup2``, ``execl``, ``execle``, ``execv``, ``execve``, ``faccessat``,
|
||||
``fchdir``, ``fchmod``, ``fchmodat``, ``fchown``, ``fchownat``, ``fcntl``,
|
||||
``fdatasync``, ``fexecve``, ``ffs``, ``fork``, ``fstat``, ``fstatat``,
|
||||
``fsync``, ``ftruncate``, ``futimens``, ``getegid``, ``geteuid``,
|
||||
``getgid``, ``getgroups``, ``getpeername``, ``getpgrp``, ``getpid``,
|
||||
``getppid``, ``getsockname``, ``getsockopt``, ``getuid``, ``htonl``,
|
||||
``htons``, ``kill``, ``link``, ``linkat``, ``listen``, ``longjmp``,
|
||||
``lseek``, ``lstat``, ``memccpy``, ``memchr``, ``memcmp``, ``memcpy``,
|
||||
``memmove``, ``memset``, ``mkdir``, ``mkdirat``, ``mkfifo``, ``mkfifoat``,
|
||||
``mknod``, ``mknodat``, ``ntohl``, ``ntohs``, ``open``, ``openat``,
|
||||
``pause``, ``pipe``, ``poll``, ``posix_trace_event``, ``pselect``,
|
||||
``pthread_kill``, ``pthread_self``, ``pthread_sigmask``, ``quick_exit``,
|
||||
``raise``, ``read``, ``readlink``, ``readlinkat``, ``recv``, ``recvfrom``,
|
||||
``recvmsg``, ``rename``, ``renameat``, ``rmdir``, ``select``, ``sem_post``,
|
||||
``send``, ``sendmsg``, ``sendto``, ``setgid``, ``setpgid``, ``setsid``,
|
||||
``setsockopt``, ``setuid``, ``shutdown``, ``sigaction``, ``sigaddset``,
|
||||
``sigdelset``, ``sigemptyset``, ``sigfillset``, ``sigismember``,
|
||||
``siglongjmp``, ``signal``, ``sigpause``, ``sigpending``, ``sigprocmask``,
|
||||
``sigqueue``, ``sigset``, ``sigsuspend``, ``sleep``, ``sockatmark``,
|
||||
``socket``, ``socketpair``, ``stat``, ``stpcpy``, ``stpncpy``,
|
||||
``strcat``, ``strchr``, ``strcmp``, ``strcpy``, ``strcspn``, ``strlen``,
|
||||
``strncat``, ``strncmp``, ``strncpy``, ``strnlen``, ``strpbrk``,
|
||||
``strrchr``, ``strspn``, ``strstr``, ``strtok_r``, ``symlink``,
|
||||
``symlinkat``, ``tcdrain``, ``tcflow``, ``tcflush``, ``tcgetattr``,
|
||||
``tcgetpgrp``, ``tcsendbreak``, ``tcsetattr``, ``tcsetpgrp``,
|
||||
``time``, ``timer_getoverrun``, ``timer_gettime``, ``timer_settime``,
|
||||
``times``, ``umask``, ``uname``, ``unlink``, ``unlinkat``, ``utime``,
|
||||
``utimensat``, ``utimes``, ``wait``, ``waitpid``, ``wcpcpy``,
|
||||
``wcpncpy``, ``wcscat``, ``wcschr``, ``wcscmp``, ``wcscpy``, ``wcscspn``,
|
||||
``wcslen``, ``wcsncat``, ``wcsncmp``, ``wcsncpy``, ``wcsnlen``, ``wcspbrk``,
|
||||
``wcsrchr``, ``wcsspn``, ``wcsstr``, ``wcstok``, ``wmemchr``, ``wmemcmp``,
|
||||
``wmemcpy``, ``wmemmove``, ``wmemset``, ``write``
|
||||
|
||||
Default is ``POSIX``.
|
||||
The function ``quick_exit`` is not included in the POSIX list but it
|
||||
is included here in the set of safe functions.
|
||||
|
||||
The default value is ``POSIX``.
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
.. title:: clang-tidy - cert-msc54-cpp
|
||||
.. meta::
|
||||
:http-equiv=refresh: 5;URL=../bugprone/signal-handler.html
|
||||
|
||||
cert-msc54-cpp
|
||||
==============
|
||||
|
||||
The cert-msc54-cpp check is an alias, please see
|
||||
`bugprone-signal-handler <../bugprone/signal-handler.html>`_
|
||||
for more information.
|
|
@ -384,6 +384,7 @@ Clang-Tidy Checks
|
|||
`cert-flp37-c <cert/flp37-c.html>`_, `bugprone-suspicious-memory-comparison <bugprone/suspicious-memory-comparison.html>`_,
|
||||
`cert-msc30-c <cert/msc30-c.html>`_, `cert-msc50-cpp <cert/msc50-cpp.html>`_,
|
||||
`cert-msc32-c <cert/msc32-c.html>`_, `cert-msc51-cpp <cert/msc51-cpp.html>`_,
|
||||
`cert-msc54-cpp <cert/msc54-cpp.html>`_, `bugprone-signal-handler <bugprone/signal-handler.html>`_,
|
||||
`cert-oop11-cpp <cert/oop11-cpp.html>`_, `performance-move-constructor-init <performance/move-constructor-init.html>`_,
|
||||
`cert-oop54-cpp <cert/oop54-cpp.html>`_, `bugprone-unhandled-self-assignment <bugprone/unhandled-self-assignment.html>`_,
|
||||
`cert-pos44-c <cert/pos44-c.html>`_, `bugprone-bad-signal-to-kill-thread <bugprone/bad-signal-to-kill-thread.html>`_,
|
||||
|
|
|
@ -13,10 +13,12 @@ typedef void (*sighandler_t)(int);
|
|||
|
||||
void _sig_ign(int);
|
||||
void _sig_dfl(int);
|
||||
void _sig_err(int);
|
||||
|
||||
#define SIGINT 1
|
||||
#define SIG_IGN _sig_ign
|
||||
#define SIG_DFL _sig_dfl
|
||||
#define SIG_ERR _sig_err
|
||||
|
||||
sighandler_t signal(int, sighandler_t);
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
//===--- Header for test bugprone-signal-handler.cpp ------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define SIGINT 1
|
||||
#define SIG_IGN std::_sig_ign
|
||||
#define SIG_DFL std::_sig_dfl
|
||||
|
||||
namespace std {
|
||||
|
||||
void _sig_ign(int);
|
||||
void _sig_dfl(int);
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
sighandler_t signal(int, sighandler_t);
|
||||
|
||||
void abort();
|
||||
void _Exit(int);
|
||||
void quick_exit(int);
|
||||
|
||||
void other_call();
|
||||
|
||||
struct SysStruct {
|
||||
void operator<<(int);
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace system_other {
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
sighandler_t signal(int, sighandler_t);
|
||||
|
||||
} // namespace system_other
|
|
@ -19,7 +19,6 @@ void f_extern_handler(int);
|
|||
void handler_printf(int) {
|
||||
printf("1234");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_printf'
|
||||
// CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_printf' registered here as signal handler
|
||||
}
|
||||
|
||||
|
@ -30,7 +29,6 @@ void test_printf(void) {
|
|||
void handler_extern(int) {
|
||||
f_extern();
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'handler_extern'
|
||||
// CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_extern' registered here as signal handler
|
||||
}
|
||||
|
||||
|
@ -53,7 +51,6 @@ void test_ok(void) {
|
|||
void f_bad(void) {
|
||||
printf("1234");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad'
|
||||
// CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_bad' called here from 'handler_bad'
|
||||
// CHECK-NOTES: :[[@LINE+8]]:18: note: function 'handler_bad' registered here as signal handler
|
||||
}
|
||||
|
@ -69,7 +66,6 @@ void test_bad(void) {
|
|||
void f_bad1(void) {
|
||||
printf("1234");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_bad1'
|
||||
// CHECK-NOTES: :[[@LINE+6]]:3: note: function 'f_bad1' called here from 'f_bad2'
|
||||
// CHECK-NOTES: :[[@LINE+9]]:3: note: function 'f_bad2' called here from 'handler_bad1'
|
||||
// CHECK-NOTES: :[[@LINE+13]]:18: note: function 'handler_bad1' registered here as signal handler
|
||||
|
@ -101,7 +97,6 @@ void handler_false_condition(int) {
|
|||
if (0)
|
||||
printf("1234");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:5: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:5: note: function 'printf' called here from 'handler_false_condition'
|
||||
// CHECK-NOTES: :[[@LINE+4]]:18: note: function 'handler_false_condition' registered here as signal handler
|
||||
}
|
||||
|
||||
|
@ -112,11 +107,9 @@ void test_false_condition(void) {
|
|||
void handler_multiple_calls(int) {
|
||||
f_extern();
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'handler_multiple_calls'
|
||||
// CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_multiple_calls' registered here as signal handler
|
||||
// CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_calls' registered here as signal handler
|
||||
printf("1234");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'handler_multiple_calls'
|
||||
// CHECK-NOTES: :[[@LINE+6]]:18: note: function 'handler_multiple_calls' registered here as signal handler
|
||||
f_extern();
|
||||
// first 'f_extern' call found only
|
||||
|
@ -137,13 +130,11 @@ void handler_recursive(int) {
|
|||
void f_recursive(void) {
|
||||
f_extern();
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: cannot verify that external function 'f_extern' is asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'f_extern' called here from 'f_recursive'
|
||||
// CHECK-NOTES: :[[@LINE-9]]:3: note: function 'f_recursive' called here from 'handler_recursive'
|
||||
// CHECK-NOTES: :[[@LINE+10]]:18: note: function 'handler_recursive' registered here as signal handler
|
||||
// CHECK-NOTES: :[[@LINE-8]]:3: note: function 'f_recursive' called here from 'handler_recursive'
|
||||
// CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_recursive' registered here as signal handler
|
||||
printf("");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_recursive'
|
||||
// CHECK-NOTES: :[[@LINE-14]]:3: note: function 'f_recursive' called here from 'handler_recursive'
|
||||
// CHECK-NOTES: :[[@LINE-12]]:3: note: function 'f_recursive' called here from 'handler_recursive'
|
||||
// CHECK-NOTES: :[[@LINE+5]]:18: note: function 'handler_recursive' registered here as signal handler
|
||||
handler_recursive(2);
|
||||
}
|
||||
|
@ -155,7 +146,6 @@ void test_recursive(void) {
|
|||
void f_multiple_paths(void) {
|
||||
printf("");
|
||||
// CHECK-NOTES: :[[@LINE-1]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-NOTES: :[[@LINE-2]]:3: note: function 'printf' called here from 'f_multiple_paths'
|
||||
// CHECK-NOTES: :[[@LINE+5]]:3: note: function 'f_multiple_paths' called here from 'handler_multiple_paths'
|
||||
// CHECK-NOTES: :[[@LINE+9]]:18: note: function 'handler_multiple_paths' registered here as signal handler
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
// RUN: %check_clang_tidy -std=c++14 %s bugprone-signal-handler %t -- -- -isystem %clang_tidy_headers -isystem %S/Inputs/signal-handler -target x86_64-unknown-unknown
|
||||
|
||||
#include "stdcpp.h"
|
||||
#include "stdio.h"
|
||||
|
||||
// Functions called "signal" that are different from the system version.
|
||||
typedef void (*callback_t)(int);
|
||||
void signal(int, callback_t, int);
|
||||
namespace ns {
|
||||
void signal(int, callback_t);
|
||||
}
|
||||
|
||||
extern "C" void handler_unsafe(int) {
|
||||
printf("xxx");
|
||||
}
|
||||
|
||||
extern "C" void handler_unsafe_1(int) {
|
||||
printf("xxx");
|
||||
}
|
||||
|
||||
namespace test_invalid_handler {
|
||||
|
||||
void handler_non_extern_c(int) {
|
||||
printf("xxx");
|
||||
}
|
||||
|
||||
struct A {
|
||||
static void handler_member(int) {
|
||||
printf("xxx");
|
||||
}
|
||||
};
|
||||
|
||||
void test() {
|
||||
std::signal(SIGINT, handler_unsafe_1);
|
||||
// CHECK-MESSAGES: :[[@LINE-17]]:3: warning: standard function 'printf' may not be asynchronous-safe; calling it from a signal handler may be dangerous [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:23: note: function 'handler_unsafe_1' registered here as signal handler
|
||||
|
||||
std::signal(SIGINT, handler_non_extern_c);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
|
||||
std::signal(SIGINT, A::handler_member);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
|
||||
std::signal(SIGINT, [](int) { printf("xxx"); });
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: lambda function is not allowed as signal handler (until C++17) [bugprone-signal-handler]
|
||||
|
||||
// This case is (deliberately) not found by the checker.
|
||||
std::signal(SIGINT, [](int) -> callback_t { return &handler_unsafe; }(1));
|
||||
}
|
||||
|
||||
} // namespace test_invalid_handler
|
||||
|
||||
namespace test_non_standard_signal_call {
|
||||
|
||||
struct Signal {
|
||||
static void signal(int, callback_t);
|
||||
};
|
||||
|
||||
void test() {
|
||||
// No diagnostics here. All these signal calls differ from the standard system one.
|
||||
signal(SIGINT, handler_unsafe, 1);
|
||||
ns::signal(SIGINT, handler_unsafe);
|
||||
Signal::signal(SIGINT, handler_unsafe);
|
||||
system_other::signal(SIGINT, handler_unsafe);
|
||||
}
|
||||
|
||||
} // namespace test_non_standard_signal_call
|
||||
|
||||
namespace test_cpp_construct_in_handler {
|
||||
|
||||
struct Struct {
|
||||
virtual ~Struct() {}
|
||||
void f1();
|
||||
int *begin();
|
||||
int *end();
|
||||
static void f2();
|
||||
};
|
||||
struct Derived : public Struct {
|
||||
};
|
||||
|
||||
struct X {
|
||||
X(int, float);
|
||||
};
|
||||
|
||||
Struct *S_Global;
|
||||
const Struct *S_GlobalConst;
|
||||
|
||||
void f_non_extern_c() {
|
||||
}
|
||||
|
||||
void f_default_arg(int P1 = 0) {
|
||||
}
|
||||
|
||||
extern "C" void handler_cpp(int) {
|
||||
using namespace ::test_cpp_construct_in_handler;
|
||||
|
||||
// These calls are not found as problems.
|
||||
// (Called functions are not analyzed if the current function has already
|
||||
// other problems.)
|
||||
f_non_extern_c();
|
||||
Struct::f2();
|
||||
// 'auto' is not disallowed
|
||||
auto Auto = 28u;
|
||||
|
||||
Struct S;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXConstructExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
S_Global->f1();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXMemberCallExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
const Struct &SRef = Struct();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:24: remark: internally, the statement is parsed as a 'CXXBindTemporaryExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
X(3, 4.4);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTemporaryObjectExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
auto L = [](int i) { printf("%d", i); };
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXConstructExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
L(2);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXOperatorCallExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
try {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXTryStmt'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
int A;
|
||||
} catch (int) {
|
||||
};
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:5: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-3]]:5: remark: internally, the statement is parsed as a 'CXXCatchStmt'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
throw(12);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXThrowExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
for (int I : S) {
|
||||
}
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-3]]:3: remark: internally, the statement is parsed as a 'CXXForRangeStmt'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
// CHECK-MESSAGES: :[[@LINE-5]]:14: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-6]]:14: remark: internally, the statement is parsed as a 'CXXMemberCallExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
int Int = *(reinterpret_cast<int *>(&S));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXReinterpretCastExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
Int = static_cast<int>(12.34);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXStaticCastExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
Derived *Der = dynamic_cast<Derived *>(S_Global);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXDynamicCastExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
Struct *SPtr = const_cast<Struct *>(S_GlobalConst);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:18: remark: internally, the statement is parsed as a 'CXXConstCastExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
Int = int(12.34);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:9: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:9: remark: internally, the statement is parsed as a 'CXXFunctionalCastExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
|
||||
int *IPtr = new int[10];
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXNewExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
delete[] IPtr;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDeleteExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
IPtr = nullptr;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:10: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:10: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
bool Bool = true;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:15: remark: internally, the statement is parsed as a 'CXXBoolLiteralExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
f_default_arg();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:3: remark: internally, the statement is parsed as a 'CXXDefaultArgExpr'
|
||||
// CHECK-MESSAGES: :198:23: note: function 'handler_cpp' registered here as signal handler
|
||||
}
|
||||
|
||||
void test() {
|
||||
std::signal(SIGINT, handler_cpp);
|
||||
}
|
||||
|
||||
} // namespace test_cpp_construct_in_handler
|
||||
|
||||
namespace test_cpp_indirect {
|
||||
|
||||
void non_extern_c() {
|
||||
int *P = nullptr;
|
||||
}
|
||||
|
||||
extern "C" void call_cpp_indirect() {
|
||||
int *P = nullptr;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: C++-only construct is not allowed in signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE-2]]:12: remark: internally, the statement is parsed as a 'CXXNullPtrLiteralExpr'
|
||||
// CHECK-MESSAGES: :[[@LINE+8]]:3: note: function 'call_cpp_indirect' called here from 'handler_cpp_indirect'
|
||||
// CHECK-MESSAGES: :[[@LINE+11]]:23: note: function 'handler_cpp_indirect' registered here as signal handler
|
||||
}
|
||||
|
||||
extern "C" void handler_cpp_indirect(int) {
|
||||
non_extern_c();
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: functions without C linkage are not allowed as signal handler (until C++17) [bugprone-signal-handler]
|
||||
// CHECK-MESSAGES: :[[@LINE+5]]:23: note: function 'handler_cpp_indirect' registered here as signal handler
|
||||
call_cpp_indirect();
|
||||
}
|
||||
|
||||
void test() {
|
||||
std::signal(SIGINT, handler_cpp_indirect);
|
||||
}
|
||||
|
||||
} // namespace test_cpp_indirect
|
Loading…
Reference in New Issue