Skip to content

Miscompilation while working on PR #50882 #52694

Closed
@glandium

Description

@glandium

(Moving this to a separate issue because PR #50882 is already full of noise)
Reduced STR:

  • Take current rust master
  • Apply the following patch:
diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs
index 84bd275..4df7730 100644
--- a/src/liballoc/alloc.rs
+++ b/src/liballoc/alloc.rs
@@ -172,7 +172,7 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
     if size != 0 {
         let layout = Layout::from_size_align_unchecked(size, align);
-        dealloc(ptr as *mut u8, layout);
+        Global.dealloc(NonNull::new_unchecked(ptr).cast(), layout);
     }
 }
 
  • Compile rust against the system llvm (5 or 6)
  • Run libstd tests (x.py test src/libstd --stage 1)

What happens then is that sync::once::tests::wait_for_force_to_finish fails with:

thread '<unnamed>' panicked at 'assertion failed: t1.join().is_ok()', libstd/sync/once.rs:582:9

The disassembly for wait_for_force_to_finish only contains one call to std::thread::JoinHandle::join, instead of the expected two when the code is not miscompiled. That call is followed by a test that jumps to a panic when the result of JoinHandle::join is ... Ok(()):

   93371:       e8 aa fd 07 00          callq  113120 <_ZN41_$LT$std..thread..JoinHandle$LT$T$GT$$GT
$4join17h0fb3b129ec2e38aeE>
   93376:       48 89 c3                mov    %rax,%rbx
   93379:       49 89 d7                mov    %rdx,%r15
   9337c:       48 85 db                test   %rbx,%rbx
   9337f:       74 1b                   je     9339c <_ZN3std4sync4once5tests24wait_for_force_to_fin
ish17h6199051fcaa3ff6aE+0x21c>

That JoinHandle::join returns a Result<(), Box<Any>>, and Ok(()) is represented as (0, whatever). The destination of that jump is the panic code.

At some point, I'm not entirely sure with what state of the tree, it was even better. The error was:

thread '<unnamed>' panicked at 'assertion failed: t2.join().is_ok()', libstd/sync/once.rs:583:9

And there were two calls to std::thread::JoinHandle::join, as expected, but they didn't have the same result handling:

   93c79:       e8 32 c5 07 00          callq  1101b0 <_ZN41_$LT$std..thread..JoinHandle$LT$T$GT$$GT$4join17hc6e7f9bb7d72483aE>
   93c7e:       48 89 c3                mov    %rax,%rbx
   93c81:       49 89 d7                mov    %rdx,%r15
   93c84:       48 85 db                test   %rbx,%rbx
   93c87:       75 5e                   jne    93ce7 <_ZN3std4sync4once5tests24wait_for_force_to_finish17h13c0ef8dd5eb6a3aE+0x267>
(snip)
   93c9f:       e8 0c c5 07 00          callq  1101b0 <_ZN41_$LT$std..thread..JoinHandle$LT$T$GT$$GT$4join17hc6e7f9bb7d72483aE>
   93ca4:       48 89 c3                mov    %rax,%rbx
   93ca7:       49 89 d7                mov    %rdx,%r15
   93caa:       48 85 db                test   %rbx,%rbx
   93cad:       74 1b                   je     93cca <_ZN3std4sync4once5tests24wait_for_force_to_finish17h13c0ef8dd5eb6a3aE+0x24a>

The destination of both jumps is panic code. The first jump, corresponding to t1.join().is_ok() is correct, and the second, corresponding to t2.join().is_ok() is broken, thus the test failure.

Even better: this doesn't happen when compiling with the bundled llvm. It also doesn't happen when extracting the test from libstd and compiling with a faulty compiler. It seems the fact that it's part of libstd, and that most of libstd is compiled along the test, plays a role.

I'm trying to get the corresponding mir and llvm-ir.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions