[clang] [C2y] Add documentation to conform to WG14 N3262; NFC (PR #98146)

John McCall via cfe-commits cfe-commits at lists.llvm.org
Wed Jul 10 11:51:55 PDT 2024


rjmccall wrote:

Oh, I completely spaced on this before, but of course there *are* constraints on `va_list` in the standard: `va_list`s are passed by value to functions like `vprintf`. That, of course, requires the value to be primitively copied.  If you call `vprintf(format, args)`, the standard says the value of `args` is indeterminate after the call.  It also specifically says that the `v*printf` functions do not call `va_end`.

As a result, the standard is clearly requiring that `va_list` be correctly "borrowed" when you pass it as an argument.  It doesn't directly say that any other forms of relocation are allowed, but I think it would be surprising if argument passing worked but builtin assignment / initialization didn't, and I'm willing to say that we would never implement such a thing in Clang.  `memcpy` is a separate question: you can imagine an ABI that requires these primitive copies to have special behavior, e.g. by storing the pointers with address-sensitive `__ptrauth` to resist data corruption.

The ownership of the value must be understood in C terms, not in terms of a C++-like object model.  A `va_list` value potentially has ownership of some resource that must be destroyed by `va_end`.  You don't have to destroy the "original" `va_list`, but you do have to destroy some primitive copy of it.  Whether changes to a `va_list` made by `va_arg` are observed in primitive copies is indeterminate.  `va_copy` produces an independent `va_list` that does not observe subsequent changes to the original `va_list` value(s) and must be separately destroyed.

How precisely we want to document this is an interesting question, but I do think it has to be more subtle than "primitive copies are UB", because we clearly can't make `vprintf` invalid.

https://github.com/llvm/llvm-project/pull/98146


More information about the cfe-commits mailing list