[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