Do I need to call va_end manually in the end of my variadic function?

I implemented a variadic function exposed to foreign modules

pub unsafe extern "C" fn my_wprintf(format: *const u16, args: ...) {
    let ap = args.as_va_list();

    let mut length = 0;
    ap.with_copy(|ap| {
        length = _vsnwprintf(ptr::null_mut(), 0, format, ap);
    });
    if length == -1 || length == 0 {
        return;
    }

    let length = length as usize;

    let mut buf = Vec::<u16>::with_capacity(length);
    buf.set_len(length);

    if _vsnwprintf(buf.as_mut_ptr(), length, format, ap) > 0 {
        ...
    }
}

Do i need to call va_end in the end? Because I noticed that VaListImpl.Drop doesn't do that

#[unstable(
    feature = "c_variadic",
    reason = "the `c_variadic` feature has not been properly tested on \
              all supported platforms",
    issue = "44930"
)]
impl<'f> Drop for VaListImpl<'f> {
    fn drop(&mut self) {
        // FIXME: this should call `va_end`, but there's no clean way to
        // guarantee that `drop` always gets inlined into its caller,
        // so the `va_end` would get directly called from the same function as
        // the corresponding `va_copy`. `man va_end` states that C requires this,
        // and LLVM basically follows the C semantics, so we need to make sure
        // that `va_end` is always called from the same function as `va_copy`.
        // For more details, see https://github.com/rust-lang/rust/pull/59625
        // and https://llvm.org/docs/LangRef.html#llvm-va-end-intrinsic.
        //
        // This works for now, since `va_end` is a no-op on all current LLVM targets.
    }
}
1 Like

Clearly, the intention of this VaListImpl API is exactly to behave like an RAII guard so that the user doesn't have to manually perform the va_end cleanup. The burden of correctness is thus on the implementation of the library.

Technically, not calling va_end() before the function that called va_start() returns is undefined behavior. However, if the library guarantees, on each supported platform individually, that This Is Fine™, then you may be able to get away with it even in the presence of optimizations.

Likely, this is one of the problems that prevent such a simple API from being stabilized.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.