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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to