Skip to content

Commit dff042a

Browse files
committed
fix scanf regex and add unit test for it
1 parent 6b29143 commit dff042a

2 files changed

Lines changed: 83 additions & 4 deletions

File tree

cli/cppcheckexecutor.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,11 @@ namespace {
144144
// Invalid scanf argument type patterns
145145
if (ruleId == "invalidScanfArgType_int" || ruleId.find("invalidScanfArgType") == 0)
146146
{
147-
// Replace "%format in format string (no. N) requires 'type *' but the argument type is 'type *'."
148-
// with "Format specifier in format string requires different argument type."
149-
std::regex scanfPattern(R"(%\w+ in format string \(no\. \d+\) requires '[^']*' but the argument type is '[^']*'\.)");
150-
result = std::regex_replace(result, scanfPattern, "Format specifier in format string requires different argument type.");
147+
// Replace "%format in format string (no. N) requires 'type *' but the argument type is type."
148+
// with "Format specifier requires different argument type than provided."
149+
// The template format is like: "%d in format string (no. 1) requires 'int *' but the argument type is Unknown."
150+
std::regex scanfPattern(R"(%\w+ in format string \(no\. \d+\) requires '[^']*' but the argument type is [^.]*\.)");
151+
result = std::regex_replace(result, scanfPattern, "Format specifier requires different argument type than provided.");
151152
}
152153

153154
// Variable name patterns - replace specific variable names with generic terms

test/testsarif.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ int main() {
249249
TEST_CASE(sarifRuleCoverage);
250250
TEST_CASE(sarifSeverityLevels);
251251
TEST_CASE(sarifNonSecurityRules);
252+
TEST_CASE(sarifInvalidScanfArgTypeGeneric);
252253
}
253254

254255
// Helper to run cppcheck and capture SARIF output
@@ -856,6 +857,83 @@ int main() {
856857

857858
ASSERT_EQUALS(true, foundNonSecurityRule);
858859
}
860+
861+
void sarifInvalidScanfArgTypeGeneric()
862+
{
863+
// Create a test specifically for invalidScanfArgType_int rule
864+
const std::string scanfTestCode = R"(
865+
#include <cstdio>
866+
867+
int main() {
868+
char str1, str2, str3, str4, str5, str6;
869+
870+
// This should trigger invalidScanfArgType_int errors
871+
// %hhx expects unsigned char* but gets char*
872+
sscanf("12 34 56 78 9A BC", "%hhx %hhx %hhx %hhx %hhx %hhx",
873+
&str1, &str2, &str3, &str4, &str5, &str6);
874+
875+
return 0;
876+
}
877+
)";
878+
879+
const std::string sarif = runCppcheckSarif(scanfTestCode);
880+
881+
std::string errorMsg;
882+
ASSERT_EQUALS(true, validateSarifJson(sarif, errorMsg));
883+
884+
// Parse and check for invalidScanfArgType_int rule
885+
picojson::value json;
886+
picojson::parse(json, sarif);
887+
const picojson::object& root = json.get<picojson::object>();
888+
const picojson::array& runs = root.at("runs").get<picojson::array>();
889+
const picojson::object& run = runs[0].get<picojson::object>();
890+
const picojson::object& tool = run.at("tool").get<picojson::object>();
891+
const picojson::object& driver = tool.at("driver").get<picojson::object>();
892+
const picojson::array& rules = driver.at("rules").get<picojson::array>();
893+
894+
// Find and verify the invalidScanfArgType_int rule has a genericized description
895+
bool foundRule = false;
896+
897+
for (const auto& rule : rules)
898+
{
899+
const picojson::object& r = rule.get<picojson::object>();
900+
const std::string ruleId = r.at("id").get<std::string>();
901+
902+
if (ruleId == "invalidScanfArgType_int")
903+
{
904+
foundRule = true;
905+
906+
const std::string name = r.at("name").get<std::string>();
907+
908+
// Verify that the rule description is properly genericized
909+
// Should be "Format specifier requires different argument type than provided."
910+
// not "%d in format string (no. 1) requires 'int *' but the argument type is Unknown."
911+
ASSERT_EQUALS("Format specifier requires different argument type than provided.", name);
912+
913+
break;
914+
}
915+
}
916+
917+
ASSERT_EQUALS(true, foundRule);
918+
919+
// Verify that results contain the invalidScanfArgType_int rule
920+
const picojson::array& results = run.at("results").get<picojson::array>();
921+
bool foundResult = false;
922+
923+
for (const auto& result : results)
924+
{
925+
const picojson::object& res = result.get<picojson::object>();
926+
const std::string ruleId = res.at("ruleId").get<std::string>();
927+
928+
if (ruleId == "invalidScanfArgType_int")
929+
{
930+
foundResult = true;
931+
break;
932+
}
933+
}
934+
935+
ASSERT_EQUALS(true, foundResult);
936+
}
859937
};
860938

861939
REGISTER_TEST(TestSarif)

0 commit comments

Comments
 (0)