https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127416
Bug ID: 127416
Summary: Bogus -Wformat-truncation for bounded %.*s with an
offset into a constexpr array member
Product: gcc
Version: 17.0
URL: https://godbolt.org/z/YxnKK7Y4d
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: hr.jonas.hansen at gmail dot com
Target Milestone: ---
Compiling the snippet below with g++ 10 (and newer) with at least -O1 and -Wall
produce a false-positive -Wformat-truncation diagnostic when snprintf reads a
bounded portion of a non-NUL-terminated character array inside a constexpr
object.
#include <cstdio>
struct Buffer {
char data[3];
};
constexpr auto buffer = Buffer{{'a', 'b', 'c'}};
int main() {
char out[3];
return std::snprintf(out, sizeof out, "%.*s", 2, buffer.data + 1) != 2;
}
Actual result:
Compilation fails with:
error: ā%.*sā directive argument is not a nul-terminated string
[-Werror=format-truncation=]
Expected result:
Compilation succeeds without this warning. snprintf writes {'b', 'c', '\0'}
into out and returns 2.
The %.*s precision limits the source access to two characters. Exactly two
characters remain in the source array at buffer.data + 1, so no source NUL
terminator is required. The three-byte destination also accommodates the output
terminator.
Possible cause:
Debugging a larger reproducer suggests that constant_byte_string() /
fold_ctor_reference() reduces the array reference to a single-character
constant. Consequently, c_strlen() sees an incorrect available source length.
This is a preliminary diagnosis.