[clang-tools-extra] 0f4c70d - [clang-tidy] Add spuriously-wake-up-functions check
via cfe-commits
cfe-commits at lists.llvm.org
Sat Mar 21 04:04:41 PDT 2020
Author: abelkocsis
Date: 2020-03-21T12:04:03+01:00
New Revision: 0f4c70dd3ec6d7ee831f868e3e483273daec18f0
URL: https://github.com/llvm/llvm-project/commit/0f4c70dd3ec6d7ee831f868e3e483273daec18f0
DIFF: https://github.com/llvm/llvm-project/commit/0f4c70dd3ec6d7ee831f868e3e483273daec18f0.diff
LOG: [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
Added:
clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.c
clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.cpp
Modified:
clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
clang-tools-extra/docs/ReleaseNotes.rst
clang-tools-extra/docs/clang-tidy/checks/list.rst
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 9dcb315a257a..d010c3ce7e52 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -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 @@ class BugproneModule : public ClangTidyModule {
"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>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index a24f3bc7eb0d..4aa3b325ce24 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -33,6 +33,7 @@ add_clang_library(clangTidyBugproneModule
SignedCharMisuseCheck.cpp
SizeofContainerCheck.cpp
SizeofExpressionCheck.cpp
+ SpuriouslyWakeUpFunctionsCheck.cpp
StringConstructorCheck.cpp
StringIntegerAssignmentCheck.cpp
StringLiteralWithEmbeddedNulCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.cpp
new file mode 100644
index 000000000000..844d672f121f
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.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
diff --git a/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
new file mode 100644
index 000000000000..d2d3745769f7
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SpuriouslyWakeUpFunctionsCheck.h
@@ -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
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index 226526d31970..6459dcf5627d 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -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 @@ class CERTModule : public ClangTidyModule {
"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>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 3b9212f6723c..745a1d1035ed 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -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
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
new file mode 100644
index 000000000000..17b81e13f579
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone-spuriously-wake-up-functions.rst
@@ -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>`_.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
new file mode 100644
index 000000000000..54fecfc2e90d
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert-con36-c.rst
@@ -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.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst b/clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
new file mode 100644
index 000000000000..3dbe89517474
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert-con54-cpp.rst
@@ -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.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 37f020d6018f..333a7ea4d5b4 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -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"
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.c
new file mode 100644
index 000000000000..fd3b94081c20
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.c
@@ -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; }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.cpp
new file mode 100644
index 000000000000..6db92ef939fa
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone-spuriously-wake-up-functions.cpp
@@ -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);
+ }
+}
More information about the cfe-commits
mailing list