Heater wrote: ↑Mon Sep 25, 2023 4:08 pm
But what about all those magic coercions that C does? If I feed a 32 bit int into where a 64 bit int is asked for can it not be silently promoted. Like passing an int to a function that wants long int.
Why not for printf as well?
Because printf has no function prototype, it is variadic.
https://en.cppreference.com/w/c/variadic
Neither the compiler nor printf know what all the "actual" arguments will be.
Printf parses the format string and then expects to find something on the stack that exactly matches each specifier.
The compiler parses the format string to validate it for security and check the actual arguments match.
A common source of problems for beginners, and even worse for scanf.
But the compiler now does pretty good static analysis, here are all the possible warnings:
Code: Select all
-Wformat
-Wformat=n
Check calls to "printf" and "scanf", etc., to make sure that the arguments supplied
have types appropriate to the format string specified, and that the conversions
specified in the format string make sense. This includes standard functions, and
others specified by format attributes, in the "printf", "scanf", "strftime" and
"strfmon" (an X/Open extension, not in the C standard) families (or other target-
specific families). Which functions are checked without format attributes having been
specified depends on the standard version selected, and such checks of functions
without the attribute specified are disabled by -ffreestanding or -fno-builtin.
The formats are checked against the format features supported by GNU libc version 2.2.
These include all ISO C90 and C99 features, as well as features from the Single Unix
Specification and some BSD and GNU extensions. Other library implementations may not
support all these features; GCC does not support warning about features that go beyond
a particular library's limitations. However, if -Wpedantic is used with -Wformat,
warnings are given about format features not in the selected standard version (but not
for "strfmon" formats, since those are not in any version of the C standard).
-Wformat=1
-Wformat
Option -Wformat is equivalent to -Wformat=1, and -Wno-format is equivalent to
-Wformat=0. Since -Wformat also checks for null format arguments for several
functions, -Wformat also implies -Wnonnull. Some aspects of this level of format
checking can be disabled by the options: -Wno-format-contains-nul,
-Wno-format-extra-args, and -Wno-format-zero-length. -Wformat is enabled by
-Wall.
-Wformat=2
Enable -Wformat plus additional format checks. Currently equivalent to -Wformat
-Wformat-nonliteral -Wformat-security -Wformat-y2k.
-Wno-format-contains-nul
If -Wformat is specified, do not warn about format strings that contain NUL bytes.
-Wno-format-extra-args
If -Wformat is specified, do not warn about excess arguments to a "printf" or "scanf"
format function. The C standard specifies that such arguments are ignored.
Where the unused arguments lie between used arguments that are specified with $
operand number specifications, normally warnings are still given, since the
implementation could not know what type to pass to "va_arg" to skip the unused
arguments. However, in the case of "scanf" formats, this option suppresses the
warning if the unused arguments are all pointers, since the Single Unix Specification
says that such unused arguments are allowed.
-Wformat-overflow
-Wformat-overflow=level
Warn about calls to formatted input/output functions such as "sprintf" and "vsprintf"
that might overflow the destination buffer. When the exact number of bytes written by
a format directive cannot be determined at compile-time it is estimated based on
heuristics that depend on the level argument and on optimization. While enabling
optimization will in most cases improve the accuracy of the warning, it may also
result in false positives.
-Wformat-overflow
-Wformat-overflow=1
Level 1 of -Wformat-overflow enabled by -Wformat employs a conservative approach
that warns only about calls that most likely overflow the buffer. At this level,
numeric arguments to format directives with unknown values are assumed to have the
value of one, and strings of unknown length to be empty. Numeric arguments that
are known to be bounded to a subrange of their type, or string arguments whose
output is bounded either by their directive's precision or by a finite set of
string literals, are assumed to take on the value within the range that results in
the most bytes on output. For example, the call to "sprintf" below is diagnosed
because even with both a and b equal to zero, the terminating NUL character ('\0')
appended by the function to the destination buffer will be written past its end.
Increasing the size of the buffer by a single byte is sufficient to avoid the
warning, though it may not be sufficient to avoid the overflow.
void f (int a, int b)
{
char buf [13];
sprintf (buf, "a = %i, b = %i\n", a, b);
}
-Wformat-overflow=2
Level 2 warns also about calls that might overflow the destination buffer given an
argument of sufficient length or magnitude. At level 2, unknown numeric arguments
are assumed to have the minimum representable value for signed types with a
precision greater than 1, and the maximum representable value otherwise. Unknown
string arguments whose length cannot be assumed to be bounded either by the
directive's precision, or by a finite set of string literals they may evaluate to,
or the character array they may point to, are assumed to be 1 character long.
At level 2, the call in the example above is again diagnosed, but this time
because with a equal to a 32-bit "INT_MIN" the first %i directive will write some
of its digits beyond the end of the destination buffer. To make the call safe
regardless of the values of the two variables, the size of the destination buffer
must be increased to at least 34 bytes. GCC includes the minimum size of the
buffer in an informational note following the warning.
An alternative to increasing the size of the destination buffer is to constrain
the range of formatted values. The maximum length of string arguments can be
bounded by specifying the precision in the format directive. When numeric
arguments of format directives can be assumed to be bounded by less than the
precision of their type, choosing an appropriate length modifier to the format
specifier will reduce the required buffer size. For example, if a and b in the
example above can be assumed to be within the precision of the "short int" type
then using either the %hi format directive or casting the argument to "short"
reduces the maximum required size of the buffer to 24 bytes.
void f (int a, int b)
{
char buf [23];
sprintf (buf, "a = %hi, b = %i\n", a, (short)b);
}
-Wno-format-zero-length
If -Wformat is specified, do not warn about zero-length formats. The C standard
specifies that zero-length formats are allowed.
-Wformat-nonliteral
If -Wformat is specified, also warn if the format string is not a string literal and
so cannot be checked, unless the format function takes its format arguments as a
"va_list".
-Wformat-security
If -Wformat is specified, also warn about uses of format functions that represent
possible security problems. At present, this warns about calls to "printf" and
"scanf" functions where the format string is not a string literal and there are no
format arguments, as in "printf (foo);". This may be a security hole if the format
string came from untrusted input and contains %n. (This is currently a subset of what
-Wformat-nonliteral warns about, but in future warnings may be added to
-Wformat-security that are not included in -Wformat-nonliteral.)
-Wformat-signedness
If -Wformat is specified, also warn if the format string requires an unsigned argument
and the argument is signed and vice versa.
-Wformat-truncation
-Wformat-truncation=level
Warn about calls to formatted input/output functions such as "snprintf" and
"vsnprintf" that might result in output truncation. When the exact number of bytes
written by a format directive cannot be determined at compile-time it is estimated
based on heuristics that depend on the level argument and on optimization. While
enabling optimization will in most cases improve the accuracy of the warning, it may
also result in false positives. Except as noted otherwise, the option uses the same
logic -Wformat-overflow.
-Wformat-truncation
-Wformat-truncation=1
Level 1 of -Wformat-truncation enabled by -Wformat employs a conservative approach
that warns only about calls to bounded functions whose return value is unused and
that will most likely result in output truncation.
-Wformat-truncation=2
Level 2 warns also about calls to bounded functions whose return value is used and
that might result in truncation given an argument of sufficient length or
magnitude.
-Wformat-y2k
If -Wformat is specified, also warn about "strftime" formats that may yield only a
two-digit year.