61             if (!tok->variable() || !tok->variable()->isPointer())
 
   76     std::list<const Token*> callstack{ tok };
 
   78         callstack.push_back(strValue);
 
   80     std::string errmsg(
"Modifying string literal");
 
   82         std::string s = strValue->
str();
 
   85             s.replace(17, std::string::npos, 
"..\"");
 
   88     errmsg += 
" directly or indirectly is undefined behaviour.";
 
  102     logChecker(
"CheckString::checkAlwaysTrueOrFalseStringCompare"); 
 
  105         if (tok->isName() && tok->strAt(1) == 
"(" && 
Token::Match(tok, 
"memcmp|strncmp|strcmp|stricmp|strverscmp|bcmp|strcmpi|strcasecmp|strncasecmp|strncasecmp_l|strcasecmp_l|wcsncasecmp|wcscasecmp|wmemcmp|wcscmp|wcscasecmp_l|wcsncasecmp_l|wcsncmp|_mbscmp|_mbscmp_l|_memicmp|_memicmp_l|_stricmp|_wcsicmp|_mbsicmp|_stricmp_l|_wcsicmp_l|_mbsicmp_l")) {
 
  107                 const std::string &str1 = tok->strAt(2);
 
  108                 const std::string &str2 = tok->strAt(4);
 
  109                 if (!tok->isExpandedMacro() && !tok->tokAt(2)->isExpandedMacro() && !tok->tokAt(4)->isExpandedMacro())
 
  112             } 
else if (
Token::Match(tok->tokAt(2), 
"%name% , %name% ,|)")) {
 
  113                 const std::string &str1 = tok->strAt(2);
 
  114                 const std::string &str2 = tok->strAt(4);
 
  118             } 
else if (
Token::Match(tok->tokAt(2), 
"%name% . c_str ( ) , %name% . c_str ( ) ,|)")) {
 
  119                 const std::string &str1 = tok->strAt(2);
 
  120                 const std::string &str2 = tok->strAt(8);
 
  123                 tok = tok->tokAt(13);
 
  125         } 
else if (tok->isName() && 
Token::Match(tok, 
"QString :: compare ( %str% , %str% )")) {
 
  126             const std::string &str1 = tok->strAt(4);
 
  127             const std::string &str2 = tok->strAt(6);
 
  130         } 
else if (
Token::Match(tok, 
"!!+ %str% ==|!= %str% !!+")) {
 
  131             const std::string &str1 = tok->strAt(1);
 
  132             const std::string &str2 = tok->strAt(3);
 
  143     constexpr std::size_t stringLen = 10;
 
  144     const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + 
"..");
 
  145     const std::string string2 = (str2.size() < stringLen) ? str2 : (str2.substr(0, stringLen-2) + 
"..");
 
  148                 "Unnecessary comparison of static strings.\n" 
  149                 "The compared strings, '" + string1 + 
"' and '" + string2 + 
"', are always " + (str1==str2?
"identical":
"unequal") + 
". " 
  156                 "Comparison of identical string variables.\n" 
  157                 "The compared strings, '" + str1 + 
"' and '" + str2 + 
"', are identical. " 
  171     logChecker(
"CheckString::checkSuspiciousStringCompare"); 
 
  176             if (!tok->isComparisonOp())
 
  181             if (!varTok || !litTok)  
 
  184                 std::swap(varTok, litTok);
 
  196                 if (varTok->
isC() || (varType && varType->
pointer))
 
  207     const std::string cmpFunc = isLong ? 
"wcscmp" : 
"strcmp";
 
  209                 "$symbol:" + var + 
"\nString literal compared with variable '$symbol'. Did you intend to use " + cmpFunc + 
"() instead?", 
CWE595, 
Certainty::normal);
 
  215                 "$symbol:" + var + 
"\nChar literal compared with pointer '$symbol'. Did you intend to dereference it?", 
CWE595, 
Certainty::normal);
 
  234             if (tok->str() == 
"+") {
 
  235                 if (tok->astOperand1() && (tok->astOperand1()->tokType() == 
Token::eString)) { 
 
  236                     if (tok->astOperand2() && (tok->astOperand2()->tokType() == 
Token::eChar || 
isChar(tok->astOperand2()->variable()))) 
 
  246     std::string charType = 
"char";
 
  248         charType = tok->
astOperand2()->variable()->typeStartToken()->str();
 
  250         charType = 
"wchar_t";
 
  257         while (parent && parent->isCast())
 
  258             parent = parent->astParent();
 
  261         if (parent->isExpandedMacro())
 
  263         if (parent->isUnaryOp(
"!") || parent->isComparisonOp()) {
 
  282     logChecker(
"CheckString::checkIncorrectStringCompare"); 
 
  291                 tok = tok->next()->link();
 
  298                         begin = begin->
link()->previous();
 
  300                         begin = begin->
tokAt(-2);
 
  333     const std::string literalType = charLiteral ? 
"char" : 
"string";
 
  337                 charLiteral ? 
"incorrectCharBooleanError" : 
"incorrectStringBooleanError",
 
  338                 "Conversion of " + literalType + 
" literal " + 
string + 
" to bool always evaluates to " + result + 
'.', 
CWE571, 
Certainty::normal);
 
  355             if (tok->str() != 
"||")
 
  357             std::list<const Token *> equals0;
 
  358             std::list<const Token *> notEquals0;
 
  362                 if (t->
str() == 
"||") {
 
  363                     return ChildrenToVisit::op1_and_op2;
 
  365                 if (t->
str() == 
"==") {
 
  366                     if (Token::simpleMatch(t->astOperand1(), 
"(") && Token::simpleMatch(t->astOperand2(), 
"0"))
 
  367                         equals0.push_back(t->astOperand1());
 
  368                     else if (Token::simpleMatch(t->astOperand2(), 
"(") && Token::simpleMatch(t->astOperand1(), 
"0"))
 
  369                         equals0.push_back(t->astOperand2());
 
  370                     return ChildrenToVisit::none;
 
  372                 if (t->
str() == 
"!=") {
 
  373                     if (Token::simpleMatch(t->astOperand1(), 
"(") && Token::simpleMatch(t->astOperand2(), 
"0"))
 
  374                         notEquals0.push_back(t->astOperand1());
 
  375                     else if (Token::simpleMatch(t->astOperand2(), 
"(") && Token::simpleMatch(t->astOperand1(), 
"0"))
 
  376                         notEquals0.push_back(t->astOperand2());
 
  377                     return ChildrenToVisit::none;
 
  381                 else if (t->
str() == 
"(")
 
  382                     notEquals0.push_back(t);
 
  386             for (
const Token *eq0 : equals0) {
 
  387                 for (
const Token * ne0 : notEquals0) {
 
  392                     const std::vector<const Token *> args1 = 
getArguments(eq0->previous());
 
  393                     const std::vector<const Token *> args2 = 
getArguments(ne0->previous());
 
  394                     if (args1.size() != 2 || args2.size() != 2)
 
  396                     if (args1[1]->isLiteral() &&
 
  397                         args2[1]->isLiteral() &&
 
  398                         args1[1]->str() != args2[1]->str() &&
 
  409     std::string eq0Expr(eq0 ? eq0->
expressionString() : std::string(
"strcmp(x,\"abc\")"));
 
  410     if (eq0 && eq0->
astParent()->str() == 
"!")
 
  411         eq0Expr = 
"!" + eq0Expr;
 
  415     const std::string ne0Expr = (ne0 ? ne0->
expressionString() : std::string(
"strcmp(x,\"def\")")) + 
" != 0";
 
  417     reportError(ne0, 
Severity::warning, 
"overlappingStrcmp", 
"The expression '" + ne0Expr + 
"' is suspicious. It overlaps '" + eq0Expr + 
"'.");
 
  426     logChecker(
"CheckString::sprintfOverlappingData");
 
  434             const std::vector<const Token *> args = 
getArguments(tok);
 
  437             for (
unsigned int argnr = formatString + 1; argnr < args.size(); ++argnr) {
 
  438                 const Token *dest = args[0];
 
  441                 const Token *arg = args[argnr];
 
  463     const std::string func = funcTok ? funcTok->
str() : 
"s[n]printf";
 
  466                 "$symbol:" + varname + 
"\n" 
  467                 "Undefined behavior: Variable '$symbol' is used as parameter and destination in " + func + 
"().\n" +
 
  468                 "The variable '$symbol' is used both as a parameter and as destination in " +
 
  469                 func + 
"(). The origin and destination buffers overlap. Quote from glibc (C-library) " 
  470                 "documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): " 
  471                 "\"If copying takes place between objects that overlap as a result of a call " 
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
 
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
 
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
 
bool isUsedAsBool(const Token *const tok, const Settings &settings)
Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for.
 
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
 
static const CWE CWE571(571U)
 
static bool isMacroUsage(const Token *tok)
 
static const CWE CWE595(595U)
 
static const CWE CWE758(758U)
 
static const CWE CWE570(570U)
 
static const CWE CWE665(665U)
 
static bool isChar(const Variable *var)
 
static const CWE CWE628(628U)
 
Detect misusage of C-style strings and related standard functions.
 
void checkSuspiciousStringCompare()
Check for comparison of a string literal with a char* variable
 
void checkIncorrectStringCompare()
Check for using bad usage of strncmp and substr
 
void suspiciousStringCompareError(const Token *tok, const std::string &var, bool isLong)
 
void incorrectStringBooleanError(const Token *tok, const std::string &string)
 
void overlappingStrcmp()
Check for overlapping strcmp()
 
void incorrectStringCompareError(const Token *tok, const std::string &func, const std::string &string)
 
void strPlusCharError(const Token *tok)
 
void suspiciousStringCompareError_char(const Token *tok, const std::string &var)
 
void sprintfOverlappingData()
Check for overlapping source and destination passed to sprintf()
 
void stringLiteralWriteError(const Token *tok, const Token *strValue)
 
void alwaysTrueStringVariableCompareError(const Token *tok, const std::string &str1, const std::string &str2)
 
void overlappingStrcmpError(const Token *eq0, const Token *ne0)
 
void stringLiteralWrite()
undefined behaviour, writing string literal
 
void strPlusChar()
str plus char (unusual pointer arithmetic)
 
void alwaysTrueFalseStringCompareError(const Token *tok, const std::string &str1, const std::string &str2)
 
void sprintfOverlappingDataError(const Token *funcTok, const Token *tok, const std::string &varname)
 
void checkAlwaysTrueOrFalseStringCompare()
Check for suspicious code that compares string literals for equality
 
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
 
const Settings *const mSettings
 
const Tokenizer *const mTokenizer
 
void logChecker(const char id[])
log checker
 
static biguint toBigUNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
 
unsigned long long biguint
 
const Token * bodyStart
'{' token
 
const Token * bodyEnd
'}' token
 
SimpleEnableGroup< Severity > severity
 
bool isEnabled(T flag) const
 
std::vector< const Scope * > functionScopes
Fast access to function scopes.
 
The token list that the TokenList generates is a linked-list of this class.
 
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
 
const Token * getValueTokenMinStrSize(const Settings &settings, MathLib::bigint *path=nullptr) const
 
static nonneg int getStrLength(const Token *tok)
 
const ValueType * valueType() const
 
const std::string & strAt(int index) const
 
void astOperand1(Token *tok)
 
void function(const Function *f)
Associate this token with given function.
 
std::string expressionString() const
 
const Token * tokAt(int index) const
 
Token::Type tokType() const
 
void astOperand2(Token *tok)
 
void link(Token *linkToToken)
Create link to given token.
 
const Token * linkAt(int index) const
 
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
 
void astParent(Token *tok)
 
const Token * tokens() const
 
const SymbolDatabase * getSymbolDatabase() const
 
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
 
Information about a member variable.
 
bool isArray() const
Is variable an array.
 
const Token * typeStartToken() const
Get type start token.
 
bool isPointer() const
Is pointer variable.
 
@ error
Programming error.
 
bool endsWith(const std::string &str, char c)
 
static bool isCharLiteral(const std::string &str)
 
static const char * bool_to_string(bool b)
 
static std::string getCharLiteral(const std::string &str)