Skip to content

Variadic functions don't allow "system" on non-x86 Windows #110505

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
kennykerr opened this issue Apr 18, 2023 · 8 comments · Fixed by #119587
Closed

Variadic functions don't allow "system" on non-x86 Windows #110505

kennykerr opened this issue Apr 18, 2023 · 8 comments · Fixed by #119587
Labels
A-ABI Area: Concerning the application binary interface (ABI) C-bug Category: This is a bug. O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@kennykerr
Copy link
Contributor

kennykerr commented Apr 18, 2023

While testing variadic function support with raw-dylib I discovered that Rust requires such functions to use either "C" or "cdecl" ABIs but raw-dylib requires the "system" ABI on non-x86 Windows.

My undertstanding from discussing with @dpaoliello is that this is not an issue with raw-dylib itself but with Rust's insistence that such functions aren't allowed to use the "system" ABI. It's just that raw-dylib is very strict about calling convention so that's where the issue surfaced.

#[link(name = "library", modifiers = "+verbatim")]
extern "system" {
    pub fn DbgPrint(format: *const u8, ...) -> u32;
}

On x64 I should be able to compile this but Rust says no:

error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
 --> src\lib.rs:3:5
  |
3 |     pub fn DbgPrint(format: *const u8, ...) -> u32;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention

This example works if I change the ABI to "cdecl" but that's not meant to be a valid ABI on x64 and so when I try to compile this with raw-dylib it fails:

#[link(name = "library", kind = "raw-dylib", modifiers = "+verbatim")]
extern "cdecl" {
    pub fn DbgPrint(format: *const u8, ...) -> u32;
}
error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
 --> src\lib.rs:3:5
  |
3 |     pub fn DbgPrint(format: *const u8, ...) -> u32;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The practical result is that it is impossible to link this function with raw-dylib on non-x86.

@compiler-errors
Copy link
Member

cc #97971 which originally added variadics support to some other calling conventions (though not extern "system" it seems) behind the feature gate #![feature(extended_varargs_abi_support)].

@kennykerr
Copy link
Contributor Author

A workaround is to use "C" on non-x86 as I implemented here: microsoft/windows-rs#2458

@dpaoliello
Copy link
Contributor

@wesleywiser @nagisa Thoughts on permitting variadic parameters with the system calling convention for non-x86 Windows? If #87678 gets merged then we'll be pushing folks to use system so that they get the correct calling convention for Windows APIs on all architectures, but that breaks compatibility with variadic parameters.

@jyn514 jyn514 added O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. A-ABI Area: Concerning the application binary interface (ABI) labels Apr 20, 2023
@RalfJung
Copy link
Member

RalfJung commented Jan 4, 2024

A workaround is to use "C" on non-x86 as I implemented here: microsoft/windows-rs#2458

This work-around is causing pain. Would be great if there was a way that it could be avoided. :)

@RalfJung
Copy link
Member

RalfJung commented Jan 4, 2024

Thoughts on permitting variadic parameters with the system calling convention for non-x86 Windows?

There's a comment saying this can't work:

// * C and Cdecl obviously support varargs.
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
// * EfiApi is based on Win64 or C, so it also supports it.
//
// * Stdcall does not, because it would be impossible for the callee to clean
// up the arguments. (callee doesn't know how many arguments are there)
// * Same for Fastcall, Vectorcall and Thiscall.
// * System can become Stdcall, so is also a no-no.
// * Other calling conventions are related to hardware or the compiler itself.

        // * Stdcall does not, because it would be impossible for the callee to clean
        //   up the arguments. (callee doesn't know how many arguments are there)
        // * System can become Stdcall, so is also a no-no.

I don't understand anything about these ABIs so I can't say how accurate this is.

Also I see nothing here special-casing x86, so why does the issue specifically mention non-x86?

@kennykerr
Copy link
Contributor Author

Would be great if there was a way that it could be avoided.

Happy to update windows-rs as soon as there's a way to avoid it. 😊

@beepster4096
Copy link
Contributor

Can we make system equal to cdecl when applied to a variadic function? It's supposed to be whatever ABI is correct for the system api and cdecl is the correct ABI for a variadic win32 function. According to the docs __stdcall acts as __cdecl when applied to a variadic function.

@beepster4096
Copy link
Contributor

Went ahead and opened #119587 for this.

@bors bors closed this as completed in 7b507db Jan 13, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Jan 13, 2024
Rollup merge of rust-lang#119587 - beepster4096:system_varargs, r=petrochenkov

Varargs support for system ABI

This PR allows functions with the `system` ABI to be variadic (under the `extended_varargs_abi_support` feature tracked in rust-lang#100189). On x86 windows, the `system` ABI is equivalent to `C` for variadic functions. On other platforms, `system` is already equivalent to `C`.

Fixes rust-lang#110505
jhpratt added a commit to jhpratt/rust that referenced this issue Jun 14, 2025
…workingjubilee

variadic functions: remove list of supported ABIs from error

I think this list is problematic for multiple reasons:
- It is bound to go out-of-date as it is in a very different place from where we actually define which functions support varagrs (`fn supports_varargs`).
- Many of the ABIs we list only work on some targets; it makes no sense to mention "aapcs" as a possible ABI when building for x86_64. (This led to a lot of confusion in rust-lang#110505 where the author thought they should use "cdecl" and then were promptly told that "cdecl" is not a legal ABI on their target.)
- Typically, when the programmer wrote `extern "foobar"`, it is because they need the "foobar" ABI. It is of little use to tell them that there are other ABIs with which varargs would work.

Cc `@workingjubilee`
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Jun 14, 2025
…workingjubilee

variadic functions: remove list of supported ABIs from error

I think this list is problematic for multiple reasons:
- It is bound to go out-of-date as it is in a very different place from where we actually define which functions support varagrs (`fn supports_varargs`).
- Many of the ABIs we list only work on some targets; it makes no sense to mention "aapcs" as a possible ABI when building for x86_64. (This led to a lot of confusion in rust-lang#110505 where the author thought they should use "cdecl" and then were promptly told that "cdecl" is not a legal ABI on their target.)
- Typically, when the programmer wrote `extern "foobar"`, it is because they need the "foobar" ABI. It is of little use to tell them that there are other ABIs with which varargs would work.

Cc ``@workingjubilee``
rust-timer added a commit that referenced this issue Jun 14, 2025
Rollup merge of #142464 - RalfJung:variadic-fn-abi-error, r=workingjubilee

variadic functions: remove list of supported ABIs from error

I think this list is problematic for multiple reasons:
- It is bound to go out-of-date as it is in a very different place from where we actually define which functions support varagrs (`fn supports_varargs`).
- Many of the ABIs we list only work on some targets; it makes no sense to mention "aapcs" as a possible ABI when building for x86_64. (This led to a lot of confusion in #110505 where the author thought they should use "cdecl" and then were promptly told that "cdecl" is not a legal ABI on their target.)
- Typically, when the programmer wrote `extern "foobar"`, it is because they need the "foobar" ABI. It is of little use to tell them that there are other ABIs with which varargs would work.

Cc ``@workingjubilee``
RalfJung pushed a commit to RalfJung/miri that referenced this issue Jun 15, 2025
…bilee

variadic functions: remove list of supported ABIs from error

I think this list is problematic for multiple reasons:
- It is bound to go out-of-date as it is in a very different place from where we actually define which functions support varagrs (`fn supports_varargs`).
- Many of the ABIs we list only work on some targets; it makes no sense to mention "aapcs" as a possible ABI when building for x86_64. (This led to a lot of confusion in rust-lang/rust#110505 where the author thought they should use "cdecl" and then were promptly told that "cdecl" is not a legal ABI on their target.)
- Typically, when the programmer wrote `extern "foobar"`, it is because they need the "foobar" ABI. It is of little use to tell them that there are other ABIs with which varargs would work.

Cc ``@workingjubilee``
github-actions bot pushed a commit to rust-lang/rustc-dev-guide that referenced this issue Jun 16, 2025
…bilee

variadic functions: remove list of supported ABIs from error

I think this list is problematic for multiple reasons:
- It is bound to go out-of-date as it is in a very different place from where we actually define which functions support varagrs (`fn supports_varargs`).
- Many of the ABIs we list only work on some targets; it makes no sense to mention "aapcs" as a possible ABI when building for x86_64. (This led to a lot of confusion in rust-lang/rust#110505 where the author thought they should use "cdecl" and then were promptly told that "cdecl" is not a legal ABI on their target.)
- Typically, when the programmer wrote `extern "foobar"`, it is because they need the "foobar" ABI. It is of little use to tell them that there are other ABIs with which varargs would work.

Cc ``@workingjubilee``
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ABI Area: Concerning the application binary interface (ABI) C-bug Category: This is a bug. O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants