-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Varargs are completely unchecked if passed as generics #61275
Comments
|
From the C Standard.
And indeed if you were to attempt to use
It would be trivial to automatically promote |
Triage: Would be great if someone could produce a minimized reproducer of this problem. Right now the .zip contains almost 600 lines of Rust code. |
I see the problem. When the type is an instantiated one, we do check to see if it is "C-variadic safe", and demand people correctly pass the argument, casting if necessary. The problem is that when the type is still generic, we can't check that until it is monomorphized. |
This code should not compile: //@ compile-flags: --edition 2021
use core::ffi;
extern "C" {
fn printf(ptr: *const ffi::c_char, ...) -> ffi::c_int;
}
fn generic_printf<T>(c: &ffi::CStr, arg: T) {
unsafe { printf(c.as_ptr(), arg) };
}
fn main() {
generic_printf(c"%d", 2u8);
generic_printf(c"%f", 3.333_f32);
generic_printf(c"%s", vec![6, 2, 8, 3, 1, 8, 5, 3, 0]);
} |
@apiraino This is a compiler bug. |
This is a miscompilation. |
There is no actual stdlib API involved, and there's barely anything for T-lang to decide aside from possibly some details on how we mitigate the fallout. This is T-compiler's to fix. |
What C does
What rustc doesn't do
My opinionThese programs seem to have no specified behavior in Rust. Rust does not promote the arguments via default argument promotions because there is no such notion in the language5. This is not part of the ABI spec, in my opinion, but a detail of C source semantics. This, however, violates the C Standard's intent and implementation, which are the only meaningful spec we have for C's varargs. These calls thus seem to be UB, but within AfterwordInterestingly, we do not lint on this program that passes repr(Rust) types to C varargs6: use std::ffi::{c_char, c_int};
extern "C" {
fn printf(c: *const c_char, ...) -> c_int;
}
fn main() {
let allocated_cstring = c", but it is still UB\n".to_owned();
unsafe { printf(c"this kinda makes sense%s".as_ptr(), allocated_cstring) };
let allocated_repr_rust = vec!["lol what"];
unsafe { printf(c"but this doesn't: %s".as_ptr(), allocated_repr_rust) };
} Footnotes
|
I've figured out enough to know about what needs to be implemented to at least close the miscompilation part soon, it's now just a matter of finding the right place to slot in the necessary operations before the call. |
I am trying to call the function DftiSetValue from the Intel Math Library. The function has the layout MKL_LONG DftiSetValue(DFTI_DESCRIPTOR_HANDLE, enum DFTI_CONFIG_PARAM, ...), the first is an 8 byte pointer (windows 64 bit), the second is an enum which is 4 bytes long, and the last parameter is a floating point number.
I can call this function from c++ just fine as a float or double, but cannot call this from rust without making it a double. This is with the enum being treated as 32 bit int, and I get an error if I try to call it with a u4 from the ux package. According to the documentation this function should be a float because I am using floating point fft precision.
I have attached some code that shows the fft being called with some sample values and you can see that one time it is called and returns all zeros which is incorrect and the second time it is called it comes back correctly with non-zero values.
Example.zip
The text was updated successfully, but these errors were encountered: