Index: clang-tidy/misc/CMakeLists.txt =================================================================== --- clang-tidy/misc/CMakeLists.txt +++ clang-tidy/misc/CMakeLists.txt @@ -25,6 +25,7 @@ StringIntegerAssignmentCheck.cpp SuspiciousMissingCommaCheck.cpp SuspiciousSemicolonCheck.cpp + SuspiciousStringCompareCheck.cpp SwappedArgumentsCheck.cpp ThrowByValueCatchByReferenceCheck.cpp UndelegatedConstructor.cpp Index: clang-tidy/misc/MiscTidyModule.cpp =================================================================== --- clang-tidy/misc/MiscTidyModule.cpp +++ clang-tidy/misc/MiscTidyModule.cpp @@ -33,6 +33,7 @@ #include "StringIntegerAssignmentCheck.h" #include "SuspiciousMissingCommaCheck.h" #include "SuspiciousSemicolonCheck.h" +#include "SuspiciousStringCompareCheck.h" #include "SwappedArgumentsCheck.h" #include "ThrowByValueCatchByReferenceCheck.h" #include "UndelegatedConstructor.h" @@ -93,6 +94,8 @@ "misc-suspicious-missing-comma"); CheckFactories.registerCheck( "misc-suspicious-semicolon"); + CheckFactories.registerCheck( + "misc-suspicious-string-compare"); CheckFactories.registerCheck( "misc-swapped-arguments"); CheckFactories.registerCheck( Index: clang-tidy/misc/SuspiciousStringCompareCheck.h =================================================================== --- /dev/null +++ clang-tidy/misc/SuspiciousStringCompareCheck.h @@ -0,0 +1,35 @@ +//===--- 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) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace misc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SUSPICIOUS_STRING_COMPARE_H Index: clang-tidy/misc/SuspiciousStringCompareCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/misc/SuspiciousStringCompareCheck.cpp @@ -0,0 +1,139 @@ +//===--- 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 { + +void SuspiciousStringCompareCheck::registerMatchers(MatchFinder *Finder) { + // Match a call to a string compare functions. + const auto StringCompareCallExpr = + callExpr(hasDeclaration(functionDecl( + hasAnyName("__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", + "memcmp", + "memicmp", + "strcasecmp", + "strcmp", + "strcmpi", + "stricmp", + "strncasecmp", + "strncmp", + "strnicmp", + "wcscasecmp", + "wcscmp", + "wcsicmp", + "wcsncmp", + "wcsnicmp", + "wmemcmp")).bind("decl"))).bind("call"); + + // Detect suspicious calls to string compare with implicit comparison: + // 'if (strcmp())' -> 'if (strcmp() != 0)' + // 'if (!strcmp())' is considered valid. + Finder->addMatcher( + implicitCastExpr(hasType(isInteger()), + hasSourceExpression(StringCompareCallExpr), + unless(hasParent(unaryOperator(hasOperatorName("!"))))) + .bind("missing-comparison"), + this); + + // Detect suspicious cast to an inconsistant type. + Finder->addMatcher( + implicitCastExpr(unless(hasType(isInteger())), + hasSourceExpression(StringCompareCallExpr)) + .bind("invalid-conversion"), + 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( + anyOf(hasOperatorName("=="), + hasOperatorName("!="), + hasOperatorName("<"), + hasOperatorName("<="), + hasOperatorName(">"), + hasOperatorName(">=")), + hasEitherOperand(StringCompareCallExpr), + hasEitherOperand(InvalidLiteral) + ).bind("invalid-comparison"), + this); +} + +void SuspiciousStringCompareCheck::check( + const MatchFinder::MatchResult &Result) { + const auto *Decl = Result.Nodes.getNodeAs("decl"); + const auto *Call = Result.Nodes.getNodeAs("call"); + assert(Decl != nullptr && Call != nullptr); + + if (Result.Nodes.getNodeAs("missing-comparison") != nullptr) { + 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->getName() + << FixItHint::CreateInsertion(EndLoc, " != 0"); + } + + if (Result.Nodes.getNodeAs("invalid-comparison") != nullptr) { + diag(Call->getLocStart(), + "function '%0' is compared to a suspicious constant") + << Decl->getName(); + } + + if (Result.Nodes.getNodeAs("invalid-conversion") != nullptr) { + diag(Call->getLocStart(), + "function '%0' has suspicious implicit cast") + << Decl->getName(); + }} + +} // namespace misc +} // namespace tidy +} // namespace clang Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -68,6 +68,7 @@ misc-string-integer-assignment misc-suspicious-missing-comma misc-suspicious-semicolon + misc-suspicious-string-compare misc-swapped-arguments misc-throw-by-value-catch-by-reference misc-undelegated-constructor Index: docs/clang-tidy/checks/misc-suspicious-string-compare.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/misc-suspicious-string-compare.rst @@ -0,0 +1,34 @@ +.. title:: clang-tidy - misc-suspicious-string-compare + +misc-suspicious-string-compare +============================== + +Find suspicious usage of runtime string comparison functions. + + +Checks for calls with implicit comparator and proposed to explicitly add it. + +Example: + if (strcmp(...)) // Implicitly compare to zero + if (!strcmp(...)) // Won't warn + if (strcmp(...) != 0) // Won't warn + + +Checks that compare function (i,e, ``strcmp``) are compare to valid constant. +A common mistake is to compare them to '1' or '-1'. The resulting value is + + < 0 when lower than, + > 0 when greater than, + == 0 when equals. + +Example: + if (strcmp(...) == -1) // Incorrect usage of the returned value. + + +Additionally, the check warns if the results value is implicitly cast to an +*suspicious* non-integer type. It's happening when the returned value is used in +wrong context. + +Example: + if (strcmp(...) < 0.) // Incorrect usage of the returned value. + Index: test/clang-tidy/misc-suspicious-string-compare.cpp =================================================================== --- /dev/null +++ test/clang-tidy/misc-suspicious-string-compare.cpp @@ -0,0 +1,298 @@ +// RUN: %check_clang_tidy %s misc-suspicious-string-compare %t + +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")) + return 0; + + if (!strcmp(A, "a") || + strcmp(A, "b")) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is called without explicitly comparing result [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + + if (strcmp(A, "a") == -1) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant [misc-suspicious-string-compare] + + if (strcmp(A, "a") == true) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant [misc-suspicious-string-compare] + + if (strcmp(A, "a") < '0') + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' is compared to a suspicious constant [misc-suspicious-string-compare] + + if (strcmp(A, "a") < 0.) + return 0; + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: function 'strcmp' has suspicious implicit cast [misc-suspicious-string-compare] +} + +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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // 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 [misc-suspicious-string-compare] + // CHECK-FIXES: _mbsnbicmp_l(U, V, 1, locale) != 0) + + return 1; +} \ No newline at end of file