diff --git a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql index 1deb9493ca35..1dd1668a8805 100644 --- a/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql +++ b/cpp/ql/src/Likely Bugs/Format/WrongNumberOfFormatArguments.ql @@ -16,6 +16,20 @@ import cpp +class SyntaxError extends CompilerError { + SyntaxError() { this.getTag().matches("exp_%") } + + predicate affects(Element e) { + exists(Location l1, Location l2 | + l1 = this.getLocation() and + l2 = e.getLocation() + | + l1.getFile() = l2.getFile() and + l1.getStartLine() = l2.getStartLine() + ) + } +} + from FormatLiteral fl, FormattingFunctionCall ffc, int expected, int given, string ffcName where ffc = fl.getUse() and @@ -27,7 +41,10 @@ where if ffc.isInMacroExpansion() then ffcName = ffc.getTarget().getName() + " (in a macro expansion)" else ffcName = ffc.getTarget().getName() - ) + ) and + // A typical problem is that string literals are concatenated, but if one of the string + // literals is an undefined macro, then this just leads to a syntax error. + not exists(SyntaxError e | e.affects(fl)) select ffc, "Format for " + ffcName + " expects " + expected.toString() + " arguments but given " + given.toString() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/syntax_errors.c b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/syntax_errors.c new file mode 100644 index 000000000000..8dfa8b9418c8 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongNumberOfFormatArguments/syntax_errors.c @@ -0,0 +1,7 @@ +// semmle-extractor-options: --expect_errors + +extern int printf(const char *fmt, ...); + +void test_syntax_error() { + printf("Error code %d: " FMT_MSG, 0, ""); +}