--------------------------------------------------------------------------- Check , and ---------------------------------------------------------------------------
| 106 | // Check <valid>, <strz> and <not-bool> |
| 107 | //--------------------------------------------------------------------------- |
| 108 | void CheckFunctionsImpl::invalidFunctionUsage() |
| 109 | { |
| 110 | logChecker("CheckFunctions::invalidFunctionUsage"); |
| 111 | const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase(); |
| 112 | for (const Scope *scope : symbolDatabase->functionScopes) { |
| 113 | for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) { |
| 114 | tok = skipUnreachableBranch(tok); |
| 115 | if (!Token::Match(tok, "%name% ( !!)")) |
| 116 | continue; |
| 117 | const Token * const functionToken = tok; |
| 118 | const std::vector<const Token *> arguments = getArguments(tok); |
| 119 | for (int argnr = 1; argnr <= arguments.size(); ++argnr) { |
| 120 | const Token * const argtok = arguments[argnr-1]; |
| 121 | |
| 122 | // check <valid>...</valid> |
| 123 | const ValueFlow::Value *invalidValue = argtok->getInvalidValue(functionToken,argnr,mSettings); |
| 124 | if (invalidValue) { |
| 125 | invalidFunctionArgError(argtok, functionToken->next()->astOperand1()->expressionString(), argnr, invalidValue, mSettings.library.validarg(functionToken, argnr)); |
| 126 | } |
| 127 | |
| 128 | if (astIsBool(argtok)) { |
| 129 | // check <not-bool> |
| 130 | if (mSettings.library.isboolargbad(functionToken, argnr)) |
| 131 | invalidFunctionArgBoolError(argtok, functionToken->str(), argnr); |
| 132 | |
| 133 | // Are the values 0 and 1 valid? |
| 134 | else if (!mSettings.library.isIntArgValid(functionToken, argnr, 0, mSettings)) |
| 135 | invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings.library.validarg(functionToken, argnr)); |
| 136 | else if (!mSettings.library.isIntArgValid(functionToken, argnr, 1, mSettings)) |
| 137 | invalidFunctionArgError(argtok, functionToken->str(), argnr, nullptr, mSettings.library.validarg(functionToken, argnr)); |
| 138 | } |
| 139 | // check <strz> |
| 140 | if (mSettings.library.isargstrz(functionToken, argnr)) { |
| 141 | if (Token::Match(argtok, "& %var% !![") && argtok->next() && argtok->next()->valueType()) { |
| 142 | const ValueType * valueType = argtok->next()->valueType(); |
| 143 | const Variable * variable = argtok->next()->variable(); |
| 144 | if ((valueType->type == ValueType::Type::CHAR || valueType->type == ValueType::Type::WCHAR_T || (valueType->type == ValueType::Type::RECORD && Token::Match(argtok, "& %var% . %var% ,|)"))) && |
| 145 | !variable->isArray() && |
| 146 | (variable->isConst() || !variable->isGlobal()) && |
| 147 | (!argtok->next()->hasKnownValue() || argtok->next()->getValue(0) == nullptr)) { |
| 148 | invalidFunctionArgStrError(argtok, functionToken->str(), argnr); |
| 149 | } |
| 150 | } |
| 151 | const ValueType* const valueType = argtok->valueType(); |
| 152 | const Variable* const variable = argtok->variable(); |
| 153 | // Is non-null terminated local variable of type char (e.g. char buf[] = {'x'};) ? |
| 154 | if (variable && variable->isLocal() |
| 155 | && valueType && (valueType->type == ValueType::Type::CHAR || valueType->type == ValueType::Type::WCHAR_T) |
| 156 | && !isVariablesChanged(variable->declEndToken(), functionToken, valueType->pointer, { variable }, mSettings)) { |
| 157 | const Token* varTok = variable->declEndToken(); |
| 158 | MathLib::bigint count = -1; // Find out explicitly set count, e.g.: char buf[3] = {...}. Variable 'count' is set to 3 then. |
| 159 | if (varTok && Token::simpleMatch(varTok->astOperand1(), "[")) |
| 160 | { |
| 161 | const Token* const countTok = varTok->astOperand1()->astOperand2(); |
| 162 | if (countTok && countTok->hasKnownIntValue()) |
| 163 | count = countTok->getKnownIntValue(); |
| 164 | } |
| 165 | if (Token::simpleMatch(varTok, "= {")) { |
no test coverage detected