| 91 | //--------------------------------------------------------------------------- |
| 92 | |
| 93 | void CheckVaargImpl::va_list_usage() |
| 94 | { |
| 95 | if (mSettings.clang) |
| 96 | return; |
| 97 | |
| 98 | logChecker("CheckVaarg::va_list_usage"); // notclang |
| 99 | |
| 100 | const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 101 | for (const Variable* var : symbolDatabase->variableList()) { |
| 102 | if (!var || var->isPointer() || var->isReference() || var->isArray() || !var->scope() || var->typeStartToken()->str() != "va_list") |
| 103 | continue; |
| 104 | if (!var->isLocal() && !var->isArgument()) // Check only local variables and arguments |
| 105 | continue; |
| 106 | |
| 107 | bool open = var->isArgument(); // va_list passed as argument are opened |
| 108 | bool exitOnEndOfStatement = false; |
| 109 | |
| 110 | const Token* tok = var->nameToken()->next(); |
| 111 | for (; tok && tok != var->scope()->bodyEnd; tok = tok->next()) { |
| 112 | // Skip lambdas |
| 113 | const Token* tok2 = findLambdaEndToken(tok); |
| 114 | if (tok2) |
| 115 | tok = tok2; |
| 116 | if (Token::Match(tok, "va_start ( %varid%", var->declarationId())) { |
| 117 | if (open) |
| 118 | va_start_subsequentCallsError(tok, var->name()); |
| 119 | open = true; |
| 120 | tok = tok->linkAt(1); |
| 121 | } else if (Token::Match(tok, "va_end ( %varid%", var->declarationId())) { |
| 122 | if (!open) |
| 123 | va_list_usedBeforeStartedError(tok, var->name()); |
| 124 | open = false; |
| 125 | tok = tok->linkAt(1); |
| 126 | } else if (Token::simpleMatch(tok, "va_copy (")) { |
| 127 | bool nopen = open; |
| 128 | if (tok->linkAt(1)->previous()->varId() == var->declarationId()) { // Source |
| 129 | if (!open) |
| 130 | va_list_usedBeforeStartedError(tok, var->name()); |
| 131 | } |
| 132 | if (tok->tokAt(2)->varId() == var->declarationId()) { // Destination |
| 133 | if (open) |
| 134 | va_start_subsequentCallsError(tok, var->name()); |
| 135 | nopen = true; |
| 136 | } |
| 137 | open = nopen; |
| 138 | tok = tok->linkAt(1); |
| 139 | } else if (Token::Match(tok, "throw|return")) |
| 140 | exitOnEndOfStatement = true; |
| 141 | else if (tok->str() == "break") { |
| 142 | tok = findNextTokenFromBreak(tok); |
| 143 | if (!tok) |
| 144 | return; |
| 145 | } else if (tok->str() == "goto" || (tok->isCpp() && tok->str() == "try")) { |
| 146 | open = false; |
| 147 | break; |
| 148 | } else if (!open && tok->varId() == var->declarationId()) |
| 149 | va_list_usedBeforeStartedError(tok, var->name()); |
| 150 | else if (exitOnEndOfStatement && tok->str() == ";") |
no test coverage detected