42 #include <unordered_set>
76 if (
Token::Match(tok,
"std :: cout|cerr !!.") && tok->next()->astParent() && tok->next()->astParent()->astOperand1() == tok->next()) {
102 if (str.find(
'+', 1) != std::string::npos)
104 if (str.find(
'w') != std::string::npos || str.find(
'a') != std::string::npos)
106 if (str.find(
'r') != std::string::npos)
115 enum class Operation {NONE, UNIMPORTANT, READ, WRITE, POSITIONING, OPEN, CLOSE, UNKNOWN_OP} lastOperation = Operation::NONE;
117 enum class AppendMode { UNKNOWN_AM, APPEND, APPEND_EX };
118 AppendMode append_mode = AppendMode::UNKNOWN_AM;
119 std::string filename;
124 const std::unordered_set<std::string> whitelist = {
"clearerr",
"feof",
"ferror",
"fgetpos",
"ftell",
"setbuf",
"setvbuf",
"ungetc",
"ungetwc" };
133 std::map<int, Filepointer> filepointers;
139 if (!var || !var->declarationId() || var->isArray() || !
Token::simpleMatch(var->typeStartToken(),
"FILE *"))
142 if (var->isLocal()) {
143 if (var->nameToken()->strAt(1) ==
"(")
146 filepointers.insert(std::make_pair(var->declarationId(), Filepointer(
OpenMode::CLOSED)));
157 tok = tok->linkAt(1);
160 if (tok->str() ==
"{")
162 else if (tok->str() ==
"}") {
164 for (std::pair<const int, Filepointer>& filepointer : filepointers) {
165 if (
indent < filepointer.second.mode_indent) {
166 filepointer.second.mode_indent = 0;
169 if (
indent < filepointer.second.op_indent) {
170 filepointer.second.op_indent = 0;
171 filepointer.second.lastOperation = Filepointer::Operation::UNKNOWN_OP;
174 }
else if (tok->str() ==
"return" || tok->str() ==
"continue" || tok->str() ==
"break" ||
mSettings->
library.
isnoreturn(tok)) {
175 for (std::pair<const int, Filepointer>& filepointer : filepointers) {
176 filepointer.second.mode_indent = 0;
178 filepointer.second.op_indent = 0;
179 filepointer.second.lastOperation = Filepointer::Operation::UNKNOWN_OP;
182 (tok->strAt(2) !=
"fopen" && tok->strAt(2) !=
"freopen" && tok->strAt(2) !=
"tmpfile" &&
183 (windows ? (tok->str() !=
"_wfopen" && tok->str() !=
"_wfreopen") :
true))) {
184 const std::map<int, Filepointer>::iterator i = filepointers.find(tok->varId());
185 if (i != filepointers.end()) {
187 i->second.lastOperation = Filepointer::Operation::UNKNOWN_OP;
189 }
else if (
Token::Match(tok,
"%name% (") && tok->previous() && (!tok->previous()->isName() ||
Token::Match(tok->previous(),
"return|throw"))) {
191 const Token* fileTok =
nullptr;
192 const Token* fileNameTok =
nullptr;
193 Filepointer::Operation operation = Filepointer::Operation::NONE;
195 if ((tok->str() ==
"fopen" || tok->str() ==
"freopen" || tok->str() ==
"tmpfile" ||
196 (windows && (tok->str() ==
"_wfopen" || tok->str() ==
"_wfreopen"))) &&
197 tok->strAt(-1) ==
"=") {
198 if (tok->str() !=
"tmpfile") {
204 fileTok = tok->
tokAt(-2);
205 operation = Filepointer::Operation::OPEN;
207 fileNameTok = tok->
tokAt(2);
208 }
else if (windows &&
Token::Match(tok,
"fopen_s|freopen_s|_wfopen_s|_wfreopen_s ( & %name%")) {
212 fileTok = tok->
tokAt(3);
213 operation = Filepointer::Operation::OPEN;
214 }
else if ((tok->str() ==
"rewind" || tok->str() ==
"fseek" || tok->str() ==
"fsetpos" || tok->str() ==
"fflush") ||
215 (windows && tok->str() ==
"_fseeki64")) {
216 fileTok = tok->
tokAt(2);
217 if (printPortability && fileTok && tok->
str() ==
"fflush") {
218 if (fileTok->
str() ==
"stdin")
221 const Filepointer& f = filepointers[fileTok->
varId()];
226 operation = Filepointer::Operation::POSITIONING;
227 }
else if (tok->str() ==
"fgetc" || tok->str() ==
"fgetwc" ||
228 tok->str() ==
"fgets" || tok->str() ==
"fgetws" || tok->str() ==
"fread" ||
229 tok->str() ==
"fscanf" || tok->str() ==
"fwscanf" || tok->str() ==
"getc" ||
230 (windows && (tok->str() ==
"fscanf_s" || tok->str() ==
"fwscanf_s"))) {
231 if (tok->str().find(
"scanf") != std::string::npos)
232 fileTok = tok->
tokAt(2);
235 operation = Filepointer::Operation::READ;
236 }
else if (tok->str() ==
"fputc" || tok->str() ==
"fputwc" ||
237 tok->str() ==
"fputs" || tok->str() ==
"fputws" || tok->str() ==
"fwrite" ||
238 tok->str() ==
"fprintf" || tok->str() ==
"fwprintf" || tok->str() ==
"putcc" ||
239 (windows && (tok->str() ==
"fprintf_s" || tok->str() ==
"fwprintf_s"))) {
240 if (tok->str().find(
"printf") != std::string::npos)
241 fileTok = tok->
tokAt(2);
244 operation = Filepointer::Operation::WRITE;
245 }
else if (tok->str() ==
"fclose") {
246 fileTok = tok->
tokAt(2);
247 operation = Filepointer::Operation::CLOSE;
248 }
else if (whitelist.find(tok->str()) != whitelist.end()) {
249 fileTok = tok->
tokAt(2);
250 if ((tok->str() ==
"ungetc" || tok->str() ==
"ungetwc") && fileTok)
252 operation = Filepointer::Operation::UNIMPORTANT;
256 if (!tok->function() || (tok->function()->nestedIn && tok->function()->nestedIn->isClassOrStruct())) {
257 for (std::pair<const int, Filepointer>& filepointer : filepointers) {
261 filepointer.second.mode_indent = 0;
262 filepointer.second.op_indent =
indent;
263 filepointer.second.lastOperation = Filepointer::Operation::UNKNOWN_OP;
269 for (
const Token* tok2 = tok->
tokAt(2); tok2 != end2; tok2 = tok2->
next()) {
270 if (tok2->varId() && filepointers.find(tok2->varId()) != filepointers.end()) {
272 operation = Filepointer::Operation::UNKNOWN_OP;
279 fileTok = fileTok->
tokAt(2);
281 if (!fileTok || !fileTok->
varId() || fileTok->
strAt(1) ==
"[")
284 if (filepointers.find(fileTok->
varId()) == filepointers.end()) {
288 Filepointer& f = filepointers[fileTok->
varId()];
291 case Filepointer::Operation::OPEN:
293 for (std::map<int, Filepointer>::const_iterator it = filepointers.cbegin(); it != filepointers.cend(); ++it) {
294 const Filepointer &fptr = it->second;
299 f.filename = fileNameTok->
str();
303 if (mode.find(
'a') != std::string::npos) {
305 f.append_mode = Filepointer::AppendMode::APPEND_EX;
307 f.append_mode = Filepointer::AppendMode::APPEND;
309 f.append_mode = Filepointer::AppendMode::UNKNOWN_AM;
312 case Filepointer::Operation::POSITIONING:
315 else if (f.append_mode == Filepointer::AppendMode::APPEND && tok->str() !=
"fflush" && printWarnings)
318 case Filepointer::Operation::READ:
323 else if (f.lastOperation == Filepointer::Operation::WRITE)
326 case Filepointer::Operation::WRITE:
331 else if (f.lastOperation == Filepointer::Operation::READ)
334 case Filepointer::Operation::CLOSE:
341 case Filepointer::Operation::UNIMPORTANT:
345 case Filepointer::Operation::UNKNOWN_OP:
352 if (operation != Filepointer::Operation::NONE && operation != Filepointer::Operation::UNIMPORTANT) {
354 f.lastOperation = operation;
358 for (std::pair<const int, Filepointer>& filepointer : filepointers) {
359 filepointer.second.op_indent = 0;
361 filepointer.second.lastOperation = Filepointer::Operation::UNKNOWN_OP;
369 "fflushOnInputStream",
"fflush() called on input stream '" + varname +
"' may result in undefined behaviour on non-linux systems.",
CWE398,
Certainty::normal);
375 "IOWithoutPositioning",
"Read and write operations without a call to a positioning function (fseek, fsetpos or rewind) or fflush in between result in undefined behaviour.",
CWE664,
Certainty::normal);
387 "writeReadOnlyFile",
"Write operation on a file that was opened only for reading.",
CWE664,
Certainty::normal);
399 "seekOnAppendedFile",
"Repositioning operation performed on a file opened in append mode has no effect.",
CWE398,
Certainty::normal);
405 "incompatibleFileOpen",
"The file '" + filename +
"' is opened for read and write access at the same time on different streams",
CWE664,
Certainty::normal);
420 const Token *formatToken =
nullptr;
422 formatToken = tok->
tokAt(2);
423 else if (
Token::Match(tok,
"sscanf|vsscanf|fscanf|vfscanf (")) {
426 formatToken = nextArg;
435 const std::string &formatstr(formatToken->
str());
436 for (std::size_t i = 1; i < formatstr.length(); i++) {
437 if (formatstr[i] ==
'%')
443 else if (std::isdigit(formatstr[i]) || formatstr[i] ==
'*') {
447 else if (std::isalpha((
unsigned char)formatstr[i]) || formatstr[i] ==
'[') {
448 if (formatstr[i] ==
's' || formatstr[i] ==
'[' || formatstr[i] ==
'S' || (formatstr[i] ==
'l' && formatstr[i+1] ==
's'))
459 const std::string fname = (tok ? tok->
str() : std::string(
"scanf"));
461 "invalidscanf", fname +
"() without field width limits can crash with huge input data.\n" +
462 fname +
"() without field width limits can crash with huge input data. Add a field width "
463 "specifier to fix this problem.\n"
465 "Sample program that can crash:\n"
467 "#include <stdio.h>\n"
471 " scanf(\"%s\", c);\n"
475 "Typing in 5 or more characters may make the program crash. The correct usage "
476 "here is 'scanf(\"%4s\", c);', as the maximum field width does not include the "
477 "terminating null byte.\n"
478 "Source: http://linux.die.net/man/3/scanf\n"
479 "Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c",
490 const Token *&formatStringTok,
const Token *&formatArgTok)
492 const Token* argTok = firstArg;
494 for (
int i = 0; i < arg && argTok; ++i)
499 formatStringTok = argTok;
506 (argTok->
variable()->dimensions().size() == 1 &&
507 argTok->
variable()->dimensionKnown(0) &&
508 argTok->
variable()->dimension(0) != 0))) {
510 if (!argTok->
values().empty()) {
511 const std::list<ValueFlow::Value>::const_iterator value = std::find_if(
513 if (value != argTok->
values().cend() && value->isTokValue() && value->tokvalue &&
515 formatStringTok = value->tokvalue;
524 static inline bool typesMatch(
const std::string& iToTest,
const std::string& iTypename,
const std::string& iOptionalPrefix =
"std::")
526 return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename);
534 logChecker(
"CheckIO::checkWrongPrintfScanfArguments");
538 if (!tok->isName())
continue;
540 const Token* argListTok =
nullptr;
541 const Token* formatStringTok =
nullptr;
544 bool scanf_s =
false;
545 int formatStringArgNo = -1;
553 if (formatStringArgNo >= 0) {
555 if (!
findFormat(formatStringArgNo, tok->tokAt(2), formatStringTok, argListTok))
558 if (
Token::Match(tok->tokAt(2)->nextArgument(),
"%str%")) {
560 if (!
findFormat(1, tok->tokAt(2), formatStringTok, argListTok))
564 if (!
findFormat(2, tok->tokAt(2), formatStringTok, argListTok))
567 }
else if (isWindows &&
Token::Match(tok,
"sprintf_s|swprintf_s (")) {
569 if (
findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) {
570 if (!formatStringTok)
574 else if (
findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
575 if (!formatStringTok)
578 }
else if (isWindows &&
Token::Match(tok,
"_snprintf_s|_snwprintf_s (")) {
580 if (
findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
581 if (!formatStringTok)
585 else if (
findFormat(3, tok->tokAt(2), formatStringTok, argListTok)) {
586 if (!formatStringTok)
593 if (!formatStringTok)
602 const Token *
const formatStringTok,
603 const Token * argListTok,
609 const std::string &formatString = formatStringTok->
str();
614 bool percent =
false;
615 const Token* argListTok2 = argListTok;
616 std::set<int> parameterPositionsUsed;
617 for (std::string::const_iterator i = formatString.cbegin(); i != formatString.cend(); ++i) {
620 }
else if (percent && *i ==
'[') {
621 while (i != formatString.cend()) {
637 if (i == formatString.cend())
639 }
else if (percent) {
642 bool _continue =
false;
645 int parameterPosition = 0;
646 bool hasParameterPosition =
false;
647 while (i != formatString.cend() && *i !=
'[' && !std::isalpha((
unsigned char)*i)) {
657 }
else if (std::isdigit(*i)) {
659 }
else if (*i ==
'$') {
660 parameterPosition = strToInt<int>(width);
661 hasParameterPosition =
true;
666 auto bracketBeg = formatString.cend();
667 if (i != formatString.cend() && *i ==
'[') {
669 while (i != formatString.cend()) {
675 if (scanf_s && !skip) {
682 if (i == formatString.cend())
687 if (scan || *i !=
'm') {
691 if (hasParameterPosition) {
692 if (parameterPositionsUsed.find(parameterPosition) == parameterPositionsUsed.end())
693 parameterPositionsUsed.insert(parameterPosition);
703 std::string specifier;
709 specifier += (*i ==
's' || bracketBeg == formatString.end()) ? std::string{
's' } : std::string{ bracketBeg, i + 1 };
711 if (!width.empty()) {
712 const int numWidth = strToInt<int>(width);
734 if (!width.empty()) {
735 const int numWidth = strToInt<int>(width);
764 switch (specifier[0]) {
766 if (specifier[1] ==
'h') {
773 if (specifier[1] ==
'l') {
788 if (specifier.find(
"I64") != std::string::npos) {
791 }
else if (specifier.find(
"I32") != std::string::npos) {
844 switch (specifier[0]) {
846 if (specifier[1] ==
'h') {
853 if (specifier[1] ==
'l') {
866 if (specifier.find(
"I64") != std::string::npos) {
869 }
else if (specifier.find(
"I32") != std::string::npos) {
921 switch (specifier[0]) {
940 if ((i+1 != formatString.cend() && *(i+1) ==
'6' &&
941 i+2 != formatString.cend() && *(i+2) ==
'4') ||
942 (i+1 != formatString.cend() && *(i+1) ==
'3' &&
943 i+2 != formatString.cend() && *(i+2) ==
'2')) {
946 if ((i+1) != formatString.cend() && !isalpha(*(i+1))) {
954 if ((i+1) != formatString.cend() && !isalpha(*(i+1))) {
965 if (i+1 != formatString.cend() && *(i+1) == *i)
974 if ((i + 1) != formatString.end() && !isalpha(*(i+1))) {
987 }
else if (printWarning) {
988 std::string specifier;
991 if (i == formatString.end()) {
1025 switch (specifier[0]) {
1027 if (specifier[1] ==
'h') {
1034 if (specifier[1] ==
'l') {
1059 if (specifier.find(
"I64") != std::string::npos) {
1062 }
else if (specifier.find(
"I32") != std::string::npos) {
1098 switch (specifier[0]) {
1100 if (specifier[1] ==
'h') {
1107 if (specifier[1] ==
'l') {
1128 if (specifier.find(
"I64") != std::string::npos) {
1131 }
else if (specifier.find(
"I32") != std::string::npos) {
1173 switch (specifier[0]) {
1175 if (specifier[1] ==
'h') {
1182 if (specifier[1] ==
'l') {
1207 if (specifier.find(
"I64") != std::string::npos) {
1210 }
else if (specifier.find(
"I32") != std::string::npos) {
1263 if ((i + 1) != formatString.end() && *(i + 1) == *i) {
1264 if ((i + 2) != formatString.end() && !isalpha(*(i + 2))) {
1265 std::string modifier;
1267 modifier += *(i + 1);
1275 if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
1276 std::string modifier;
1287 if ((*(i+1) ==
'3' && *(i+2) ==
'2') ||
1288 (*(i+1) ==
'6' && *(i+2) ==
'4')) {
1298 if ((i + 1) != formatString.end() && !isalpha(*(i+1))) {
1321 int numFunction = 0;
1322 while (argListTok2) {
1331 for (
const int i : parameterPositionsUsed) {
1332 if ((i == 0) || (i > numFormat))
1338 if ((numFormat + numSecure) != numFunction)
1354 const Token *top = arg;
1355 while (top->
str() ==
"(" && !top->
isCast())
1360 if (valuetype && valuetype->
type >= ValueType::Type::BOOL) {
1391 if (valuetype->
sign == ValueType::Sign::UNSIGNED)
1393 else if (valuetype->
sign == ValueType::Sign::SIGNED)
1398 for (
int p = 0; p < valuetype->
pointer; p++)
1414 (
Token::Match(arg,
"static_cast|reinterpret_cast|const_cast <") &&
1417 if (
Token::Match(arg,
"static_cast|reinterpret_cast|const_cast")) {
1423 if (arg->
str() ==
"&") {
1428 arg = arg->
tokAt(2);
1431 const Token *varTok =
nullptr;
1433 for (; tok1; tok1 = tok1->
next()) {
1434 if (tok1->
str() ==
"," || tok1->
str() ==
")") {
1438 const Function *
function = varTok->
link()->previous()->function();
1439 if (
function && function->retType && function->retType->isEnumType()) {
1440 if (function->retType->classScope->enumType)
1441 typeToken =
function->retType->classScope->enumType;
1447 }
else if (
function && function->retDef) {
1458 if (
function && function->retType && function->retType->isEnumType()) {
1459 if (function->retType->classScope->enumType)
1460 typeToken =
function->retType->classScope->enumType;
1466 }
else if (
function && function->retDef) {
1478 if (tok1->
str() ==
"(" || tok1->
str() ==
"{" || tok1->
str() ==
"[")
1479 tok1 = tok1->
link();
1480 else if (tok1->
link() && tok1->
str() ==
"<")
1481 tok1 = tok1->
link();
1487 if (tok1->
next()->
str() ==
"size") {
1503 }
else if (tok1->
next()->
str() ==
"empty") {
1505 }
else if (tok1->
next()->
str() ==
"c_str") {
1561 while (tempToken->next())
1562 tempToken->deleteNext();
1569 const std::set<std::string> stl_vector = {
"array",
"vector" };
1570 const std::set<std::string> stl_string = {
"string",
"u16string",
"u32string",
"wstring" };
1577 if (variableInfo->isStlType(stl_vector)) {
1578 typeToken = variableInfo->typeStartToken()->tokAt(4);
1582 if (variableInfo->isStlType(stl_string)) {
1583 tempToken =
new Token(variableInfo->typeStartToken());
1584 if (variableInfo->typeStartToken()->strAt(2) ==
"string")
1585 tempToken->str(
"char");
1587 tempToken->str(
"wchar_t");
1588 typeToken = tempToken;
1591 if (variableInfo->type() && !variableInfo->type()->derivedFrom.empty()) {
1592 const std::vector<Type::BaseInfo>& derivedFrom = variableInfo->type()->derivedFrom;
1594 const Token* nameTok = i.nameTok;
1596 typeToken = nameTok->
tokAt(4);
1601 tempToken =
new Token(variableInfo->typeStartToken());
1602 if (nameTok->
strAt(2) ==
"string")
1603 tempToken->str(
"char");
1605 tempToken->str(
"wchar_t");
1606 typeToken = tempToken;
1610 }
else if (variableInfo->type()) {
1611 const Scope * classScope = variableInfo->
type()->classScope;
1614 if (func.
name() ==
"operator[]") {
1628 "array",
"bitset",
"deque",
"forward_list",
1629 "hash_map",
"hash_multimap",
"hash_set",
1630 "list",
"map",
"multimap",
"multiset",
1631 "priority_queue",
"queue",
"set",
"stack",
1632 "unordered_map",
"unordered_multimap",
"unordered_multiset",
"unordered_set",
"vector"
1651 const Token* nameTok = baseInfo.nameTok;
1652 if (
Token::Match(nameTok,
"std :: vector|array|bitset|deque|list|forward_list|map|multimap|multiset|priority_queue|queue|set|stack|hash_map|hash_multimap|hash_set|unordered_map|unordered_multimap|unordered_set|unordered_multiset <")) {
1653 typeToken = nameTok->
tokAt(4);
1657 typeToken = nameTok;
1671 if (variableInfo && !_template)
1672 return variableInfo->isArrayOrPointer();
1674 const Token *tok = typeToken;
1677 return tok && tok->
strAt(1) ==
"*";
1682 if (variableInfo->type())
1685 const Token* varTypeTok = typeToken;
1686 if (varTypeTok->
str() ==
"std")
1687 varTypeTok = varTypeTok->
tokAt(2);
1689 return ((variableInfo->isStlStringType() || (varTypeTok->
strAt(1) ==
"<" && varTypeTok->
linkAt(1) && varTypeTok->
linkAt(1)->
strAt(1) !=
"::")) && !variableInfo->isArrayOrPointer());
1695 return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType());
1697 return (typeToken->isStandardType() || functionInfo->retType ||
Token::Match(typeToken,
"std :: string|wstring"));
1699 return typeToken->isStandardType() ||
Token::Match(typeToken,
"std :: string|wstring");
1704 return typeToken && typeToken->isStandardType() && settings.
library.
podtype(typeToken->str());
1708 const std::string &functionName,
1716 std::ostringstream errmsg;
1717 errmsg << functionName
1718 <<
" format string requires "
1720 <<
" parameter" << (numFormat != 1 ?
"s" :
"") <<
" but "
1721 << (numFormat > numFunction ?
"only " :
"")
1723 << (numFunction != 1 ?
" are" :
" is")
1734 std::ostringstream errmsg;
1735 errmsg << functionName <<
": ";
1737 errmsg <<
"parameter positions start at 1, not 0";
1739 errmsg <<
"referencing parameter " << index <<
" while " << numFunction <<
" arguments given";
1749 std::ostringstream errmsg;
1750 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires a \'";
1751 if (specifier[0] ==
's')
1753 else if (specifier[0] ==
'S')
1754 errmsg <<
"wchar_t";
1755 errmsg <<
" *\' but the argument type is ";
1765 std::ostringstream errmsg;
1766 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1767 if (specifier[0] ==
'h') {
1768 if (specifier[1] ==
'h')
1769 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"char";
1771 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"short";
1772 }
else if (specifier[0] ==
'l') {
1773 if (specifier[1] ==
'l')
1774 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1776 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long";
1777 }
else if (specifier.find(
"I32") != std::string::npos) {
1778 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"__int32";
1779 }
else if (specifier.find(
"I64") != std::string::npos) {
1780 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"__int64";
1781 }
else if (specifier[0] ==
'I') {
1782 errmsg << (isUnsigned ?
"size_t" :
"ptrdiff_t");
1783 }
else if (specifier[0] ==
'j') {
1785 errmsg <<
"uintmax_t";
1787 errmsg <<
"intmax_t";
1788 }
else if (specifier[0] ==
'z') {
1789 if (specifier[1] ==
'd' || specifier[1] ==
'i')
1790 errmsg <<
"ssize_t";
1793 }
else if (specifier[0] ==
't') {
1794 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"ptrdiff_t";
1795 }
else if (specifier[0] ==
'L') {
1796 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1798 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"int";
1800 errmsg <<
" *\' but the argument type is ";
1810 std::ostringstream errmsg;
1811 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1812 if (specifier[0] ==
'l' && specifier[1] !=
'l')
1814 else if (specifier[0] ==
'L')
1815 errmsg <<
"long double";
1818 errmsg <<
" *\' but the argument type is ";
1829 std::ostringstream errmsg;
1830 errmsg <<
"%s in format string (no. " << numFormat <<
") requires \'char *\' but the argument type is ";
1840 std::ostringstream errmsg;
1841 errmsg <<
"%n in format string (no. " << numFormat <<
") requires \'int *\' but the argument type is ";
1851 std::ostringstream errmsg;
1852 errmsg <<
"%p in format string (no. " << numFormat <<
") requires an address but the argument type is ";
1860 if (specifier[0] ==
'l') {
1861 if (specifier[1] ==
'l')
1862 os << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1864 os << (isUnsigned ?
"unsigned " :
"") <<
"long";
1865 }
else if (specifier[0] ==
'h') {
1866 if (specifier[1] ==
'h')
1867 os << (isUnsigned ?
"unsigned " :
"") <<
"char";
1869 os << (isUnsigned ?
"unsigned " :
"") <<
"short";
1870 }
else if (specifier.find(
"I32") != std::string::npos) {
1871 os << (isUnsigned ?
"unsigned " :
"") <<
"__int32";
1872 }
else if (specifier.find(
"I64") != std::string::npos) {
1873 os << (isUnsigned ?
"unsigned " :
"") <<
"__int64";
1874 }
else if (specifier[0] ==
'I') {
1875 os << (isUnsigned ?
"size_t" :
"ptrdiff_t");
1876 }
else if (specifier[0] ==
'j') {
1881 }
else if (specifier[0] ==
'z') {
1882 if (specifier[1] ==
'd' || specifier[1] ==
'i')
1886 }
else if (specifier[0] ==
't') {
1887 os << (isUnsigned ?
"unsigned " :
"") <<
"ptrdiff_t";
1888 }
else if (specifier[0] ==
'L') {
1889 os << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1891 os << (isUnsigned ?
"unsigned " :
"") <<
"int";
1901 std::ostringstream errmsg;
1902 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires ";
1904 errmsg <<
" but the argument type is ";
1915 std::ostringstream errmsg;
1916 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires ";
1918 errmsg <<
" but the argument type is ";
1928 std::ostringstream errmsg;
1929 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1930 if (specifier[0] ==
'L')
1932 errmsg <<
"double\' but the argument type is ";
1950 os <<
"const wchar_t *";
1952 os <<
"const char *";
1955 if (type->
strAt(-1) ==
"const")
1958 os << type->
str() <<
" ";
1959 type = type->
next();
1962 os << type->
str() <<
"::";
1963 type = type->
tokAt(2);
1965 os << type->
stringify(
false,
true,
false);
1982 os <<
" {aka " << type->
stringify(
false,
true,
false);
1997 std::ostringstream errmsg;
1998 errmsg <<
"'" << modifier <<
"' in format string (no. " << numFormat <<
") is a length modifier and cannot be used without a conversion specifier.";
2005 std::string varname;
2009 varname = var->
name();
2012 std::ostringstream errmsg;
2013 if (arrlen > width) {
2016 errmsg <<
"Width " << width <<
" given in format string (no. " << numFormat <<
") is smaller than destination buffer"
2017 <<
" '" << varname <<
"[" << arrlen <<
"]'.";
2020 errmsg <<
"Width " << width <<
" given in format string (no. " << numFormat <<
") is larger than destination buffer '"
2021 << varname <<
"[" << arrlen <<
"]', use %" << (specifier ==
"c" ? arrlen : (arrlen - 1)) << specifier <<
" to prevent overflowing it.";
bool isUnevaluated(const Token *tok)
static void printfFormatType(std::ostream &os, const std::string &specifier, bool isUnsigned)
static bool findFormat(nonneg int arg, const Token *firstArg, const Token *&formatStringTok, const Token *&formatArgTok)
static const CWE CWE398(398U)
static const CWE CWE704(704U)
static const std::set< std::string > stl_container
static const CWE CWE687(687U)
static const CWE CWE119(119U)
static const CWE CWE910(910U)
static const CWE CWE685(685U)
static bool typesMatch(const std::string &iToTest, const std::string &iTypename, const std::string &iOptionalPrefix="std::")
static const CWE CWE686(686U)
static OpenMode getMode(const std::string &str)
static const CWE CWE664(664U)
const Variable * variableInfo
bool isArrayOrPointer() const
const Function * functionInfo
bool isLibraryType(const Settings &settings) const
bool isStdContainer(const Token *tok)
ArgumentInfo(const Token *arg, const Settings &settings, bool _isCPP)
bool isComplexType() const
bool isStdVectorOrString()
Check input output operations.
void invalidPrintfArgTypeError_uint(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo)
void invalidScanf()
scanf can crash if width specifiers are not used
void invalidPrintfArgTypeError_n(const Token *tok, nonneg int numFormat, const ArgumentInfo *argInfo)
void seekOnAppendedFileError(const Token *tok)
void incompatibleFileOpenError(const Token *tok, const std::string &filename)
void invalidPrintfArgTypeError_s(const Token *tok, nonneg int numFormat, const ArgumentInfo *argInfo)
void writeReadOnlyFileError(const Token *tok)
void readWriteOnlyFileError(const Token *tok)
void invalidLengthModifierError(const Token *tok, nonneg int numFormat, const std::string &modifier)
void checkCoutCerrMisusage()
Check for missusage of std::cout
void fflushOnInputStreamError(const Token *tok, const std::string &varname)
void invalidScanfArgTypeError_float(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo)
void invalidScanfError(const Token *tok)
static void argumentType(std::ostream &os, const ArgumentInfo *argInfo)
void checkFormatString(const Token *const tok, const Token *const formatStringTok, const Token *argListTok, const bool scan, const bool scanf_s)
void wrongPrintfScanfPosixParameterPositionError(const Token *tok, const std::string &functionName, nonneg int index, nonneg int numFunction)
static Severity getSeverity(const ArgumentInfo *argInfo)
void invalidScanfFormatWidthError(const Token *tok, nonneg int numFormat, int width, const Variable *var, const std::string &specifier)
void invalidPrintfArgTypeError_sint(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo)
void coutCerrMisusageError(const Token *tok, const std::string &streamName)
void checkFileUsage()
Check usage of files
void checkWrongPrintfScanfArguments()
Checks type and number of arguments given to functions like printf or scanf
void invalidScanfArgTypeError_int(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo, bool isUnsigned)
void invalidPrintfArgTypeError_p(const Token *tok, nonneg int numFormat, const ArgumentInfo *argInfo)
void ioWithoutPositioningError(const Token *tok)
void invalidPrintfArgTypeError_float(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo)
void invalidScanfArgTypeError_s(const Token *tok, nonneg int numFormat, const std::string &specifier, const ArgumentInfo *argInfo)
void useClosedFileError(const Token *tok)
void wrongPrintfScanfArgumentsError(const Token *tok, const std::string &functionName, nonneg int numFormat, nonneg int numFunction)
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg)
report an error
const Settings *const mSettings
const Tokenizer *const mTokenizer
void logChecker(const char id[])
log checker
const std::string & name() const
const Token * retDef
function return type token
bool formatstr_function(const Token *ftok) const
bool formatstr_secure(const Token *ftok) const
bool isnoreturn(const Token *ftok) const
int formatstr_argno(const Token *ftok) const
const PodType * podtype(const std::string &name) const
bool isFunctionConst(const std::string &functionName, bool pure) const
bool formatstr_scan(const Token *ftok) const
std::list< Function > functionList
Function * function
function info for this function
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
const Scope * functionOf
scope this function belongs to
bool isClassOrStruct() const
This is just a container for general settings so that we don't need to pass individual values to func...
SimpleEnableGroup< Certainty > certainty
SimpleEnableGroup< Severity > severity
bool isEnabled(T flag) const
const Variable * getVariableFromVarId(nonneg int varId) const
const std::vector< const Variable * > & variableList() const
std::vector< const Scope * > functionScopes
Fast access to function scopes.
The token list that the TokenList generates is a linked-list of this class.
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
const std::string & originalName() const
std::string stringify(const stringifyOptions &options) const
const std::string & strAt(int index) const
void function(const Function *f)
Associate this token with given function.
const ValueType * argumentType() const
const Token * tokAt(int index) const
Token * insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string ¯oNameStr=emptyString, bool prepend=false)
Insert new token after this token.
Token::Type tokType() const
void astOperand2(Token *tok)
void link(Token *linkToToken)
Create link to given token.
const Token * linkAt(int index) const
std::string strValue() const
This can be called only for tokens that are strings, else the assert() is called.
bool isStandardType() const
void variable(const Variable *v)
Associate this token with given variable.
const std::list< ValueFlow::Value > & values() const
const Token * nextArgument() const
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
void astParent(Token *tok)
bool isC() const
Is the code C.
const SymbolDatabase * getSymbolDatabase() const
bool isCPP() const
Is the code CPP.
std::vector< BaseInfo > derivedFrom
enum ValueType::Type type
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
std::string originalTypeName
original type name as written in the source code.
enum ValueType::Sign sign
Information about a member variable.
bool isEnumType() const
Determine whether it's an enumeration type.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
const Type * type() const
Get Type pointer of known type.
bool isGlobal() const
Is variable global.
const std::string & name() const
Get name string.
MathLib::bigint dimension(nonneg int index_) const
Get array dimension length.
bool isArray() const
Is variable an array.
const Token * typeStartToken() const
Get type start token.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isStatic() const
Is variable static.
Severity
enum class for severity.
@ portability
Portability warning.
@ error
Programming error.
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)