-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
FFI calls may create out-of-bounds loads #29988
Comments
Isn't this subject to alignment by LLVM? |
@cybergeek94 what do you mean? The alloca is only 12 bytes large. That's also the amount of bytes we write in the |
@cybergeek94 here's a demo: https://gist.github.com/dotdash/2da61d4d24fa79e0a9bb Build without optimizations on x86_64 Linux, and you should be able to observe |
Reading past the end of an alloca has well-defined behavior in LLVM IR. I guess we might end up with false positives if we ever support msan. |
@eefriedman are you implying that the generated IR is fine? If so, what is the defined behaviour / where can I read up on that? http://llvm.org/docs/LangRef.html#pointeraliasing reads as if it is undefined. Without optimizations, this gives random output: fn foo() -> (i64, i64) {
let x = (0i32, 0i32, 0i32);
let y = &x as *const _ as *const (i64, i64);
unsafe {
*y
}
}
fn main() {
println!("foo() = {:?}", foo());
} With optimizations, SROA ignores the out-of-bounds read and emits a warning in debug mode, which doesn't seem like it is well-defined behaviour to me either. |
Basically, if a pointer points to valid memory, and is sufficiently aligned, you can load bytes up to the alignment... LLVM itself does this at https://github.com/llvm-mirror/llvm/blob/ef4e0adfe75684bf9017c8a9c5309e77b8aa3b7b/lib/Analysis/MemoryDependenceAnalysis.cpp#L322 etc. That said, looking a bit more closely, the given testcase performs an "align 8" load from an "align 4" pointer, which is more problematic. |
Thanks! That looks like it just assumes that the load won't trap. Part of my concern here is that we might expose additional data this way, like observing The alignment problem is probably due to bad usage of |
This has been fixed, we now only load 12 bytes: #[repr(C)]
struct S {
f1: i32,
f2: i32,
f3: i32,
}
extern {
fn foo(s: S);
}
fn main() {
let s = S { f1: 1, f2: 2, f3: 3 };
unsafe {
foo(s);
}
} %_3 = alloca %S
%s = alloca %S
%0 = getelementptr inbounds %S, %S* %s, i32 0, i32 0
store i32 1, i32* %0
%1 = getelementptr inbounds %S, %S* %s, i32 0, i32 2
store i32 2, i32* %1
%2 = getelementptr inbounds %S, %S* %s, i32 0, i32 4
store i32 3, i32* %2
%3 = bitcast %S* %s to i8*
%4 = bitcast %S* %_3 to i8*
; Copy 12 bytes with alignment of 4
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %3, i64 12, i32 4, i1 false)
%5 = bitcast %S* %_3 to { i64, i32 }*
; Load 12 bytes -- this is now fine, not loading 16 bytes
%6 = load { i64, i32 }, { i64, i32 }* %5, align 4
call void @foo({ i64, i32 } %6)
br label %bb1 |
Add some regression tests Closes rust-lang#29988 Closes rust-lang#34979 Pick up two snippets that have been fixed from rust-lang#67945 (shouldn't be closed yet!)
Add some regression tests Closes rust-lang#29988 Closes rust-lang#34979 Pick up two snippets that have been fixed from rust-lang#67945 (shouldn't be closed yet!)
Given this Rust code:
A call to
foo()
generates IR like this on x86_64 Linux:So we have a 12 byte alloca from which we then read 16 bytes.
The text was updated successfully, but these errors were encountered: