-
Couldn't load subscription status.
- Fork 399
native-lib: support all types with Scalar layout #4628
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
Conversation
|
Could we detect if a pointer is a function pointer? If so, we can change its address (if non-null) to point to some preallocated single page of memory mapped R-X which raises a signal that the supervisor can intercept & print an error |
|
We can't just change the value when it is being passed to C -- the program could realize this with some ptr2int casts. (Also, for fields in structs/unions behind ptr indirections, determining their type becomes more of a heuristic.) However, we could adjust the logic that determines the addresses of function pointer allocations to begin with, to put them all onto some R-X page. Interesting idea. |
|
Since we need to convert values into their FFI repr, could we reject all those with function provenance and error? I guess a fully ptr2int converted function pointer would still get missed. |
|
Our conversion function isn't type-driven -- it just takes the raw bytes of the argument values and sends them over. We could scan that value and all memory reachable from it for function pointers, but currently we don't do such a recursive traversal so... not sure how I feel about that. If we can pull of the R-X page, that feels more slick (and it should reliably segfault even if we don't have the supervisor that can give a nice error). EDIT: Actually, we do have the |
|
Do we care about function pointers having different addresses? If not then we can do this even more simply, just have pub extern "C" fn one_pointee_to_rule_them_all() {
panic!("unsupported operation: native code tried to call a Rust function");
}where all function pointers take its address. |
|
yeah every function pointer needs to have a unique address for Miri itself to be able to handle them properly. |
|
Then we can have that function delcared somewhere, allocate as many R-X pages as needed, fill them with |
|
That still needs platform-specific code to generate the assembly. So we still need fallback code that creates an R-- page where just jumping there segfaults (which I assume can be done with mmap). Anyway turns out Oli's suggestion is trivial to implement since we already have the I assume that |
|
Fair, Oli's is probably the reasonable approach. We could do the other you suggested; there are "weird" architectures where |
|
Thank you for contributing to Miri! |
28708b7 to
0afc133
Compare
|
Okay let's do that. :D Interestingly, when I do actually call that function, the program just hangs. I think there's a segfault and then the supervisor is getting confused since the segfault is indeed in the address range it cares about... |
|
I assume this is the issue, that we're not checking that the segfault is cleared? // in handle_segfault
- let _ = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+ let stat = wait::waitid(wait::Id::Pid(pid), WAIT_FLAGS).map_err(|_| ExecEnd(None))?;
+ match stat {
+ wait::WaitStatus::Signaled(_, s, _) | wait::WaitStatus::Stopped(_, s) | wait::WaitStatus::PtraceEvent(_, s, _) => assert!(!matches!(s, signal::SIGSEGV), "Native code segfaulted in correctly allocated memory; this is probably a function call!"),
+ _ => (),
+ } |
|
That works well, thanks :) |
Fixes #4625
However, this also means we'll silently just pass function pointers to C and things will explode in horrendous ways if C then ends up calling such a function pointer. So I don't think we can land this as-is. I am not sure what else to do... we could have a flag for people to opt-in to this and promise the function pointers will never be called?