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);
422 const Token *formatToken =
nullptr;
424 formatToken = tok->
tokAt(2);
425 else if (
Token::Match(tok,
"sscanf|vsscanf|fscanf|vfscanf (")) {
428 formatToken = nextArg;
437 const std::string &formatstr(formatToken->
str());
438 for (std::size_t i = 1; i < formatstr.length(); i++) {
439 if (formatstr[i] ==
'%')
445 else if (std::isdigit(formatstr[i]) || formatstr[i] ==
'*') {
449 else if (std::isalpha((
unsigned char)formatstr[i]) || formatstr[i] ==
'[') {
450 if (formatstr[i] ==
's' || formatstr[i] ==
'[' || formatstr[i] ==
'S' || (formatstr[i] ==
'l' && formatstr[i+1] ==
's'))
461 const std::string fname = (tok ? tok->
str() : std::string(
"scanf"));
463 "invalidscanf", fname +
"() without field width limits can crash with huge input data.\n" +
464 fname +
"() without field width limits can crash with huge input data. Add a field width "
465 "specifier to fix this problem.\n"
467 "Sample program that can crash:\n"
469 "#include <stdio.h>\n"
473 " scanf(\"%s\", c);\n"
477 "Typing in 5 or more characters may make the program crash. The correct usage "
478 "here is 'scanf(\"%4s\", c);', as the maximum field width does not include the "
479 "terminating null byte.\n"
480 "Source: http://linux.die.net/man/3/scanf\n"
481 "Source: http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/libkern/stdio/scanf.c",
492 const Token *&formatStringTok,
const Token *&formatArgTok)
494 const Token* argTok = firstArg;
496 for (
int i = 0; i < arg && argTok; ++i)
501 formatStringTok = argTok;
508 (argTok->
variable()->dimensions().size() == 1 &&
509 argTok->
variable()->dimensionKnown(0) &&
510 argTok->
variable()->dimension(0) != 0))) {
512 if (!argTok->
values().empty()) {
513 const std::list<ValueFlow::Value>::const_iterator value = std::find_if(
515 if (value != argTok->
values().cend() && value->isTokValue() && value->tokvalue &&
517 formatStringTok = value->tokvalue;
526 static inline bool typesMatch(
const std::string& iToTest,
const std::string& iTypename,
const std::string& iOptionalPrefix =
"std::")
528 return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename);
536 logChecker(
"CheckIO::checkWrongPrintfScanfArguments");
540 if (!tok->isName())
continue;
542 const Token* argListTok =
nullptr;
543 const Token* formatStringTok =
nullptr;
546 bool scanf_s =
false;
547 int formatStringArgNo = -1;
555 if (formatStringArgNo >= 0) {
557 if (!
findFormat(formatStringArgNo, tok->tokAt(2), formatStringTok, argListTok))
560 if (
Token::Match(tok->tokAt(2)->nextArgument(),
"%str%")) {
562 if (!
findFormat(1, tok->tokAt(2), formatStringTok, argListTok))
566 if (!
findFormat(2, tok->tokAt(2), formatStringTok, argListTok))
569 }
else if (isWindows &&
Token::Match(tok,
"sprintf_s|swprintf_s (")) {
571 if (
findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) {
572 if (!formatStringTok)
576 else if (
findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
577 if (!formatStringTok)
580 }
else if (isWindows &&
Token::Match(tok,
"_snprintf_s|_snwprintf_s (")) {
582 if (
findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
583 if (!formatStringTok)
587 else if (
findFormat(3, tok->tokAt(2), formatStringTok, argListTok)) {
588 if (!formatStringTok)
595 if (!formatStringTok)
604 const Token *
const formatStringTok,
605 const Token * argListTok,
611 const std::string &formatString = formatStringTok->
str();
616 bool percent =
false;
617 const Token* argListTok2 = argListTok;
618 std::set<int> parameterPositionsUsed;
619 for (std::string::const_iterator i = formatString.cbegin(); i != formatString.cend(); ++i) {
622 }
else if (percent && *i ==
'[') {
623 while (i != formatString.cend()) {
639 if (i == formatString.cend())
641 }
else if (percent) {
644 bool _continue =
false;
647 int parameterPosition = 0;
648 bool hasParameterPosition =
false;
649 while (i != formatString.cend() && *i !=
'[' && !std::isalpha((
unsigned char)*i)) {
659 }
else if (std::isdigit(*i)) {
661 }
else if (*i ==
'$') {
662 parameterPosition = strToInt<int>(width);
663 hasParameterPosition =
true;
668 auto bracketBeg = formatString.cend();
669 if (i != formatString.cend() && *i ==
'[') {
671 while (i != formatString.cend()) {
677 if (scanf_s && !skip) {
684 if (i == formatString.cend())
689 if (scan || *i !=
'm') {
693 if (hasParameterPosition) {
694 if (parameterPositionsUsed.find(parameterPosition) == parameterPositionsUsed.end())
695 parameterPositionsUsed.insert(parameterPosition);
705 std::string specifier;
711 specifier += (*i ==
's' || bracketBeg == formatString.end()) ? std::string{
's' } : std::string{ bracketBeg, i + 1 };
713 if (!width.empty()) {
714 const int numWidth = strToInt<int>(width);
736 if (!width.empty()) {
737 const int numWidth = strToInt<int>(width);
766 switch (specifier[0]) {
768 if (specifier[1] ==
'h') {
775 if (specifier[1] ==
'l') {
790 if (specifier.find(
"I64") != std::string::npos) {
793 }
else if (specifier.find(
"I32") != std::string::npos) {
846 switch (specifier[0]) {
848 if (specifier[1] ==
'h') {
855 if (specifier[1] ==
'l') {
868 if (specifier.find(
"I64") != std::string::npos) {
871 }
else if (specifier.find(
"I32") != std::string::npos) {
923 switch (specifier[0]) {
942 if ((i+1 != formatString.cend() && *(i+1) ==
'6' &&
943 i+2 != formatString.cend() && *(i+2) ==
'4') ||
944 (i+1 != formatString.cend() && *(i+1) ==
'3' &&
945 i+2 != formatString.cend() && *(i+2) ==
'2')) {
948 if ((i+1) != formatString.cend() && !isalpha(*(i+1))) {
956 if ((i+1) != formatString.cend() && !isalpha(*(i+1))) {
967 if (i+1 != formatString.cend() && *(i+1) == *i)
976 if ((i + 1) != formatString.end() && !isalpha(*(i+1))) {
989 }
else if (printWarning) {
990 std::string specifier;
993 if (i == formatString.end()) {
1027 switch (specifier[0]) {
1029 if (specifier[1] ==
'h') {
1036 if (specifier[1] ==
'l') {
1061 if (specifier.find(
"I64") != std::string::npos) {
1064 }
else if (specifier.find(
"I32") != std::string::npos) {
1100 switch (specifier[0]) {
1102 if (specifier[1] ==
'h') {
1109 if (specifier[1] ==
'l') {
1130 if (specifier.find(
"I64") != std::string::npos) {
1133 }
else if (specifier.find(
"I32") != std::string::npos) {
1175 switch (specifier[0]) {
1177 if (specifier[1] ==
'h') {
1184 if (specifier[1] ==
'l') {
1209 if (specifier.find(
"I64") != std::string::npos) {
1212 }
else if (specifier.find(
"I32") != std::string::npos) {
1265 if ((i + 1) != formatString.end() && *(i + 1) == *i) {
1266 if ((i + 2) != formatString.end() && !isalpha(*(i + 2))) {
1267 std::string modifier;
1269 modifier += *(i + 1);
1277 if ((i + 1) != formatString.end() && !isalpha(*(i + 1))) {
1278 std::string modifier;
1289 if ((*(i+1) ==
'3' && *(i+2) ==
'2') ||
1290 (*(i+1) ==
'6' && *(i+2) ==
'4')) {
1300 if ((i + 1) != formatString.end() && !isalpha(*(i+1))) {
1323 int numFunction = 0;
1324 while (argListTok2) {
1333 for (
const int i : parameterPositionsUsed) {
1334 if ((i == 0) || (i > numFormat))
1340 if ((numFormat + numSecure) != numFunction)
1356 const Token *top = arg;
1357 while (top->
str() ==
"(" && !top->
isCast())
1362 if (valuetype && valuetype->
type >= ValueType::Type::BOOL) {
1393 if (valuetype->
sign == ValueType::Sign::UNSIGNED)
1395 else if (valuetype->
sign == ValueType::Sign::SIGNED)
1400 for (
int p = 0; p < valuetype->
pointer; p++)
1416 (
Token::Match(arg,
"static_cast|reinterpret_cast|const_cast <") &&
1419 if (
Token::Match(arg,
"static_cast|reinterpret_cast|const_cast")) {
1425 if (arg->
str() ==
"&") {
1430 arg = arg->
tokAt(2);
1433 const Token *varTok =
nullptr;
1435 for (; tok1; tok1 = tok1->
next()) {
1436 if (tok1->
str() ==
"," || tok1->
str() ==
")") {
1440 const Function *
function = varTok->
link()->previous()->function();
1441 if (
function && function->retType && function->retType->isEnumType()) {
1442 if (function->retType->classScope->enumType)
1443 typeToken =
function->retType->classScope->enumType;
1449 }
else if (
function && function->retDef) {
1460 if (
function && function->retType && function->retType->isEnumType()) {
1461 if (function->retType->classScope->enumType)
1462 typeToken =
function->retType->classScope->enumType;
1468 }
else if (
function && function->retDef) {
1480 if (tok1->
str() ==
"(" || tok1->
str() ==
"{" || tok1->
str() ==
"[")
1481 tok1 = tok1->
link();
1482 else if (tok1->
link() && tok1->
str() ==
"<")
1483 tok1 = tok1->
link();
1489 if (tok1->
next()->
str() ==
"size") {
1505 }
else if (tok1->
next()->
str() ==
"empty") {
1507 }
else if (tok1->
next()->
str() ==
"c_str") {
1563 while (tempToken->next())
1564 tempToken->deleteNext();
1571 const std::set<std::string> stl_vector = {
"array",
"vector" };
1572 const std::set<std::string> stl_string = {
"string",
"u16string",
"u32string",
"wstring" };
1579 if (variableInfo->isStlType(stl_vector)) {
1580 typeToken = variableInfo->typeStartToken()->tokAt(4);
1584 if (variableInfo->isStlType(stl_string)) {
1585 tempToken =
new Token(variableInfo->typeStartToken());
1586 if (variableInfo->typeStartToken()->strAt(2) ==
"string")
1587 tempToken->str(
"char");
1589 tempToken->str(
"wchar_t");
1590 typeToken = tempToken;
1593 if (variableInfo->type() && !variableInfo->type()->derivedFrom.empty()) {
1594 const std::vector<Type::BaseInfo>& derivedFrom = variableInfo->type()->derivedFrom;
1596 const Token* nameTok = i.nameTok;
1598 typeToken = nameTok->
tokAt(4);
1603 tempToken =
new Token(variableInfo->typeStartToken());
1604 if (nameTok->
strAt(2) ==
"string")
1605 tempToken->str(
"char");
1607 tempToken->str(
"wchar_t");
1608 typeToken = tempToken;
1612 }
else if (variableInfo->type()) {
1613 const Scope * classScope = variableInfo->
type()->classScope;
1616 if (func.
name() ==
"operator[]") {
1630 "array",
"bitset",
"deque",
"forward_list",
1631 "hash_map",
"hash_multimap",
"hash_set",
1632 "list",
"map",
"multimap",
"multiset",
1633 "priority_queue",
"queue",
"set",
"stack",
1634 "unordered_map",
"unordered_multimap",
"unordered_multiset",
"unordered_set",
"vector"
1653 const Token* nameTok = baseInfo.nameTok;
1654 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 <")) {
1655 typeToken = nameTok->
tokAt(4);
1659 typeToken = nameTok;
1673 if (variableInfo && !_template)
1674 return variableInfo->isArrayOrPointer();
1676 const Token *tok = typeToken;
1679 return tok && tok->
strAt(1) ==
"*";
1684 if (variableInfo->type())
1687 const Token* varTypeTok = typeToken;
1688 if (varTypeTok->
str() ==
"std")
1689 varTypeTok = varTypeTok->
tokAt(2);
1691 return ((variableInfo->isStlStringType() || (varTypeTok->
strAt(1) ==
"<" && varTypeTok->
linkAt(1) && varTypeTok->
linkAt(1)->
strAt(1) !=
"::")) && !variableInfo->isArrayOrPointer());
1697 return (typeToken->isStandardType() || typeToken->next()->isStandardType() || isComplexType());
1699 return (typeToken->isStandardType() || functionInfo->retType ||
Token::Match(typeToken,
"std :: string|wstring"));
1701 return typeToken->isStandardType() ||
Token::Match(typeToken,
"std :: string|wstring");
1706 return typeToken && typeToken->isStandardType() && settings.
library.
podtype(typeToken->str());
1710 const std::string &functionName,
1718 std::ostringstream errmsg;
1719 errmsg << functionName
1720 <<
" format string requires "
1722 <<
" parameter" << (numFormat != 1 ?
"s" :
"") <<
" but "
1723 << (numFormat > numFunction ?
"only " :
"")
1725 << (numFunction != 1 ?
" are" :
" is")
1736 std::ostringstream errmsg;
1737 errmsg << functionName <<
": ";
1739 errmsg <<
"parameter positions start at 1, not 0";
1741 errmsg <<
"referencing parameter " << index <<
" while " << numFunction <<
" arguments given";
1751 std::ostringstream errmsg;
1752 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires a \'";
1753 if (specifier[0] ==
's')
1755 else if (specifier[0] ==
'S')
1756 errmsg <<
"wchar_t";
1757 errmsg <<
" *\' but the argument type is ";
1767 std::ostringstream errmsg;
1768 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1769 if (specifier[0] ==
'h') {
1770 if (specifier[1] ==
'h')
1771 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"char";
1773 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"short";
1774 }
else if (specifier[0] ==
'l') {
1775 if (specifier[1] ==
'l')
1776 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1778 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long";
1779 }
else if (specifier.find(
"I32") != std::string::npos) {
1780 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"__int32";
1781 }
else if (specifier.find(
"I64") != std::string::npos) {
1782 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"__int64";
1783 }
else if (specifier[0] ==
'I') {
1784 errmsg << (isUnsigned ?
"size_t" :
"ptrdiff_t");
1785 }
else if (specifier[0] ==
'j') {
1787 errmsg <<
"uintmax_t";
1789 errmsg <<
"intmax_t";
1790 }
else if (specifier[0] ==
'z') {
1791 if (specifier[1] ==
'd' || specifier[1] ==
'i')
1792 errmsg <<
"ssize_t";
1795 }
else if (specifier[0] ==
't') {
1796 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"ptrdiff_t";
1797 }
else if (specifier[0] ==
'L') {
1798 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1800 errmsg << (isUnsigned ?
"unsigned " :
"") <<
"int";
1802 errmsg <<
" *\' but the argument type is ";
1812 std::ostringstream errmsg;
1813 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1814 if (specifier[0] ==
'l' && specifier[1] !=
'l')
1816 else if (specifier[0] ==
'L')
1817 errmsg <<
"long double";
1820 errmsg <<
" *\' but the argument type is ";
1831 std::ostringstream errmsg;
1832 errmsg <<
"%s in format string (no. " << numFormat <<
") requires \'char *\' but the argument type is ";
1842 std::ostringstream errmsg;
1843 errmsg <<
"%n in format string (no. " << numFormat <<
") requires \'int *\' but the argument type is ";
1853 std::ostringstream errmsg;
1854 errmsg <<
"%p in format string (no. " << numFormat <<
") requires an address but the argument type is ";
1862 if (specifier[0] ==
'l') {
1863 if (specifier[1] ==
'l')
1864 os << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1866 os << (isUnsigned ?
"unsigned " :
"") <<
"long";
1867 }
else if (specifier[0] ==
'h') {
1868 if (specifier[1] ==
'h')
1869 os << (isUnsigned ?
"unsigned " :
"") <<
"char";
1871 os << (isUnsigned ?
"unsigned " :
"") <<
"short";
1872 }
else if (specifier.find(
"I32") != std::string::npos) {
1873 os << (isUnsigned ?
"unsigned " :
"") <<
"__int32";
1874 }
else if (specifier.find(
"I64") != std::string::npos) {
1875 os << (isUnsigned ?
"unsigned " :
"") <<
"__int64";
1876 }
else if (specifier[0] ==
'I') {
1877 os << (isUnsigned ?
"size_t" :
"ptrdiff_t");
1878 }
else if (specifier[0] ==
'j') {
1883 }
else if (specifier[0] ==
'z') {
1884 if (specifier[1] ==
'd' || specifier[1] ==
'i')
1888 }
else if (specifier[0] ==
't') {
1889 os << (isUnsigned ?
"unsigned " :
"") <<
"ptrdiff_t";
1890 }
else if (specifier[0] ==
'L') {
1891 os << (isUnsigned ?
"unsigned " :
"") <<
"long long";
1893 os << (isUnsigned ?
"unsigned " :
"") <<
"int";
1903 std::ostringstream errmsg;
1904 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires ";
1906 errmsg <<
" but the argument type is ";
1917 std::ostringstream errmsg;
1918 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires ";
1920 errmsg <<
" but the argument type is ";
1930 std::ostringstream errmsg;
1931 errmsg <<
"%" << specifier <<
" in format string (no. " << numFormat <<
") requires \'";
1932 if (specifier[0] ==
'L')
1934 errmsg <<
"double\' but the argument type is ";
1952 os <<
"const wchar_t *";
1954 os <<
"const char *";
1957 if (type->
strAt(-1) ==
"const")
1960 os << type->
str() <<
" ";
1961 type = type->
next();
1964 os << type->
str() <<
"::";
1965 type = type->
tokAt(2);
1967 os << type->
stringify(
false,
true,
false);
1984 os <<
" {aka " << type->
stringify(
false,
true,
false);
1999 std::ostringstream errmsg;
2000 errmsg <<
"'" << modifier <<
"' in format string (no. " << numFormat <<
") is a length modifier and cannot be used without a conversion specifier.";
2007 std::string varname;
2011 varname = var->
name();
2014 std::ostringstream errmsg;
2015 if (arrlen > width) {
2018 errmsg <<
"Width " << width <<
" given in format string (no. " << numFormat <<
") is smaller than destination buffer"
2019 <<
" '" << varname <<
"[" << arrlen <<
"]'.";
2022 errmsg <<
"Width " << width <<
" given in format string (no. " << numFormat <<
") is larger than destination buffer '"
2023 << 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...
bool isPremiumEnabled(const char id[]) const
Is checker id enabled by premiumArgs.
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)