-
Notifications
You must be signed in to change notification settings - Fork 13k
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
null fn check incorrect on release builds #40913
Comments
Here is a simplified testcase: https://play.rust-lang.org/?gist=2438d07552b441017c9a870e347edef2 This code should print "Ok!" and does on debug builds, and stable release builds, but not on nightly release builds. type ReadFn = extern fn(*mut u8, usize) -> isize;
#[repr(C)]
#[derive(Clone)]
pub struct mp4parse_io {
pub read: ReadFn,
}
unsafe extern fn mp4parse_new(io: *const mp4parse_io) -> *mut mp4parse_io {
if ((*io).read as *mut std::os::raw::c_void).is_null() {
return std::ptr::null_mut();
}
let parser = Box::new( (*io).clone() );
Box::into_raw(parser)
}
fn boom() {
let parser = unsafe {
let io = mp4parse_io {
read: std::mem::transmute::<*const (), ReadFn>(std::ptr::null()),
};
mp4parse_new(&io)
};
assert!(parser.is_null());
}
fn main() {
println!("Testing null read callback... ");
boom();
println!("Ok!");
} Note: I'm willing to believe the code is bad, but I don't understand how, so looking for guidance either way. :) |
Tagging and nominating. |
I did a bit more experimentation. The function call between creating the struct and the null check is important. The |
That transmute seems like UB, no? Anyways, nightly produces this for the null check: %4 = load i64 (i8*, i64)*, i64 (i8*, i64)** %3, !dbg !275, !nonnull !49
%5 = bitcast i64 (i8*, i64)* %4 to i8*, !dbg !275
%6 = call zeroext i1 @"_ZN4core3ptr31_$LT$impl$u20$$BP$mut$u20$T$GT$7is_null17hdd9ae6e9ddd6f4bcE"(i8* %5), !dbg !275 ...and Beta this: %4 = load i64 (i8*, i64)*, i64 (i8*, i64)** %3, !dbg !254
%5 = bitcast i64 (i8*, i64)* %4 to i8*, !dbg !254
%6 = call zeroext i1 @"_ZN4core3ptr31_$LT$impl$u20$$BP$mut$u20$T$GT$7is_null17hdd9ae6e9ddd6f4bcE"(i8* %5), !dbg !254 So it's pretty clear what's happening :) |
The transmute is to represent receiving a null function pointer over FFI from C, just to make the testcase easier to run. |
@rillian function pointers are not allowed to be If you want to represent nullable function pointers, use |
Winapi consistently uses Rust function pointers are like Rust references, they can never be null. There is also no raw pointer equivalent of a Rust function pointer, so |
This addresses https://bugzilla.mozilla.org/show_bug.cgi?id=1351497, which was filed as a rustc bug in rust-lang/rust#40913, but revealed to be undefined behaviour that happened to work with earlier compiler versions. As the comment removed in this patch describes, the only reason this code existed was to work around a limitation of rusty-cheddar.
This addresses https://bugzilla.mozilla.org/show_bug.cgi?id=1351497, which was filed as a rustc bug in rust-lang/rust#40913, but revealed to be undefined behaviour that happened to work with earlier compiler versions. As the comment removed in this patch describes, the only reason this code existed was to work around a limitation of rusty-cheddar.
I marked function pointer loads as However, null function pointers are UB since, well, forever (see |
Thanks @arielb1. Do you think it would be reasonable to revert the That's three opinions for this being a new optimization, instead of a regression, but the null ptr optimization of In our code the function pointer isn't nullable semantically. It's an error for it to be invalid, which is what the unit test was verifying. Since the struct is filled out by unsafe C code, the value in the struct can certainly be null, but I like being able to verify that once at initialization time instead of checking at every callsite. If the compiler is going to assume function pointers are nonnull even in unsafe code, then I would need two different structs to express that, one with an |
Because |
@rillian If the C library is filling in the struct then you must use Also, if returning a non-null function pointer is part of the contract of the C library, then it would make more sense to verify that in the test suite for the C library, rather than on the rust side, which avoids the problem you are having. Unsafe doesn't mean that all of the constraints, like the aliasing rules are allowed to be broken - anything guaranteed to the compiler in safe rust is also guaranteed in unsafe rust. Unsafe rust just means that the compiler will allow you to do things which it can't prove don't invalidate those constraints. Actually invalidating them would still be UB. |
(nominating for lang team discussion, mostly to check whether lang team is satisfied with status quo of null fn ptr's being undefined behavior.) |
Thanks pnkfelix. |
If we made null function pointers legal then |
(to be clear, my inclination is to leave null fn ptr's as undefined behavior... i just wanted to make sure the lang team was aware of the matter.) |
This addresses https://bugzilla.mozilla.org/show_bug.cgi?id=1351497, which was filed as a rustc bug in rust-lang/rust#40913, but revealed to be undefined behaviour that happened to work with earlier compiler versions. As the comment removed in this patch describes, the only reason this code existed was to work around a limitation of rusty-cheddar.
Can we close this? |
@arielb1 the Lang team only addresses nominates issues every other week, so we will look at it in a week (However it might suffice if I just got the members to weigh in outside of the weekly mtg format ) |
(removing T-compiler flag since this is currently sitting in T-lang queue alone.) |
consensus of lang team is that we are not going to change the behavior here. So decision is that this is at most documentation issue, not a bug in the compiler/language. |
Awesome. Thanks for taking a look at the issue. We've migrated our code to |
Testing Firefox against rustc 1.17.0-nightly (ccce2c6 2017-03-27) I have a unit test failure where it looks like a nullptr check on a function pointer in a struct passed over FFI doesn't work correctly. The failing test is supposed to check for a null callback function pointer and return null in that case. Instead it returns an allocated context object.
One can verify with
./mach gtest rust.MP4MetadataEmpty
withac_add_options --enable-optimize
in mozconfig.See also https://bugzilla.mozilla.org/show_bug.cgi?id=1351497
The text was updated successfully, but these errors were encountered: