Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upnull fn check incorrect on release builds #40913
Comments
This comment has been minimized.
This comment has been minimized.
|
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. :) |
This comment has been minimized.
This comment has been minimized.
|
Tagging and nominating. |
This comment has been minimized.
This comment has been minimized.
|
I did a bit more experimentation. The function call between creating the struct and the null check is important. The |
This comment has been minimized.
This comment has been minimized.
|
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 !254So it's pretty clear what's happening :) |
This comment has been minimized.
This comment has been minimized.
|
The transmute is to represent receiving a null function pointer over FFI from C, just to make the testcase easier to run. |
This comment has been minimized.
This comment has been minimized.
|
@rillian function pointers are not allowed to be If you want to represent nullable function pointers, use |
This comment has been minimized.
This comment has been minimized.
|
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 |
kinetiknz
added a commit
to kinetiknz/mp4parse-rust
that referenced
this issue
Mar 30, 2017
kinetiknz
added a commit
to kinetiknz/mp4parse-rust
that referenced
this issue
Mar 30, 2017
kinetiknz
referenced this issue
Mar 30, 2017
Merged
Fix UB caused by casting a Rust fn ptr to a *c_void (BMO bug #1351497) #81
This comment has been minimized.
This comment has been minimized.
|
I marked function pointer loads as However, null function pointers are UB since, well, forever (see |
This comment has been minimized.
This comment has been minimized.
|
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 |
This comment has been minimized.
This comment has been minimized.
|
Because |
This comment has been minimized.
This comment has been minimized.
|
@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. |
pnkfelix
added
the
T-lang
label
Mar 30, 2017
This comment has been minimized.
This comment has been minimized.
|
(nominating for lang team discussion, mostly to check whether lang team is satisfied with status quo of null fn ptr's being undefined behavior.) |
This comment has been minimized.
This comment has been minimized.
|
Thanks pnkfelix. |
This comment has been minimized.
This comment has been minimized.
|
If we made null function pointers legal then |
This comment has been minimized.
This comment has been minimized.
|
(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.) |
kinetiknz
added a commit
to kinetiknz/mp4parse-rust
that referenced
this issue
Mar 31, 2017
This comment has been minimized.
This comment has been minimized.
|
Can we close this? |
This comment has been minimized.
This comment has been minimized.
|
@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 ) |
This comment has been minimized.
This comment has been minimized.
|
(removing T-compiler flag since this is currently sitting in T-lang queue alone.) |
pnkfelix
removed
the
T-compiler
label
Apr 6, 2017
This comment has been minimized.
This comment has been minimized.
|
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. |
This comment has been minimized.
This comment has been minimized.
|
Awesome. Thanks for taking a look at the issue. We've migrated our code to |
rillian commentedMar 29, 2017
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.MP4MetadataEmptywithac_add_options --enable-optimizein mozconfig.See also https://bugzilla.mozilla.org/show_bug.cgi?id=1351497