On 5/27/25 15:42, Markus Armbruster wrote:
Paolo Bonzini <pbonz...@redhat.com> writes:
Rust makes the current file available as a statically-allocated string,
but without a NUL terminator. Allow this by storing an optional maximum
length in the Error.
Note that for portability I am not relying on fprintf's precision
specifier not accessing memory beyond what will be printed.
Can you elaborate on the portability problem? I figure ...
{
if (errp == &error_abort) {
+ const char *src = err->src;
+ if (err->src_len >= 0) {
+ /* No need to free it, the program will abort very soon... */
+ src = g_strndup(err->src, err->src_len);
+ }
fprintf(stderr, "Unexpected error in %s() at %s:%d:\n",
- err->func, err->src, err->line);
+ err->func, src, err->line);
... you're avoiding the simpler
fprintf(stderr, "Unexpected error in %s() at %.*s:%d:\n",
err->func, err->src_len, err->src, err->line);
because of it.
I couldn't find anything that says %s is allowed to not be
NUL-terminated if a precision is given. That is, whether something like
this:
char foo[] = {'H', 'e', 'l', 'l', 'o'};
printf("%.5s\n", foo);
is guaranteed to work.
This is opposed to:
1) strnlen
(https://pubs.opengroup.org/onlinepubs/9699919799/functions/strnlen.html),
which is guaranteed to examine no more than the number of bytes given by
the second character;
2) strndup, for which I found at least a clarification at
https://www.austingroupbugs.net/view.php?id=1397.
3) g_strndup, which guarantees that the allocated block is of length n+1
and padded with NULs (though in the case above there will be just one
NUL anyway)
And also, for strndup/g_strndup it would be quite asinine to implement
it using some kind of min(strlen(s), n) but for printf the complexity is
greater so you never know. I erred on the side of caution because
avoiding an allocation before an abort() isn't particularly interesting.
Paolo