mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-14 03:45:33 +00:00
[clang-tidy] Add spuriously-wake-up-functions check
Summary: According to https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop and https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop misc-spuriously-wake-up-functions check is created. The check finds `cnd_wait` or `wait` function calls in an `IfStmt` and warns the user to replace it with a `WhileStmt` or use it with a lambda parameter. Reviewers: aaron.ballman, alexfh, hokein, jfb, Charusso Reviewed By: aaron.ballman Subscribers: sylvestre.ledru, whisperity, Eugene.Zelenko, mgorny, dexonsmith, cfe-commits, gerazo, xazax.hun, steakhal, Charusso Tags: #clang-tools-extra, #clang Differential Revision: https://reviews.llvm.org/D70876
This commit is contained in:
parent
c5fd9e3888
commit
0f4c70dd3e
@ -41,6 +41,7 @@
|
||||
#include "SignedCharMisuseCheck.h"
|
||||
#include "SizeofContainerCheck.h"
|
||||
#include "SizeofExpressionCheck.h"
|
||||
#include "SpuriouslyWakeUpFunctionsCheck.h"
|
||||
#include "StringConstructorCheck.h"
|
||||
#include "StringIntegerAssignmentCheck.h"
|
||||
#include "StringLiteralWithEmbeddedNulCheck.h"
|
||||
@ -133,6 +134,8 @@ public:
|
||||
"bugprone-sizeof-container");
|
||||
CheckFactories.registerCheck<SizeofExpressionCheck>(
|
||||
"bugprone-sizeof-expression");
|
||||
CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
|
||||
"bugprone-spuriously-wake-up-functions");
|
||||
CheckFactories.registerCheck<StringConstructorCheck>(
|
||||
"bugprone-string-constructor");
|
||||
CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
|
||||
|
@ -33,6 +33,7 @@ add_clang_library(clangTidyBugproneModule
|
||||
SignedCharMisuseCheck.cpp
|
||||
SizeofContainerCheck.cpp
|
||||
SizeofExpressionCheck.cpp
|
||||
SpuriouslyWakeUpFunctionsCheck.cpp
|
||||
StringConstructorCheck.cpp
|
||||
StringIntegerAssignmentCheck.cpp
|
||||
StringLiteralWithEmbeddedNulCheck.cpp
|
||||
|
@ -0,0 +1,108 @@
|
||||
//===--- SpuriouslyWakeUpFunctionsCheck.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 "SpuriouslyWakeUpFunctionsCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace bugprone {
|
||||
|
||||
void SpuriouslyWakeUpFunctionsCheck::registerMatchers(MatchFinder *Finder) {
|
||||
|
||||
auto hasUniqueLock = hasDescendant(declRefExpr(
|
||||
hasDeclaration(varDecl(hasType(recordDecl(classTemplateSpecializationDecl(
|
||||
hasName("::std::unique_lock"),
|
||||
hasTemplateArgument(
|
||||
0, templateArgument(refersToType(qualType(hasDeclaration(
|
||||
cxxRecordDecl(hasName("::std::mutex"))))))))))))));
|
||||
|
||||
auto hasWaitDescendantCPP = hasDescendant(
|
||||
cxxMemberCallExpr(
|
||||
anyOf(
|
||||
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
|
||||
allOf(hasName("::std::condition_variable::wait"),
|
||||
parameterCountIs(1)))))),
|
||||
onImplicitObjectArgument(
|
||||
declRefExpr(to(varDecl(hasType(references(recordDecl(
|
||||
hasName("::std::condition_variable")))))))),
|
||||
hasUniqueLock),
|
||||
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
|
||||
allOf(hasName("::std::condition_variable::wait_for"),
|
||||
parameterCountIs(2)))))),
|
||||
onImplicitObjectArgument(
|
||||
declRefExpr(to(varDecl(hasType(references(recordDecl(
|
||||
hasName("::std::condition_variable")))))))),
|
||||
hasUniqueLock),
|
||||
allOf(hasDescendant(memberExpr(hasDeclaration(functionDecl(
|
||||
allOf(hasName("::std::condition_variable::wait_until"),
|
||||
parameterCountIs(2)))))),
|
||||
onImplicitObjectArgument(
|
||||
declRefExpr(to(varDecl(hasType(references(recordDecl(
|
||||
hasName("::std::condition_variable")))))))),
|
||||
hasUniqueLock)
|
||||
|
||||
))
|
||||
.bind("wait"));
|
||||
|
||||
auto hasWaitDescendantC = hasDescendant(
|
||||
callExpr(callee(functionDecl(
|
||||
anyOf(hasName("cnd_wait"), hasName("cnd_timedwait")))))
|
||||
.bind("wait"));
|
||||
if (getLangOpts().CPlusPlus) {
|
||||
// Check for `CON54-CPP`
|
||||
Finder->addMatcher(
|
||||
ifStmt(
|
||||
|
||||
allOf(hasWaitDescendantCPP,
|
||||
unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantCPP)),
|
||||
hasDescendant(whileStmt(hasWaitDescendantCPP)),
|
||||
hasDescendant(forStmt(hasWaitDescendantCPP)),
|
||||
hasDescendant(doStmt(hasWaitDescendantCPP)))))
|
||||
|
||||
),
|
||||
this);
|
||||
} else {
|
||||
// Check for `CON36-C`
|
||||
Finder->addMatcher(
|
||||
|
||||
ifStmt(
|
||||
allOf(hasWaitDescendantC,
|
||||
unless(anyOf(hasDescendant(ifStmt(hasWaitDescendantC)),
|
||||
hasDescendant(whileStmt(hasWaitDescendantC)),
|
||||
hasDescendant(forStmt(hasWaitDescendantC)),
|
||||
hasDescendant(doStmt(hasWaitDescendantC)),
|
||||
hasParent(whileStmt()),
|
||||
hasParent(compoundStmt(hasParent(whileStmt()))),
|
||||
hasParent(forStmt()),
|
||||
hasParent(compoundStmt(hasParent(forStmt()))),
|
||||
hasParent(doStmt()),
|
||||
hasParent(compoundStmt(hasParent(doStmt())))))
|
||||
|
||||
))
|
||||
|
||||
,
|
||||
this);
|
||||
}
|
||||
}
|
||||
|
||||
void SpuriouslyWakeUpFunctionsCheck::check(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
const auto *MatchedWait = Result.Nodes.getNodeAs<CallExpr>("wait");
|
||||
StringRef WaitName = MatchedWait->getDirectCallee()->getName();
|
||||
diag(MatchedWait->getExprLoc(),
|
||||
"'%0' should be placed inside a while statement %select{|or used with a "
|
||||
"conditional parameter}1")
|
||||
<< WaitName << (WaitName != "cnd_wait" && WaitName != "cnd_timedwait");
|
||||
}
|
||||
} // namespace bugprone
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
@ -0,0 +1,37 @@
|
||||
//===--- SpuriouslyWakeUpFunctionsCheck.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_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
|
||||
|
||||
#include "../ClangTidyCheck.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace bugprone {
|
||||
|
||||
/// Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
|
||||
/// ``wait_until`` function calls when the function is not invoked from a loop
|
||||
/// that checks whether a condition predicate holds or the function has a
|
||||
/// condition parameter.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-spuriously-wake-up-functions.html
|
||||
class SpuriouslyWakeUpFunctionsCheck : public ClangTidyCheck {
|
||||
public:
|
||||
SpuriouslyWakeUpFunctionsCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace bugprone
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPURIOUSLYWAKEUPFUNCTIONSCHECK_H
|
@ -11,6 +11,7 @@
|
||||
#include "../ClangTidyModuleRegistry.h"
|
||||
#include "../bugprone/BadSignalToKillThreadCheck.h"
|
||||
#include "../bugprone/ReservedIdentifierCheck.h"
|
||||
#include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
|
||||
#include "../bugprone/UnhandledSelfAssignmentCheck.h"
|
||||
#include "../google/UnnamedNamespaceInHeaderCheck.h"
|
||||
#include "../misc/NewDeleteOverloadsCheck.h"
|
||||
@ -42,6 +43,9 @@ class CERTModule : public ClangTidyModule {
|
||||
public:
|
||||
void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
|
||||
// C++ checkers
|
||||
// CON
|
||||
CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
|
||||
"cert-con54-cpp");
|
||||
// DCL
|
||||
CheckFactories.registerCheck<PostfixOperatorCheck>(
|
||||
"cert-dcl21-cpp");
|
||||
@ -80,6 +84,9 @@ public:
|
||||
"cert-oop58-cpp");
|
||||
|
||||
// C checkers
|
||||
// CON
|
||||
CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
|
||||
"cert-con36-c");
|
||||
// DCL
|
||||
CheckFactories.registerCheck<misc::StaticAssertCheck>("cert-dcl03-c");
|
||||
CheckFactories.registerCheck<readability::UppercaseLiteralSuffixCheck>(
|
||||
|
@ -87,6 +87,14 @@ New checks
|
||||
result of a memory allocation function (``malloc()``, ``calloc()``,
|
||||
``realloc()``, ``alloca()``) instead of its argument.
|
||||
|
||||
- New :doc:`bugprone-spuriously-wake-up-functions
|
||||
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` check.
|
||||
|
||||
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
|
||||
``wait_until`` function calls when the function is not invoked from a loop
|
||||
that checks whether a condition predicate holds or the function has a
|
||||
condition parameter.
|
||||
|
||||
- New :doc:`bugprone-reserved-identifier
|
||||
<clang-tidy/checks/bugprone-reserved-identifier>` check.
|
||||
|
||||
@ -124,6 +132,16 @@ New checks
|
||||
New check aliases
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
- New alias :doc:`cert-con36-c
|
||||
<clang-tidy/checks/cert-con36-c>` to
|
||||
:doc:`bugprone-spuriously-wake-up-functions
|
||||
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
|
||||
|
||||
- New alias :doc:`cert-con54-cpp
|
||||
<clang-tidy/checks/cert-con54-cpp>` to
|
||||
:doc:`bugprone-spuriously-wake-up-functions
|
||||
<clang-tidy/checks/bugprone-spuriously-wake-up-functions>` was added.
|
||||
|
||||
- New alias :doc:`cert-dcl37-c
|
||||
<clang-tidy/checks/cert-dcl37-c>` to
|
||||
:doc:`bugprone-reserved-identifier
|
||||
|
@ -0,0 +1,29 @@
|
||||
.. title:: clang-tidy - bugprone-spuriously-wake-up-functions
|
||||
|
||||
bugprone-spuriously-wake-up-functions
|
||||
=====================================
|
||||
|
||||
Finds ``cnd_wait``, ``cnd_timedwait``, ``wait``, ``wait_for``, or
|
||||
``wait_until`` function calls when the function is not invoked from a loop
|
||||
that checks whether a condition predicate holds or the function has a
|
||||
condition parameter.
|
||||
|
||||
.. code-block: c++
|
||||
|
||||
if (condition_predicate) {
|
||||
condition.wait(lk);
|
||||
}
|
||||
|
||||
.. code-block: c
|
||||
|
||||
if (condition_predicate) {
|
||||
if (thrd_success != cnd_wait(&condition, &lock)) {
|
||||
}
|
||||
}
|
||||
|
||||
This check corresponds to the CERT C++ Coding Standard rule
|
||||
`CON54-CPP. Wrap functions that can spuriously wake up in a loop
|
||||
<https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON54-CPP.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.
|
||||
and CERT C Coding Standard rule
|
||||
`CON36-C. Wrap functions that can spuriously wake up in a loop
|
||||
<https://wiki.sei.cmu.edu/confluence/display/c/CON36-C.+Wrap+functions+that+can+spuriously+wake+up+in+a+loop>`_.
|
10
clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
Normal file
10
clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
Normal file
@ -0,0 +1,10 @@
|
||||
.. title:: clang-tidy - cert-con36-c
|
||||
.. meta::
|
||||
:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
|
||||
|
||||
cert-con36-c
|
||||
============
|
||||
|
||||
The cert-con36-c check is an alias, please see
|
||||
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_
|
||||
for more information.
|
10
clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
Normal file
10
clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
Normal file
@ -0,0 +1,10 @@
|
||||
.. title:: clang-tidy - cert-con54-cpp
|
||||
.. meta::
|
||||
:http-equiv=refresh: 5;URL=bugprone-spuriously-wake-up-functions.html
|
||||
|
||||
cert-con54-cpp
|
||||
==============
|
||||
|
||||
The cert-con54-cpp check is an alias, please see
|
||||
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_
|
||||
for more information.
|
@ -76,6 +76,7 @@ Clang-Tidy Checks
|
||||
`bugprone-signed-char-misuse <bugprone-signed-char-misuse.html>`_,
|
||||
`bugprone-sizeof-container <bugprone-sizeof-container.html>`_,
|
||||
`bugprone-sizeof-expression <bugprone-sizeof-expression.html>`_,
|
||||
`bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
|
||||
`bugprone-string-constructor <bugprone-string-constructor.html>`_, "Yes"
|
||||
`bugprone-string-integer-assignment <bugprone-string-integer-assignment.html>`_, "Yes"
|
||||
`bugprone-string-literal-with-embedded-nul <bugprone-string-literal-with-embedded-nul.html>`_,
|
||||
@ -300,6 +301,8 @@ Clang-Tidy Checks
|
||||
.. csv-table:: Aliases..
|
||||
:header: "Name", "Redirect", "Offers fixes"
|
||||
|
||||
`cert-con36-c <cert-con36-c.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
|
||||
`cert-con54-cpp <cert-con54-cpp.html>`_, `bugprone-spuriously-wake-up-functions <bugprone-spuriously-wake-up-functions.html>`_,
|
||||
`cert-dcl03-c <cert-dcl03-c.html>`_, `misc-static-assert <misc-static-assert.html>`_, "Yes"
|
||||
`cert-dcl16-c <cert-dcl16-c.html>`_, `readability-uppercase-literal-suffix <readability-uppercase-literal-suffix.html>`_, "Yes"
|
||||
`cert-dcl37-c <cert-dcl37-c.html>`_, `bugprone-reserved-identifier <bugprone-reserved-identifier.html>`_, "Yes"
|
||||
|
@ -0,0 +1,164 @@
|
||||
// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
|
||||
#define NULL 0
|
||||
|
||||
struct Node1 {
|
||||
void *Node1;
|
||||
struct Node1 *next;
|
||||
};
|
||||
|
||||
typedef struct mtx_t {
|
||||
} mtx_t;
|
||||
typedef struct cnd_t {
|
||||
} cnd_t;
|
||||
struct timespec {};
|
||||
|
||||
int cnd_wait(cnd_t *cond, mtx_t *mutex){};
|
||||
int cnd_timedwait(cnd_t *cond, mtx_t *mutex,
|
||||
const struct timespec *time_point){};
|
||||
|
||||
struct Node1 list_c;
|
||||
static mtx_t lock;
|
||||
static cnd_t condition_c;
|
||||
struct timespec ts;
|
||||
|
||||
void consume_list_element(void) {
|
||||
|
||||
if (list_c.next == NULL) {
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
}
|
||||
if (list_c.next == NULL)
|
||||
if (0 != cnd_wait(&condition_c, &lock))
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
;
|
||||
if (list_c.next == NULL && 0 != cnd_wait(&condition_c, &lock))
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
;
|
||||
while (list_c.next == NULL) {
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
if (0 != cnd_wait(&condition_c, &lock))
|
||||
;
|
||||
if (list_c.next == NULL) {
|
||||
cnd_wait(&condition_c, &lock);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
if (list_c.next == NULL)
|
||||
cnd_wait(&condition_c, &lock);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_wait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
while (list_c.next == NULL) {
|
||||
cnd_wait(&condition_c, &lock);
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
cnd_wait(&condition_c, &lock);
|
||||
|
||||
do {
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
} while (list_c.next == NULL);
|
||||
do
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
while (list_c.next == NULL);
|
||||
do
|
||||
if (0 != cnd_wait(&condition_c, &lock))
|
||||
;
|
||||
while (list_c.next == NULL);
|
||||
do {
|
||||
cnd_wait(&condition_c, &lock);
|
||||
} while (list_c.next == NULL);
|
||||
do
|
||||
cnd_wait(&condition_c, &lock);
|
||||
while (list_c.next == NULL);
|
||||
for (;; list_c.next == NULL) {
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
if (0 != cnd_wait(&condition_c, &lock)) {
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
if (0 != cnd_wait(&condition_c, &lock))
|
||||
;
|
||||
for (;; list_c.next == NULL) {
|
||||
cnd_wait(&condition_c, &lock);
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
cnd_wait(&condition_c, &lock);
|
||||
|
||||
if (list_c.next == NULL) {
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
}
|
||||
if (list_c.next == NULL)
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
;
|
||||
if (list_c.next == NULL && 0 != cnd_timedwait(&condition_c, &lock, &ts))
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
;
|
||||
while (list_c.next == NULL) {
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
|
||||
;
|
||||
if (list_c.next == NULL) {
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
if (list_c.next == NULL)
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: 'cnd_timedwait' should be placed inside a while statement [bugprone-spuriously-wake-up-functions]
|
||||
while (list_c.next == NULL) {
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
}
|
||||
while (list_c.next == NULL)
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
|
||||
do {
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
} while (list_c.next == NULL);
|
||||
do
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
while (list_c.next == NULL);
|
||||
do
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
|
||||
;
|
||||
while (list_c.next == NULL);
|
||||
do {
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
} while (list_c.next == NULL);
|
||||
do
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
while (list_c.next == NULL);
|
||||
for (;; list_c.next == NULL) {
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts)) {
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
if (0 != cnd_timedwait(&condition_c, &lock, &ts))
|
||||
;
|
||||
for (;; list_c.next == NULL) {
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
}
|
||||
for (;; list_c.next == NULL)
|
||||
cnd_timedwait(&condition_c, &lock, &ts);
|
||||
}
|
||||
int main() { return 0; }
|
@ -0,0 +1,191 @@
|
||||
// RUN: %check_clang_tidy %s bugprone-spuriously-wake-up-functions %t -- --
|
||||
#define NULL 0
|
||||
|
||||
namespace std {
|
||||
using intmax_t = int;
|
||||
|
||||
template <intmax_t N, intmax_t D = 1>
|
||||
class ratio {
|
||||
public:
|
||||
static constexpr intmax_t num = 0;
|
||||
static constexpr intmax_t den = 0;
|
||||
typedef ratio<num, den> type;
|
||||
};
|
||||
typedef ratio<1, 1000> milli;
|
||||
namespace chrono {
|
||||
|
||||
template <class Rep, class Period = ratio<1>>
|
||||
class duration {
|
||||
public:
|
||||
using rep = Rep;
|
||||
using period = Period;
|
||||
|
||||
public:
|
||||
constexpr duration() = default;
|
||||
template <class Rep2>
|
||||
constexpr explicit duration(const Rep2 &r);
|
||||
template <class Rep2, class Period2>
|
||||
constexpr duration(const duration<Rep2, Period2> &d);
|
||||
~duration() = default;
|
||||
duration(const duration &) = default;
|
||||
};
|
||||
|
||||
template <class Clock, class Duration = typename Clock::duration>
|
||||
class time_point {
|
||||
public:
|
||||
using clock = Clock;
|
||||
using duration = Duration;
|
||||
|
||||
public:
|
||||
constexpr time_point();
|
||||
constexpr explicit time_point(const duration &d);
|
||||
template <class Duration2>
|
||||
constexpr time_point(const time_point<clock, Duration2> &t);
|
||||
};
|
||||
|
||||
using milliseconds = duration<int, milli>;
|
||||
|
||||
class system_clock {
|
||||
public:
|
||||
typedef milliseconds duration;
|
||||
typedef duration::rep rep;
|
||||
typedef duration::period period;
|
||||
typedef chrono::time_point<system_clock> time_point;
|
||||
|
||||
static time_point now() noexcept;
|
||||
};
|
||||
} // namespace chrono
|
||||
|
||||
class mutex;
|
||||
template <class Mutex>
|
||||
class unique_lock {
|
||||
public:
|
||||
typedef Mutex mutex_type;
|
||||
|
||||
unique_lock() noexcept;
|
||||
explicit unique_lock(mutex_type &m);
|
||||
};
|
||||
|
||||
class mutex {
|
||||
public:
|
||||
constexpr mutex() noexcept;
|
||||
~mutex();
|
||||
mutex(const mutex &) = delete;
|
||||
mutex &operator=(const mutex &) = delete;
|
||||
};
|
||||
|
||||
enum class cv_status {
|
||||
no_timeout,
|
||||
timeout
|
||||
};
|
||||
|
||||
class condition_variable {
|
||||
public:
|
||||
condition_variable();
|
||||
~condition_variable();
|
||||
condition_variable(const condition_variable &) = delete;
|
||||
|
||||
void wait(unique_lock<mutex> &lock);
|
||||
template <class Predicate>
|
||||
void wait(unique_lock<mutex> &lock, Predicate pred);
|
||||
template <class Clock, class Duration>
|
||||
cv_status wait_until(unique_lock<mutex> &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time){};
|
||||
template <class Clock, class Duration, class Predicate>
|
||||
bool wait_until(unique_lock<mutex> &lock,
|
||||
const chrono::time_point<Clock, Duration> &abs_time,
|
||||
Predicate pred){};
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(unique_lock<mutex> &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time){};
|
||||
template <class Rep, class Period, class Predicate>
|
||||
bool wait_for(unique_lock<mutex> &lock,
|
||||
const chrono::duration<Rep, Period> &rel_time,
|
||||
Predicate pred){};
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
struct Node1 {
|
||||
void *Node1;
|
||||
struct Node1 *next;
|
||||
};
|
||||
|
||||
static Node1 list;
|
||||
static std::mutex m;
|
||||
static std::condition_variable condition;
|
||||
|
||||
void consume_list_element(std::condition_variable &condition) {
|
||||
std::unique_lock<std::mutex> lk(m);
|
||||
|
||||
if (list.next == nullptr) {
|
||||
condition.wait(lk);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
|
||||
while (list.next == nullptr) {
|
||||
condition.wait(lk);
|
||||
}
|
||||
|
||||
do {
|
||||
condition.wait(lk);
|
||||
} while (list.next == nullptr);
|
||||
|
||||
for (;; list.next == nullptr) {
|
||||
condition.wait(lk);
|
||||
}
|
||||
|
||||
if (list.next == nullptr) {
|
||||
while (list.next == nullptr) {
|
||||
condition.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
if (list.next == nullptr) {
|
||||
do {
|
||||
condition.wait(lk);
|
||||
} while (list.next == nullptr);
|
||||
}
|
||||
|
||||
if (list.next == nullptr) {
|
||||
for (;; list.next == nullptr) {
|
||||
condition.wait(lk);
|
||||
}
|
||||
}
|
||||
using durtype = std::chrono::duration<int, std::milli>;
|
||||
durtype dur = std::chrono::duration<int, std::milli>();
|
||||
if (list.next == nullptr) {
|
||||
condition.wait_for(lk, dur);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_for' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
if (list.next == nullptr) {
|
||||
condition.wait_for(lk, dur, [] { return 1; });
|
||||
}
|
||||
while (list.next == nullptr) {
|
||||
condition.wait_for(lk, dur);
|
||||
}
|
||||
do {
|
||||
condition.wait_for(lk, dur);
|
||||
} while (list.next == nullptr);
|
||||
for (;; list.next == nullptr) {
|
||||
condition.wait_for(lk, dur);
|
||||
}
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
if (list.next == nullptr) {
|
||||
condition.wait_until(lk, now);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: 'wait_until' should be placed inside a while statement or used with a conditional parameter [bugprone-spuriously-wake-up-functions]
|
||||
}
|
||||
if (list.next == nullptr) {
|
||||
condition.wait_until(lk, now, [] { return 1; });
|
||||
}
|
||||
while (list.next == nullptr) {
|
||||
condition.wait_until(lk, now);
|
||||
}
|
||||
do {
|
||||
condition.wait_until(lk, now);
|
||||
} while (list.next == nullptr);
|
||||
for (;; list.next == nullptr) {
|
||||
condition.wait_until(lk, now);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user