Because printf
format strings are interpreted at runtime rather than validated by the compiler, they can contain errors that lead to
unexpected behavior or runtime errors. This rule statically validates the good behavior of printf
formats.
The related rule S3457 is about errors that produce an unexpected string, while this rule is about errors that will create undefined
behavior.
Starting with C++23, std::print
should be preferred: its arguments are validated at compile-time, making it more secure.
Noncompliant code example
printf("%d", 1.2); // Noncompliant, an "int" is expected rather than a "double"
printf("%d %d", 1); // Noncompliant, the second argument is missing
printf("%0$d ", 1); // Noncompliant, arguments are numbered starting from 1
printf("%1$d %d", 1, 2); // Noncompliant, positional and non-positional arguments can not be mixed
printf("%*d", 1.1, 2); // Noncompliant, field width should be an integer
printf("ab\0cd"); // Noncompliant, format string contains null char
int x;
printf("%+p", (void*)&x); // Noncompliant, flag "+" has undefined behavior with conversion specifier "p"
printf("%vd", x); //Noncompliant, conversion specifier "v" is not valid
Compliant solution
printf("%f", 1.2); // Compliant, format is consistent with the corresponding argument
printf("%d", 1); // Compliant, number of specifiers is consistent with number of arguments
printf("%1$d ", 1); // Compliant, number of positional argument is consistent
Exceptions
This rule will only work if the format string is provided as a string literal.