Qt-Generic-FormatSpecifier¶
Validates the use of format specifiers
Required inputs: IR
printf/scanf family of functions.
Due to these functions using C varargs, compilers cannot check that the
parameter types expected by the function. In cases where the format
argument to these function is a string literal, this rule will verify that the
remaining arguments are compatible with those expected by the format string.
This rule also checks for invalid combination of flags/modifiers and conversion
specifiers.
Bad code:
#include <stdio.h>
void f() {
const char *str = "Hello, World!";
int num = 42;
int count;
char buf1[10];
char *buf2;
// printf
printf("%s: %d\n", str); // ERROR: format '%d' expects a matching 'signed int' argument
printf("%s: %d\n", str, num, num); // ERROR: Too many arguments for format.
printf("%ld\n", num); // ERROR: format '%ld' expects argument of type 'signed long', but argument 1 has type 'signed int'
printf("%Ld\n", num); // ERROR: %d does not support the 'L' length modifier
printf("%0\n", num); // ERROR: Invalid or non-standard conversion specification '%0'
printf("%.*p\n", num, str); // ERROR: Precision must not be used with %p conversion specifier
printf("%#s\n", str); // ERROR: %s does not support the '#' flag
printf("%0s\n", str); // ERROR: %s does not support the '0' flag
printf("%1%"); // ERROR: Cannot use any flags or modifiers with '%%'
printf("%s%+n", str, &count); // ERROR: %n does not support flags
printf("%s%1n", str, &count); // ERROR: %n does not support field width
// printf GNU extensions:
printf("%'s\n", str); // ERROR: %s does not support the "'" flag
printf("%Is\n", str); // ERROR: %s does not support the 'I' flag
// scanf
scanf("%s", buf1); // ERROR: Potential buffer overflow: format '%s' has no limit on amount of characters read.
scanf("%10s", buf1); // ERROR: format '%s' may write up to 11 characters to buffer of size 10.
scanf("%9s", buf2); // ERROR: Potential buffer overflow: format '%s' used with buffer of unknown size.
scanf("%d%*n", &num, &count); // ERROR: %n does not support assignment suppression
}
Good code:
#include <stdio.h>
void f() {
const char *str = "Hello, World!";
int num = 42;
double pi = 3.14159;
int count;
char buf1[10];
// printf
printf("%s: %d\n", str, num); // OK: format and argument count match
printf("%d\n", num); // OK: format '%d' matches 'signed int' argument
printf("%5d\n", num); // OK: field width of 5
printf("%05d\n", num); // OK: zero-padded to width 5
printf("%-5d\n", num); // OK: left-aligned to width 5
printf("%+d\n", num); // OK: show sign
printf("%.2f\n", pi); // OK: precision of 2 decimal places
printf("%8.2f\n", pi); // OK: width 8, precision 2
printf("%p\n", (void*)str); // OK: no precision with %p
printf("%%\n"); // OK: no flags with '%%'
printf("%s%n\n", str, &count); // OK: %n without flags
// printf GNU extensions:
printf("%'d\n", num); // OK: thousand separator
printf("%Id\n", num); // OK: locale specific digits
// scanf
scanf("%9s", buf1); // OK: limited to 9 characters for 10-byte buffer
scanf("%d%n", &num, &count); // OK: %n without assignment suppression
}
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
arg_type_mismatch |
{} expects argument of type ‘{}’, but argument {} has type ‘{}’ |
None |
False |
buffer_too_small |
{} may write up to {} characters to buffer of size {}. |
None |
False |
invalid_conversion |
Invalid or non-standard conversion specification |
None |
False |
matching_arg_expected |
{} expects a matching ‘{}’ argument |
None |
False |
precision_for_conversion |
Precision must not be used with %{} conversion specifier |
None |
False |
too_many_args |
Too many arguments for format. |
None |
False |
unlimited_read |
Potential buffer overflow: {} has no limit on amount of characters read. |
None |
False |
unsupported_assignment_suppression |
%n does not support assignment suppression |
None |
False |
unsupported_field_width |
%n does not support field width |
None |
False |
unsupported_flags |
%n does not support flags |
None |
False |
unsupported_flags_modifiers |
Cannot use any flags or modifiers with ‘%%’ |
None |
False |
unsupported_hash |
%{} does not support the ‘#’ flag |
None |
False |
unsupported_i_flag |
%{} does not support the ‘I’ flag |
None |
False |
unsupported_length_modifier |
%{} does not support the ‘{}’ length modifier |
None |
False |
unsupported_tick |
%{} does not support the “’” flag |
None |
False |
unsupported_zero |
%{} does not support the ‘0’ flag |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
allow_extra_args¶
allow_extra_args : bool = False
allow_gnu_extensions¶
allow_gnu_extensions : bool = True
allow_unknown_specs¶
allow_unknown_specs : bool = False
functions¶
functions
A dictionary mapping the names of the functions to check, to a tripleType: dict[bauhaus.analysis.config.QualifiedName, typing.Tuple[str, int, typing.Optional[int]]]
Default:
{ '_printf_l': ('printf', 1, 3), 'fprintf': ('printf', 1, 2), 'fscanf': ('scanf', 1, 2), 'printf': ('printf', 0, 1), 'scanf': ('scanf', 0, 1), 'snprintf': ('printf', 2, 3), 'sprintf': ('printf', 1, 2), 'sscanf': ('scanf', 1, 2), 'vfprintf': ('printf', 1, None), 'vfscanf': ('scanf', 1, None), 'vprintf': ('printf', 0, None), 'vscanf': ('scanf', 0, None), 'vsnprintf': ('printf', 2, None), 'vsprintf': ('printf', 1, None), 'vsscanf': ('scanf', 1, None) }
(function_kind, fmt_param_index, arg_start_index) where
function_kind is either printf or scanf,
fmt_param_index is the index of the format-string parameter, and
arg_start_index is the index of the first variadic argument.
use_static_semantic_analysis¶
use_static_semantic_analysis : bool = True
StaticSemanticAnalysis
to be enabled, but will produce less accurate results if it is not.