-
Notifications
You must be signed in to change notification settings - Fork 13.4k
ABI code generates oversize loads when returning with a cast #45543
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Comments
This also happens when casting arguments - currently arguments can be "arbitrary" temporaries, so the return value fix won't work, but this still can't directly be used for the "end of page" segfaults: #![crate_type="rlib"]
#[repr(C)]
#[derive(Copy, Clone)]
pub struct U24(u8, u8, u8);
extern "C" {
fn bar(x: U24) -> U24;
}
pub extern "C" fn foo(x: U24) -> U24 {
unsafe { bar(x) }
} generates: ; ModuleID = 'cast2.cgu-0.rs'
source_filename = "cast2.cgu-0.rs"
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
%U24 = type { i8, [0 x i8], i8, [0 x i8], i8, [0 x i8] }
; cast2::foo
; Function Attrs: nounwind uwtable
define i32 @_ZN5cast23foo17h1f3d5ac3e0c9cc02E(i32) unnamed_addr #0 {
start:
%abi_cast1 = alloca i32
%_3 = alloca %U24
%x = alloca %U24
%_0 = alloca %U24
%abi_cast = alloca i32
%arg0 = alloca %U24
store i32 %0, i32* %abi_cast
%1 = bitcast %U24* %arg0 to i8*
%2 = bitcast i32* %abi_cast to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %1, i8* %2, i64 3, i32 1, i1 false)
%3 = bitcast %U24* %arg0 to i8*
%4 = bitcast %U24* %x to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %4, i8* %3, i64 3, i32 1, i1 false)
%5 = bitcast %U24* %x to i8*
%6 = bitcast %U24* %_3 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %6, i8* %5, i64 3, i32 1, i1 false)
%7 = bitcast %U24* %_3 to i32*
%8 = load i32, i32* %7, align 1 ; bad load #1
%9 = call i32 @bar(i32 %8)
store i32 %9, i32* %abi_cast1
%10 = bitcast %U24* %_0 to i8*
%11 = bitcast i32* %abi_cast1 to i8*
call void @llvm.memcpy.p0i8.p0i8.i64(i8* %10, i8* %11, i64 3, i32 1, i1 false)
br label %bb1
bb1: ; preds = %start
%12 = bitcast %U24* %_0 to i32*
%13 = load i32, i32* %12, align 1 ; bad load #2
ret i32 %13
}
; Function Attrs: argmemonly nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1
; Function Attrs: nounwind
declare i32 @bar(i32) unnamed_addr #2
attributes #0 = { nounwind uwtable "probe-stack"="__rust_probestack" }
attributes #1 = { argmemonly nounwind }
attributes #2 = { nounwind "probe-stack"="__rust_probestack" } |
The example above makes doing the alloca oversize less of a good idea - we eventually want to allow passing references to struct fields directly as function parameters, where we do not want to add a "guard byte". I think the "i24" case (which I think also includes 5/6/7-byte fields) should just be handled by doing an ugly memcpy. |
I remember fixing this, I don't understand how we're still having issues like these. |
We fixed this for stores, where the problems were obvious (stack corruption), to actually get a problem with a load is harder - you have to engage an LLVM optimization. |
triage: P-medium |
According to #29988 (comment) this was fixed once. |
Question: Do we feel this needs to stay P-high? This hasn't yet cropped up in the wild as far as I know, but it'd be good to get it done so that it never does. @dotdash, think you'll have time to investigate? |
I have a fix for x86_64 where the return type is just wrong (should be i24)
but there's a slightly more involved issue for (at least) sparc64, where a
24 bit struct is passed as i32 instead of i24, so the current bitcast for
the load of the return vakue just won't do.
I can probably finish that on the weekend. Or I can just submit the fix for
x86_64 first and add the rest later.
Am 18.01.2018 16:16 schrieb "Niko Matsakis" <notifications@github.com>:
… Question: Do we feel this needs to stay P-high? This hasn't yet cropped up
in the wild as far as I know, but it'd be good to get it done so that it
never does.
@dotdash <https://github.com/dotdash>, think you'll have time to
investigate?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#45543 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAOGMpAiKZqZjvT1M_OA5yvU8Fdi3WxHks5tL2BTgaJpZM4QG9B8>
.
|
The x86_64 SysV ABI should use exact sizes for small structs passed in registers, i.e. a struct that occupies 3 bytes should use an i24, instead of the i32 it currently uses. Refs rust-lang#45543
Fix oversized loads on x86_64 SysV FFI calls The x86_64 SysV ABI should use exact sizes for small structs passed in registers, i.e. a struct that occupies 3 bytes should use an i24, instead of the i32 it currently uses. Refs #45543
Fix oversized loads on x86_64 SysV FFI calls The x86_64 SysV ABI should use exact sizes for small structs passed in registers, i.e. a struct that occupies 3 bytes should use an i24, instead of the i32 it currently uses. Refs #45543
Triage: don't have a good way to test this out, since I don't really know anything about sparc64. |
Meta
STR
target is x86_64-unknown-linux-gnu
Expected Result
Code generated should not have UB
Actual Result
The generated no-opt LLVM IR is:
This loads 4 bytes of an alloca of size 3. I couldn't trivially turn this to an end-to-end mis-code-generation (this can't be used to load from anything but the return pointer, so you can't do the standard "load at end of page" trick), but I can't see how can oversize loads can be anything but UB.
cc @eddyb - I think one solution would be to pad the return pointer alloca to always have enough space for the cast, aka:
I think the problem load is the one in
rust/src/librustc_trans/mir/block.rs
Line 247 in e847f30
The text was updated successfully, but these errors were encountered: