Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it legal to empty-initialize `va_list` with `{}` in C23 before calling `va_start()`?

TL;DR: is C23's universal initialization type var = {}; safe for all types, including standard opaque ones, such as va_list?


I have code that uses variable arguments. An older version of a static analyzer Coverity has started to report a dubious warning about uninitialized variable when processing code compiled with GCC15 that chooses C23 standard by default.

That compiler internally uses a new builtin __builtin_c23_va_start() to implement va_start() (instead of older __builtin_va_start()). Apparently, Coverity does not yet understand that this builtin is meant to initialize the passed variable.

E.g. in the following function:

#include <stdarg.h>
#include <stdio.h>

void warning(const char *file, unsigned line, const char *fmt, ...) {
        va_list va;
        va_start(va, fmt);
        fprintf(stderr, "warning %s:%u: ", file, line);
        vfprintf(stderr, fmt, va);
        va_end(va);
        fprintf(stderr, "\n");
}

The analyzer reports: Using uninitialized value "va" when calling "__builtin_c23_va_start". on the second line of warning().

Possible approaches to suppress such false positives are: 1) update Coverity to a newer version (currently in progress), 2) suppress individual warning sites by annotations in comments (does the thing but makes code messier).

I am considering a third alternative: use empty initalization at the same line where the va is defined. That is, to have code like this:

va_list va = {};
va_start(va, fmt);

Adding = {} makes Coverity stop complaining. But I am not sure if this is allowed for objects of opaque standard types such as va_list. va will be initialized by va_start() on the next line, so it should be OK to use it afterwards. But isn't it undefined behavior already at that point?

like image 836
Grigory Rechistov Avatar asked Nov 01 '25 13:11

Grigory Rechistov


1 Answers

If it is truly opaque - an incomplete struct not visible to whoever includes the header - then you wouldn't be able to declare an object of it in the first place. So it can't be. Furthermore, C actually guarantees that it is not an opaque type:

C23 7.16.1

va_list
which is a complete object type suitable for holding information needed by the macros...

(There's also a non-normative note saying that passing around pointers to a va_list object is fine.)

Meaning it is either an object defined in some internals of a header or it is a macro/typedef hiding a pointer. In either case you can initialize it to zero. va_list va={0}; is valid C for all types (no matter if aggregate/union/scalar etc).

In case of "scalars", for example int x = {0};, this is fine, the braces are optional (C23 6.7.11). In case of pointers the zero becomes a null pointer constant. And so on.

As for {} in C23 it is just "syntactic sugar" for {0}, as per the rules of default initialization (C23 6.7.11).

like image 188
Lundin Avatar answered Nov 03 '25 04:11

Lundin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!