1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2019 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 
20 //---------------------------------------------------------------------------
21 // Remove includes from the benchmark run
22 // Included files aren't found anyway
23 //#include "checkother.h"
24 //#include "mathlib.h"
25 //#include "symboldatabase.h"
26 
27 //#include <cctype> // std::isupper
28 //#include <cmath> // fabs()
29 //#include <stack>
30 //---------------------------------------------------------------------------
31 
32 // Register this check class (by creating a static instance of it)
33 namespace {
34     CheckOther instance;
35 }
36 
37 //---------------------------------------------------------------------------
38 
checkIncrementBoolean()39 void CheckOther::checkIncrementBoolean()
40 {
41     if (!_settings->isEnabled("style"))
42         return;
43 
44     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
45         if (Token::Match(tok, "%var% ++")) {
46             if (tok->varId()) {
47                 const Token *declTok = Token::findmatch(_tokenizer->tokens(), "bool %varid%", tok->varId());
48                 if (declTok)
49                     incrementBooleanError(tok);
50             }
51         }
52     }
53 }
54 
incrementBooleanError(const Token * tok)55 void CheckOther::incrementBooleanError(const Token *tok)
56 {
57     reportError(
58         tok,
59         Severity::style,
60         "incrementboolean",
61         "The use of a variable of type bool with the ++ postfix operator is always true and deprecated by the C++ Standard.\n"
62         "The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true\n"
63         );
64 }
65 
66 //---------------------------------------------------------------------------
67 
68 
clarifyCalculation()69 void CheckOther::clarifyCalculation()
70 {
71     if (!_settings->isEnabled("style"))
72         return;
73     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
74         if (tok->strAt(1) == "?") {
75             // condition
76             const Token *cond = tok;
77             if (cond->isName() || cond->isNumber())
78                 cond = cond->previous();
79             else if (cond->str() == ")")
80                 cond = cond->link()->previous();
81             else
82                 continue;
83 
84             // calculation
85             if (!cond->isArithmeticalOp())
86                 continue;
87 
88             const std::string &op = cond->str();
89             cond = cond->previous();
90 
91             // skip previous multiplications..
92             while (cond && cond->strAt(-1) == "*" && (cond->isName() || cond->isNumber()))
93                 cond = cond->tokAt(-2);
94 
95             if (!cond)
96                 continue;
97 
98             // first multiplication operand
99             if (cond->str() == ")") {
100                 clarifyCalculationError(cond, op);
101             } else if (cond->isName() || cond->isNumber()) {
102                 if (Token::Match(cond->previous(),("return|=|+|-|,|(|"+op).c_str()))
103                     clarifyCalculationError(cond, op);
104             }
105         }
106     }
107 }
108 
clarifyCalculationError(const Token * tok,const std::string & op)109 void CheckOther::clarifyCalculationError(const Token *tok, const std::string &op)
110 {
111     // suspicious calculation
112     const std::string calc("'a" + op + "b?c:d'");
113 
114     // recommended calculation #1
115     const std::string s1("'(a" + op + "b)?c:d'");
116 
117     // recommended calculation #2
118     const std::string s2("'a" + op + "(b?c:d)'");
119 
120     reportError(tok,
121                 Severity::style,
122                 "clarifyCalculation",
123                 "Clarify calculation precedence for " + op + " and ?\n"
124                 "Suspicious calculation. Please use parentheses to clarify the code. "
125                 "The code " + calc + " should be written as either " + s1 + " or " + s2 + ".");
126 }
127 
128 
129 // Clarify condition '(x = a < 0)' into '((x = a) < 0)' or '(x = (a < 0))'
clarifyCondition()130 void CheckOther::clarifyCondition()
131 {
132     if (!_settings->isEnabled("style"))
133         return;
134     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
135         if (Token::Match(tok, "( %var% =")) {
136             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
137                 if (tok2->str() == "(" || tok2->str() == "[")
138                     tok2 = tok2->link();
139                 else if (Token::Match(tok2, "&&|%oror%|?|)"))
140                     break;
141                 else if (Token::Match(tok2, "<|<=|==|!=|>|>= %num% )")) {
142                     clarifyConditionError(tok);
143                     break;
144                 }
145             }
146         }
147     }
148 }
149 
clarifyConditionError(const Token * tok)150 void CheckOther::clarifyConditionError(const Token *tok)
151 {
152     reportError(tok,
153                 Severity::style,
154                 "clarifyCondition",
155                 "Suspicious condition (assignment+comparison), it can be clarified with parentheses");
156 }
157 
158 
159 
warningOldStylePointerCast()160 void CheckOther::warningOldStylePointerCast()
161 {
162     if (!_settings->isEnabled("style") ||
163         (_tokenizer->tokens() && _tokenizer->fileLine(_tokenizer->tokens()).find(".cpp") == std::string::npos))
164         return;
165 
166     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
167         // Old style pointer casting..
168         if (!Token::Match(tok, "( const| %type% * ) %var%") &&
169             !Token::Match(tok, "( const| %type% * ) (| new"))
170             continue;
171 
172         int addToIndex = 0;
173         if (tok->tokAt(1)->str() == "const")
174             addToIndex = 1;
175 
176         if (tok->tokAt(4 + addToIndex)->str() == "const")
177             continue;
178 
179         // Is "type" a class?
180         const std::string pattern("class " + tok->tokAt(1 + addToIndex)->str());
181         if (!Token::findmatch(_tokenizer->tokens(), pattern.c_str()))
182             continue;
183 
184         cstyleCastError(tok);
185     }
186 }
187 
188 //---------------------------------------------------------------------------
189 // fflush(stdin) <- fflush only applies to output streams in ANSI C
190 //---------------------------------------------------------------------------
checkFflushOnInputStream()191 void CheckOther::checkFflushOnInputStream()
192 {
193     const Token *tok = _tokenizer->tokens();
194     while (tok && ((tok = Token::findsimplematch(tok, "fflush ( stdin )")) != NULL)) {
195         fflushOnInputStreamError(tok, tok->strAt(2));
196         tok = tok->tokAt(4);
197     }
198 }
199 
checkSizeofForNumericParameter()200 void CheckOther::checkSizeofForNumericParameter()
201 {
202     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
203         if (Token::Match(tok, "sizeof ( %num% )")
204             || Token::Match(tok, "sizeof ( - %num% )")
205             || Token::Match(tok, "sizeof %num%")
206             || Token::Match(tok, "sizeof - %num%")
207             ) {
208             sizeofForNumericParameterError(tok);
209         }
210     }
211 }
212 
checkSizeofForArrayParameter()213 void CheckOther::checkSizeofForArrayParameter()
214 {
215     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
216         if (Token::Match(tok, "sizeof ( %var% )") || Token::Match(tok, "sizeof %var%")) {
217             int tokIdx = 1;
218             if (tok->tokAt(tokIdx)->str() == "(") {
219                 ++tokIdx;
220             }
221             if (tok->tokAt(tokIdx)->varId() > 0) {
222                 const Token *declTok = Token::findmatch(_tokenizer->tokens(), "%varid%", tok->tokAt(tokIdx)->varId());
223                 if (declTok) {
224                     if (Token::simpleMatch(declTok->next(), "[")) {
225                         declTok = declTok->next()->link();
226                         // multidimensional array
227                         while (Token::simpleMatch(declTok->next(), "[")) {
228                             declTok = declTok->next()->link();
229                         }
230                         if (!(Token::Match(declTok->next(), "= %str%")) && !(Token::simpleMatch(declTok->next(), "= {")) && !(Token::simpleMatch(declTok->next(), ";"))) {
231                             if (Token::simpleMatch(declTok->next(), ",")) {
232                                 declTok = declTok->next();
233                                 while (!Token::simpleMatch(declTok, ";")) {
234                                     if (Token::simpleMatch(declTok, ")")) {
235                                         sizeofForArrayParameterError(tok);
236                                         break;
237                                     }
238                                     if (Token::Match(declTok, "(|[|{")) {
239                                         declTok = declTok->link();
240                                     }
241                                     declTok = declTok->next();
242                                 }
243                             }
244                         }
245                         if (Token::simpleMatch(declTok->next(), ")")) {
246                             sizeofForArrayParameterError(tok);
247                         }
248                     }
249                 }
250             }
251         }
252     }
253 }
254 
255 
256 
257 //---------------------------------------------------------------------------
258 //    switch (x)
259 //    {
260 //        case 2:
261 //            y = a;        // <- this assignment is redundant
262 //        case 3:
263 //            y = b;        // <- case 2 falls through and sets y twice
264 //    }
265 //---------------------------------------------------------------------------
checkRedundantAssignmentInSwitch()266 void CheckOther::checkRedundantAssignmentInSwitch()
267 {
268     const char switchPattern[] = "switch ( %any% ) { case";
269     const char breakPattern[] = "break|continue|return|exit|goto|throw";
270     const char functionPattern[] = "%var% (";
271 
272     // Find the beginning of a switch. E.g.:
273     //   switch (var) { ...
274     const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern);
275     while (tok) {
276 
277         // Check the contents of the switch statement
278         std::map<unsigned int, const Token*> varsAssigned;
279         int indentLevel = 0;
280         for (const Token *tok2 = tok->tokAt(5); tok2; tok2 = tok2->next()) {
281             if (tok2->str() == "{") {
282                 // Inside a conditional or loop. Don't mark variable accesses as being redundant. E.g.:
283                 //   case 3: b = 1;
284                 //   case 4: if (a) { b = 2; }    // Doesn't make the b=1 redundant because it's conditional
285                 if (Token::Match(tok2->previous(), ")|else {") && tok2->link()) {
286                     const Token* endOfConditional = tok2->link();
287                     for (const Token* tok3 = tok2; tok3 != endOfConditional; tok3 = tok3->next()) {
288                         if (tok3->varId() != 0)
289                             varsAssigned.erase(tok3->varId());
290                         else if (Token::Match(tok3, functionPattern) || Token::Match(tok3, breakPattern))
291                             varsAssigned.clear();
292                     }
293                     tok2 = endOfConditional;
294                 } else
295                     ++indentLevel;
296             } else if (tok2->str() == "}") {
297                 --indentLevel;
298 
299                 // End of the switch block
300                 if (indentLevel < 0)
301                     break;
302             }
303 
304             // Variable assignment. Report an error if it's assigned to twice before a break. E.g.:
305             //    case 3: b = 1;    // <== redundant
306             //    case 4: b = 2;
307             if (Token::Match(tok2->previous(), ";|{|}|: %var% = %any% ;") && tok2->varId() != 0) {
308                 std::map<unsigned int, const Token*>::iterator i = varsAssigned.find(tok2->varId());
309                 if (i == varsAssigned.end())
310                     varsAssigned[tok2->varId()] = tok2;
311                 else
312                     redundantAssignmentInSwitchError(i->second, i->second->str());
313             }
314             // Not a simple assignment so there may be good reason if this variable is assigned to twice. E.g.:
315             //    case 3: b = 1;
316             //    case 4: b++;
317             else if (tok2->varId() != 0)
318                 varsAssigned.erase(tok2->varId());
319 
320             // Reset our record of assignments if there is a break or function call. E.g.:
321             //    case 3: b = 1; break;
322             if (Token::Match(tok2, functionPattern) || Token::Match(tok2, breakPattern))
323                 varsAssigned.clear();
324 
325         }
326 
327         tok = Token::findmatch(tok->next(), switchPattern);
328     }
329 }
330 
331 
checkSwitchCaseFallThrough()332 void CheckOther::checkSwitchCaseFallThrough()
333 {
334     if (!(_settings->isEnabled("style") && _settings->experimental))
335         return;
336 
337     const char switchPattern[] = "switch (";
338     const char breakPattern[] = "break|continue|return|exit|goto|throw";
339 
340     // Find the beginning of a switch. E.g.:
341     //   switch (var) { ...
342     const Token *tok = Token::findmatch(_tokenizer->tokens(), switchPattern);
343     while (tok) {
344 
345         // Check the contents of the switch statement
346         std::stack<std::pair<Token *, bool>> ifnest;
347         std::stack<Token *> loopnest;
348         std::stack<Token *> scopenest;
349         bool justbreak = true;
350         bool firstcase = true;
351         for (const Token *tok2 = tok->tokAt(1)->link()->tokAt(2); tok2; tok2 = tok2->next()) {
352             if (Token::simpleMatch(tok2, "if (")) {
353                 tok2 = tok2->tokAt(1)->link()->next();
354                 if (tok2->link() == NULL) {
355                     std::ostringstream errmsg;
356                     errmsg << "unmatched if in switch: " << tok2->linenr();
357                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
358                     break;
359                 }
360                 ifnest.push(std::make_pair(tok2->link(), false));
361                 justbreak = false;
362             } else if (Token::simpleMatch(tok2, "while (")) {
363                 tok2 = tok2->tokAt(1)->link()->next();
364                 // skip over "do { } while ( ) ;" case
365                 if (tok2->str() == "{") {
366                     if (tok2->link() == NULL) {
367                         std::ostringstream errmsg;
368                         errmsg << "unmatched while in switch: " << tok2->linenr();
369                         reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
370                         break;
371                     }
372                     loopnest.push(tok2->link());
373                 }
374                 justbreak = false;
375             } else if (Token::simpleMatch(tok2, "do {")) {
376                 tok2 = tok2->tokAt(1);
377                 if (tok2->link() == NULL) {
378                     std::ostringstream errmsg;
379                     errmsg << "unmatched do in switch: " << tok2->linenr();
380                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
381                     break;
382                 }
383                 loopnest.push(tok2->link());
384                 justbreak = false;
385             } else if (Token::simpleMatch(tok2, "for (")) {
386                 tok2 = tok2->tokAt(1)->link()->next();
387                 if (tok2->link() == NULL) {
388                     std::ostringstream errmsg;
389                     errmsg << "unmatched for in switch: " << tok2->linenr();
390                     reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
391                     break;
392                 }
393                 loopnest.push(tok2->link());
394                 justbreak = false;
395             } else if (Token::Match(tok2, switchPattern)) {
396                 // skip over nested switch, we'll come to that soon
397                 tok2 = tok2->tokAt(1)->link()->next()->link();
398             } else if (Token::Match(tok2, breakPattern)) {
399                 if (loopnest.empty()) {
400                     justbreak = true;
401                 }
402                 tok2 = Token::findsimplematch(tok2, ";");
403             } else if (Token::Match(tok2, "case|default")) {
404                 if (!justbreak && !firstcase) {
405                     switchCaseFallThrough(tok2);
406                 }
407                 tok2 = Token::findsimplematch(tok2, ":");
408                 justbreak = true;
409                 firstcase = false;
410             } else if (tok2->str() == "{") {
411                 scopenest.push(tok2->link());
412             } else if (tok2->str() == "}") {
413                 if (!ifnest.empty() && tok2 == ifnest.top().first) {
414                     if (tok2->next()->str() == "else") {
415                         tok2 = tok2->tokAt(2);
416                         ifnest.pop();
417                         if (tok2->link() == NULL) {
418                             std::ostringstream errmsg;
419                             errmsg << "unmatched if in switch: " << tok2->linenr();
420                             reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
421                             break;
422                         }
423                         ifnest.push(std::make_pair(tok2->link(), justbreak));
424                         justbreak = false;
425                     } else {
426                         justbreak &= ifnest.top().second;
427                         ifnest.pop();
428                     }
429                 } else if (!loopnest.empty() && tok2 == loopnest.top()) {
430                     loopnest.pop();
431                 } else if (!scopenest.empty() && tok2 == scopenest.top()) {
432                     scopenest.pop();
433                 } else {
434                     if (!ifnest.empty() || !loopnest.empty() || !scopenest.empty()) {
435                         std::ostringstream errmsg;
436                         errmsg << "unexpected end of switch: ";
437                         errmsg << "ifnest=" << ifnest.size();
438                         if (!ifnest.empty())
439                             errmsg << "," << ifnest.top().first->linenr();
440                         errmsg << ", loopnest=" << loopnest.size();
441                         if (!loopnest.empty())
442                             errmsg << "," << loopnest.top()->linenr();
443                         errmsg << ", scopenest=" << scopenest.size();
444                         if (!scopenest.empty())
445                             errmsg << "," << scopenest.top()->linenr();
446                         reportError(_tokenizer->tokens(), Severity::debug, "debug", errmsg.str());
447                     }
448                     // end of switch block
449                     break;
450                 }
451             } else if (tok2->str() != ";") {
452                 justbreak = false;
453             }
454 
455         }
456 
457         tok = Token::findmatch(tok->next(), switchPattern);
458     }
459 }
460 
461 
462 //---------------------------------------------------------------------------
463 //    int x = 1;
464 //    x = x;            // <- redundant assignment to self
465 //
466 //    int y = y;        // <- redundant initialization to self
467 //---------------------------------------------------------------------------
checkSelfAssignment()468 void CheckOther::checkSelfAssignment()
469 {
470     if (!_settings->isEnabled("style"))
471         return;
472 
473     // POD variables..
474     std::set<unsigned int> pod;
475     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
476         if (tok->isStandardType() && Token::Match(tok->tokAt(2), "[,);]") && tok->next()->varId())
477             pod.insert(tok->next()->varId());
478     }
479 
480     const char selfAssignmentPattern[] = "%var% = %var% ;|=|)";
481     const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern);
482     while (tok) {
483         if (Token::Match(tok->previous(), "[;{}]") &&
484             tok->varId() && tok->varId() == tok->tokAt(2)->varId() &&
485             pod.find(tok->varId()) != pod.end()) {
486             selfAssignmentError(tok, tok->str());
487         }
488 
489         tok = Token::findmatch(tok->next(), selfAssignmentPattern);
490     }
491 }
492 
493 //---------------------------------------------------------------------------
494 //    int a = 1;
495 //    assert(a = 2);            // <- assert should not have a side-effect
496 //---------------------------------------------------------------------------
checkAssignmentInAssert()497 void CheckOther::checkAssignmentInAssert()
498 {
499     if (!_settings->isEnabled("style"))
500         return;
501 
502     const char assertPattern[] = "assert ( %any%";
503     const Token *tok = Token::findmatch(_tokenizer->tokens(), assertPattern);
504     const Token *endTok = tok ? tok->next()->link() : NULL;
505 
506     while (tok && endTok) {
507         const Token* varTok = Token::findmatch(tok->tokAt(2), "%var% --|++|+=|-=|*=|/=|&=|^=|=", endTok);
508         if (varTok) {
509             assignmentInAssertError(tok, varTok->str());
510         } else if (NULL != (varTok = Token::findmatch(tok->tokAt(2), "--|++ %var%", endTok))) {
511             assignmentInAssertError(tok, varTok->strAt(1));
512         }
513 
514         tok = Token::findmatch(endTok->next(), assertPattern);
515         endTok = tok ? tok->next()->link() : NULL;
516     }
517 }
518 
519 //---------------------------------------------------------------------------
520 //    if ((x != 1) || (x != 3))            // <- always true
521 //    if ((x == 1) && (x == 3))            // <- always false
522 //    if ((x < 1)  && (x > 3))             // <- always false
523 //    if ((x > 3)  || (x < 10))            // <- always true
524 //---------------------------------------------------------------------------
checkIncorrectLogicOperator()525 void CheckOther::checkIncorrectLogicOperator()
526 {
527     if (!_settings->isEnabled("style"))
528         return;
529 
530     const char conditionPattern[] = "if|while (";
531     const Token *tok = Token::findmatch(_tokenizer->tokens(), conditionPattern);
532     const Token *endTok = tok ? tok->next()->link() : NULL;
533 
534     while (tok && endTok) {
535         // Find a pair of OR'd terms, with or without parentheses
536         // e.g. if (x != 3 || x != 4)
537         const Token *logicTok = NULL, *term1Tok = NULL, *term2Tok = NULL;
538         const Token *op1Tok = NULL, *op2Tok = NULL, *op3Tok = NULL, *nextTok = NULL;
539         if (NULL != (logicTok = Token::findmatch(tok, "( %any% !=|==|<|>|>=|<= %any% ) &&|%oror% ( %any% !=|==|<|>|>=|<= %any% ) %any%", endTok))) {
540             term1Tok = logicTok->next();
541             term2Tok = logicTok->tokAt(7);
542             op1Tok = logicTok->tokAt(2);
543             op2Tok = logicTok->tokAt(5);
544             op3Tok = logicTok->tokAt(8);
545             nextTok = logicTok->tokAt(11);
546         } else if (NULL != (logicTok = Token::findmatch(tok, "%any% !=|==|<|>|>=|<= %any% &&|%oror% %any% !=|==|<|>|>=|<= %any% %any%", endTok))) {
547             term1Tok = logicTok;
548             term2Tok = logicTok->tokAt(4);
549             op1Tok = logicTok->tokAt(1);
550             op2Tok = logicTok->tokAt(3);
551             op3Tok = logicTok->tokAt(5);
552             nextTok = logicTok->tokAt(7);
553         }
554 
555         if (logicTok) {
556             // Find the common variable and the two different-valued constants
557             unsigned int variableTested = 0;
558             std::string firstConstant, secondConstant;
559             bool varFirst1, varFirst2;
560             unsigned int varId;
561             if (Token::Match(term1Tok, "%var% %any% %num%")) {
562                 varId = term1Tok->varId();
563                 if (!varId) {
564                     tok = Token::findmatch(endTok->next(), conditionPattern);
565                     endTok = tok ? tok->next()->link() : NULL;
566                     continue;
567                 }
568                 varFirst1 = true;
569                 firstConstant = term1Tok->tokAt(2)->str();
570             } else if (Token::Match(term1Tok, "%num% %any% %var%")) {
571                 varId = term1Tok->tokAt(2)->varId();
572                 if (!varId) {
573                     tok = Token::findmatch(endTok->next(), conditionPattern);
574                     endTok = tok ? tok->next()->link() : NULL;
575                     continue;
576                 }
577                 varFirst1 = false;
578                 firstConstant = term1Tok->str();
579             } else {
580                 tok = Token::findmatch(endTok->next(), conditionPattern);
581                 endTok = tok ? tok->next()->link() : NULL;
582                 continue;
583             }
584 
585             if (Token::Match(term2Tok, "%var% %any% %num%")) {
586                 const unsigned int varId2 = term2Tok->varId();
587                 if (!varId2 || varId != varId2) {
588                     tok = Token::findmatch(endTok->next(), conditionPattern);
589                     endTok = tok ? tok->next()->link() : NULL;
590                     continue;
591                 }
592                 varFirst2 = true;
593                 secondConstant = term2Tok->tokAt(2)->str();
594                 variableTested = varId;
595             } else if (Token::Match(term2Tok, "%num% %any% %var%")) {
596                 const unsigned int varId2 = term1Tok->tokAt(2)->varId();
597                 if (!varId2 || varId != varId2) {
598                     tok = Token::findmatch(endTok->next(), conditionPattern);
599                     endTok = tok ? tok->next()->link() : NULL;
600                     continue;
601                 }
602                 varFirst2 = false;
603                 secondConstant = term2Tok->str();
604                 variableTested = varId;
605             } else {
606                 tok = Token::findmatch(endTok->next(), conditionPattern);
607                 endTok = tok ? tok->next()->link() : NULL;
608                 continue;
609             }
610 
611             if (variableTested == 0 || firstConstant.empty() || secondConstant.empty()) {
612                 tok = Token::findmatch(endTok->next(), conditionPattern);
613                 endTok = tok ? tok->next()->link() : NULL;
614                 continue;
615             }
616 
617             enum Position { First, Second, NA };
618             enum Relation { Equal, NotEqual, Less, LessEqual, More, MoreEqual };
619             struct Condition {
620                 const char *before;
621                 Position position1;
622                 const char *op1TokStr;
623                 const char *op2TokStr;
624                 Position position2;
625                 const char *op3TokStr;
626                 const char *after;
627                 Relation relation;
628                 bool state;
629             } conditions[] = {
630                 { "!!&&", NA,     "!=",   "||", NA,     "!=",   "!!&&", NotEqual,  true  }, // (x != 1) || (x != 3) <- always true
631                 { "(",    NA,     "==",   "&&", NA,     "==",   ")",    NotEqual,  false }, // (x == 1) && (x == 3) <- always false
632                 { "(",    First,  "<",    "&&", First,  ">",    ")",    LessEqual, false }, // (x < 1)  && (x > 3)  <- always false
633                 { "(",    First,  ">",    "&&", First,  "<",    ")",    MoreEqual, false }, // (x > 3)  && (x < 1)  <- always false
634                 { "(",    Second, ">",    "&&", First,  ">",    ")",    LessEqual, false }, // (1 > x)  && (x > 3)  <- always false
635                 { "(",    First,  ">",    "&&", Second, ">",    ")",    MoreEqual, false }, // (x > 3)  && (1 > x)  <- always false
636                 { "(",    First,  "<",    "&&", Second, "<",    ")",    LessEqual, false }, // (x < 1)  && (3 < x)  <- always false
637                 { "(",    Second, "<",    "&&", First,  "<",    ")",    MoreEqual, false }, // (3 < x)  && (x < 1)  <- always false
638                 { "(",    Second, ">",    "&&", Second, "<",    ")",    LessEqual, false }, // (1 > x)  && (3 < x)  <- always false
639                 { "(",    Second, "<",    "&&", Second, ">",    ")",    MoreEqual, false }, // (3 < x)  && (1 > x)  <- always false
640                 { "(",    First, ">|>=", "||", First,  "<|<=", ")",    Less,      true  },  // (x > 3)  || (x < 10) <- always true
641                 { "(",    First, "<|<=", "||", First,  ">|>=", ")",    More,      true  },  // (x < 10) || (x > 3)  <- always true
642                 { "(",    Second, "<|<=", "||", First,  "<|<=", ")",    Less,      true  }, // (3 < x)  || (x < 10) <- always true
643                 { "(",    First,  "<|<=", "||", Second, "<|<=", ")",    More,      true  }, // (x < 10) || (3 < x)  <- always true
644                 { "(",    First,  ">|>=", "||", Second, ">|>=", ")",    Less,      true  }, // (x > 3)  || (10 > x) <- always true
645                 { "(",    Second, ">|>=", "||", First,  ">|>=", ")",    More,      true  }, // (10 > x) || (x > 3)  <- always true
646                 { "(",    Second, "<|<=", "||", Second, ">|<=", ")",    Less,      true  }, // (3 < x)  || (10 > x) <- always true
647                 { "(",    Second, ">|>=", "||", Second, "<|<=", ")",    More,      true  }, // (10 > x) || (3 < x)  <- always true
648             };
649 
650             for (unsigned int i = 0; i < (sizeof(conditions) / sizeof(conditions[0])); i++) {
651                 if (!((conditions[i].position1 == NA) || (((conditions[i].position1 == First) && varFirst1) || ((conditions[i].position1 == Second) && !varFirst1))))
652                     continue;
653 
654                 if (!((conditions[i].position2 == NA) || (((conditions[i].position2 == First) && varFirst2) || ((conditions[i].position2 == Second) && !varFirst2))))
655                     continue;
656 
657                 if (!Token::Match(op1Tok, conditions[i].op1TokStr))
658                     continue;
659 
660                 if (!Token::Match(op2Tok, conditions[i].op2TokStr))
661                     continue;
662 
663                 if (!Token::Match(op3Tok, conditions[i].op3TokStr))
664                     continue;
665 
666                 if (!Token::Match(logicTok->previous(), conditions[i].before))
667                     continue;
668 
669                 if (!Token::Match(nextTok, conditions[i].after))
670                     continue;
671 
672                 if ((conditions[i].relation == Equal && MathLib::isEqual(firstConstant, secondConstant)) ||
673                     (conditions[i].relation == NotEqual && MathLib::isNotEqual(firstConstant, secondConstant)) ||
674                     (conditions[i].relation == Less && MathLib::isLess(firstConstant, secondConstant)) ||
675                     (conditions[i].relation == LessEqual && MathLib::isLessEqual(firstConstant, secondConstant)) ||
676                     (conditions[i].relation == More && MathLib::isGreater(firstConstant, secondConstant)) ||
677                     (conditions[i].relation == MoreEqual && MathLib::isGreaterEqual(firstConstant, secondConstant)))
678                     incorrectLogicOperatorError(term1Tok, conditions[i].state);
679             }
680         }
681 
682         tok = Token::findmatch(endTok->next(), conditionPattern);
683         endTok = tok ? tok->next()->link() : NULL;
684     }
685 }
686 
687 //---------------------------------------------------------------------------
688 //    try {} catch (std::exception err) {} <- Should be "std::exception& err"
689 //---------------------------------------------------------------------------
checkCatchExceptionByValue()690 void CheckOther::checkCatchExceptionByValue()
691 {
692     if (!_settings->isEnabled("style"))
693         return;
694 
695     const char catchPattern[] = "} catch (";
696     const Token *tok = Token::findmatch(_tokenizer->tokens(), catchPattern);
697     const Token *endTok = tok ? tok->tokAt(2)->link() : NULL;
698 
699     while (tok && endTok) {
700         // Find a pass-by-value declaration in the catch(), excluding basic types
701         // e.g. catch (std::exception err)
702         const Token *tokType = Token::findmatch(tok, "%type% %var% )", endTok);
703         if (tokType && !tokType->isStandardType()) {
704             catchExceptionByValueError(tokType);
705         }
706 
707         tok = Token::findmatch(endTok->next(), catchPattern);
708         endTok = tok ? tok->tokAt(2)->link() : NULL;
709     }
710 }
711 
712 //---------------------------------------------------------------------------
713 // strtol(str, 0, radix)  <- radix must be 0 or 2-36
714 //---------------------------------------------------------------------------
715 
invalidFunctionUsage()716 void CheckOther::invalidFunctionUsage()
717 {
718     // strtol and strtoul..
719     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
720         if (!Token::Match(tok, "strtol|strtoul ("))
721             continue;
722 
723         // Locate the third parameter of the function call..
724         int param = 1;
725         for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
726             if (tok2->str() == "(")
727                 tok2 = tok2->link();
728             else if (tok2->str() == ")")
729                 break;
730             else if (tok2->str() == ",") {
731                 ++param;
732                 if (param == 3) {
733                     if (Token::Match(tok2, ", %num% )")) {
734                         const MathLib::bigint radix = MathLib::toLongNumber(tok2->next()->str());
735                         if (!(radix == 0 || (radix >= 2 && radix <= 36))) {
736                             dangerousUsageStrtolError(tok2);
737                         }
738                     }
739                     break;
740                 }
741             }
742         }
743     }
744 
745     // sprintf|snprintf overlapping data
746     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
747         // Get variable id of target buffer..
748         unsigned int varid = 0;
749 
750         if (Token::Match(tok, "sprintf|snprintf ( %var% ,"))
751             varid = tok->tokAt(2)->varId();
752 
753         else if (Token::Match(tok, "sprintf|snprintf ( %var% . %var% ,"))
754             varid = tok->tokAt(4)->varId();
755 
756         if (varid == 0)
757             continue;
758 
759         // goto ","
760         const Token *tok2 = tok->tokAt(3);
761         while (tok2 && tok2->str() != ",")
762             tok2 = tok2->next();
763         if (!tok2)
764             continue;
765 
766         // is any source buffer overlapping the target buffer?
767         int parlevel = 0;
768         while ((tok2 = tok2->next()) != NULL) {
769             if (tok2->str() == "(")
770                 ++parlevel;
771             else if (tok2->str() == ")") {
772                 --parlevel;
773                 if (parlevel < 0)
774                     break;
775             } else if (parlevel == 0 && Token::Match(tok2, ", %varid% [,)]", varid)) {
776                 sprintfOverlappingDataError(tok2->next(), tok2->next()->str());
777                 break;
778             }
779         }
780     }
781 }
782 //---------------------------------------------------------------------------
783 
invalidScanf()784 void CheckOther::invalidScanf()
785 {
786     if (!_settings->isEnabled("style"))
787         return;
788     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
789         const Token *formatToken = 0;
790         if (Token::Match(tok, "scanf|vscanf ( %str% ,"))
791             formatToken = tok->tokAt(2);
792         else if (Token::Match(tok, "fscanf|vfscanf ( %var% , %str% ,"))
793             formatToken = tok->tokAt(4);
794         else
795             continue;
796 
797         bool format = false;
798 
799         // scan the string backwards, so we don't need to keep states
800         const std::string &formatstr(formatToken->str());
801         for (unsigned int i = 1; i < formatstr.length(); i++) {
802             if (formatstr[i] == '%')
803                 format = !format;
804 
805             else if (!format)
806                 continue;
807 
808             else if (std::isdigit(formatstr[i])) {
809                 format = false;
810             }
811 
812             else if (std::isalpha(formatstr[i])) {
813                 invalidScanfError(tok);
814                 format = false;
815             }
816         }
817     }
818 }
819 
820 //---------------------------------------------------------------------------
821 //    if (!x==3) <- Probably meant to be "x!=3"
822 //---------------------------------------------------------------------------
checkComparisonOfBoolWithInt()823 void CheckOther::checkComparisonOfBoolWithInt()
824 {
825     if (!_settings->isEnabled("style"))
826         return;
827 
828     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
829         if (Token::Match(tok, "( ! %var% ==|!= %num% )")) {
830             const Token *numTok = tok->tokAt(4);
831             if (numTok && numTok->str() != "0") {
832                 comparisonOfBoolWithIntError(numTok, tok->strAt(2));
833             }
834         } else if (Token::Match(tok, "( %num% ==|!= ! %var% )")) {
835             const Token *numTok = tok->tokAt(1);
836             if (numTok && numTok->str() != "0") {
837                 comparisonOfBoolWithIntError(numTok, tok->strAt(4));
838             }
839         }
840     }
841 }
842 
843 //---------------------------------------------------------------------------
844 //    switch (x)
845 //    {
846 //        case 2:
847 //            y = a;
848 //            break;
849 //            break; // <- Redundant break
850 //        case 3:
851 //            y = b;
852 //    }
853 //---------------------------------------------------------------------------
checkDuplicateBreak()854 void CheckOther::checkDuplicateBreak()
855 {
856     if (!_settings->isEnabled("style"))
857         return;
858 
859     const char breakPattern[] = "break|continue ; break|continue ;";
860 
861     // Find consecutive break or continue statements. e.g.:
862     //   break; break;
863     const Token *tok = Token::findmatch(_tokenizer->tokens(), breakPattern);
864     while (tok) {
865         duplicateBreakError(tok);
866         tok = Token::findmatch(tok->next(), breakPattern);
867     }
868 }
869 
870 
sizeofForNumericParameterError(const Token * tok)871 void CheckOther::sizeofForNumericParameterError(const Token *tok)
872 {
873     reportError(tok, Severity::error,
874                 "sizeofwithnumericparameter", "Using sizeof with a numeric constant as function "
875                 "argument might not be what you intended.\n"
876                 "It is unusual to use constant value with sizeof. For example, this code:\n"
877                 "     int f() {\n"
878                 "         return sizeof(10);\n"
879                 "     }\n"
880                 " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10."
881                 );
882 }
883 
sizeofForArrayParameterError(const Token * tok)884 void CheckOther::sizeofForArrayParameterError(const Token *tok)
885 {
886     reportError(tok, Severity::error,
887                 "sizeofwithsilentarraypointer", "Using sizeof for array given as function argument "
888                 "returns the size of pointer.\n"
889                 "Giving array as function parameter and then using sizeof-operator for the array "
890                 "argument. In this case the sizeof-operator returns the size of pointer (in the "
891                 "system). It does not return the size of the whole array in bytes as might be "
892                 "expected. For example, this code:\n"
893                 "     int f(char a[100]) {\n"
894                 "         return sizeof(a);\n"
895                 "     }\n"
896                 " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
897                 "size of the array in bytes)."
898                 );
899 }
900 
invalidScanfError(const Token * tok)901 void CheckOther::invalidScanfError(const Token *tok)
902 {
903     reportError(tok, Severity::warning,
904                 "invalidscanf", "scanf without field width limits can crash with huge input data\n"
905                 "scanf without field width limits can crash with huge input data. To fix this error "
906                 "message add a field width specifier:\n"
907                 "    %s => %20s\n"
908                 "    %i => %3i\n"
909                 "\n"
910                 "Sample program that can crash:\n"
911                 "\n"
912                 "#include <stdio.h>\n"
913                 "int main()\n"
914                 "{\n"
915                 "    int a;\n"
916                 "    scanf(\"%i\", &a);\n"
917                 "    return 0;\n"
918                 "}\n"
919                 "\n"
920                 "To make it crash:\n"
921                 "perl -e 'print \"5\"x2100000' | ./a.out");
922 }
923 
924 //---------------------------------------------------------------------------
925 // Check for unsigned divisions
926 //---------------------------------------------------------------------------
927 
checkUnsignedDivision()928 void CheckOther::checkUnsignedDivision()
929 {
930     if (!_settings->isEnabled("style"))
931         return;
932 
933     // Check for "ivar / uvar" and "uvar / ivar"
934     std::map<unsigned int, char> varsign;
935     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
936         if (Token::Match(tok, "[{};(,] %type% %var% [;=,)]")) {
937             if (tok->tokAt(1)->isUnsigned())
938                 varsign[tok->tokAt(2)->varId()] = 'u';
939             else
940                 varsign[tok->tokAt(2)->varId()] = 's';
941         }
942 
943         else if (!Token::Match(tok, "[).]") && Token::Match(tok->next(), "%var% / %num%")) {
944             if (tok->strAt(3)[0] == '-') {
945                 char sign1 = varsign[tok->tokAt(1)->varId()];
946                 if (sign1 == 'u') {
947                     udivError(tok->next());
948                 }
949             }
950         }
951 
952         else if (Token::Match(tok, "(|[|=|%op% %num% / %var%")) {
953             if (tok->strAt(1)[0] == '-') {
954                 char sign2 = varsign[tok->tokAt(3)->varId()];
955                 if (sign2 == 'u') {
956                     udivError(tok->next());
957                 }
958             }
959         }
960     }
961 }
962 
963 //---------------------------------------------------------------------------
964 // memset(p, y, 0 /* bytes to fill */) <- 2nd and 3rd arguments inverted
965 //---------------------------------------------------------------------------
checkMemsetZeroBytes()966 void CheckOther::checkMemsetZeroBytes()
967 {
968     const Token *tok = _tokenizer->tokens();
969     while (tok && ((tok = Token::findmatch(tok, "memset ( %var% , %num% , 0 )")) != NULL)) {
970         memsetZeroBytesError(tok, tok->strAt(2));
971         tok = tok->tokAt(8);
972     }
973 }
974 //---------------------------------------------------------------------------
975 
976 
977 
978 //---------------------------------------------------------------------------
979 // Usage of function variables
980 //---------------------------------------------------------------------------
981 
982 /**
983  * @brief This class is used to capture the control flow within a function.
984  */
985 class ScopeInfo {
986 public:
ScopeInfo()987     ScopeInfo() : _token(NULL), _parent(NULL) {}
ScopeInfo(const Token * token,ScopeInfo * parent_)988     ScopeInfo(const Token *token, ScopeInfo *parent_) : _token(token), _parent(parent_) {}
989     ~ScopeInfo();
990 
parent()991     ScopeInfo *parent() {
992         return _parent;
993     }
994     ScopeInfo *addChild(const Token *token);
995     void remove(ScopeInfo *scope);
996 
997 private:
998     const Token *_token;
999     ScopeInfo *_parent;
1000     std::list<ScopeInfo *> _children;
1001 };
1002 
~ScopeInfo()1003 ScopeInfo::~ScopeInfo()
1004 {
1005     while (!_children.empty()) {
1006         delete *_children.begin();
1007         _children.pop_front();
1008     }
1009 }
1010 
addChild(const Token * token)1011 ScopeInfo *ScopeInfo::addChild(const Token *token)
1012 {
1013     ScopeInfo *temp = new ScopeInfo(token, this);
1014 
1015     _children.push_back(temp);
1016 
1017     return temp;
1018 }
1019 
remove(ScopeInfo * scope)1020 void ScopeInfo::remove(ScopeInfo *scope)
1021 {
1022     std::list<ScopeInfo *>::iterator it;
1023 
1024     for (it = _children.begin(); it != _children.end(); ++it) {
1025         if (*it == scope) {
1026             delete *it;
1027             _children.erase(it);
1028             break;
1029         }
1030     }
1031 }
1032 
1033 /**
1034  * @brief This class is used create a list of variables within a function.
1035  */
1036 class Variables {
1037 public:
1038     enum VariableType { standard, array, pointer, reference, pointerArray, referenceArray, pointerPointer };
1039 
1040     /** Store information about variable usage */
1041     class VariableUsage {
1042     public:
VariableUsage(const Token * name=0,VariableType type=standard,ScopeInfo * scope=NULL,bool read=false,bool write=false,bool modified=false,bool allocateMemory=false)1043         VariableUsage(const Token *name = 0,
1044                       VariableType type = standard,
1045                       ScopeInfo *scope = NULL,
1046                       bool read = false,
1047                       bool write = false,
1048                       bool modified = false,
1049                       bool allocateMemory = false) :
1050             _name(name),
1051             _type(type),
1052             _scope(scope),
1053             _read(read),
1054             _write(write),
1055             _modified(modified),
1056             _allocateMemory(allocateMemory) {}
1057 
1058         /** variable is used.. set both read+write */
use()1059         void use() {
1060             _read = true;
1061             _write = true;
1062         }
1063 
1064         /** is variable unused? */
unused() const1065         bool unused() const {
1066             return (!_read && !_write);
1067         }
1068 
1069         const Token *_name;
1070         VariableType _type;
1071         ScopeInfo *_scope;
1072         bool _read;
1073         bool _write;
1074         bool _modified; // read/modify/write
1075         bool _allocateMemory;
1076         std::set<unsigned int> _aliases;
1077         std::set<ScopeInfo *> _assignments;
1078     };
1079 
1080     typedef std::map<unsigned int, VariableUsage> VariableMap;
1081 
clear()1082     void clear() {
1083         _varUsage.clear();
1084     }
varUsage()1085     VariableMap &varUsage() {
1086         return _varUsage;
1087     }
1088     void addVar(const Token *name, VariableType type, ScopeInfo *scope, bool write_);
1089     void allocateMemory(unsigned int varid);
1090     void read(unsigned int varid);
1091     void readAliases(unsigned int varid);
1092     void readAll(unsigned int varid);
1093     void write(unsigned int varid);
1094     void writeAliases(unsigned int varid);
1095     void writeAll(unsigned int varid);
1096     void use(unsigned int varid);
1097     void modified(unsigned int varid);
1098     VariableUsage *find(unsigned int varid);
1099     void alias(unsigned int varid1, unsigned int varid2, bool replace);
erase(unsigned int varid)1100     void erase(unsigned int varid) {
1101         _varUsage.erase(varid);
1102     }
1103     void eraseAliases(unsigned int varid);
1104     void eraseAll(unsigned int varid);
1105     void clearAliases(unsigned int varid);
1106 
1107 private:
1108     VariableMap _varUsage;
1109 };
1110 
1111 /**
1112  * Alias the 2 given variables. Either replace the existing aliases if
1113  * they exist or merge them.  You would replace an existing alias when this
1114  * assignment is in the same scope as the previous assignment.  You might
1115  * merge the aliases when this assignment is in a different scope from the
1116  * previous assignment depending on the relationship of the 2 scopes.
1117  */
alias(unsigned int varid1,unsigned int varid2,bool replace)1118 void Variables::alias(unsigned int varid1, unsigned int varid2, bool replace)
1119 {
1120     VariableUsage *var1 = find(varid1);
1121     VariableUsage *var2 = find(varid2);
1122 
1123     // alias to self
1124     if (varid1 == varid2) {
1125         if (var1)
1126             var1->use();
1127         return;
1128     }
1129 
1130     std::set<unsigned int>::iterator i;
1131 
1132     if (replace) {
1133         // remove var1 from all aliases
1134         for (i = var1->_aliases.begin(); i != var1->_aliases.end(); ++i) {
1135             VariableUsage *temp = find(*i);
1136 
1137             if (temp)
1138                 temp->_aliases.erase(var1->_name->varId());
1139         }
1140 
1141         // remove all aliases from var1
1142         var1->_aliases.clear();
1143     }
1144 
1145     // var1 gets all var2s aliases
1146     for (i = var2->_aliases.begin(); i != var2->_aliases.end(); ++i) {
1147         if (*i != varid1)
1148             var1->_aliases.insert(*i);
1149     }
1150 
1151     // var2 is an alias of var1
1152     var2->_aliases.insert(varid1);
1153     var1->_aliases.insert(varid2);
1154 
1155     if (var2->_type == Variables::pointer)
1156         var2->_read = true;
1157 }
1158 
clearAliases(unsigned int varid)1159 void Variables::clearAliases(unsigned int varid)
1160 {
1161     VariableUsage *usage = find(varid);
1162 
1163     if (usage) {
1164         // remove usage from all aliases
1165         std::set<unsigned int>::iterator i;
1166 
1167         for (i = usage->_aliases.begin(); i != usage->_aliases.end(); ++i) {
1168             VariableUsage *temp = find(*i);
1169 
1170             if (temp)
1171                 temp->_aliases.erase(usage->_name->varId());
1172         }
1173 
1174         // remove all aliases from usage
1175         usage->_aliases.clear();
1176     }
1177 }
1178 
eraseAliases(unsigned int varid)1179 void Variables::eraseAliases(unsigned int varid)
1180 {
1181     VariableUsage *usage = find(varid);
1182 
1183     if (usage) {
1184         std::set<unsigned int>::iterator aliases;
1185 
1186         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases)
1187             erase(*aliases);
1188     }
1189 }
1190 
eraseAll(unsigned int varid)1191 void Variables::eraseAll(unsigned int varid)
1192 {
1193     eraseAliases(varid);
1194     erase(varid);
1195 }
1196 
addVar(const Token * name,VariableType type,ScopeInfo * scope,bool write_)1197 void Variables::addVar(const Token *name,
1198                        VariableType type,
1199                        ScopeInfo *scope,
1200                        bool write_)
1201 {
1202     if (name->varId() > 0)
1203         _varUsage.insert(std::make_pair(name->varId(), VariableUsage(name, type, scope, false, write_, false)));
1204 }
1205 
allocateMemory(unsigned int varid)1206 void Variables::allocateMemory(unsigned int varid)
1207 {
1208     VariableUsage *usage = find(varid);
1209 
1210     if (usage)
1211         usage->_allocateMemory = true;
1212 }
1213 
read(unsigned int varid)1214 void Variables::read(unsigned int varid)
1215 {
1216     VariableUsage *usage = find(varid);
1217 
1218     if (usage)
1219         usage->_read = true;
1220 }
1221 
readAliases(unsigned int varid)1222 void Variables::readAliases(unsigned int varid)
1223 {
1224     VariableUsage *usage = find(varid);
1225 
1226     if (usage) {
1227         std::set<unsigned int>::iterator aliases;
1228 
1229         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1230             VariableUsage *aliased = find(*aliases);
1231 
1232             if (aliased)
1233                 aliased->_read = true;
1234         }
1235     }
1236 }
1237 
readAll(unsigned int varid)1238 void Variables::readAll(unsigned int varid)
1239 {
1240     VariableUsage *usage = find(varid);
1241 
1242     if (usage) {
1243         usage->_read = true;
1244 
1245         std::set<unsigned int>::iterator aliases;
1246 
1247         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1248             VariableUsage *aliased = find(*aliases);
1249 
1250             if (aliased)
1251                 aliased->_read = true;
1252         }
1253     }
1254 }
1255 
write(unsigned int varid)1256 void Variables::write(unsigned int varid)
1257 {
1258     VariableUsage *usage = find(varid);
1259 
1260     if (usage)
1261         usage->_write = true;
1262 }
1263 
writeAliases(unsigned int varid)1264 void Variables::writeAliases(unsigned int varid)
1265 {
1266     VariableUsage *usage = find(varid);
1267 
1268     if (usage) {
1269         std::set<unsigned int>::iterator aliases;
1270 
1271         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1272             VariableUsage *aliased = find(*aliases);
1273 
1274             if (aliased)
1275                 aliased->_write = true;
1276         }
1277     }
1278 }
1279 
writeAll(unsigned int varid)1280 void Variables::writeAll(unsigned int varid)
1281 {
1282     VariableUsage *usage = find(varid);
1283 
1284     if (usage) {
1285         usage->_write = true;
1286 
1287         std::set<unsigned int>::iterator aliases;
1288 
1289         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1290             VariableUsage *aliased = find(*aliases);
1291 
1292             if (aliased)
1293                 aliased->_write = true;
1294         }
1295     }
1296 }
1297 
use(unsigned int varid)1298 void Variables::use(unsigned int varid)
1299 {
1300     VariableUsage *usage = find(varid);
1301 
1302     if (usage) {
1303         usage->use();
1304 
1305         std::set<unsigned int>::iterator aliases;
1306 
1307         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1308             VariableUsage *aliased = find(*aliases);
1309 
1310             if (aliased)
1311                 aliased->use();
1312         }
1313     }
1314 }
1315 
modified(unsigned int varid)1316 void Variables::modified(unsigned int varid)
1317 {
1318     VariableUsage *usage = find(varid);
1319 
1320     if (usage) {
1321         usage->_modified = true;
1322 
1323         std::set<unsigned int>::iterator aliases;
1324 
1325         for (aliases = usage->_aliases.begin(); aliases != usage->_aliases.end(); ++aliases) {
1326             VariableUsage *aliased = find(*aliases);
1327 
1328             if (aliased)
1329                 aliased->_modified = true;
1330         }
1331     }
1332 }
1333 
find(unsigned int varid)1334 Variables::VariableUsage *Variables::find(unsigned int varid)
1335 {
1336     if (varid) {
1337         VariableMap::iterator i = _varUsage.find(varid);
1338         if (i != _varUsage.end())
1339             return &i->second;
1340     }
1341     return 0;
1342 }
1343 
doAssignment(Variables & variables,const Token * tok,bool dereference,ScopeInfo * scope)1344 static int doAssignment(Variables &variables, const Token *tok, bool dereference, ScopeInfo *scope)
1345 {
1346     int next = 0;
1347 
1348     // a = a + b;
1349     if (Token::Match(tok, "%var% = %var% !!;") && tok->str() == tok->strAt(2)) {
1350         return 2;
1351     }
1352 
1353     // check for aliased variable
1354     const unsigned int varid1 = tok->varId();
1355     Variables::VariableUsage *var1 = variables.find(varid1);
1356 
1357     if (var1) {
1358         int start = 1;
1359 
1360         // search for '='
1361         while (tok->tokAt(start)->str() != "=")
1362             start++;
1363 
1364         start++;
1365 
1366         if (Token::Match(tok->tokAt(start), "&| %var%") ||
1367             Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) &| %var%") ||
1368             Token::Match(tok->tokAt(start), "( const| struct|union| %type% *| ) ( &| %var%") ||
1369             Token::Match(tok->tokAt(start), "%any% < const| struct|union| %type% *| > ( &| %var%")) {
1370             unsigned char offset = 0;
1371             unsigned int varid2;
1372             bool addressOf = false;
1373 
1374             if (Token::Match(tok->tokAt(start), "%var% ."))
1375                 variables.use(tok->tokAt(start)->varId());   // use = read + write
1376 
1377             // check for C style cast
1378             if (tok->tokAt(start)->str() == "(") {
1379                 if (tok->tokAt(start + 1)->str() == "const")
1380                     offset++;
1381 
1382                 if (Token::Match(tok->tokAt(start + 1 + offset), "struct|union"))
1383                     offset++;
1384 
1385                 if (tok->tokAt(start + 2 + offset)->str() == "*")
1386                     offset++;
1387 
1388                 if (tok->tokAt(start + 3 + offset)->str() == "&") {
1389                     addressOf = true;
1390                     next = start + 4 + offset;
1391                 } else if (tok->tokAt(start + 3 + offset)->str() == "(") {
1392                     if (tok->tokAt(start + 4 + offset)->str() == "&") {
1393                         addressOf = true;
1394                         next = start + 5 + offset;
1395                     } else
1396                         next = start + 4 + offset;
1397                 } else
1398                     next = start + 3 + offset;
1399             }
1400 
1401             // check for C++ style cast
1402             else if (tok->tokAt(start)->str().find("cast") != std::string::npos &&
1403                      tok->tokAt(start + 1)->str() == "<") {
1404                 if (tok->tokAt(start + 2)->str() == "const")
1405                     offset++;
1406 
1407                 if (Token::Match(tok->tokAt(start + 2 + offset), "struct|union"))
1408                     offset++;
1409 
1410                 if (tok->tokAt(start + 3 + offset)->str() == "*")
1411                     offset++;
1412 
1413                 if (tok->tokAt(start + 5 + offset)->str() == "&") {
1414                     addressOf = true;
1415                     next = start + 6 + offset;
1416                 } else
1417                     next = start + 5 + offset;
1418             }
1419 
1420             // check for var ? ...
1421             else if (Token::Match(tok->tokAt(start), "%var% ?")) {
1422                 next = start;
1423             }
1424 
1425             // no cast
1426             else {
1427                 if (tok->tokAt(start)->str() == "&") {
1428                     addressOf = true;
1429                     next = start + 1;
1430                 } else if (tok->tokAt(start)->str() == "new")
1431                     return 0;
1432                 else
1433                     next = start;
1434             }
1435 
1436             // check if variable is local
1437             varid2 = tok->tokAt(next)->varId();
1438             Variables::VariableUsage *var2 = variables.find(varid2);
1439 
1440             if (var2) { // local variable (alias or read it)
1441                 if (var1->_type == Variables::pointer) {
1442                     if (dereference)
1443                         variables.read(varid2);
1444                     else {
1445                         if (addressOf ||
1446                             var2->_type == Variables::array ||
1447                             var2->_type == Variables::pointer) {
1448                             bool replace = true;
1449 
1450                             // check if variable declared in same scope
1451                             if (scope == var1->_scope)
1452                                 replace = true;
1453 
1454                             // not in same scope as declaration
1455                             else {
1456                                 std::set<ScopeInfo *>::iterator assignment;
1457 
1458                                 // check for an assignment in this scope
1459                                 assignment = var1->_assignments.find(scope);
1460 
1461                                 // no other assignment in this scope
1462                                 if (assignment == var1->_assignments.end()) {
1463                                     // nothing to replace
1464                                     if (var1->_assignments.empty())
1465                                         replace = false;
1466 
1467                                     // this variable has previous assignments
1468                                     else {
1469                                         /**
1470                                          * @todo determine if existing aliases should be replaced or merged
1471                                          */
1472 
1473                                         replace = false;
1474                                     }
1475                                 }
1476 
1477                                 // assignment in this scope
1478                                 else {
1479                                     // replace when only one other assignment
1480                                     if (var1->_assignments.size() == 1)
1481                                         replace = true;
1482 
1483                                     // otherwise, merge them
1484                                     else
1485                                         replace = false;
1486                                 }
1487                             }
1488 
1489                             variables.alias(varid1, varid2, replace);
1490                         } else if (tok->tokAt(next + 1)->str() == "?") {
1491                             if (var2->_type == Variables::reference)
1492                                 variables.readAliases(varid2);
1493                             else
1494                                 variables.read(varid2);
1495                         }
1496                     }
1497                 } else if (var1->_type == Variables::reference) {
1498                     variables.alias(varid1, varid2, true);
1499                 } else {
1500                     if (var2->_type == Variables::pointer && tok->tokAt(next + 1)->str() == "[")
1501                         variables.readAliases(varid2);
1502 
1503                     variables.read(varid2);
1504                 }
1505             } else { // not a local variable (or an unsupported local variable)
1506                 if (var1->_type == Variables::pointer && !dereference) {
1507                     // check if variable declaration is in this scope
1508                     if (var1->_scope == scope)
1509                         variables.clearAliases(varid1);
1510                     else {
1511                         std::set<ScopeInfo *>::iterator assignment;
1512 
1513                         // check for an assignment in this scope
1514                         assignment = var1->_assignments.find(scope);
1515 
1516                         // no other assignment in this scope
1517                         if (assignment == var1->_assignments.end()) {
1518                             /**
1519                              * @todo determine if existing aliases should be discarded
1520                              */
1521                         }
1522 
1523                         // this assignment replaces the last assignment in this scope
1524                         else {
1525                             // aliased variables in a larger scope are not supported
1526                             // remove all aliases
1527                             variables.clearAliases(varid1);
1528                         }
1529                     }
1530                 }
1531             }
1532         }
1533 
1534         var1->_assignments.insert(scope);
1535     }
1536 
1537     // check for alias to struct member
1538     // char c[10]; a.b = c;
1539     else if (Token::Match(tok->tokAt(-2), "%var% .")) {
1540         if (Token::Match(tok->tokAt(2), "%var%")) {
1541             unsigned int varid2 = tok->tokAt(2)->varId();
1542             Variables::VariableUsage *var2 = variables.find(varid2);
1543 
1544             // struct member aliased to local variable
1545             if (var2 && (var2->_type == Variables::array ||
1546                          var2->_type == Variables::pointer)) {
1547                 // erase aliased variable and all variables that alias it
1548                 // to prevent false positives
1549                 variables.eraseAll(varid2);
1550             }
1551         }
1552     }
1553 
1554     return next;
1555 }
1556 
nextIsStandardType(const Token * tok)1557 static bool nextIsStandardType(const Token *tok)
1558 {
1559     tok = tok->next();
1560 
1561     if (tok->str() == "static")
1562         tok = tok->next();
1563 
1564     return tok->isStandardType();
1565 }
1566 
nextIsStandardTypeOrVoid(const Token * tok)1567 static bool nextIsStandardTypeOrVoid(const Token *tok)
1568 {
1569     tok = tok->next();
1570 
1571     if (tok->str() == "static")
1572         tok = tok->next();
1573 
1574     if (tok->str() == "const")
1575         tok = tok->next();
1576 
1577     return tok->isStandardType() || tok->str() == "void";
1578 }
1579 
isRecordTypeWithoutSideEffects(const Token * tok)1580 bool CheckOther::isRecordTypeWithoutSideEffects(const Token *tok)
1581 {
1582     const Variable * var = _tokenizer->getSymbolDatabase()->getVariableFromVarId(tok->varId());
1583 
1584     // a type that has no side effects (no constructors and no members with constructors)
1585     /** @todo false negative: check base class for side effects */
1586     /** @todo false negative: check constructors for side effects */
1587     if (var && var->type() && var->type()->numConstructors == 0 &&
1588         (var->type()->varlist.empty() || var->type()->needInitialization == Scope::True) &&
1589         var->type()->derivedFrom.empty())
1590         return true;
1591 
1592     return false;
1593 }
1594 
functionVariableUsage()1595 void CheckOther::functionVariableUsage()
1596 {
1597     if (!_settings->isEnabled("style"))
1598         return;
1599 
1600     // Parse all executing scopes..
1601     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
1602 
1603     std::list<Scope>::const_iterator scope;
1604 
1605     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
1606         // only check functions
1607         if (scope->type != Scope::eFunction)
1608             continue;
1609 
1610         // First token for the current scope..
1611         const Token *const tok1 = scope->classStart;
1612 
1613         // varId, usage {read, write, modified}
1614         Variables variables;
1615 
1616         // scopes
1617         ScopeInfo scopes;
1618         ScopeInfo *info = &scopes;
1619 
1620         unsigned int indentlevel = 0;
1621         for (const Token *tok = tok1; tok; tok = tok->next()) {
1622             if (tok->str() == "{") {
1623                 // replace the head node when found
1624                 if (indentlevel == 0)
1625                     scopes = ScopeInfo(tok, NULL);
1626                 // add the new scope
1627                 else
1628                     info = info->addChild(tok);
1629                 ++indentlevel;
1630             } else if (tok->str() == "}") {
1631                 --indentlevel;
1632 
1633                 info = info->parent();
1634 
1635                 if (indentlevel == 0)
1636                     break;
1637             } else if (Token::Match(tok, "struct|union|class {") ||
1638                        Token::Match(tok, "struct|union|class %type% {|:")) {
1639                 while (tok->str() != "{")
1640                     tok = tok->next();
1641                 tok = tok->link();
1642                 if (!tok)
1643                     break;
1644             }
1645 
1646             if (Token::Match(tok, "[;{}] asm ( ) ;")) {
1647                 variables.clear();
1648                 break;
1649             }
1650 
1651             // standard type declaration with possible initialization
1652             // int i; int j = 0; static int k;
1653             if (Token::Match(tok, "[;{}] static| %type% %var% ;|=") &&
1654                 !Token::Match(tok->next(), "return|throw")) {
1655                 tok = tok->next();
1656 
1657                 const bool isStatic = tok->str() == "static";
1658                 if (isStatic)
1659                     tok = tok->next();
1660 
1661                 if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next())) {
1662                     variables.addVar(tok->next(), Variables::standard, info,
1663                                      tok->tokAt(2)->str() == "=" || isStatic);
1664                 }
1665                 tok = tok->next();
1666             }
1667 
1668             // standard const type declaration
1669             // const int i = x;
1670             else if (Token::Match(tok, "[;{}] const %type% %var% =")) {
1671                 tok = tok->next()->next();
1672 
1673                 if (tok->isStandardType() || isRecordTypeWithoutSideEffects(tok->next()))
1674                     variables.addVar(tok->next(), Variables::standard, info, true);
1675 
1676                 tok = tok->next();
1677             }
1678 
1679             // std::string declaration with possible initialization
1680             // std::string s; std::string s = "string";
1681             else if (Token::Match(tok, "[;{}] static| std :: string %var% ;|=")) {
1682                 tok = tok->next();
1683 
1684                 const bool isStatic = tok->str() == "static";
1685                 if (isStatic)
1686                     tok = tok->next();
1687 
1688                 tok = tok->tokAt(3);
1689                 variables.addVar(tok, Variables::standard, info,
1690                                  tok->next()->str() == "=" || isStatic);
1691             }
1692 
1693             // standard struct type declaration with possible initialization
1694             // struct S s; struct S s = { 0 }; static struct S s;
1695             else if (Token::Match(tok, "[;{}] static| struct %type% %var% ;|=") &&
1696                      (isRecordTypeWithoutSideEffects(tok->strAt(1) == "static" ? tok->tokAt(4) : tok->tokAt(3)))) {
1697                 tok = tok->next();
1698 
1699                 bool isStatic = tok->str() == "static";
1700                 if (isStatic)
1701                     tok = tok->next();
1702 
1703                 tok = tok->next();
1704 
1705                 variables.addVar(tok->next(), Variables::standard, info,
1706                                  tok->tokAt(2)->str() == "=" || isStatic);
1707                 tok = tok->next();
1708             }
1709 
1710             // standard type declaration and initialization using constructor
1711             // int i(0); static int j(0);
1712             else if (Token::Match(tok, "[;{}] static| %type% %var% ( %any% ) ;") &&
1713                      nextIsStandardType(tok)) {
1714                 tok = tok->next();
1715 
1716                 if (tok->str() == "static")
1717                     tok = tok->next();
1718 
1719                 variables.addVar(tok->next(), Variables::standard, info, true);
1720 
1721                 // check if a local variable is used to initialize this variable
1722                 if (tok->tokAt(3)->varId() > 0)
1723                     variables.readAll(tok->tokAt(3)->varId());
1724                 tok = tok->tokAt(4);
1725             }
1726 
1727             // standard type declaration of array of with possible initialization
1728             // int i[10]; int j[2] = { 0, 1 }; static int k[2] = { 2, 3 };
1729             else if (Token::Match(tok, "[;{}] static| const| %type% *| %var% [ %any% ] ;|=") &&
1730                      nextIsStandardType(tok)) {
1731                 tok = tok->next();
1732 
1733                 const bool isStatic = tok->str() == "static";
1734                 if (isStatic)
1735                     tok = tok->next();
1736 
1737                 if (tok->str() == "const")
1738                     tok = tok->next();
1739 
1740                 if (tok->str() != "return" && tok->str() != "throw") {
1741                     bool isPointer = bool(tok->strAt(1) == "*");
1742                     const Token * const nametok = tok->tokAt(isPointer ? 2 : 1);
1743 
1744                     variables.addVar(nametok, isPointer ? Variables::pointerArray : Variables::array, info,
1745                                      nametok->tokAt(4)->str() == "=" || isStatic);
1746 
1747                     // check for reading array size from local variable
1748                     if (nametok->tokAt(2)->varId() != 0)
1749                         variables.read(nametok->tokAt(2)->varId());
1750 
1751                     // look at initializers
1752                     if (Token::simpleMatch(nametok->tokAt(4), "= {")) {
1753                         tok = nametok->tokAt(6);
1754                         while (tok->str() != "}") {
1755                             if (Token::Match(tok, "%var%"))
1756                                 variables.read(tok->varId());
1757                             tok = tok->next();
1758                         }
1759                     } else
1760                         tok = nametok->tokAt(3);
1761                 }
1762             }
1763 
1764             // pointer or reference declaration with possible initialization
1765             // int * i; int * j = 0; static int * k = 0;
1766             else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% ;|=")) {
1767                 tok = tok->next();
1768 
1769                 const bool isStatic = tok->str() == "static";
1770                 if (isStatic)
1771                     tok = tok->next();
1772 
1773                 if (tok->str() == "const")
1774                     tok = tok->next();
1775 
1776                 if (tok->strAt(1) == "::")
1777                     tok = tok->tokAt(2);
1778 
1779                 if (tok->str() != "return" && tok->str() != "throw") {
1780                     Variables::VariableType type;
1781 
1782                     if (tok->next()->str() == "*")
1783                         type = Variables::pointer;
1784                     else
1785                         type = Variables::reference;
1786 
1787                     bool written = tok->tokAt(3)->str() == "=";
1788 
1789                     variables.addVar(tok->tokAt(2), type, info, written || isStatic);
1790 
1791                     int offset = 0;
1792 
1793                     // check for assignment
1794                     if (written)
1795                         offset = doAssignment(variables, tok->tokAt(2), false, info);
1796 
1797                     tok = tok->tokAt(2 + offset);
1798                 }
1799             }
1800 
1801             // pointer to pointer declaration with possible initialization
1802             // int ** i; int ** j = 0; static int ** k = 0;
1803             else if (Token::Match(tok, "[;{}] static| const| %type% * * %var% ;|=")) {
1804                 tok = tok->next();
1805 
1806                 const bool isStatic = tok->str() == "static";
1807                 if (isStatic)
1808                     tok = tok->next();
1809 
1810                 if (tok->str() == "const")
1811                     tok = tok->next();
1812 
1813                 if (tok->str() != "return") {
1814                     bool written = tok->tokAt(4)->str() == "=";
1815 
1816                     variables.addVar(tok->tokAt(3), Variables::pointerPointer, info, written || isStatic);
1817 
1818                     int offset = 0;
1819 
1820                     // check for assignment
1821                     if (written)
1822                         offset = doAssignment(variables, tok->tokAt(3), false, info);
1823 
1824                     tok = tok->tokAt(3 + offset);
1825                 }
1826             }
1827 
1828             // pointer or reference of struct or union declaration with possible initialization
1829             // struct s * i; struct s * j = 0; static struct s * k = 0;
1830             else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% ;|=")) {
1831                 Variables::VariableType type;
1832 
1833                 tok = tok->next();
1834 
1835                 const bool isStatic = tok->str() == "static";
1836                 if (isStatic)
1837                     tok = tok->next();
1838 
1839                 if (tok->str() == "const")
1840                     tok = tok->next();
1841 
1842                 if (tok->strAt(2) == "*")
1843                     type = Variables::pointer;
1844                 else
1845                     type = Variables::reference;
1846 
1847                 const bool written = tok->strAt(4) == "=";
1848 
1849                 variables.addVar(tok->tokAt(3), type, info, written || isStatic);
1850 
1851                 int offset = 0;
1852 
1853                 // check for assignment
1854                 if (written)
1855                     offset = doAssignment(variables, tok->tokAt(3), false, info);
1856 
1857                 tok = tok->tokAt(3 + offset);
1858             }
1859 
1860             // pointer or reference declaration with initialization using constructor
1861             // int * i(j); int * k(i); static int * l(i);
1862             else if (Token::Match(tok, "[;{}] static| const| %type% &|* %var% ( %any% ) ;") &&
1863                      nextIsStandardTypeOrVoid(tok)) {
1864                 Variables::VariableType type;
1865 
1866                 tok = tok->next();
1867 
1868                 if (tok->str() == "static")
1869                     tok = tok->next();
1870 
1871                 if (tok->str() == "const")
1872                     tok = tok->next();
1873 
1874                 if (tok->next()->str() == "*")
1875                     type = Variables::pointer;
1876                 else
1877                     type = Variables::reference;
1878 
1879                 unsigned int varid = 0;
1880 
1881                 // check for aliased variable
1882                 if (Token::Match(tok->tokAt(4), "%var%"))
1883                     varid = tok->tokAt(4)->varId();
1884 
1885                 variables.addVar(tok->tokAt(2), type, info, true);
1886 
1887                 // check if a local variable is used to initialize this variable
1888                 if (varid > 0) {
1889                     Variables::VariableUsage *var = variables.find(varid);
1890 
1891                     if (type == Variables::pointer) {
1892                         variables.use(tok->tokAt(4)->varId());
1893 
1894                         if (var && (var->_type == Variables::array ||
1895                                     var->_type == Variables::pointer))
1896                             var->_aliases.insert(tok->varId());
1897                     } else {
1898                         variables.readAll(tok->tokAt(4)->varId());
1899                         if (var)
1900                             var->_aliases.insert(tok->varId());
1901                     }
1902                 }
1903                 tok = tok->tokAt(5);
1904             }
1905 
1906             // array of pointer or reference declaration with possible initialization
1907             // int * p[10]; int * q[10] = { 0 }; static int * * r[10] = { 0 };
1908             else if (Token::Match(tok, "[;{}] static| const| %type% *|& %var% [ %any% ] ;|=")) {
1909                 tok = tok->next();
1910 
1911                 const bool isStatic = tok->str() == "static";
1912                 if (isStatic)
1913                     tok = tok->next();
1914 
1915                 if (tok->str() == "const")
1916                     tok = tok->next();
1917 
1918                 if (tok->str() != "return") {
1919                     variables.addVar(tok->tokAt(2),
1920                                      tok->next()->str() == "*" ? Variables::pointerArray : Variables::referenceArray, info,
1921                                      tok->tokAt(6)->str() == "=" || isStatic);
1922 
1923                     // check for reading array size from local variable
1924                     if (tok->tokAt(4)->varId() != 0)
1925                         variables.read(tok->tokAt(4)->varId());
1926 
1927                     tok = tok->tokAt(5);
1928                 }
1929             }
1930 
1931             // array of pointer or reference of struct or union declaration with possible initialization
1932             // struct S * p[10]; struct T * q[10] = { 0 }; static struct S * r[10] = { 0 };
1933             else if (Token::Match(tok, "[;{}] static| const| struct|union %type% *|& %var% [ %any% ] ;|=")) {
1934                 tok = tok->next();
1935 
1936                 const bool isStatic = tok->str() == "static";
1937                 if (isStatic)
1938                     tok = tok->next();
1939 
1940                 if (tok->str() == "const")
1941                     tok = tok->next();
1942 
1943                 variables.addVar(tok->tokAt(3),
1944                                  tok->tokAt(2)->str() == "*" ? Variables::pointerArray : Variables::referenceArray, info,
1945                                  tok->tokAt(7)->str() == "=" || isStatic);
1946 
1947                 // check for reading array size from local variable
1948                 if (tok->tokAt(5)->varId() != 0)
1949                     variables.read(tok->tokAt(5)->varId());
1950 
1951                 tok = tok->tokAt(6);
1952             }
1953 
1954             // Freeing memory (not considered "using" the pointer if it was also allocated in this function)
1955             else if (Token::Match(tok, "free|g_free|kfree|vfree ( %var% )") ||
1956                      Token::Match(tok, "delete %var% ;") ||
1957                      Token::Match(tok, "delete [ ] %var% ;")) {
1958                 unsigned int varid = 0;
1959                 if (tok->str() != "delete") {
1960                     varid = tok->tokAt(2)->varId();
1961                     tok = tok->tokAt(3);
1962                 } else if (tok->strAt(1) == "[") {
1963                     varid = tok->tokAt(3)->varId();
1964                     tok = tok->tokAt(4);
1965                 } else {
1966                     varid = tok->next()->varId();
1967                     tok = tok->tokAt(2);
1968                 }
1969 
1970                 Variables::VariableUsage *var = variables.find(varid);
1971                 if (var && !var->_allocateMemory) {
1972                     variables.readAll(varid);
1973                 }
1974             }
1975 
1976             else if (Token::Match(tok, "return|throw %var%"))
1977                 variables.readAll(tok->next()->varId());
1978 
1979             // assignment
1980             else if (Token::Match(tok, "*| (| ++|--| %var% ++|--| )| =") ||
1981                      Token::Match(tok, "*| ( const| %type% *| ) %var% =")) {
1982                 bool dereference = false;
1983                 bool pre = false;
1984                 bool post = false;
1985 
1986                 if (tok->str() == "*") {
1987                     dereference = true;
1988                     tok = tok->next();
1989                 }
1990 
1991                 if (Token::Match(tok, "( const| %type% *| ) %var% ="))
1992                     tok = tok->link()->next();
1993 
1994                 else if (tok->str() == "(")
1995                     tok = tok->next();
1996 
1997                 if (Token::Match(tok, "++|--")) {
1998                     pre = true;
1999                     tok = tok->next();
2000                 }
2001 
2002                 if (Token::Match(tok->next(), "++|--"))
2003                     post = true;
2004 
2005                 const unsigned int varid1 = tok->varId();
2006                 const Token *start = tok;
2007 
2008                 tok = tok->tokAt(doAssignment(variables, tok, dereference, info));
2009 
2010                 if (pre || post)
2011                     variables.use(varid1);
2012 
2013                 if (dereference) {
2014                     Variables::VariableUsage *var = variables.find(varid1);
2015                     if (var && var->_type == Variables::array)
2016                         variables.write(varid1);
2017                     variables.writeAliases(varid1);
2018                     variables.read(varid1);
2019                 } else {
2020                     Variables::VariableUsage *var = variables.find(varid1);
2021                     if (var && var->_type == Variables::reference) {
2022                         variables.writeAliases(varid1);
2023                         variables.read(varid1);
2024                     }
2025                     // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
2026                     else if (var && var->_type == Variables::pointer &&
2027                              Token::Match(start, "%var% = new|malloc|calloc|g_malloc|kmalloc|vmalloc")) {
2028                         bool allocate = true;
2029 
2030                         if (start->strAt(2) == "new") {
2031                             // is it a user defined type?
2032                             if (!start->tokAt(3)->isStandardType()) {
2033                                 if (!isRecordTypeWithoutSideEffects(start))
2034                                     allocate = false;
2035                             }
2036                         }
2037 
2038                         if (allocate)
2039                             variables.allocateMemory(varid1);
2040                         else
2041                             variables.write(varid1);
2042                     } else if (varid1 && Token::Match(tok, "%varid% .", varid1)) {
2043                         variables.use(varid1);
2044                     } else {
2045                         variables.write(varid1);
2046                     }
2047 
2048                     Variables::VariableUsage *var2 = variables.find(tok->varId());
2049                     if (var2) {
2050                         if (var2->_type == Variables::reference) {
2051                             variables.writeAliases(tok->varId());
2052                             variables.read(tok->varId());
2053                         } else if (tok->varId() != varid1 && Token::Match(tok, "%var% ."))
2054                             variables.read(tok->varId());
2055                         else if (tok->varId() != varid1 &&
2056                                  var2->_type == Variables::standard &&
2057                                  tok->strAt(-1) != "&")
2058                             variables.use(tok->varId());
2059                     }
2060                 }
2061 
2062                 const Token *equal = tok->next();
2063 
2064                 if (Token::Match(tok->next(), "[ %any% ]"))
2065                     equal = tok->tokAt(4);
2066 
2067                 // checked for chained assignments
2068                 if (tok != start && equal->str() == "=") {
2069                     Variables::VariableUsage *var = variables.find(tok->varId());
2070 
2071                     if (var && var->_type != Variables::reference)
2072                         var->_read = true;
2073 
2074                     tok = tok->previous();
2075                 }
2076             }
2077 
2078             // assignment
2079             else if (Token::Match(tok, "%var% [") && Token::simpleMatch(tok->next()->link(), "] =")) {
2080                 unsigned int varid = tok->varId();
2081                 const Variables::VariableUsage *var = variables.find(varid);
2082 
2083                 if (var) {
2084                     // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable
2085                     if (var->_type == Variables::pointer &&
2086                         Token::Match(tok->next()->link(), "] = new|malloc|calloc|g_malloc|kmalloc|vmalloc")) {
2087                         variables.allocateMemory(varid);
2088                     } else if (var->_type == Variables::pointer || var->_type == Variables::reference) {
2089                         variables.read(varid);
2090                         variables.writeAliases(varid);
2091                     } else
2092                         variables.writeAll(varid);
2093                 }
2094             }
2095 
2096             else if (Token::Match(tok, ">>|& %var%"))
2097                 variables.use(tok->next()->varId());    // use = read + write
2098             else if (Token::Match(tok, "[;{}] %var% >>"))
2099                 variables.use(tok->next()->varId());    // use = read + write
2100 
2101             // function parameter
2102             else if (Token::Match(tok, "[(,] %var% ["))
2103                 variables.use(tok->next()->varId());   // use = read + write
2104             else if (Token::Match(tok, "[(,] %var% [,)]") && tok->previous()->str() != "*")
2105                 variables.use(tok->next()->varId());   // use = read + write
2106             else if (Token::Match(tok, "[(,] (") &&
2107                      Token::Match(tok->next()->link(), ") %var% [,)]"))
2108                 variables.use(tok->next()->link()->next()->varId());   // use = read + write
2109 
2110             // function
2111             else if (Token::Match(tok, "%var% (")) {
2112                 variables.read(tok->varId());
2113                 if (Token::Match(tok->tokAt(2), "%var% ="))
2114                     variables.read(tok->tokAt(2)->varId());
2115             }
2116 
2117             else if (Token::Match(tok, "[{,] %var% [,}]"))
2118                 variables.read(tok->next()->varId());
2119 
2120             else if (Token::Match(tok, "%var% ."))
2121                 variables.use(tok->varId());   // use = read + write
2122 
2123             else if ((Token::Match(tok, "[(=&!]") || tok->isExtendedOp()) &&
2124                      (Token::Match(tok->next(), "%var%") && !Token::Match(tok->next(), "true|false|new")))
2125                 variables.readAll(tok->next()->varId());
2126 
2127             else if (Token::Match(tok, "%var%") && (tok->next()->str() == ")" || tok->next()->isExtendedOp()))
2128                 variables.readAll(tok->varId());
2129 
2130             else if (Token::Match(tok, "; %var% ;"))
2131                 variables.readAll(tok->next()->varId());
2132 
2133             if (Token::Match(tok, "++|-- %var%")) {
2134                 if (tok->strAt(-1) != ";")
2135                     variables.use(tok->next()->varId());
2136                 else
2137                     variables.modified(tok->next()->varId());
2138             }
2139 
2140             else if (Token::Match(tok, "%var% ++|--")) {
2141                 if (tok->strAt(-1) != ";")
2142                     variables.use(tok->varId());
2143                 else
2144                     variables.modified(tok->varId());
2145             }
2146 
2147             else if (tok->isAssignmentOp()) {
2148                 for (const Token *tok2 = tok->next(); tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
2149                     if (tok2->varId()) {
2150                         variables.read(tok2->varId());
2151                         if (tok2->next()->isAssignmentOp())
2152                             variables.write(tok2->varId());
2153                     }
2154                 }
2155             }
2156         }
2157 
2158         // Check usage of all variables in the current scope..
2159         Variables::VariableMap::const_iterator it;
2160         for (it = variables.varUsage().begin(); it != variables.varUsage().end(); ++it) {
2161             const Variables::VariableUsage &usage = it->second;
2162             const std::string &varname = usage._name->str();
2163 
2164             // variable has been marked as unused so ignore it
2165             if (usage._name->isUnused())
2166                 continue;
2167 
2168             // skip things that are only partially implemented to prevent false positives
2169             if (usage._type == Variables::pointerPointer ||
2170                 usage._type == Variables::pointerArray ||
2171                 usage._type == Variables::referenceArray)
2172                 continue;
2173 
2174             // variable has had memory allocated for it, but hasn't done
2175             // anything with that memory other than, perhaps, freeing it
2176             if (usage.unused() && !usage._modified && usage._allocateMemory)
2177                 allocatedButUnusedVariableError(usage._name, varname);
2178 
2179             // variable has not been written, read, or modified
2180             else if (usage.unused() && !usage._modified)
2181                 unusedVariableError(usage._name, varname);
2182 
2183             // variable has not been written but has been modified
2184             else if (usage._modified & !usage._write)
2185                 unassignedVariableError(usage._name, varname);
2186 
2187             // variable has been written but not read
2188             else if (!usage._read && !usage._modified)
2189                 unreadVariableError(usage._name, varname);
2190 
2191             // variable has been read but not written
2192             else if (!usage._write && !usage._allocateMemory)
2193                 unassignedVariableError(usage._name, varname);
2194         }
2195     }
2196 }
2197 
unusedVariableError(const Token * tok,const std::string & varname)2198 void CheckOther::unusedVariableError(const Token *tok, const std::string &varname)
2199 {
2200     reportError(tok, Severity::style, "unusedVariable", "Unused variable: " + varname);
2201 }
2202 
allocatedButUnusedVariableError(const Token * tok,const std::string & varname)2203 void CheckOther::allocatedButUnusedVariableError(const Token *tok, const std::string &varname)
2204 {
2205     reportError(tok, Severity::style, "unusedAllocatedMemory", "Variable '" + varname + "' is allocated memory that is never used");
2206 }
2207 
unreadVariableError(const Token * tok,const std::string & varname)2208 void CheckOther::unreadVariableError(const Token *tok, const std::string &varname)
2209 {
2210     reportError(tok, Severity::style, "unreadVariable", "Variable '" + varname + "' is assigned a value that is never used");
2211 }
2212 
unassignedVariableError(const Token * tok,const std::string & varname)2213 void CheckOther::unassignedVariableError(const Token *tok, const std::string &varname)
2214 {
2215     reportError(tok, Severity::style, "unassignedVariable", "Variable '" + varname + "' is not assigned a value");
2216 }
2217 //---------------------------------------------------------------------------
2218 
2219 
2220 
2221 
2222 
2223 //---------------------------------------------------------------------------
2224 // Check scope of variables..
2225 //---------------------------------------------------------------------------
2226 
checkVariableScope()2227 void CheckOther::checkVariableScope()
2228 {
2229     if (!_settings->isEnabled("information"))
2230         return;
2231 
2232     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
2233 
2234     std::list<Scope>::const_iterator scope;
2235 
2236     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
2237         // only check functions
2238         if (scope->type != Scope::eFunction)
2239             continue;
2240 
2241         // Walk through all tokens..
2242         int indentlevel = 0;
2243         for (const Token *tok = scope->classStart; tok; tok = tok->next()) {
2244             // Skip function local class and struct declarations..
2245             if ((tok->str() == "class") || (tok->str() == "struct") || (tok->str() == "union")) {
2246                 for (const Token *tok2 = tok; tok2; tok2 = tok2->next()) {
2247                     if (tok2->str() == "{") {
2248                         tok = tok2->link();
2249                         break;
2250                     }
2251                     if (Token::Match(tok2, "[,);]")) {
2252                         break;
2253                     }
2254                 }
2255                 if (!tok)
2256                     break;
2257             }
2258 
2259             else if (tok->str() == "{") {
2260                 ++indentlevel;
2261             } else if (tok->str() == "}") {
2262                 --indentlevel;
2263                 if (indentlevel == 0)
2264                     break;
2265             }
2266 
2267             if (indentlevel > 0 && Token::Match(tok, "[{};]")) {
2268                 // First token of statement..
2269                 const Token *tok1 = tok->next();
2270                 if (!tok1)
2271                     continue;
2272 
2273                 if ((tok1->str() == "return") ||
2274                     (tok1->str() == "throw") ||
2275                     (tok1->str() == "delete") ||
2276                     (tok1->str() == "goto") ||
2277                     (tok1->str() == "else"))
2278                     continue;
2279 
2280                 // Variable declaration?
2281                 if (Token::Match(tok1, "%type% %var% ; %var% = %num% ;")) {
2282                     // Tokenizer modify "int i = 0;" to "int i; i = 0;",
2283                     // so to handle this situation we just skip
2284                     // initialization (see ticket #272).
2285                     const unsigned int firstVarId = tok1->next()->varId();
2286                     const unsigned int secondVarId = tok1->tokAt(3)->varId();
2287                     if (firstVarId > 0 && firstVarId == secondVarId) {
2288                         lookupVar(tok1->tokAt(6), tok1->strAt(1));
2289                     }
2290                 } else if (tok1->isStandardType() && Token::Match(tok1, "%type% %var% [;=]")) {
2291                     lookupVar(tok1, tok1->strAt(1));
2292                 }
2293             }
2294         }
2295     }
2296 
2297 }
2298 //---------------------------------------------------------------------------
2299 
lookupVar(const Token * tok1,const std::string & varname)2300 void CheckOther::lookupVar(const Token *tok1, const std::string &varname)
2301 {
2302     const Token *tok = tok1;
2303 
2304     // Skip the variable declaration..
2305     while (tok && tok->str() != ";")
2306         tok = tok->next();
2307 
2308     // Check if the variable is used in this indentlevel..
2309     bool used1 = false;   // used in one sub-scope -> reducable
2310     bool used2 = false;   // used in more sub-scopes -> not reducable
2311     int indentlevel = 0;
2312     int parlevel = 0;
2313     bool for_or_while = false;  // is sub-scope a "for/while/etc". anything that is not "if"
2314     while (tok) {
2315         if (tok->str() == "{") {
2316             if (tok->strAt(-1) == "=") {
2317                 if (Token::findmatch(tok, varname.c_str(), tok->link())) {
2318                     return;
2319                 }
2320 
2321                 tok = tok->link();
2322             } else
2323                 ++indentlevel;
2324         }
2325 
2326         else if (tok->str() == "}") {
2327             if (indentlevel == 0)
2328                 break;
2329             --indentlevel;
2330             if (indentlevel == 0) {
2331                 if (for_or_while && used2)
2332                     return;
2333                 used2 |= used1;
2334                 used1 = false;
2335             }
2336         }
2337 
2338         else if (tok->str() == "(") {
2339             ++parlevel;
2340         }
2341 
2342         else if (tok->str() == ")") {
2343             --parlevel;
2344         }
2345 
2346         // Bail out if references are used
2347         else if (Token::simpleMatch(tok, (std::string("& ") + varname).c_str())) {
2348             return;
2349         }
2350 
2351         else if (tok->str() == varname) {
2352             if (indentlevel == 0)
2353                 return;
2354             used1 = true;
2355             if (for_or_while && !Token::simpleMatch(tok->next(), "="))
2356                 used2 = true;
2357             if (used1 && used2)
2358                 return;
2359         }
2360 
2361         else if (indentlevel == 0) {
2362             // %unknown% ( %any% ) {
2363             // If %unknown% is anything except if, we assume
2364             // that it is a for or while loop or a macro hiding either one
2365             if (Token::simpleMatch(tok->next(), "(") &&
2366                 Token::simpleMatch(tok->next()->link(), ") {")) {
2367                 if (tok->str() != "if")
2368                     for_or_while = true;
2369             }
2370 
2371             else if (Token::simpleMatch(tok, "do {"))
2372                 for_or_while = true;
2373 
2374             // possible unexpanded macro hiding for/while..
2375             else if (tok->str() != "else" && Token::Match(tok->previous(), "[;{}] %type% {")) {
2376                 for_or_while = true;
2377             }
2378 
2379             if (parlevel == 0 && (tok->str() == ";"))
2380                 for_or_while = false;
2381         }
2382 
2383         tok = tok->next();
2384     }
2385 
2386     // Warning if this variable:
2387     // * not used in this indentlevel
2388     // * used in lower indentlevel
2389     if (used1 || used2)
2390         variableScopeError(tok1, varname);
2391 }
2392 //---------------------------------------------------------------------------
2393 
2394 
2395 //---------------------------------------------------------------------------
2396 // Check for constant function parameters
2397 //---------------------------------------------------------------------------
2398 
checkConstantFunctionParameter()2399 void CheckOther::checkConstantFunctionParameter()
2400 {
2401     if (!_settings->isEnabled("style"))
2402         return;
2403 
2404     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
2405 
2406     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2407         // TODO: False negatives. This pattern only checks for string.
2408         //       Investigate if there are other classes in the std
2409         //       namespace and add them to the pattern. There are
2410         //       streams for example (however it seems strange with
2411         //       const stream parameter).
2412         if (Token::Match(tok, "[,(] const std :: string %var% [,)]")) {
2413             passedByValueError(tok, tok->strAt(5));
2414         }
2415 
2416         else if (Token::Match(tok, "[,(] const std :: %type% < %type% > %var% [,)]")) {
2417             passedByValueError(tok, tok->strAt(8));
2418         }
2419 
2420         else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% > %var% [,)]")) {
2421             passedByValueError(tok, tok->strAt(10));
2422         }
2423 
2424         else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , std :: %type% > %var% [,)]")) {
2425             passedByValueError(tok, tok->strAt(14));
2426         }
2427 
2428         else if (Token::Match(tok, "[,(] const std :: %type% < %type% , std :: %type% > %var% [,)]")) {
2429             passedByValueError(tok, tok->strAt(12));
2430         }
2431 
2432         else if (Token::Match(tok, "[,(] const std :: %type% < std :: %type% , %type% > %var% [,)]")) {
2433             passedByValueError(tok, tok->strAt(12));
2434         }
2435 
2436         else if (Token::Match(tok, "[,(] const std :: %type% < %type% , %type% > %var% [,)]")) {
2437             passedByValueError(tok, tok->strAt(10));
2438         }
2439 
2440         else if (Token::Match(tok, "[,(] const %type% %var% [,)]")) {
2441             // Check if type is a struct or class.
2442             if (symbolDatabase->isClassOrStruct(tok->strAt(2))) {
2443                 passedByValueError(tok, tok->strAt(3));
2444             }
2445         }
2446     }
2447 }
2448 //---------------------------------------------------------------------------
2449 
2450 
2451 //---------------------------------------------------------------------------
2452 // Check that all struct members are used
2453 //---------------------------------------------------------------------------
2454 
checkStructMemberUsage()2455 void CheckOther::checkStructMemberUsage()
2456 {
2457     if (!_settings->isEnabled("style"))
2458         return;
2459 
2460     std::string structname;
2461     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2462         if (tok->fileIndex() != 0)
2463             continue;
2464 
2465         if (Token::Match(tok, "struct|union %type% {")) {
2466             structname.clear();
2467             if (Token::simpleMatch(tok->previous(), "extern"))
2468                 continue;
2469             if ((!tok->previous() || Token::simpleMatch(tok->previous(), ";")) && Token::Match(tok->tokAt(2)->link(), ("} ; " + tok->strAt(1) + " %var% ;").c_str()))
2470                 continue;
2471 
2472             structname = tok->strAt(1);
2473 
2474             // Bail out if struct/union contain any functions
2475             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
2476                 if (tok2->str() == "(") {
2477                     structname.clear();
2478                     break;
2479                 }
2480 
2481                 if (tok2->str() == "}")
2482                     break;
2483             }
2484 
2485             // bail out if struct is inherited
2486             if (!structname.empty() && Token::findmatch(tok, (",|private|protected|public " + structname).c_str()))
2487                 structname.clear();
2488 
2489             // Bail out if some data is casted to struct..
2490             const std::string s("( struct| " + tok->next()->str() + " * ) & %var% [");
2491             if (Token::findmatch(tok, s.c_str()))
2492                 structname.clear();
2493 
2494             // Try to prevent false positives when struct members are not used directly.
2495             if (Token::findmatch(tok, (structname + " *").c_str()))
2496                 structname.clear();
2497             else if (Token::findmatch(tok, (structname + " %type% *").c_str()))
2498                 structname = "";
2499         }
2500 
2501         if (tok->str() == "}")
2502             structname.clear();
2503 
2504         if (!structname.empty() && Token::Match(tok, "[{;]")) {
2505             // Declaring struct variable..
2506             std::string varname;
2507 
2508             // declaring a POD variable?
2509             if (!tok->next()->isStandardType())
2510                 continue;
2511 
2512             if (Token::Match(tok->next(), "%type% %var% [;[]"))
2513                 varname = tok->strAt(2);
2514             else if (Token::Match(tok->next(), "%type% %type% %var% [;[]"))
2515                 varname = tok->strAt(3);
2516             else if (Token::Match(tok->next(), "%type% * %var% [;[]"))
2517                 varname = tok->strAt(3);
2518             else if (Token::Match(tok->next(), "%type% %type% * %var% [;[]"))
2519                 varname = tok->strAt(4);
2520             else
2521                 continue;
2522 
2523             // Check if the struct variable is used anywhere in the file
2524             const std::string usagePattern(". " + varname);
2525             bool used = false;
2526             for (const Token *tok2 = _tokenizer->tokens(); tok2; tok2 = tok2->next()) {
2527                 if (Token::simpleMatch(tok2, usagePattern.c_str())) {
2528                     used = true;
2529                     break;
2530                 }
2531             }
2532 
2533             if (!used) {
2534                 unusedStructMemberError(tok->next(), structname, varname);
2535             }
2536         }
2537     }
2538 }
2539 
2540 
2541 
2542 
2543 
2544 //---------------------------------------------------------------------------
2545 // Check usage of char variables..
2546 //---------------------------------------------------------------------------
2547 
checkCharVariable()2548 void CheckOther::checkCharVariable()
2549 {
2550     if (!_settings->isEnabled("style"))
2551         return;
2552 
2553     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2554         // Declaring the variable..
2555         if (Token::Match(tok, "[{};(,] const| char *| %var% [;=,)]") ||
2556             Token::Match(tok, "[{};(,] const| char %var% [")) {
2557             // goto 'char' token
2558             tok = tok->next();
2559             if (tok->str() == "const")
2560                 tok = tok->next();
2561 
2562             // Check for unsigned char
2563             if (tok->isUnsigned())
2564                 continue;
2565 
2566             // Set tok to point to the variable name
2567             tok = tok->next();
2568             const bool isPointer(tok->str() == "*" || tok->strAt(1) == "[");
2569             if (tok->str() == "*")
2570                 tok = tok->next();
2571 
2572             // Check usage of char variable..
2573             int indentlevel = 0;
2574             for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
2575                 if (tok2->str() == "{")
2576                     ++indentlevel;
2577 
2578                 else if (tok2->str() == "}") {
2579                     --indentlevel;
2580                     if (indentlevel <= 0)
2581                         break;
2582                 }
2583 
2584                 if (!isPointer) {
2585                     std::string temp = "%var% [ " + tok->str() + " ]";
2586                     if ((tok2->str() != ".") && Token::Match(tok2->next(), temp.c_str())) {
2587                         charArrayIndexError(tok2->next());
2588                         break;
2589                     }
2590                 }
2591 
2592                 if (Token::Match(tok2, "[;{}] %var% = %any% [&|] %any% ;")) {
2593                     // is the char variable used in the calculation?
2594                     if (tok2->tokAt(3)->varId() != tok->varId() && tok2->tokAt(5)->varId() != tok->varId())
2595                         continue;
2596 
2597                     // it's ok with a bitwise and where the other operand is 0xff or less..
2598                     if (tok2->strAt(4) == "&") {
2599                         if (tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
2600                             continue;
2601                         if (tok2->tokAt(5)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(5)))
2602                             continue;
2603                     }
2604 
2605                     // is the result stored in a short|int|long?
2606                     if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId()))
2607                         continue;
2608 
2609                     // This is an error..
2610                     charBitOpError(tok2);
2611                     break;
2612                 }
2613 
2614                 if (isPointer && Token::Match(tok2, "[;{}] %var% = %any% [&|] ( * %varid% ) ;", tok->varId())) {
2615                     // it's ok with a bitwise and where the other operand is 0xff or less..
2616                     if (tok2->strAt(4) == "&" && tok2->tokAt(3)->isNumber() && MathLib::isGreater("0x100", tok2->strAt(3)))
2617                         continue;
2618 
2619                     // is the result stored in a short|int|long?
2620                     if (!Token::findmatch(_tokenizer->tokens(), "short|int|long %varid%", tok2->next()->varId()))
2621                         continue;
2622 
2623                     // This is an error..
2624                     charBitOpError(tok2);
2625                     break;
2626                 }
2627             }
2628         }
2629     }
2630 }
2631 //---------------------------------------------------------------------------
2632 
2633 
2634 
2635 
2636 
2637 
2638 //---------------------------------------------------------------------------
2639 // Incomplete statement..
2640 //---------------------------------------------------------------------------
2641 
checkIncompleteStatement()2642 void CheckOther::checkIncompleteStatement()
2643 {
2644     if (!_settings->isEnabled("style"))
2645         return;
2646 
2647     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2648         if (tok->str() == "(") {
2649             tok = tok->link();
2650             if (Token::simpleMatch(tok, ") {") && Token::simpleMatch(tok->next()->link(), "} ;"))
2651                 tok = tok->next()->link();
2652         }
2653 
2654         else if (Token::simpleMatch(tok, "= {"))
2655             tok = tok->next()->link();
2656 
2657         else if (tok->str() == "{" && Token::Match(tok->tokAt(-2), "%type% %var%"))
2658             tok = tok->link();
2659 
2660         else if (Token::Match(tok, "[;{}] %str%") || Token::Match(tok, "[;{}] %num%")) {
2661             // bailout if there is a "? :" in this statement
2662             bool bailout = false;
2663             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
2664                 if (tok2->str() == "?")
2665                     bailout = true;
2666                 else if (tok2->str() == ";")
2667                     break;
2668             }
2669             if (bailout)
2670                 continue;
2671 
2672             constStatementError(tok->next(), tok->next()->isNumber() ? "numeric" : "string");
2673         }
2674     }
2675 }
2676 //---------------------------------------------------------------------------
2677 
2678 
2679 
2680 
2681 
2682 
2683 //---------------------------------------------------------------------------
2684 // str plus char
2685 //---------------------------------------------------------------------------
2686 
strPlusChar()2687 void CheckOther::strPlusChar()
2688 {
2689     // Don't use this check for Java and C# programs..
2690     if (_tokenizer->isJavaOrCSharp()) {
2691         return;
2692     }
2693 
2694     bool charVars[10000] = {0};
2695 
2696     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2697         // Declaring char variable..
2698         if (Token::Match(tok, "char|int|short %var% [;=]")) {
2699             unsigned int varid = tok->next()->varId();
2700             if (varid > 0 && varid < 10000)
2701                 charVars[varid] = true;
2702         }
2703 
2704         //
2705         else if (Token::Match(tok, "[=(] %str% + %any%")) {
2706             // char constant..
2707             const std::string s = tok->strAt(3);
2708             if (s[0] == '\'')
2709                 strPlusChar(tok->next());
2710 
2711             // char variable..
2712             unsigned int varid = tok->tokAt(3)->varId();
2713             if (varid > 0 && varid < 10000 && charVars[varid])
2714                 strPlusChar(tok->next());
2715         }
2716     }
2717 }
2718 
checkZeroDivision()2719 void CheckOther::checkZeroDivision()
2720 {
2721     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2722 
2723         if (Token::Match(tok, "/ %num%") &&
2724             MathLib::isInt(tok->next()->str()) &&
2725             MathLib::toLongNumber(tok->next()->str()) == 0L) {
2726             zerodivError(tok);
2727         } else if (Token::Match(tok, "div|ldiv|lldiv|imaxdiv ( %num% , %num% )") &&
2728                    MathLib::isInt(tok->tokAt(4)->str()) &&
2729                    MathLib::toLongNumber(tok->tokAt(4)->str()) == 0L) {
2730             zerodivError(tok);
2731         }
2732     }
2733 }
2734 
2735 
checkMathFunctions()2736 void CheckOther::checkMathFunctions()
2737 {
2738     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2739         // case log(-2)
2740         if (tok->varId() == 0 &&
2741             Token::Match(tok, "log|log10 ( %num% )") &&
2742             MathLib::isNegative(tok->tokAt(2)->str()) &&
2743             MathLib::isInt(tok->tokAt(2)->str()) &&
2744             MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0) {
2745             mathfunctionCallError(tok);
2746         }
2747         // case log(-2.0)
2748         else if (tok->varId() == 0 &&
2749                  Token::Match(tok, "log|log10 ( %num% )") &&
2750                  MathLib::isNegative(tok->tokAt(2)->str()) &&
2751                  MathLib::isFloat(tok->tokAt(2)->str()) &&
2752                  MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.) {
2753             mathfunctionCallError(tok);
2754         }
2755 
2756         // case log(0.0)
2757         else if (tok->varId() == 0 &&
2758                  Token::Match(tok, "log|log10 ( %num% )") &&
2759                  !MathLib::isNegative(tok->tokAt(2)->str()) &&
2760                  MathLib::isFloat(tok->tokAt(2)->str()) &&
2761                  MathLib::toDoubleNumber(tok->tokAt(2)->str()) <= 0.) {
2762             mathfunctionCallError(tok);
2763         }
2764 
2765         // case log(0)
2766         else if (tok->varId() == 0 &&
2767                  Token::Match(tok, "log|log10 ( %num% )") &&
2768                  !MathLib::isNegative(tok->tokAt(2)->str()) &&
2769                  MathLib::isInt(tok->tokAt(2)->str()) &&
2770                  MathLib::toLongNumber(tok->tokAt(2)->str()) <= 0) {
2771             mathfunctionCallError(tok);
2772         }
2773         // acos( x ), asin( x )  where x is defined for interval [-1,+1], but not beyond
2774         else if (tok->varId() == 0 &&
2775                  Token::Match(tok, "acos|asin ( %num% )") &&
2776                  std::fabs(MathLib::toDoubleNumber(tok->tokAt(2)->str())) > 1.0) {
2777             mathfunctionCallError(tok);
2778         }
2779         // sqrt( x ): if x is negative the result is undefined
2780         else if (tok->varId() == 0 &&
2781                  Token::Match(tok, "sqrt|sqrtf|sqrtl ( %num% )") &&
2782                  MathLib::isNegative(tok->tokAt(2)->str())) {
2783             mathfunctionCallError(tok);
2784         }
2785         // atan2 ( x , y): x and y can not be zero, because this is mathematically not defined
2786         else if (tok->varId() == 0 &&
2787                  Token::Match(tok, "atan2 ( %num% , %num% )") &&
2788                  MathLib::isNullValue(tok->tokAt(2)->str()) &&
2789                  MathLib::isNullValue(tok->tokAt(4)->str())) {
2790             mathfunctionCallError(tok, 2);
2791         }
2792         // fmod ( x , y) If y is zero, then either a range error will occur or the function will return zero (implementation-defined).
2793         else if (tok->varId() == 0 &&
2794                  Token::Match(tok, "fmod ( %num% , %num% )") &&
2795                  MathLib::isNullValue(tok->tokAt(4)->str())) {
2796             mathfunctionCallError(tok, 2);
2797         }
2798         // pow ( x , y) If x is zero, and y is negative --> division by zero
2799         else if (tok->varId() == 0 &&
2800                  Token::Match(tok, "pow ( %num% , %num% )") &&
2801                  MathLib::isNullValue(tok->tokAt(2)->str()) &&
2802                  MathLib::isNegative(tok->tokAt(4)->str())) {
2803             mathfunctionCallError(tok, 2);
2804         }
2805 
2806     }
2807 }
2808 
2809 /** Is there a function with given name? */
isFunction(const std::string & name,const Token * startToken)2810 static bool isFunction(const std::string &name, const Token *startToken)
2811 {
2812     const std::string pattern1(name + " (");
2813     for (const Token *tok = startToken; tok; tok = tok->next()) {
2814         // skip executable scopes etc
2815         if (tok->str() == "(") {
2816             tok = tok->link();
2817             if (Token::simpleMatch(tok, ") {"))
2818                 tok = tok->next()->link();
2819             else if (Token::simpleMatch(tok, ") const {"))
2820                 tok = tok->tokAt(2)->link();
2821         }
2822 
2823         // function declaration/implementation found
2824         if ((tok->str() == "*" || (tok->isName() && tok->str().find(":") ==std::string::npos))
2825             && Token::simpleMatch(tok->next(), pattern1.c_str()))
2826             return true;
2827     }
2828     return false;
2829 }
2830 
checkMisusedScopedObject()2831 void CheckOther::checkMisusedScopedObject()
2832 {
2833     // Skip this check for .c files
2834     {
2835         const std::string fname = _tokenizer->getFiles()->at(0);
2836         size_t position         = fname.rfind(".");
2837 
2838         if (position != std::string::npos) {
2839             const std::string ext = fname.substr(position);
2840             if (ext == ".c" || ext == ".C")
2841                 return;
2842         }
2843     }
2844 
2845     const SymbolDatabase * const symbolDatabase = _tokenizer->getSymbolDatabase();
2846 
2847     std::list<Scope>::const_iterator scope;
2848 
2849     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
2850         // only check functions
2851         if (scope->type != Scope::eFunction)
2852             continue;
2853 
2854         unsigned int depth = 0;
2855 
2856         for (const Token *tok = scope->classStart; tok; tok = tok->next()) {
2857             if (tok->str() == "{") {
2858                 ++depth;
2859             } else if (tok->str() == "}") {
2860                 --depth;
2861                 if (depth == 0)
2862                     break;
2863             }
2864 
2865             if (Token::Match(tok, "[;{}] %var% (")
2866                 && Token::simpleMatch(tok->tokAt(2)->link(), ") ;")
2867                 && symbolDatabase->isClassOrStruct(tok->next()->str())
2868                 && !isFunction(tok->next()->str(), _tokenizer->tokens())) {
2869                 tok = tok->next();
2870                 misusedScopeObjectError(tok, tok->str());
2871                 tok = tok->next();
2872             }
2873         }
2874     }
2875 }
2876 
checkIncorrectStringCompare()2877 void CheckOther::checkIncorrectStringCompare()
2878 {
2879     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
2880         if (Token::Match(tok, ". substr ( %any% , %num% ) ==|!= %str%")) {
2881             size_t clen = MathLib::toLongNumber(tok->tokAt(5)->str());
2882             size_t slen = Token::getStrLength(tok->tokAt(8));
2883             if (clen != slen) {
2884                 incorrectStringCompareError(tok->next(), "substr", tok->tokAt(8)->str(), tok->tokAt(5)->str());
2885             }
2886         }
2887         if (Token::Match(tok, "%str% ==|!= %var% . substr ( %any% , %num% )")) {
2888             size_t clen = MathLib::toLongNumber(tok->tokAt(8)->str());
2889             size_t slen = Token::getStrLength(tok);
2890             if (clen != slen) {
2891                 incorrectStringCompareError(tok->next(), "substr", tok->str(), tok->tokAt(8)->str());
2892             }
2893         }
2894     }
2895 }
2896 
2897 //-----------------------------------------------------------------------------
2898 // check for duplicate expressions in if statements
2899 // if (a) { } else if (a) { }
2900 //-----------------------------------------------------------------------------
2901 
stringifyTokens(const Token * start,const Token * end)2902 static const std::string stringifyTokens(const Token *start, const Token *end)
2903 {
2904     const Token *tok = start;
2905     std::string stringified;
2906 
2907     if (tok->isUnsigned())
2908         stringified.append("unsigned ");
2909     else if (tok->isSigned())
2910         stringified.append("signed ");
2911 
2912     if (tok->isLong())
2913         stringified.append("long ");
2914 
2915     stringified.append(tok->str());
2916 
2917     while (tok && tok->next() && tok != end) {
2918         if (tok->isUnsigned())
2919             stringified.append("unsigned ");
2920         else if (tok->isSigned())
2921             stringified.append("signed ");
2922 
2923         if (tok->isLong())
2924             stringified.append("long ");
2925 
2926         tok = tok->next();
2927         stringified.append(" ");
2928         stringified.append(tok->str());
2929     }
2930 
2931     return stringified;
2932 }
2933 
expressionHasSideEffects(const Token * first,const Token * last)2934 static bool expressionHasSideEffects(const Token *first, const Token *last)
2935 {
2936     for (const Token *tok = first; tok != last->next(); tok = tok->next()) {
2937         // check for assignment
2938         if (tok->isAssignmentOp())
2939             return true;
2940 
2941         // check for inc/dec
2942         else if (Token::Match(tok, "++|--"))
2943             return true;
2944 
2945         // check for function call
2946         else if (Token::Match(tok, "%var% (") &&
2947                  !(Token::Match(tok, "c_str|string") || tok->isStandardType()))
2948             return true;
2949     }
2950 
2951     return false;
2952 }
2953 
checkDuplicateIf()2954 void CheckOther::checkDuplicateIf()
2955 {
2956     if (!_settings->isEnabled("style"))
2957         return;
2958 
2959     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
2960 
2961     std::list<Scope>::const_iterator scope;
2962 
2963     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
2964         // only check functions
2965         if (scope->type != Scope::eFunction)
2966             continue;
2967 
2968         // check all the code in the function for if (...) and else if (...) statements
2969         for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
2970             if (Token::simpleMatch(tok, "if (") && tok->strAt(-1) != "else" &&
2971                 Token::simpleMatch(tok->next()->link(), ") {")) {
2972                 std::map<std::string, const Token*> expressionMap;
2973 
2974                 // get the expression from the token stream
2975                 std::string expression = stringifyTokens(tok->tokAt(2), tok->next()->link()->previous());
2976 
2977                 // save the expression and its location
2978                 expressionMap.insert(std::make_pair(expression, tok));
2979 
2980                 // find the next else if (...) statement
2981                 const Token *tok1 = tok->next()->link()->next()->link();
2982 
2983                 // check all the else if (...) statements
2984                 while (Token::simpleMatch(tok1, "} else if (") &&
2985                        Token::simpleMatch(tok1->tokAt(3)->link(), ") {")) {
2986                     // get the expression from the token stream
2987                     expression = stringifyTokens(tok1->tokAt(4), tok1->tokAt(3)->link()->previous());
2988 
2989                     // try to look up the expression to check for duplicates
2990                     std::map<std::string, const Token *>::iterator it = expressionMap.find(expression);
2991 
2992                     // found a duplicate
2993                     if (it != expressionMap.end()) {
2994                         // check for expressions that have side effects and ignore them
2995                         if (!expressionHasSideEffects(tok1->tokAt(4), tok1->tokAt(3)->link()->previous()))
2996                             duplicateIfError(it->second, tok1->next());
2997                     }
2998 
2999                     // not a duplicate expression so save it and its location
3000                     else
3001                         expressionMap.insert(std::make_pair(expression, tok1->next()));
3002 
3003                     // find the next else if (...) statement
3004                     tok1 = tok1->tokAt(3)->link()->next()->link();
3005                 }
3006 
3007                 tok = tok->next()->link()->next();
3008             }
3009         }
3010     }
3011 }
3012 
duplicateIfError(const Token * tok1,const Token * tok2)3013 void CheckOther::duplicateIfError(const Token *tok1, const Token *tok2)
3014 {
3015     std::list<const Token *> toks;
3016     toks.push_back(tok2);
3017     toks.push_back(tok1);
3018 
3019     reportError(toks, Severity::style, "duplicateIf", "Found duplicate if expressions.\n"
3020                 "Finding the same expression more than once is suspicious and might indicate "
3021                 "a cut and paste or logic error. Please examine this code carefully to determine "
3022                 "if it is correct.");
3023 }
3024 
3025 //-----------------------------------------------------------------------------
3026 // check for duplicate code in if and else branches
3027 // if (a) { b = true; } else { b = true; }
3028 //-----------------------------------------------------------------------------
3029 
checkDuplicateBranch()3030 void CheckOther::checkDuplicateBranch()
3031 {
3032     if (!_settings->isEnabled("style"))
3033         return;
3034 
3035     if (!_settings->inconclusive)
3036         return;
3037 
3038     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
3039 
3040     std::list<Scope>::const_iterator scope;
3041 
3042     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
3043         // only check functions
3044         if (scope->type != Scope::eFunction)
3045             continue;
3046 
3047         // check all the code in the function for if (..) else
3048         for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
3049             if (Token::simpleMatch(tok, "if (") && tok->strAt(-1) != "else" &&
3050                 Token::simpleMatch(tok->next()->link(), ") {") &&
3051                 Token::simpleMatch(tok->next()->link()->next()->link(), "} else {")) {
3052                 // save if branch code
3053                 std::string branch1 = stringifyTokens(tok->next()->link()->tokAt(2), tok->next()->link()->next()->link()->previous());
3054 
3055                 // find else branch
3056                 const Token *tok1 = tok->next()->link()->next()->link();
3057 
3058                 // save else branch code
3059                 std::string branch2 = stringifyTokens(tok1->tokAt(3), tok1->tokAt(2)->link()->previous());
3060 
3061                 // check for duplicates
3062                 if (branch1 == branch2)
3063                     duplicateBranchError(tok, tok1->tokAt(2));
3064 
3065                 tok = tok->next()->link()->next();
3066             }
3067         }
3068     }
3069 }
3070 
duplicateBranchError(const Token * tok1,const Token * tok2)3071 void CheckOther::duplicateBranchError(const Token *tok1, const Token *tok2)
3072 {
3073     std::list<const Token *> toks;
3074     toks.push_back(tok2);
3075     toks.push_back(tok1);
3076 
3077     reportError(toks, Severity::style, "duplicateBranch", "Found duplicate branches for if and else.\n"
3078                 "Finding the same code for an if branch and an else branch is suspicious and "
3079                 "might indicate a cut and paste or logic error. Please examine this code "
3080                 "carefully to determine if it is correct.");
3081 }
3082 
3083 //---------------------------------------------------------------------------
3084 // check for the same expression on both sides of an operator
3085 // (x == x), (x && x), (x || x)
3086 // (x.y == x.y), (x.y && x.y), (x.y || x.y)
3087 //---------------------------------------------------------------------------
3088 
checkDuplicateExpression()3089 void CheckOther::checkDuplicateExpression()
3090 {
3091     if (!_settings->isEnabled("style"))
3092         return;
3093 
3094     // Parse all executing scopes..
3095     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
3096 
3097     std::list<Scope>::const_iterator scope;
3098 
3099     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
3100         // only check functions
3101         if (scope->type != Scope::eFunction)
3102             continue;
3103 
3104         for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
3105             if (Token::Match(tok, "(|&&|%oror% %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% )|&&|%oror%") &&
3106                 tok->strAt(1) == tok->strAt(3)) {
3107                 // float == float and float != float are valid NaN checks
3108                 if (Token::Match(tok->tokAt(2), "==|!=") && tok->next()->varId()) {
3109                     const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
3110                     if (var && var->typeStartToken() == var->typeEndToken()) {
3111                         if (Token::Match(var->typeStartToken(), "float|double"))
3112                             continue;
3113                     }
3114                 }
3115 
3116                 duplicateExpressionError(tok->next(), tok->tokAt(3), tok->strAt(2));
3117             } else if (Token::Match(tok, "(|&&|%oror% %var% . %var% &&|%oror%|==|!=|<=|>=|<|>|-|%or% %var% . %var% )|&&|%oror%") &&
3118                        tok->strAt(1) == tok->strAt(5) && tok->strAt(3) == tok->strAt(7)) {
3119                 duplicateExpressionError(tok->next(), tok->tokAt(6), tok->strAt(4));
3120             }
3121         }
3122     }
3123 }
3124 
duplicateExpressionError(const Token * tok1,const Token * tok2,const std::string & op)3125 void CheckOther::duplicateExpressionError(const Token *tok1, const Token *tok2, const std::string &op)
3126 {
3127     std::list<const Token *> toks;
3128     toks.push_back(tok2);
3129     toks.push_back(tok1);
3130 
3131     reportError(toks, Severity::style, "duplicateExpression", "Same expression on both sides of \'" + op + "\'.\n"
3132                 "Finding the same expression on both sides of an operator is suspicious and might "
3133                 "indicate a cut and paste or logic error. Please examine this code carefully to "
3134                 "determine if it is correct.");
3135 }
3136 
3137 
3138 //---------------------------------------------------------------------------
3139 // Check for string comparison involving two static strings.
3140 // if(strcmp("00FF00","00FF00")==0) // <- statement is always true
3141 //---------------------------------------------------------------------------
3142 
checkAlwaysTrueOrFalseStringCompare()3143 void CheckOther::checkAlwaysTrueOrFalseStringCompare()
3144 {
3145     if (!_settings->isEnabled("style"))
3146         return;
3147 
3148     const char pattern1[] = "strcmp|stricmp|strcmpi|strcasecmp|wcscmp ( %str% , %str% )";
3149     const char pattern2[] = "QString :: compare ( %str% , %str% )";
3150 
3151     const Token *tok = _tokenizer->tokens();
3152     while (tok && (tok = Token::findmatch(tok, pattern1)) != NULL) {
3153         alwaysTrueFalseStringCompare(tok, tok->strAt(2), tok->strAt(4));
3154         tok = tok->tokAt(5);
3155     }
3156 
3157     tok = _tokenizer->tokens();
3158     while (tok && (tok = Token::findmatch(tok, pattern2)) != NULL) {
3159         alwaysTrueFalseStringCompare(tok, tok->strAt(4), tok->strAt(6));
3160         tok = tok->tokAt(7);
3161     }
3162 }
3163 
alwaysTrueFalseStringCompare(const Token * tok,const std::string & str1,const std::string & str2)3164 void CheckOther::alwaysTrueFalseStringCompare(const Token *tok, const std::string& str1, const std::string& str2)
3165 {
3166     const size_t stringLen = 10;
3167     const std::string string1 = (str1.size() < stringLen) ? str1 : (str1.substr(0, stringLen-2) + "..");
3168     const std::string string2 = (str2.size() < stringLen) ? str2 : (str2.substr(0, stringLen-2) + "..");
3169 
3170     if (str1 == str2) {
3171         reportError(tok, Severity::warning, "staticStringCompare",
3172                     "Comparison of always identical static strings.\n"
3173                     "The compared strings, '" + string1 + "' and '" + string2 + "', are always identical. "
3174                     "If the purpose is to compare these two strings, the comparison is unnecessary. "
3175                     "If the strings are supposed to be different, then there is a bug somewhere.");
3176     } else {
3177         reportError(tok, Severity::performance, "staticStringCompare",
3178                     "Unnecessary comparison of static strings.\n"
3179                     "The compared strings, '" + string1 + "' and '" + string2 + "', are static and always different. "
3180                     "If the purpose is to compare these two strings, the comparison is unnecessary.");
3181     }
3182 }
3183 
3184 //-----------------------------------------------------------------------------
3185 
cstyleCastError(const Token * tok)3186 void CheckOther::cstyleCastError(const Token *tok)
3187 {
3188     reportError(tok, Severity::style, "cstyleCast", "C-style pointer casting");
3189 }
3190 
dangerousUsageStrtolError(const Token * tok)3191 void CheckOther::dangerousUsageStrtolError(const Token *tok)
3192 {
3193     reportError(tok, Severity::error, "dangerousUsageStrtol", "Invalid radix in call to strtol or strtoul. Must be 0 or 2-36");
3194 }
3195 
sprintfOverlappingDataError(const Token * tok,const std::string & varname)3196 void CheckOther::sprintfOverlappingDataError(const Token *tok, const std::string &varname)
3197 {
3198     reportError(tok, Severity::error, "sprintfOverlappingData",
3199                 "Undefined behavior: variable is used as parameter and destination in s[n]printf().\n"
3200                 "The variable '" + varname + "' is used both as a parameter and as a destination in "
3201                 "s[n]printf(). The origin and destination buffers overlap. Quote from glibc (C-library) "
3202                 "documentation (http://www.gnu.org/software/libc/manual/html_mono/libc.html#Formatted-Output-Functions): "
3203                 "'If copying takes place between objects that overlap as a result of a call "
3204                 "to sprintf() or snprintf(), the results are undefined.'");
3205 }
3206 
udivError(const Token * tok)3207 void CheckOther::udivError(const Token *tok)
3208 {
3209     reportError(tok, Severity::error, "udivError", "Unsigned division. The result will be wrong.");
3210 }
3211 
unusedStructMemberError(const Token * tok,const std::string & structname,const std::string & varname)3212 void CheckOther::unusedStructMemberError(const Token *tok, const std::string &structname, const std::string &varname)
3213 {
3214     reportError(tok, Severity::style, "unusedStructMember", "struct or union member '" + structname + "::" + varname + "' is never used");
3215 }
3216 
passedByValueError(const Token * tok,const std::string & parname)3217 void CheckOther::passedByValueError(const Token *tok, const std::string &parname)
3218 {
3219     reportError(tok, Severity::performance, "passedByValue",
3220                 "Function parameter '" + parname + "' should be passed by reference.\n"
3221                 "Parameter '" +  parname + "' is passed as a value. It could be passed "
3222                 "as a (const) reference which is usually faster and recommended in C++.");
3223 }
3224 
constStatementError(const Token * tok,const std::string & type)3225 void CheckOther::constStatementError(const Token *tok, const std::string &type)
3226 {
3227     reportError(tok, Severity::warning, "constStatement", "Redundant code: Found a statement that begins with " + type + " constant");
3228 }
3229 
charArrayIndexError(const Token * tok)3230 void CheckOther::charArrayIndexError(const Token *tok)
3231 {
3232     reportError(tok,
3233                 Severity::warning,
3234                 "charArrayIndex",
3235                 "Using char type as array index\n"
3236                 "Using signed char type as array index. If the value "
3237                 "can be greater than 127 there will be a buffer overflow "
3238                 "(because of sign extension).");
3239 }
3240 
charBitOpError(const Token * tok)3241 void CheckOther::charBitOpError(const Token *tok)
3242 {
3243     reportError(tok,
3244                 Severity::warning,
3245                 "charBitOp",
3246                 "When using char variables in bit operations, sign extension can generate unexpected results.\n"
3247                 "When using char variables in bit operations, sign extension can generate unexpected results. For example:\n"
3248                 "    char c = 0x80;\n"
3249                 "    int i = 0 | c;\n"
3250                 "    if (i & 0x8000)\n"
3251                 "        printf(\"not expected\");\n"
3252                 "The 'not expected' will be printed on the screen.");
3253 }
3254 
variableScopeError(const Token * tok,const std::string & varname)3255 void CheckOther::variableScopeError(const Token *tok, const std::string &varname)
3256 {
3257     reportError(tok,
3258                 Severity::information,
3259                 "variableScope",
3260                 "The scope of the variable '" + varname + "' can be reduced\n"
3261                 "The scope of the variable '" + varname + "' can be reduced. Warning: It can be unsafe "
3262                 "to fix this message. Be careful. Especially when there are inner loops. Here is an "
3263                 "example where cppcheck will write that the scope for 'i' can be reduced:\n"
3264                 "void f(int x)\n"
3265                 "{\n"
3266                 "    int i = 0;\n"
3267                 "    if (x) {\n"
3268                 "        // it's safe to move 'int i = 0' here\n"
3269                 "        for (int n = 0; n < 10; ++n) {\n"
3270                 "            // it is possible but not safe to move 'int i = 0' here\n"
3271                 "            do_something(&i);\n"
3272                 "        }\n"
3273                 "    }\n"
3274                 "}\n"
3275                 "When you see this message it is always safe to reduce the variable scope 1 level.");
3276 }
3277 
conditionAlwaysTrueFalse(const Token * tok,const std::string & truefalse)3278 void CheckOther::conditionAlwaysTrueFalse(const Token *tok, const std::string &truefalse)
3279 {
3280     reportError(tok, Severity::style, "conditionAlwaysTrueFalse", "Condition is always " + truefalse);
3281 }
3282 
strPlusChar(const Token * tok)3283 void CheckOther::strPlusChar(const Token *tok)
3284 {
3285     reportError(tok, Severity::error, "strPlusChar", "Unusual pointer arithmetic");
3286 }
3287 
zerodivError(const Token * tok)3288 void CheckOther::zerodivError(const Token *tok)
3289 {
3290     reportError(tok, Severity::error, "zerodiv", "Division by zero");
3291 }
3292 
mathfunctionCallError(const Token * tok,const unsigned int numParam)3293 void CheckOther::mathfunctionCallError(const Token *tok, const unsigned int numParam)
3294 {
3295     if (tok) {
3296         if (numParam == 1)
3297             reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " to " + tok->str() + "() leads to undefined result");
3298         else if (numParam == 2)
3299             reportError(tok, Severity::error, "wrongmathcall", "Passing value " + tok->tokAt(2)->str() + " and " + tok->tokAt(4)->str() + " to " + tok->str() + "() leads to undefined result");
3300     } else
3301         reportError(tok, Severity::error, "wrongmathcall", "Passing value " " to " "() leads to undefined result");
3302 }
3303 
fflushOnInputStreamError(const Token * tok,const std::string & varname)3304 void CheckOther::fflushOnInputStreamError(const Token *tok, const std::string &varname)
3305 {
3306     reportError(tok, Severity::error,
3307                 "fflushOnInputStream", "fflush() called on input stream \"" + varname + "\" may result in undefined behaviour");
3308 }
3309 
sizeofsizeof()3310 void CheckOther::sizeofsizeof()
3311 {
3312     if (!_settings->isEnabled("style"))
3313         return;
3314     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
3315         if (Token::Match(tok, "sizeof (| sizeof")) {
3316             sizeofsizeofError(tok);
3317             tok = tok->next();
3318         }
3319     }
3320 }
3321 
sizeofsizeofError(const Token * tok)3322 void CheckOther::sizeofsizeofError(const Token *tok)
3323 {
3324     reportError(tok, Severity::warning,
3325                 "sizeofsizeof", "Calling sizeof for 'sizeof'.\n"
3326                 "Calling sizeof for 'sizeof looks like a suspicious code and "
3327                 "most likely there should be just one 'sizeof'. The current "
3328                 "code is equivalent to 'sizeof(size_t)'");
3329 }
3330 
sizeofCalculation()3331 void CheckOther::sizeofCalculation()
3332 {
3333     if (!_settings->isEnabled("style"))
3334         return;
3335     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
3336         if (Token::simpleMatch(tok, "sizeof (")) {
3337             unsigned int parlevel = 0;
3338             for (const Token *tok2 = tok->tokAt(2); tok2; tok2 = tok2->next()) {
3339                 if (tok2->str() == "(")
3340                     ++parlevel;
3341                 else if (tok2->str() == ")") {
3342                     if (parlevel <= 1)
3343                         break;
3344                     --parlevel;
3345                 } else if (Token::Match(tok2, "+|/")) {
3346                     sizeofCalculationError(tok2);
3347                     break;
3348                 }
3349             }
3350         }
3351     }
3352 }
3353 
sizeofCalculationError(const Token * tok)3354 void CheckOther::sizeofCalculationError(const Token *tok)
3355 {
3356     reportError(tok, Severity::warning,
3357                 "sizeofCalculation", "Found calculation inside sizeof()");
3358 }
3359 
redundantAssignmentInSwitchError(const Token * tok,const std::string & varname)3360 void CheckOther::redundantAssignmentInSwitchError(const Token *tok, const std::string &varname)
3361 {
3362     reportError(tok, Severity::warning,
3363                 "redundantAssignInSwitch", "Redundant assignment of \"" + varname + "\" in switch");
3364 }
3365 
switchCaseFallThrough(const Token * tok)3366 void CheckOther::switchCaseFallThrough(const Token *tok)
3367 {
3368     reportError(tok, Severity::style,
3369                 "switchCaseFallThrough", "Switch falls through case without comment");
3370 }
3371 
selfAssignmentError(const Token * tok,const std::string & varname)3372 void CheckOther::selfAssignmentError(const Token *tok, const std::string &varname)
3373 {
3374     reportError(tok, Severity::warning,
3375                 "selfAssignment", "Redundant assignment of \"" + varname + "\" to itself");
3376 }
3377 
assignmentInAssertError(const Token * tok,const std::string & varname)3378 void CheckOther::assignmentInAssertError(const Token *tok, const std::string &varname)
3379 {
3380     reportError(tok, Severity::warning,
3381                 "assignmentInAssert", "Assert statement modifies '" + varname + "'.\n"
3382                 "Variable '" + varname + "' is modified inside assert statement. "
3383                 "Assert statements are removed from release builds so the code inside "
3384                 "assert statement is not run. If the code is needed also in release "
3385                 "builds this is a bug.");
3386 }
3387 
incorrectLogicOperatorError(const Token * tok,bool always)3388 void CheckOther::incorrectLogicOperatorError(const Token *tok, bool always)
3389 {
3390     if (always)
3391         reportError(tok, Severity::warning,
3392                     "incorrectLogicOperator", "Mutual exclusion over || always evaluates to true. Did you intend to use && instead?");
3393     else
3394         reportError(tok, Severity::warning,
3395                     "incorrectLogicOperator", "Expression always evaluates to false. Did you intend to use || instead?");
3396 }
3397 
misusedScopeObjectError(const Token * tok,const std::string & varname)3398 void CheckOther::misusedScopeObjectError(const Token *tok, const std::string& varname)
3399 {
3400     reportError(tok, Severity::error,
3401                 "unusedScopedObject", "instance of \"" + varname + "\" object destroyed immediately");
3402 }
3403 
catchExceptionByValueError(const Token * tok)3404 void CheckOther::catchExceptionByValueError(const Token *tok)
3405 {
3406     reportError(tok, Severity::style,
3407                 "catchExceptionByValue", "Exception should be caught by reference.\n"
3408                 "The exception is caught as a value. It could be caught "
3409                 "as a (const) reference which is usually recommended in C++.");
3410 }
3411 
memsetZeroBytesError(const Token * tok,const std::string & varname)3412 void CheckOther::memsetZeroBytesError(const Token *tok, const std::string &varname)
3413 {
3414     const std::string summary("memset() called to fill 0 bytes of \'" + varname + "\'");
3415     const std::string verbose(summary + ". Second and third arguments might be inverted.");
3416     reportError(tok, Severity::warning, "memsetZeroBytes", summary + "\n" + verbose);
3417 }
3418 
incorrectStringCompareError(const Token * tok,const std::string & func,const std::string & string,const std::string & len)3419 void CheckOther::incorrectStringCompareError(const Token *tok, const std::string& func, const std::string &string, const std::string &len)
3420 {
3421     reportError(tok, Severity::warning, "incorrectStringCompare", "String literal " + string + " doesn't match length argument for " + func + "(" + len + ").");
3422 }
3423 
comparisonOfBoolWithIntError(const Token * tok,const std::string & varname)3424 void CheckOther::comparisonOfBoolWithIntError(const Token *tok, const std::string &varname)
3425 {
3426     reportError(tok, Severity::warning, "comparisonOfBoolWithInt",
3427                 "Comparison of a boolean with a non-zero integer\n"
3428                 "The expression \"!" + varname + "\" is of type 'bool' but is compared against a non-zero 'int'.");
3429 }
3430 
duplicateBreakError(const Token * tok)3431 void CheckOther::duplicateBreakError(const Token *tok)
3432 {
3433     reportError(tok, Severity::style, "duplicateBreak",
3434                 "Consecutive break or continue statements are unnecessary\n"
3435                 "The second of the two statements can never be executed, and so should be removed\n");
3436 }
3437 
3438 
checkAssignBoolToPointer()3439 void CheckOther::checkAssignBoolToPointer()
3440 {
3441     for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) {
3442         if (Token::Match(tok, "[;{}] %var% = %bool% ;")) {
3443             const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
3444 
3445             const Variable *var1(symbolDatabase->getVariableFromVarId(tok->next()->varId()));
3446 
3447             // Is variable a pointer?
3448             if (var1 && var1->nameToken()->strAt(-1) == "*")
3449                 assignBoolToPointerError(tok->next());
3450         }
3451     }
3452 }
3453 
assignBoolToPointerError(const Token * tok)3454 void CheckOther::assignBoolToPointerError(const Token *tok)
3455 {
3456     reportError(tok, Severity::error, "assignBoolToPointer",
3457                 "Assigning bool value to pointer (converting bool value to address)");
3458 }
3459 
3460 //---------------------------------------------------------------------------
3461 // Check testing sign of unsigned variables.
3462 //---------------------------------------------------------------------------
3463 
checkSignOfUnsignedVariable()3464 void CheckOther::checkSignOfUnsignedVariable()
3465 {
3466     if (!_settings->isEnabled("style"))
3467         return;
3468 
3469     const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
3470 
3471     std::list<Scope>::const_iterator scope;
3472 
3473     for (scope = symbolDatabase->scopeList.begin(); scope != symbolDatabase->scopeList.end(); ++scope) {
3474         // only check functions
3475         if (scope->type != Scope::eFunction)
3476             continue;
3477 
3478         // check all the code in the function
3479         for (const Token *tok = scope->classStart; tok && tok != scope->classStart->link(); tok = tok->next()) {
3480             if (Token::Match(tok, "( %var% <|<= 0 )") && tok->next()->varId()) {
3481                 const Variable * var = symbolDatabase->getVariableFromVarId(tok->next()->varId());
3482                 if (var && var->typeEndToken()->isUnsigned())
3483                     unsignedLessThanZero(tok->next(), tok->next()->str());
3484             } else if (Token::Match(tok, "( 0 > %var% )") && tok->tokAt(3)->varId()) {
3485                 const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
3486                 if (var && var->typeEndToken()->isUnsigned())
3487                     unsignedLessThanZero(tok->tokAt(3), tok->strAt(3));
3488             } else if (Token::Match(tok, "( 0 <= %var% )") && tok->tokAt(3)->varId()) {
3489                 const Variable * var = symbolDatabase->getVariableFromVarId(tok->tokAt(3)->varId());
3490                 if (var && var->typeEndToken()->isUnsigned())
3491                     unsignedPositive(tok->tokAt(3), tok->strAt(3));
3492             }
3493         }
3494     }
3495 }
3496 
unsignedLessThanZero(const Token * tok,const std::string & varname)3497 void CheckOther::unsignedLessThanZero(const Token *tok, const std::string &varname)
3498 {
3499     reportError(tok, Severity::style, "unsignedLessThanZero",
3500                 "Checking if unsigned variable '" + varname + "' is less than zero.\n"
3501                 "An unsigned variable will never be negative so it is either pointless or "
3502                 "an error to check if it is.");
3503 }
3504 
unsignedPositive(const Token * tok,const std::string & varname)3505 void CheckOther::unsignedPositive(const Token *tok, const std::string &varname)
3506 {
3507     reportError(tok, Severity::style, "unsignedPositive",
3508                 "Checking if unsigned variable '" + varname + "' is positive is always true.\n"
3509                 "An unsigned variable can't be negative so it is either pointless or "
3510                 "an error to check if it is.");
3511 }
3512