Description
I'm writing PNG files from a C++ background thread. It used to work on Rust stable 1.83.0, but it crashes on Rust stable 1.84.0 and nightly. I'm using the png
crate, but it or its dependencies shouldn't have any code, which would cause the crash.
The crash happens on macOS and Rust 1.84.0 (I tested on arm and intel macs). The program runs without issues on Ubuntu linux Rust 1.84.0. I didn't test Windows. There are no issues writing PNGs from the C++ main thread, but PNG writing crashes on the C++ background thread. If I write the same program in pure Rust without ffi and using Rust threads, then everything works without issues.
Could this be a regression in the Rust standard library? Or is the Rust function called from the C++ background thread in a way that is incompatible with Rust 1.84.0?
Code
Here's a minimal example project as a zip file so that you can see the code and try it yourself: test-cthread-png.zip
I expected to see this happen: Two PNG files should be written to the current folder: 'out-png-1.png' and 'out-png-2.png'
Instead, this happened: Only one PNG file is written: 'out-png-1.png' (on the main thread) and then the program crashes:
Rust PNG writing to 'out-png-1.png'
Waiting thread to finish..
Rust PNG writing to 'out-png-2.png'
zsh: bus error ./main
Version it worked on
It most recently worked on: Rust 1.83
Version with regression
rustc --version --verbose
:
rustc 1.84.0 (9fc6b4312 2025-01-07)
binary: rustc
commit-hash: 9fc6b43126469e3858e2fe86cafb4f0fd5068869
commit-date: 2025-01-07
host: aarch64-apple-darwin
release: 1.84.0
LLVM version: 19.1.5
LLVM Stack Trace
Stack trace of the example project
Process 62208 launched: '/Users/temp/rust/test-cthread-png/main' (arm64)
Rust PNG writing to 'out-png-1.png'
Waiting thread to finish..
Rust PNG writing to 'out-png-2.png'
Process 62208 stopped
* thread #2, stop reason = EXC_BAD_ACCESS (code=2, address=0x16fe036b0)
frame #0: 0x000000010005a334 main`alloc::boxed::Box$LT$core..mem..maybe_uninit..MaybeUninit$LT$T$GT$$C$A$GT$::write::hf0470a3673d75fd5(boxed=0x0000000000000000, value=<unavailable>) at boxed.rs:1008
1005 /// ```
1006 #[unstable(feature = "box_uninit_write", issue = "129397")]
1007 #[inline]
-> 1008 pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
1009 unsafe {
1010 (*boxed).write(value);
1011 boxed.assume_init()
Target 0: (main) stopped.
(lldb) thread backtrace
* thread #2, stop reason = EXC_BAD_ACCESS (code=2, address=0x16fe036b0)
* frame #0: 0x000000010005a334 main`alloc::boxed::Box$LT$core..mem..maybe_uninit..MaybeUninit$LT$T$GT$$C$A$GT$::write::hf0470a3673d75fd5(boxed=0x0000000000000000, value=<unavailable>) at boxed.rs:1008
frame #1: 0x000000010005a540 main`_$LT$alloc..boxed..Box$LT$T$GT$$u20$as$u20$core..default..Default$GT$::default::h770abf79bd18dfcf at boxed.rs:1733:9
frame #2: 0x0000000100045818 main`miniz_oxide::deflate::core::DictOxide::new::hf9b523780f33e231(flags=4112) at core.rs:1156:16
frame #3: 0x000000010004116c main`_$LT$miniz_oxide..deflate..core..CompressorOxide$u20$as$u20$core..default..Default$GT$::default::h98fdbfee01692241 at core.rs:436:19
frame #4: 0x000000010003dea8 main`_$LT$alloc..boxed..Box$LT$T$GT$$u20$as$u20$core..default..Default$GT$::default::h89b44e0f0b402adf at boxed.rs:1733:39
frame #5: 0x000000010003ecc8 main`_$LT$flate2..ffi..rust..Deflate$u20$as$u20$flate2..ffi..DeflateBackend$GT$::make::hee247c1da637a407(level=(__0 = 6), zlib_header=true, _window_bits='\x0f') at rust.rs:131:47
frame #6: 0x000000010003fc8c main`flate2::mem::Compress::new::h1c4d10d7643a257f(level=(__0 = 6), zlib_header=true) at mem.rs:197:20
frame #7: 0x000000010002d1dc main`flate2::zlib::write::ZlibEncoder$LT$W$GT$::new::h9b8a7495719a8ece(w=Vec<u8, alloc::alloc::Global> @ 0x000000016fe863a8, level=(__0 = 6)) at write.rs:43:40
frame #8: 0x000000010000c398 main`png::encoder::Writer$LT$W$GT$::write_image_data::h1a6cf982c65de46c(self=0x000000016fe86b98, data=(data_ptr = "", length = 307200)) at encoder.rs:742:32
frame #9: 0x000000010000b99c main`rspng_write(filenumber='\x02') at lib.rs:20:8
frame #10: 0x00000001000022fc main`MyThread::run(this=0x000000016fdff32b) at main.cpp:9:13
frame #11: 0x0000000100002e54 main`decltype(*std::declval<MyThread*>().*std::declval<void (MyThread::*)()>()()) std::__1::__invoke[abi:ne180100]<void (MyThread::*)(), MyThread*, void>(__f=0x0000600002b940c8, __a0=0x0000600002b940d8) at invoke.h:312:25
frame #12: 0x0000000100002d84 main`void std::__1::__thread_execute[abi:ne180100]<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (MyThread::*)(), MyThread*, 2ul>(__t=size=3, (null)=__tuple_indices<2UL> @ 0x000000016fe86f7f) at thread.h:199:3
frame #13: 0x0000000100002680 main`void* std::__1::__thread_proxy[abi:ne180100]<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct>>, void (MyThread::*)(), MyThread*>>(__vp=0x0000600002b940c0) at thread.h:208:3
frame #14: 0x0000000188b272e4 libsystem_pthread.dylib`_pthread_start + 136
(lldb)