Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions lib/checkio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <cctype>
#include <cstdlib>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <set>
Expand Down Expand Up @@ -794,6 +795,20 @@ void CheckIOImpl::checkWrongPrintfScanfArguments()
}
}

// Convert the digits of a format string width or parameter position.
// A value that does not fit in an int is clamped to INT_MAX so a huge
// width or position is still reported instead of aborting the check.
static int formatStringNumber(const std::string& digits)
{
MathLib::bigint value = 0;
for (const char c : digits) {
value = value * 10 + (c - '0');
if (value > std::numeric_limits<int>::max())
return std::numeric_limits<int>::max();
}
return static_cast<int>(value);
}

void CheckIOImpl::checkFormatString(const Token * const tok,
const Token * const formatStringTok,
const Token * argListTok,
Expand Down Expand Up @@ -853,8 +868,10 @@ void CheckIOImpl::checkFormatString(const Token * const tok,
} else if (std::isdigit(*i)) {
width += *i;
} else if (*i == '$') {
parameterPosition = strToInt<int>(width);
hasParameterPosition = true;
if (!width.empty()) {
parameterPosition = formatStringNumber(width);
hasParameterPosition = true;
}
width.clear();
}
++i;
Expand Down Expand Up @@ -906,7 +923,7 @@ void CheckIOImpl::checkFormatString(const Token * const tok,
specifier += (*i == 's' || bracketBeg == formatString.end()) ? std::string{ 's' } : std::string{ bracketBeg, i + 1 };
if (argInfo.variableInfo && argInfo.isKnownType() && argInfo.variableInfo->isArray() && (argInfo.variableInfo->dimensions().size() == 1) && argInfo.variableInfo->dimensions()[0].known) {
if (!width.empty()) {
const int numWidth = strToInt<int>(width);
const int numWidth = formatStringNumber(width);
if (numWidth != (argInfo.variableInfo->dimension(0) - 1))
invalidScanfFormatWidthError(tok, numFormat, numWidth, argInfo.variableInfo, specifier);
}
Expand All @@ -929,7 +946,7 @@ void CheckIOImpl::checkFormatString(const Token * const tok,
case 'c':
if (argInfo.variableInfo && argInfo.isKnownType() && argInfo.variableInfo->isArray() && (argInfo.variableInfo->dimensions().size() == 1) && argInfo.variableInfo->dimensions()[0].known) {
if (!width.empty()) {
const int numWidth = strToInt<int>(width);
const int numWidth = formatStringNumber(width);
if (numWidth > argInfo.variableInfo->dimension(0))
invalidScanfFormatWidthError(tok, numFormat, numWidth, argInfo.variableInfo, std::string(1, *i));
}
Expand Down
16 changes: 16 additions & 0 deletions test/testio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,14 @@ class TestIO : public TestFixture {
" scanf (\"%70s\",str);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4:3]: (error) Width 70 given in format string (no. 1) is larger than destination buffer 'str[8]', use %7s to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str());

// width that does not fit in an int
check("void f()\n"
"{\n"
" char str [8];\n"
" scanf (\"%99999999999s\",str);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4:3]: (error) Width 2147483647 given in format string (no. 1) is larger than destination buffer 'str[8]', use %7s to prevent overflowing it. [invalidScanfFormatWidth]\n", errout_str());
}

void testScanf5() { // #10632
Expand Down Expand Up @@ -4274,6 +4282,14 @@ class TestIO : public TestFixture {
"[test.cpp:5:3]: (warning) scanf: referencing parameter 2 while 1 arguments given [wrongPrintfScanfParameterPositionError]\n"
"[test.cpp:6:3]: (warning) printf: parameter positions start at 1, not 0 [wrongPrintfScanfParameterPositionError]\n"
"", errout_str());

// parameter position without digits, with a leading zero or too large for an int
check("void foo() {\n"
" printf(\"%$d\", 1);\n"
" printf(\"%01$d\", 1);\n"
" printf(\"%99999999999$d\", 1);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4:3]: (warning) printf: referencing parameter 2147483647 while 1 arguments given [wrongPrintfScanfParameterPositionError]\n", errout_str());
}


Expand Down
Loading