Skip to content

Rust's optimization broken some code since 1.80 #134958

Closed as not planned
Closed as not planned
@Norgerman

Description

@Norgerman

I tried this code:

use js_sys::Float32Array;
use wasm_bindgen::prelude::wasm_bindgen;

#[repr(C)]
#[derive(Debug, Copy, Clone, Default)]
#[wasm_bindgen]
pub struct Mat4 {
    a1: f32,
    a2: f32,
    a3: f32,
    a4: f32,
    b1: f32,
    b2: f32,
    b3: f32,
    b4: f32,
    c1: f32,
    c2: f32,
    c3: f32,
    c4: f32,
    d1: f32,
    d2: f32,
    d3: f32,
    d4: f32,
}

impl Mat4 {
    fn one() -> Self {
        Self {
            a1: 1.,
            b2: 1.,
            c3: 1.,
            d4: 1.,
            ..Default::default()
        }
    }
}

unsafe impl Zeroable for Mat4 {}
unsafe impl Pod for Mat4 {}

// returns Mat4::one when use release mode (with optimization), debug mode works fine.
pub fn from_js(value: &Float32Array) -> Mat4 {
    let mat = [Mat4::one()];
    unsafe {
        let ptr: *const f32 = &mat[0].a1;
        let dest = Float32Array::view(std::slice::from_raw_parts(ptr, 16));
        dest.set(&value, 0);
    }
    mat[0]
}

// returns current value.
pub fn from_js2(value: &Float32Array) -> Mat4 {
    let mat = Mat4::one();
    unsafe {
        let ptr: *const f32 = &mat.a1;
        let dest = Float32Array::view(std::slice::from_raw_parts(ptr, 16));
        dest.set(&value, 0);
    }
    mat
}

// is the actually broken code without simplify.
pub fn from_js3(value: &Float32Array) -> Mat4 {
    let mat = [Mat4::one()];
    unsafe {
        let dest = Float32Array::view(cast_slice(&mat));
        dest.set(&value, 0);
    }
    mat[0]
}

Current this bug can reproduce with wasm_bindgen & js_sys.

The code broken in release mode since 1.80(specially nightly-05-04).

In release mode from_js is different from from_js2.

  • from_js drop memcpy(in debug mode, will do the copy) just modify the output with Mat4::one
  • from_js2 mat with Mat4::one, and do memcpy to output.
  • in llvm-ir code from_js3 is alias of from_js

llvm-ir attached.

@_ZN9rust_wasm8from_js317h614dde9a38e9443bE = unnamed_addr alias void (ptr, ptr), ptr @_ZN9rust_wasm7from_js17h8e9edadfd73d2621E

; rust_wasm::from_js
; Function Attrs: uwtable
define void @_ZN9rust_wasm7from_js17h8e9edadfd73d2621E(ptr dead_on_unwind noalias nocapture noundef writable sret([64 x i8]) align 4 dereferenceable(64) %_0, ptr noalias noundef readonly align 4 dereferenceable(4) %value) unnamed_addr #5 personality ptr @__CxxFrameHandler3 {
start:
  %dest = alloca [4 x i8], align 4
  %mat = alloca [64 x i8], align 4
  call void @llvm.lifetime.start.p0(i64 64, ptr nonnull %mat)
  store float 1.000000e+00, ptr %_0, align 4
  %0 = getelementptr inbounds i8, ptr %_0, i64 4
  %1 = getelementptr inbounds i8, ptr %_0, i64 20
  tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %0, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %1, align 4
  %2 = getelementptr inbounds i8, ptr %_0, i64 24
  %3 = getelementptr inbounds i8, ptr %_0, i64 40
  tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %2, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %3, align 4
  %4 = getelementptr inbounds i8, ptr %_0, i64 44
  %5 = getelementptr inbounds i8, ptr %_0, i64 60
  tail call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %4, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %5, align 4
  call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(64) %mat, ptr noundef nonnull align 4 dereferenceable(64) %_0, i64 64, i1 false)
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %dest)
; call js_sys::Float32Array::view
  %6 = call noundef i32 @_ZN6js_sys12Float32Array4view17hc0104ce26e3ee0a4E(ptr noalias noundef nonnull readonly align 4 %mat, i64 noundef 16)
  store i32 %6, ptr %dest, align 4
; invoke js_sys::Float32Array::set
  invoke void @_ZN6js_sys12Float32Array3set17he863ee21f8d02321E(ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %dest, ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %value, i32 noundef 0)
          to label %bb2 unwind label %funclet_bb4

funclet_bb4:                                      ; preds = %start
  %cleanuppad = cleanuppad within none []
  %_2.i.i.i.i = icmp ugt i32 %6, 131
  br i1 %_2.i.i.i.i, label %bb1.i.i.i.i, label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit"

bb1.i.i.i.i:                                      ; preds = %funclet_bb4
; call wasm_bindgen::__wbindgen_object_drop_ref
  call void @_ZN12wasm_bindgen26__wbindgen_object_drop_ref17h7b23851dfe1382a1E(i32 noundef %6) #19 [ "funclet"(token %cleanuppad) ]
  br label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit"

"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit": ; preds = %funclet_bb4, %bb1.i.i.i.i
  cleanupret from %cleanuppad unwind to caller

bb2:                                              ; preds = %start
  %_2.i.i.i.i2 = icmp ugt i32 %6, 131
  br i1 %_2.i.i.i.i2, label %bb1.i.i.i.i3, label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4"

bb1.i.i.i.i3:                                     ; preds = %bb2
; call wasm_bindgen::__wbindgen_object_drop_ref
  call void @_ZN12wasm_bindgen26__wbindgen_object_drop_ref17h7b23851dfe1382a1E(i32 noundef %6) #19, !noalias !20
  br label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4"

"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4": ; preds = %bb2, %bb1.i.i.i.i3
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %dest)
  call void @llvm.lifetime.end.p0(i64 64, ptr nonnull %mat)
  ret void
}

; rust_wasm::from_js2
; Function Attrs: uwtable
define void @_ZN9rust_wasm8from_js217hcd7ecb72bc48b9a8E(ptr dead_on_unwind noalias nocapture noundef writable writeonly sret([64 x i8]) align 4 dereferenceable(64) %_0, ptr noalias noundef readonly align 4 dereferenceable(4) %value) unnamed_addr #5 personality ptr @__CxxFrameHandler3 {
start:
  %dest = alloca [4 x i8], align 4
  %mat = alloca [64 x i8], align 4
  call void @llvm.lifetime.start.p0(i64 64, ptr nonnull %mat)
  store float 1.000000e+00, ptr %mat, align 4
  %0 = getelementptr inbounds i8, ptr %mat, i64 4
  %1 = getelementptr inbounds i8, ptr %mat, i64 20
  call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %0, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %1, align 4
  %2 = getelementptr inbounds i8, ptr %mat, i64 24
  %3 = getelementptr inbounds i8, ptr %mat, i64 40
  call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %2, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %3, align 4
  %4 = getelementptr inbounds i8, ptr %mat, i64 44
  %5 = getelementptr inbounds i8, ptr %mat, i64 60
  call void @llvm.memset.p0.i64(ptr noundef nonnull align 4 dereferenceable(16) %4, i8 0, i64 16, i1 false)
  store float 1.000000e+00, ptr %5, align 4
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %dest)
; call js_sys::Float32Array::view
  %6 = call noundef i32 @_ZN6js_sys12Float32Array4view17hc0104ce26e3ee0a4E(ptr noalias noundef nonnull readonly align 4 %mat, i64 noundef 16)
  store i32 %6, ptr %dest, align 4
; invoke js_sys::Float32Array::set
  invoke void @_ZN6js_sys12Float32Array3set17he863ee21f8d02321E(ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %dest, ptr noalias noundef nonnull readonly align 4 dereferenceable(4) %value, i32 noundef 0)
          to label %bb2 unwind label %funclet_bb4

funclet_bb4:                                      ; preds = %start
  %cleanuppad = cleanuppad within none []
  %_2.i.i.i.i = icmp ugt i32 %6, 131
  br i1 %_2.i.i.i.i, label %bb1.i.i.i.i, label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit"

bb1.i.i.i.i:                                      ; preds = %funclet_bb4
; call wasm_bindgen::__wbindgen_object_drop_ref
  call void @_ZN12wasm_bindgen26__wbindgen_object_drop_ref17h7b23851dfe1382a1E(i32 noundef %6) #19 [ "funclet"(token %cleanuppad) ]
  br label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit"

"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit": ; preds = %funclet_bb4, %bb1.i.i.i.i
  cleanupret from %cleanuppad unwind to caller

bb2:                                              ; preds = %start
  %_2.i.i.i.i2 = icmp ugt i32 %6, 131
  br i1 %_2.i.i.i.i2, label %bb1.i.i.i.i3, label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4"

bb1.i.i.i.i3:                                     ; preds = %bb2
; call wasm_bindgen::__wbindgen_object_drop_ref
  call void @_ZN12wasm_bindgen26__wbindgen_object_drop_ref17h7b23851dfe1382a1E(i32 noundef %6) #19, !noalias !23
  br label %"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4"

"_ZN4core3ptr41drop_in_place$LT$js_sys..Float32Array$GT$17hdb2dd2e4998ada5bE.exit4": ; preds = %bb2, %bb1.i.i.i.i3
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %dest)
  call void @llvm.memcpy.p0.p0.i64(ptr noundef nonnull align 4 dereferenceable(64) %_0, ptr noundef nonnull align 4 dereferenceable(64) %mat, i64 64, i1 false)
  call void @llvm.lifetime.end.p0(i64 64, ptr nonnull %mat)
  ret void
}

Meta

rustc --version --verbose:

rustc 1.83.0 (90b35a623 2024-11-26)
binary: rustc
commit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf
commit-date: 2024-11-26
host: x86_64-pc-windows-msvc
release: 1.83.0
LLVM version: 19.1.1
Backtrace

RUST_BACKTRACE=1 cargo build --release
   Compiling proc-macro2 v1.0.92
   Compiling unicode-ident v1.0.14
   Compiling wasm-bindgen-shared v0.2.92
   Compiling bumpalo v3.16.0
   Compiling once_cell v1.20.2
   Compiling log v0.4.22
   Compiling wasm-bindgen v0.2.92
   Compiling cfg-if v1.0.0
   Compiling bytemuck v1.21.0
   Compiling quote v1.0.38
   Compiling syn v2.0.93
   Compiling wasm-bindgen-backend v0.2.92
   Compiling wasm-bindgen-macro-support v0.2.92
   Compiling wasm-bindgen-macro v0.2.92
   Compiling js-sys v0.3.69
   Compiling rust-wasm v0.1.0 (C:\Users\daodao\Desktop\rust-wasm)
    Finished `release` profile [optimized] target(s) in 9.50s

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-gubCategory: the reverse of a compiler bug is generally UB

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions