[clang-tools-extra] r267009 - [clang-tidy] Add new checker for comparison with runtime string functions.

Etienne Bergeron via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 21 10:19:36 PDT 2016


Author: etienneb
Date: Thu Apr 21 12:19:36 2016
New Revision: 267009

URL: http://llvm.org/viewvc/llvm-project?rev=267009&view=rev
Log:
[clang-tidy] Add new checker for comparison with runtime string functions.

Summary:
This checker is validating suspicious usage of string compare functions.

Example:
```
  if (strcmp(...))       // Implicitly compare to zero
  if (!strcmp(...))      // Won't warn
  if (strcmp(...) != 0)  // Won't warn
```

This patch was checked over large amount of code.
There is three checks:
  [*] Implicit comparator to zero (coding-style, many warnings found),
  [*] Suspicious implicit cast to non-integral (bugs!?, almost none found),
  [*] Comparison to suspicious constant (bugs!?, found two cases),

Example:
[[https://github.com/kylepjohnson/sigma/blob/master/sigma/native-installers/debian/dependencies/files/opt/sigma/E/HEURISTICS/che_to_precgen.c |
https://github.com/kylepjohnson/sigma/blob/master/sigma/native-installers/debian/dependencies/files/opt/sigma/E/HEURISTICS/che_to_precgen.c]]

```
      else if(strcmp(id, "select") == 0)
      {
         array->array[i].key1 = 25;
      }
      else if(strcmp(id, "sk") == 28)      // BUG!?
      {
         array->array[i].key1 = 20;
      }
```

Reviewers: alexfh

Subscribers: Eugene.Zelenko, cfe-commits

Differential Revision: http://reviews.llvm.org/D18703

Added:
    clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp
    clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst
    clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c
    clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt?rev=267009&r1=267008&r2=267009&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt Thu Apr 21 12:19:36 2016
@@ -29,6 +29,7 @@ add_clang_library(clangTidyMiscModule
   StringLiteralWithEmbeddedNulCheck.cpp
   SuspiciousMissingCommaCheck.cpp
   SuspiciousSemicolonCheck.cpp
+  SuspiciousStringCompareCheck.cpp
   SwappedArgumentsCheck.cpp
   ThrowByValueCatchByReferenceCheck.cpp
   UndelegatedConstructor.cpp

Modified: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp?rev=267009&r1=267008&r2=267009&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp Thu Apr 21 12:19:36 2016
@@ -37,6 +37,7 @@
 #include "StringLiteralWithEmbeddedNulCheck.h"
 #include "SuspiciousMissingCommaCheck.h"
 #include "SuspiciousSemicolonCheck.h"
+#include "SuspiciousStringCompareCheck.h"
 #include "SwappedArgumentsCheck.h"
 #include "ThrowByValueCatchByReferenceCheck.h"
 #include "UndelegatedConstructor.h"
@@ -106,6 +107,8 @@ public:
         "misc-suspicious-missing-comma");
     CheckFactories.registerCheck<SuspiciousSemicolonCheck>(
         "misc-suspicious-semicolon");
+    CheckFactories.registerCheck<SuspiciousStringCompareCheck>(
+        "misc-suspicious-string-compare");    
     CheckFactories.registerCheck<SwappedArgumentsCheck>(
         "misc-swapped-arguments");
     CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(

Added: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp?rev=267009&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.cpp Thu Apr 21 12:19:36 2016
@@ -0,0 +1,221 @@
+//===--- SuspiciousStringCompareCheck.cpp - clang-tidy---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousStringCompareCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+AST_MATCHER(BinaryOperator, isComparisonOperator) {
+  return Node.isComparisonOp();
+}
+
+constexpr char KnownStringCompareFunctions[] = "__builtin_memcmp;"
+                                               "__builtin_strcasecmp;"
+                                               "__builtin_strcmp;"
+                                               "__builtin_strncasecmp;"
+                                               "__builtin_strncmp;"
+                                               "_mbscmp;"
+                                               "_mbscmp_l;"
+                                               "_mbsicmp;"
+                                               "_mbsicmp_l;"
+                                               "_mbsnbcmp;"
+                                               "_mbsnbcmp_l;"
+                                               "_mbsnbicmp;"
+                                               "_mbsnbicmp_l;"
+                                               "_mbsncmp;"
+                                               "_mbsncmp_l;"
+                                               "_mbsnicmp;"
+                                               "_mbsnicmp_l;"
+                                               "_memicmp;"
+                                               "_memicmp_l;"
+                                               "_stricmp;"
+                                               "_stricmp_l;"
+                                               "_strnicmp;"
+                                               "_strnicmp_l;"
+                                               "_wcsicmp;"
+                                               "_wcsicmp_l;"
+                                               "_wcsnicmp;"
+                                               "_wcsnicmp_l;"
+                                               "lstrcmp;"
+                                               "lstrcmpi;"
+                                               "memcmp;"
+                                               "memicmp;"
+                                               "strcasecmp;"
+                                               "strcmp;"
+                                               "strcmpi;"
+                                               "stricmp;"
+                                               "strncasecmp;"
+                                               "strncmp;"
+                                               "strnicmp;"
+                                               "wcscasecmp;"
+                                               "wcscmp;"
+                                               "wcsicmp;"
+                                               "wcsncmp;"
+                                               "wcsnicmp;"
+                                               "wmemcmp;";
+
+static const char StringCompareLikeFunctionsDelimiter[] = ";";
+
+static void ParseFunctionNames(StringRef Option,
+                               std::vector<std::string> *Result) {
+  SmallVector<StringRef, 4> Functions;
+  Option.split(Functions, StringCompareLikeFunctionsDelimiter);
+  for (StringRef &Function : Functions) {
+    Function = Function.trim();
+    if (!Function.empty())
+      Result->push_back(Function);
+  }
+}
+
+SuspiciousStringCompareCheck::SuspiciousStringCompareCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      WarnOnImplicitComparison(Options.get("WarnOnImplicitComparison", 1)),
+      WarnOnLogicalNotComparison(Options.get("WarnOnLogicalNotComparison", 1)),
+      StringCompareLikeFunctions(
+          Options.get("StringCompareLikeFunctions", "")) {}
+
+void SuspiciousStringCompareCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "WarnOnImplicitComparison", WarnOnImplicitComparison);
+  Options.store(Opts, "WarnOnLogicalNotComparison", WarnOnLogicalNotComparison);
+  Options.store(Opts, "StringCompareLikeFunctions", StringCompareLikeFunctions);
+}
+
+void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) {
+  // Match relational operators.
+  const auto ComparisonUnaryOperator = unaryOperator(hasOperatorName("!"));
+  const auto ComparisonBinaryOperator = binaryOperator(isComparisonOperator());
+  const auto ComparisonOperator =
+      expr(anyOf(ComparisonUnaryOperator, ComparisonBinaryOperator));
+
+  // Add the list of known string compare-like functions and add user-defined
+  // functions.
+  std::vector<std::string> FunctionNames;
+  ParseFunctionNames(KnownStringCompareFunctions, &FunctionNames);
+  ParseFunctionNames(StringCompareLikeFunctions, &FunctionNames);
+  const auto FunctionCompareDecl =
+      functionDecl(hasAnyName(std::vector<StringRef>(FunctionNames.begin(),
+                                                     FunctionNames.end())))
+          .bind("decl");
+
+  // Match a call to a string compare functions.
+  const auto StringCompareCallExpr =
+      callExpr(hasDeclaration(FunctionCompareDecl)).bind("call");
+
+  if (WarnOnImplicitComparison) {
+    // Detect suspicious calls to string compare (missing comparator) [only C]:
+    //     'if (strcmp())'  ->  'if (strcmp() != 0)'
+    Finder->addMatcher(
+        stmt(anyOf(ifStmt(hasCondition(StringCompareCallExpr)),
+                   whileStmt(hasCondition(StringCompareCallExpr)),
+                   doStmt(hasCondition(StringCompareCallExpr)),
+                   forStmt(hasCondition(StringCompareCallExpr))))
+            .bind("missing-comparison"),
+        this);
+
+    Finder->addMatcher(expr(StringCompareCallExpr,
+                            unless(hasParent(ComparisonOperator)),
+                            unless(hasParent(implicitCastExpr())))
+                           .bind("missing-comparison"),
+                       this);
+
+    // Detect suspicious calls to string compare with implicit comparison:
+    //     'if (strcmp())'  ->  'if (strcmp() != 0)'
+    //     'if (!strcmp())' is considered valid (see WarnOnLogicalNotComparison)
+    Finder->addMatcher(
+        implicitCastExpr(hasType(isInteger()),
+                         hasSourceExpression(StringCompareCallExpr),
+                         unless(hasParent(ComparisonOperator)))
+            .bind("missing-comparison"),
+        this);
+
+    // Detect suspicious cast to an inconsistant type.
+    Finder->addMatcher(
+        implicitCastExpr(unless(hasType(isInteger())),
+                         hasSourceExpression(StringCompareCallExpr))
+            .bind("invalid-conversion"),
+        this);
+  }
+
+  if (WarnOnLogicalNotComparison) {
+    // Detect suspicious calls to string compared with '!' operator:
+    //     'if (!strcmp())'  ->  'if (strcmp() == 0)'
+    Finder->addMatcher(unaryOperator(hasOperatorName("!"),
+                                     hasUnaryOperand(ignoringParenImpCasts(
+                                         StringCompareCallExpr)))
+                           .bind("logical-not-comparison"),
+                       this);
+  }
+
+  // Detect suspicious calls to string compare functions: 'strcmp() == -1'.
+  const auto InvalidLiteral = ignoringParenImpCasts(
+      anyOf(integerLiteral(unless(equals(0))),
+            unaryOperator(hasOperatorName("-"),
+                          has(integerLiteral(unless(equals(0))))),
+            characterLiteral(), cxxBoolLiteral()));
+
+  Finder->addMatcher(binaryOperator(isComparisonOperator(),
+                                    hasEitherOperand(StringCompareCallExpr),
+                                    hasEitherOperand(InvalidLiteral))
+                         .bind("invalid-comparison"),
+                     this);
+}
+
+void SuspiciousStringCompareCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *Decl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+  const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
+  assert(Decl != nullptr && Call != nullptr);
+
+  if (Result.Nodes.getNodeAs<Stmt>("missing-comparison")) {
+    SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+        Call->getRParenLoc(), 0, Result.Context->getSourceManager(),
+        Result.Context->getLangOpts());
+
+    diag(Call->getLocStart(),
+         "function %0 is called without explicitly comparing result")
+        << Decl << FixItHint::CreateInsertion(EndLoc, " != 0");
+  }
+
+  if (const auto *E = Result.Nodes.getNodeAs<Expr>("logical-not-comparison")) {
+    SourceLocation EndLoc = Lexer::getLocForEndOfToken(
+        Call->getRParenLoc(), 0, Result.Context->getSourceManager(),
+        Result.Context->getLangOpts());
+    SourceLocation NotLoc = E->getLocStart();
+
+    diag(Call->getLocStart(),
+         "function %0 is compared using logical not operator")
+        << Decl << FixItHint::CreateRemoval(
+                       CharSourceRange::getTokenRange(NotLoc, NotLoc))
+        << FixItHint::CreateInsertion(EndLoc, " == 0");
+  }
+
+  if (Result.Nodes.getNodeAs<Stmt>("invalid-comparison")) {
+    diag(Call->getLocStart(),
+         "function %0 is compared to a suspicious constant")
+        << Decl;
+  }
+
+  if (Result.Nodes.getNodeAs<Stmt>("invalid-conversion")) {
+    diag(Call->getLocStart(), "function %0 has suspicious implicit cast")
+        << Decl;
+  }
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h?rev=267009&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/SuspiciousStringCompareCheck.h Thu Apr 21 12:19:36 2016
@@ -0,0 +1,40 @@
+//===--- SuspiciousStringCompareCheck.h - clang-tidy-------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Find suspicious calls to string compare functions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-suspicious-string-compare.html
+class SuspiciousStringCompareCheck : public ClangTidyCheck {
+public:
+  SuspiciousStringCompareCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  const bool WarnOnImplicitComparison;
+  const bool WarnOnLogicalNotComparison;
+  const std::string StringCompareLikeFunctions;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=267009&r1=267008&r2=267009&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Thu Apr 21 12:19:36 2016
@@ -73,6 +73,7 @@ Clang-Tidy Checks
    misc-string-literal-with-embedded-nul
    misc-suspicious-missing-comma
    misc-suspicious-semicolon
+   misc-suspicious-string-compare   
    misc-swapped-arguments
    misc-throw-by-value-catch-by-reference
    misc-undelegated-constructor

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst?rev=267009&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-suspicious-string-compare.rst Thu Apr 21 12:19:36 2016
@@ -0,0 +1,40 @@
+.. title:: clang-tidy - misc-suspicious-string-compare
+
+misc-suspicious-string-compare
+==============================
+
+Find suspicious usage of runtime string comparison functions.
+This check is valid in C and C++.
+
+Checks for calls with implicit comparator and proposed to explicitly add it.
+
+.. code:: c++
+
+    if (strcmp(...))       // Implicitly compare to zero
+    if (!strcmp(...))      // Won't warn
+    if (strcmp(...) != 0)  // Won't warn
+
+
+Checks that compare function results (i,e, ``strcmp``) are compared to valid
+constant. The resulting value is
+
+.. code::
+
+    <  0    when lower than,
+    >  0    when greater than,
+    == 0    when equals.
+
+A common mistake is to compare the result to '1' or '-1'. 
+
+.. code:: c++
+
+    if (strcmp(...) == -1)  // Incorrect usage of the returned value.
+
+
+Additionally, the check warns if the results value is implicitly cast to a
+*suspicious* non-integer type. It's happening when the returned value is used in
+a wrong context.
+
+.. code:: c++
+
+    if (strcmp(...) < 0.)  // Incorrect usage of the returned value.

Added: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c?rev=267009&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c (added)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.c Thu Apr 21 12:19:36 2016
@@ -0,0 +1,66 @@
+// RUN: %check_clang_tidy %s misc-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: misc-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN:   {key: misc-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: -- -std=c99
+
+static const char A[] = "abc";
+
+int strcmp(const char *, const char *);
+
+int test_warning_patterns() {
+  if (strcmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [misc-suspicious-string-compare]
+  // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+  if (strcmp(A, "a") != 0 ||
+      strcmp(A, "b"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: strcmp(A, "b") != 0)
+
+  if (strcmp(A, "a") == 1)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") == -1)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") < '0')
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") < 0.)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+
+  if (!strcmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:8: warning: function 'strcmp' is compared using logical not operator
+  // CHECK-FIXES: if (strcmp(A, "a") == 0)
+}
+
+void test_structure_patterns() {
+  if (strcmp(A, "a")) {}
+  // CHECK-MESSAGES: [[@LINE-1]]:7: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: if (strcmp(A, "a") != 0) {}
+
+  while (strcmp(A, "a")) {}
+  // CHECK-MESSAGES: [[@LINE-1]]:10: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: while (strcmp(A, "a") != 0) {}
+
+  for (;strcmp(A, "a");) {}
+  // CHECK-MESSAGES: [[@LINE-1]]:9: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: for (;strcmp(A, "a") != 0;) {}
+}
+
+int test_valid_patterns() {
+  // The following cases are valid.
+  if (strcmp(A, "a") < 0) return 0;
+  if (strcmp(A, "a") == 0) return 0;
+  if (strcmp(A, "a") <= 0) return 0;
+  if (strcmp(A, "a") == strcmp(A, "b")) return 0;
+  return 1;
+}

Added: clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp?rev=267009&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-suspicious-string-compare.cpp Thu Apr 21 12:19:36 2016
@@ -0,0 +1,299 @@
+// RUN: %check_clang_tidy %s misc-suspicious-string-compare %t -- \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: misc-suspicious-string-compare.WarnOnImplicitComparison, value: 1}, \
+// RUN:   {key: misc-suspicious-string-compare.WarnOnLogicalNotComparison, value: 1}]}' \
+// RUN: --
+
+typedef __SIZE_TYPE__ size;
+
+struct locale_t {
+  void* dummy;
+} locale;
+
+static const char A[] = "abc";
+static const unsigned char U[] = "abc";
+static const unsigned char V[] = "xyz";
+static const wchar_t W[] = L"abc";
+
+int memcmp(const void *, const void *, size);
+int wmemcmp(const wchar_t *, const wchar_t *, size);
+int memicmp(const void *, const void *, size);
+int _memicmp(const void *, const void *, size);
+int _memicmp_l(const void *, const void *, size, locale_t);
+
+int strcmp(const char *, const char *);
+int strncmp(const char *, const char *, size);
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size);
+int stricmp(const char *, const char *);
+int strcmpi(const char *, const char *);
+int strnicmp(const char *, const char *, size);
+int _stricmp(const char *, const char * );
+int _strnicmp(const char *, const char *, size);
+int _stricmp_l(const char *, const char *, locale_t);
+int _strnicmp_l(const char *, const char *, size, locale_t);
+
+int wcscmp(const wchar_t *, const wchar_t *);
+int wcsncmp(const wchar_t *, const wchar_t *, size);
+int wcscasecmp(const wchar_t *, const wchar_t *);
+int wcsicmp(const wchar_t *, const wchar_t *);
+int wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp(const wchar_t *, const wchar_t *);
+int _wcsnicmp(const wchar_t *, const wchar_t *, size);
+int _wcsicmp_l(const wchar_t *, const wchar_t *, locale_t);
+int _wcsnicmp_l(const wchar_t *, const wchar_t *, size, locale_t);
+
+int _mbscmp(const unsigned char *, const unsigned char *);
+int _mbsncmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbcmp(const unsigned char *, const unsigned char *, size);
+int _mbsnbicmp(const unsigned char *, const unsigned char *, size);
+int _mbsicmp(const unsigned char *, const unsigned char *);
+int _mbsnicmp(const unsigned char *, const unsigned char *, size);
+int _mbscmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsncmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsicmp_l(const unsigned char *, const unsigned char *, locale_t);
+int _mbsnicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbcmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+int _mbsnbicmp_l(const unsigned char *, const unsigned char *, size, locale_t);
+
+int test_warning_patterns() {
+  if (strcmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [misc-suspicious-string-compare]
+  // CHECK-FIXES: if (strcmp(A, "a") != 0)
+
+  if (strcmp(A, "a") == 0 ||
+      strcmp(A, "b"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: strcmp(A, "b") != 0)
+
+  if (strcmp(A, "a") == 1)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") == -1)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") == true)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") < '0')
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant
+
+  if (strcmp(A, "a") < 0.)
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast
+}
+
+int test_valid_patterns() {
+  // The following cases are valid.
+  if (strcmp(A, "a") < 0)
+    return 0;
+  if (strcmp(A, "a") == 0)
+    return 0;
+  if (strcmp(A, "a") <= 0)
+    return 0;
+
+  if (wcscmp(W, L"a") < 0)
+    return 0;
+  if (wcscmp(W, L"a") == 0)
+    return 0;
+  if (wcscmp(W, L"a") <= 0)
+    return 0;
+
+  return 1;
+}
+
+int test_implicit_compare_with_functions() {
+
+  if (memcmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memcmp' is called without explicitly comparing result
+  // CHECK-FIXES: memcmp(A, "a", 1) != 0)
+
+  if (wmemcmp(W, L"a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wmemcmp' is called without explicitly comparing result
+  // CHECK-FIXES: wmemcmp(W, L"a", 1) != 0)
+
+  if (memicmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'memicmp' is called without explicitly comparing result
+  // CHECK-FIXES: memicmp(A, "a", 1) != 0)
+
+  if (_memicmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _memicmp(A, "a", 1) != 0)
+
+  if (_memicmp_l(A, "a", 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_memicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _memicmp_l(A, "a", 1, locale) != 0)
+
+  if (strcmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result
+  // CHECK-FIXES: strcmp(A, "a") != 0)
+
+  if (strncmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncmp' is called without explicitly comparing result
+  // CHECK-FIXES: strncmp(A, "a", 1) != 0)
+
+  if (strcasecmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcasecmp' is called without explicitly comparing result
+  // CHECK-FIXES: strcasecmp(A, "a") != 0)
+
+  if (strncasecmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strncasecmp' is called without explicitly comparing result
+  // CHECK-FIXES: strncasecmp(A, "a", 1) != 0)
+
+  if (stricmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'stricmp' is called without explicitly comparing result
+  // CHECK-FIXES: stricmp(A, "a") != 0)
+
+  if (strcmpi(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmpi' is called without explicitly comparing result
+  // CHECK-FIXES: strcmpi(A, "a") != 0)
+
+  if (_stricmp(A, "a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp' is called without explicitly comparing result
+  // CHECK-FIXES: _stricmp(A, "a") != 0)
+
+  if (strnicmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strnicmp' is called without explicitly comparing result
+  // CHECK-FIXES: strnicmp(A, "a", 1) != 0)
+
+  if (_strnicmp(A, "a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _strnicmp(A, "a", 1) != 0)
+
+  if (_stricmp_l(A, "a", locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_stricmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _stricmp_l(A, "a", locale) != 0)
+
+  if (_strnicmp_l(A, "a", 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_strnicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _strnicmp_l(A, "a", 1, locale) != 0)
+
+  if (wcscmp(W, L"a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscmp' is called without explicitly comparing result
+  // CHECK-FIXES: wcscmp(W, L"a") != 0)
+
+  if (wcsncmp(W, L"a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsncmp' is called without explicitly comparing result
+  // CHECK-FIXES: wcsncmp(W, L"a", 1) != 0)
+
+  if (wcscasecmp(W, L"a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcscasecmp' is called without explicitly comparing result
+  // CHECK-FIXES: wcscasecmp(W, L"a") != 0)
+
+  if (wcsicmp(W, L"a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsicmp' is called without explicitly comparing result
+  // CHECK-FIXES: wcsicmp(W, L"a") != 0)
+
+  if (_wcsicmp(W, L"a"))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _wcsicmp(W, L"a") != 0)
+
+  if (_wcsicmp_l(W, L"a", locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _wcsicmp_l(W, L"a", locale) != 0)
+
+  if (wcsnicmp(W, L"a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'wcsnicmp' is called without explicitly comparing result
+  // CHECK-FIXES: wcsnicmp(W, L"a", 1) != 0)
+
+  if (_wcsnicmp(W, L"a", 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _wcsnicmp(W, L"a", 1) != 0)
+
+  if (_wcsnicmp_l(W, L"a", 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_wcsnicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _wcsnicmp_l(W, L"a", 1, locale) != 0)
+
+  if (_mbscmp(U, V))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbscmp(U, V) != 0)
+
+  if (_mbsncmp(U, V, 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsncmp(U, V, 1) != 0)
+
+  if (_mbsnbcmp(U, V, 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnbcmp(U, V, 1) != 0)
+
+  if (_mbsnbicmp(U, V, 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnbicmp(U, V, 1) != 0)
+
+  if (_mbsicmp(U, V))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsicmp(U, V) != 0)
+
+  if (_mbsnicmp(U, V, 1))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnicmp(U, V, 1) != 0)
+
+  if (_mbscmp_l(U, V, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbscmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbscmp_l(U, V, locale) != 0)
+
+  if (_mbsncmp_l(U, V, 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsncmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsncmp_l(U, V, 1, locale) != 0)
+
+  if (_mbsicmp_l(U, V, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsicmp_l(U, V, locale) != 0)
+
+  if (_mbsnicmp_l(U, V, 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnicmp_l(U, V, 1, locale) != 0)
+
+  if (_mbsnbcmp_l(U, V, 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbcmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnbcmp_l(U, V, 1, locale) != 0)
+
+  if (_mbsnbicmp_l(U, V, 1, locale))
+    return 0;
+  // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function '_mbsnbicmp_l' is called without explicitly comparing result
+  // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0)
+
+  return 1;
+}




More information about the cfe-commits mailing list