[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