Skip to content

Commit 6a29b12

Browse files
authored
Fix #14899: FP invalidPrintfArgType_float with _sprintf_s_l() (#8729)
1 parent 8276218 commit 6a29b12

2 files changed

Lines changed: 38 additions & 10 deletions

File tree

lib/checkio.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,20 @@ void CheckIOImpl::wrongfeofUsage(const Token * tok)
666666
// printf("", 1); // Too much arguments
667667
//---------------------------------------------------------------------------
668668

669-
static bool findFormat(nonneg int arg, const Token *firstArg,
669+
static bool findFormat(nonneg int arg, nonneg int argc, const Token *firstArg,
670670
const Token *&formatStringTok, const Token *&formatArgTok)
671671
{
672+
formatArgTok = firstArg;
673+
674+
for (int i = 0; i < argc && formatArgTok; ++i)
675+
formatArgTok = formatArgTok->nextArgument();
676+
672677
const Token* argTok = firstArg;
673678

674679
for (int i = 0; i < arg && argTok; ++i)
675680
argTok = argTok->nextArgument();
676681

677682
if (Token::Match(argTok, "%str% [,)]")) {
678-
formatArgTok = argTok->nextArgument();
679683
formatStringTok = argTok;
680684
return true;
681685
}
@@ -686,7 +690,6 @@ static bool findFormat(nonneg int arg, const Token *firstArg,
686690
(argTok->variable()->dimensions().size() == 1 &&
687691
argTok->variable()->dimensionKnown(0) &&
688692
argTok->variable()->dimension(0) != 0))) {
689-
formatArgTok = argTok->nextArgument();
690693
if (!argTok->values().empty()) {
691694
const auto value = std::find_if(
692695
argTok->values().cbegin(), argTok->values().cend(), std::mem_fn(&ValueFlow::Value::isTokValue));
@@ -706,6 +709,17 @@ static inline bool typesMatch(const std::string& iToTest, const std::string& iTy
706709
return (iToTest == iTypename) || (iToTest == iOptionalPrefix + iTypename);
707710
}
708711

712+
static int getMaxArgNo(const Library::Function *func)
713+
{
714+
const auto &checks = func->argumentChecks;
715+
return std::max_element(checks.cbegin(), checks.cend(),
716+
[](const std::pair<int, Library::ArgumentChecks> &lhs,
717+
const std::pair<int, Library::ArgumentChecks> &rhs) {
718+
return lhs.first < rhs.first;
719+
}
720+
)->first;
721+
}
722+
709723
void CheckIOImpl::checkWrongPrintfScanfArguments()
710724
{
711725
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
@@ -723,46 +737,48 @@ void CheckIOImpl::checkWrongPrintfScanfArguments()
723737
bool scan = false;
724738
bool scanf_s = false;
725739
int formatStringArgNo = -1;
740+
int argc = -1;
726741

727742
if (tok->strAt(1) == "(" && mSettings.library.formatstr_function(tok)) {
743+
argc = getMaxArgNo(mSettings.library.getFunction(tok));
728744
formatStringArgNo = mSettings.library.formatstr_argno(tok);
729745
scan = mSettings.library.formatstr_scan(tok);
730746
scanf_s = mSettings.library.formatstr_secure(tok);
731747
}
732748

733749
if (formatStringArgNo >= 0) {
734750
// formatstring found in library. Find format string and first argument belonging to format string.
735-
if (!findFormat(formatStringArgNo, tok->tokAt(2), formatStringTok, argListTok))
751+
if (!findFormat(formatStringArgNo, argc, tok->tokAt(2), formatStringTok, argListTok))
736752
continue;
737753
} else if (Token::simpleMatch(tok, "swprintf (")) {
738754
if (Token::Match(tok->tokAt(2)->nextArgument(), "%str%")) {
739755
// Find third parameter and format string
740-
if (!findFormat(1, tok->tokAt(2), formatStringTok, argListTok))
756+
if (!findFormat(1, 2, tok->tokAt(2), formatStringTok, argListTok))
741757
continue;
742758
} else {
743759
// Find fourth parameter and format string
744-
if (!findFormat(2, tok->tokAt(2), formatStringTok, argListTok))
760+
if (!findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok))
745761
continue;
746762
}
747763
} else if (isWindows && Token::Match(tok, "sprintf_s|swprintf_s (")) {
748764
// template <size_t size> int sprintf_s(char (&buffer)[size], const char *format, ...);
749-
if (findFormat(1, tok->tokAt(2), formatStringTok, argListTok)) {
765+
if (findFormat(1, 2, tok->tokAt(2), formatStringTok, argListTok)) {
750766
if (!formatStringTok)
751767
continue;
752768
}
753769
// int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format, ...);
754-
else if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
770+
else if (findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok)) {
755771
if (!formatStringTok)
756772
continue;
757773
}
758774
} else if (isWindows && Token::Match(tok, "_snprintf_s|_snwprintf_s (")) {
759775
// template <size_t size> int _snprintf_s(char (&buffer)[size], size_t count, const char *format, ...);
760-
if (findFormat(2, tok->tokAt(2), formatStringTok, argListTok)) {
776+
if (findFormat(2, 3, tok->tokAt(2), formatStringTok, argListTok)) {
761777
if (!formatStringTok)
762778
continue;
763779
}
764780
// int _snprintf_s(char *buffer, size_t sizeOfBuffer, size_t count, const char *format, ...);
765-
else if (findFormat(3, tok->tokAt(2), formatStringTok, argListTok)) {
781+
else if (findFormat(3, 4, tok->tokAt(2), formatStringTok, argListTok)) {
766782
if (!formatStringTok)
767783
continue;
768784
}

test/testio.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4791,6 +4791,18 @@ class TestIO : public TestFixture {
47914791
"[test.cpp:17:5]: (warning) %s in format string (no. 5) requires 'char *' but the argument type is 'signed int'. [invalidPrintfArgType_s]\n"
47924792
"[test.cpp:17:5]: (warning) sprintf_s format string requires 5 parameters but 6 are given. [wrongPrintfScanfArgNum]\n", errout_str());
47934793

4794+
check("int main()\n"
4795+
"{\n"
4796+
" double value = 3.14;\n"
4797+
" const size_t buffer_size = 64;\n"
4798+
" char buffer[buffer_size];\n"
4799+
" int precision = 2;\n"
4800+
" _locale_t locale = _create_locale(LC_ALL, \"C\");\n"
4801+
" _sprintf_s_l(buffer, buffer_size, \"%.*f\", locale, precision, value);\n"
4802+
" _free_locale(locale);\n"
4803+
" return 0;\n"
4804+
"}\n");
4805+
ASSERT_EQUALS("", errout_str());
47944806
}
47954807

47964808
void testMicrosoftSecureScanfArgument() {

0 commit comments

Comments
 (0)