rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.76k stars 891 forks source link

Possible Winit segmentation fault on close of application on Mac Os on a Mac Air M1 #3379

Closed apps4uco closed 8 months ago

apps4uco commented 8 months ago

In a small project that only has 3 direct dependencies, on MacOs M1 there is a segmentation fault on program exit (click on close button) Im not exactly sure what crate is causing the UB so I figured Id report it in case it was winit.

 cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.29s
     Running `target/debug/winit-softbuffer-tinyskia`
zsh: segmentation fault  cargo run

cargo run --release
...
zsh: segmentation fault  cargo run --release

Cargo.toml has

[dependencies]
softbuffer = "0.4.0"
tiny-skia = { version = "0.11.3", default-features = false, features = ["std"] }
winit = "0.29.9"

winit-softbuffer-tinyskia.zip

lldb --file  target/debug/winit-softbuffer-tinyskia
(lldb) target create "target/debug/winit-softbuffer-tinyskia"
Current executable set to '/Users/andy/rust/winit-softbuffer-tinyskia/target/debug/winit-softbuffer-tinyskia' (arm64).
(lldb) run
Process 48191 launched: '/Users/andy/rust/winit-softbuffer-tinyskia/target/debug/winit-softbuffer-tinyskia' (arm64)
2024-01-09 18:20:28.005570-0500 winit-softbuffer-tinyskia[48191:15380570] [Window] Warning: Window WinitWindow 0x10050de00 ordered front from a non-active application and may order beneath the active application's windows.
2024-01-09 18:20:28.064757-0500 winit-softbuffer-tinyskia[48191:15380570] [Window] Warning: Window WinitWindow 0x10050de00 ordered front from a non-active application and may order beneath the active application's windows.
Process 48191 stopped
* thread #1, name = 'main', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x20)
    frame #0: 0x00000001a96445f8 libobjc.A.dylib`objc_release + 16
libobjc.A.dylib`objc_release:
->  0x1a96445f8 <+16>: ldr    x17, [x2, #0x20]
    0x1a96445fc <+20>: tbz    w17, #0x2, 0x1a964465c    ; <+116>
    0x1a9644600 <+24>: tbz    w16, #0x0, 0x1a9644678    ; <+144>
    0x1a9644604 <+28>: lsr    x17, x16, #55
Target 0: (winit-softbuffer-tinyskia) stopped.
(lldb) bt
* thread #1, name = 'main', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x20)
  * frame #0: 0x00000001a96445f8 libobjc.A.dylib`objc_release + 16
    frame #1: 0x000000010002b18c winit-softbuffer-tinyskia`objc2::runtime::retain_release_fast::objc_release_fast::h3dbba14de5d2d14e(obj=0x000000010050de00) at retain_release_fast.rs:102:9
    frame #2: 0x000000010002b3c0 winit-softbuffer-tinyskia`_$LT$objc2..rc..id..Id$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::h4f3f139c95ee8d98(self=0x0000600000213da8) at id.rs:669:18
    frame #3: 0x0000000100032b90 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$objc2..rc..id..Id$LT$winit..platform_impl..platform..window..WinitWindow$GT$$GT$::h25d5465bf0093efb((null)=0x0000600000213da8) at mod.rs:507:1
    frame #4: 0x000000010002fad0 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$core..option..Option$LT$objc2..rc..id..Id$LT$winit..platform_impl..platform..window..WinitWindow$GT$$GT$$GT$::h32bc6ec2c3e8216f((null)=0x0000600000213da8) at mod.rs:507:1
    frame #5: 0x0000000100030460 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$objc2..declare..ivar_drop..IvarDrop$LT$objc2..rc..id..Id$LT$winit..platform_impl..platform..window..WinitWindow$GT$$GT$$GT$::hf15fb14e4a006141((null)=0x0000600000213da8) at mod.rs:507:1
    frame #6: 0x000000010007def0 winit-softbuffer-tinyskia`_$LT$objc2..declare..ivar..Ivar$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::h73b575c6bf675fe7(self=0x0000600000213da0) at ivar.rs:187:22
    frame #7: 0x000000010002f748 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$objc2..declare..ivar..Ivar$LT$winit..platform_impl..platform..window_delegate..ivars..window$GT$$GT$::h93a8446511c187aa((null)=0x0000600000213da0) at mod.rs:507:1
    frame #8: 0x0000000100032888 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$winit..platform_impl..platform..window_delegate..WinitWindowDelegate$GT$::h49fd87929667283a((null)=0x0000600000213da0) at mod.rs:507:1
    frame #9: 0x00000001000505c8 winit-softbuffer-tinyskia`_$LT$winit..platform_impl..platform..window_delegate..WinitWindowDelegate$u20$as$u20$objc2..class_type..ClassType$GT$::class::_$u7b$$u7b$closure$u7d$$u7d$::__objc2_dealloc::h32dc87189f471982(__objc2_self=0x0000600000213da0, __objc2_cmd=Sel @ 0x000000016fdfe7f8) at declare_class.rs:576:34
    frame #10: 0x000000010002b18c winit-softbuffer-tinyskia`objc2::runtime::retain_release_fast::objc_release_fast::h3dbba14de5d2d14e(obj=0x0000600000213da0) at retain_release_fast.rs:102:9
    frame #11: 0x000000010002b360 winit-softbuffer-tinyskia`_$LT$objc2..rc..id..Id$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::h385d2c6030bcbb0b(self=0x0000600000215e18) at id.rs:669:18
    frame #12: 0x000000010002f648 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$objc2..rc..id..Id$LT$winit..platform_impl..platform..window_delegate..WinitWindowDelegate$GT$$GT$::h1fe3e139a0d67fe0((null)=0x0000600000215e18) at mod.rs:507:1
    frame #13: 0x000000010000f748 winit-softbuffer-tinyskia`core::mem::manually_drop::ManuallyDrop$LT$T$GT$::drop::h5524a735efcf9c81(slot=0x0000600000215e18) at manually_drop.rs:144:18
    frame #14: 0x0000000100011c74 winit-softbuffer-tinyskia`_$LT$icrate..Foundation..additions..thread..MainThreadBound$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::_$u7b$$u7b$closure$u7d$$u7d$::hc4817c73623bc522((null)=(_priv = core::marker::PhantomData<void *> @ 0x000000016fdfe8b7)) at thread.rs:249:26
    frame #15: 0x0000000100011f08 winit-softbuffer-tinyskia`icrate::Foundation::additions::thread::MainThreadMarker::run_on_main::ha91e91ffba29bc2f(f={closure_env#0}<objc2::rc::id::Id<winit::platform_impl::platform::window_delegate::WinitWindowDelegate>> @ 0x000000016fdfe908) at thread.rs:182:13
    frame #16: 0x00000001000154d8 winit-softbuffer-tinyskia`_$LT$icrate..Foundation..additions..thread..MainThreadBound$LT$T$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::hd1c90e33ec193854(self=0x0000600000215e18) at thread.rs:241:13
    frame #17: 0x0000000100015de8 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$icrate..Foundation..additions..thread..MainThreadBound$LT$objc2..rc..id..Id$LT$winit..platform_impl..platform..window_delegate..WinitWindowDelegate$GT$$GT$$GT$::hbaefeb15bb39f86a((null)=0x0000600000215e18) at mod.rs:507:1
    frame #18: 0x0000000100016878 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$winit..platform_impl..platform..window..Window$GT$::h6966fff530544bab((null)=0x0000600000215e10) at mod.rs:507:1
    frame #19: 0x00000001000160e8 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$winit..window..Window$GT$::h2bf7651c5ba37fed((null)=0x0000600000215e10) at mod.rs:507:1
    frame #20: 0x00000001000170b0 winit-softbuffer-tinyskia`_$LT$alloc..rc..Rc$LT$T$C$A$GT$$u20$as$u20$core..ops..drop..Drop$GT$::drop::h1234f1df2788dab8(self=0x000000016fdfee00) at rc.rs:2092:17
    frame #21: 0x00000001000166fc winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$alloc..rc..Rc$LT$winit..window..Window$GT$$GT$::h23ce6bf25a0db733((null)=0x000000016fdfee00) at mod.rs:507:1
    frame #22: 0x0000000100016fc8 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$softbuffer..ContextDispatch$LT$alloc..rc..Rc$LT$winit..window..Window$GT$$GT$$GT$::h72af1e3aff90212f((null)=0x000000016fdfee00) at mod.rs:507:1
    frame #23: 0x0000000100016d30 winit-softbuffer-tinyskia`core::ptr::drop_in_place$LT$softbuffer..Context$LT$alloc..rc..Rc$LT$winit..window..Window$GT$$GT$$GT$::h2e0b3f2f4c3369be((null)=0x000000016fdfee00) at mod.rs:507:1
    frame #24: 0x000000010000a938 winit-softbuffer-tinyskia`winit_softbuffer_tinyskia::main::h26c68627deae5a89 at main.rs:77:1
    frame #25: 0x000000010001575c winit-softbuffer-tinyskia`core::ops::function::FnOnce::call_once::h2394911a5cdacab1((null)=(winit-softbuffer-tinyskia`winit_softbuffer_tinyskia::main::h26c68627deae5a89 at main.rs:8), (null)=<unavailable>) at function.rs:250:5
    frame #26: 0x000000010000bfcc winit-softbuffer-tinyskia`std::sys_common::backtrace::__rust_begin_short_backtrace::h2ed4a8eecaa2c542(f=(winit-softbuffer-tinyskia`winit_softbuffer_tinyskia::main::h26c68627deae5a89 at main.rs:8)) at backtrace.rs:155:18
    frame #27: 0x00000001000135c8 winit-softbuffer-tinyskia`std::rt::lang_start::_$u7b$$u7b$closure$u7d$$u7d$::hd80ea26b24792a51 at rt.rs:166:18
    frame #28: 0x00000001000c2a30 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] core::ops::function::impls::_$LT$impl$u20$core..ops..function..FnOnce$LT$A$GT$$u20$for$u20$$RF$F$GT$::call_once::h278b41ef8ba00c2a at function.rs:284:13 [opt]
    frame #29: 0x00000001000c2a28 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panicking::try::do_call::h60f520898671bba3 at panicking.rs:552:40 [opt]
    frame #30: 0x00000001000c2a28 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panicking::try::h9df10db54138612e at panicking.rs:516:19 [opt]
    frame #31: 0x00000001000c2a28 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panic::catch_unwind::h30c7790f78098534 at panic.rs:142:14 [opt]
    frame #32: 0x00000001000c2a28 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::rt::lang_start_internal::_$u7b$$u7b$closure$u7d$$u7d$::had6f352018002dd0 at rt.rs:148:48 [opt]
    frame #33: 0x00000001000c2a28 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panicking::try::do_call::h6f3ddf53b1105257 at panicking.rs:552:40 [opt]
    frame #34: 0x00000001000c2a24 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panicking::try::h0e09eeefe56060ca at panicking.rs:516:19 [opt]
    frame #35: 0x00000001000c2a24 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 [inlined] std::panic::catch_unwind::h9d43e29760c56e5b at panic.rs:142:14 [opt]
    frame #36: 0x00000001000c2a24 winit-softbuffer-tinyskia`std::rt::lang_start_internal::hfae4a28da42f4228 at rt.rs:148:20 [opt]
    frame #37: 0x0000000100013594 winit-softbuffer-tinyskia`std::rt::lang_start::hbd9fbed6ee207d03(main=(winit-softbuffer-tinyskia`winit_softbuffer_tinyskia::main::h26c68627deae5a89 at main.rs:8), argc=1, argv=0x000000016fdff3b8, sigpipe='\0') at rt.rs:165:17
    frame #38: 0x000000010000a9a8 winit-softbuffer-tinyskia`main + 36
    frame #39: 0x00000001a9687f28 dyld`start + 2236
(lldb) quit
Quitting LLDB will kill one or more processes. Do you really want to proceed: [Y/n] y

rustc -V

rustc 1.77.0-nightly (3cdd004e5 2023-12-29)

uname -a

Darwin .....-mac-m1 22.5.0 Darwin Kernel Version 22.5.0: Thu Jun 8 22:22:19 PDT 2023; root:xnu-8796.121.3~7/RELEASE_ARM64_T8103 arm64

madsmtm commented 8 months ago

The example doesn't actually seem to be using tiny-skia? And in any case, I can't seem to reproduce the issue, are you sure you posted the correct code?

apps4uco commented 8 months ago

The example doesn't actually seem to be using tiny-skia? And in any case, I can't seem to reproduce the issue, are you sure you posted the correct code?

Sorry for the delay in replying....

Yes it is the code that produces the Exception

Just re downloaded it to check and also changed to stable, just in case it was nightly that caused the problem. The segmentation fault occurs with both nightly and stable

You are correct that the example does not use tiny-skia. It must have been late... (or too early). Removing the unused dependency in Cargo.toml Im attaching the revised, minimal test case.

zsh: segmentation fault  cargo run
% rustc -V
rustc 1.75.0 (82e1608df 2023-12-21)
zsh: segmentation fault  cargo run
% rustc -V
rustc 1.77.0-nightly (3cdd004e5 2023-12-29)

Commenting out softbuffer line

//let mut surface = softbuffer::Surface::new(&context, window.clone()).unwrap();

Does not produce the segmentation fault on exit at least not on a Mac Air m1. So it could be UB in SoftBuffer, and/or some MacOs specific bug

winit-softbuffer.zip

kchibisov commented 8 months ago

The general code in the example is unsafe, so it might not be an UB at the end of the day, the reason why it's unsafe, because people just hacked up something, so it could be not a real world problem, but just some unsound code in the example. Make sure to drop the Surface and the Context from softbuffer inside the loop before exiting it.

kchibisov commented 8 months ago

This is related to this issue https://github.com/rust-windowing/winit/issues/3317 , however since softbuffer is using raw-window-handle it's not a soundness problem in winit/softbuffer, but rather the code user has since raw-window-handle is unsafe in general.

madsmtm commented 8 months ago

Tried again, still cannot reproduce on Macbook Pro w. M2 Pro running macOS Sonoma 14.2.1.

While I agree with @kchibisov, I think this kind of thing still shouldn't cause segmentation faults, especially not while releasing objects; to me, that hints more towards a double-free somewhere in Winit or softbuffer.

@apps4uco perhaps you can try to wrap the surface creation in an autorelease pool? Something like (using the objc2 crate):

let mut surface = objc2::rc::autoreleasepool(|_| {
    softbuffer::Surface::new(&context, window.clone()).unwrap()
});
apps4uco commented 8 months ago

Hi,

If I try to drop the surface and context inside the loop

if window_id == window.id() => {
                    //println!("Dropping");

                    mem::drop(surface);
                    mem::drop(context);
                    elwt.exit();

I get a compile error

cannot move out of `surface`, a captured variable in an `FnMut` closure

Using @madsmtm idea of using objc2 pool

https://github.com/rust-windowing/winit/issues/3379#issuecomment-1892586177

gives the same segmentation fault

adding these lines right at the end of main.

println!("Sleep 1");
    thread::sleep(Duration::from_secs(1));
    println!("Dropping surface");
    mem::drop(surface);
    println!("Dropping context");
    mem::drop(context);
    println!("Sleep 2");
    thread::sleep(Duration::from_secs(2));

I get the output

Sleep 1
Dropping surface
Dropping context
zsh: segmentation fault  cargo run

So it appears (to me) to be that the drop of the context is causing the segmentation fault.

Its weird that it cant be reproduced on another Mac, on mine it consistently fails.

Attaching the current source code

winit-softbuffer-objc2.zip

kchibisov commented 8 months ago

You can use the Option to achieve dropping inside the loop, so once you drop you assign None.

apps4uco commented 8 months ago

Thanks for looking into this....

I tried @kchibisov 's suggestion. New code attached.

winit-softbuffer-objc2-option.zip

I also set the following variables in the shell, as indicated by https://developer.apple.com/library/archive/documentation/Performance/Conceptual/ManagingMemory/Articles/MallocDebug.html

MallocStackLogging=1 MallocCheckHeapStart=1000 MallocCheckHeapEach=100 MallocStackLoggingNoCompact=1 MallocScribble=1

Output

Running `target/debug/winit-softbuffer`
Set surface to None
Set context to None
Calling exit
zsh: segmentation fault  cargo run

Note the println of Sleep 1 is never printed

I also tried

 lldb target/debug/winit-softbuffer
(lldb) target create "target/debug/winit-softbuffer"
Current executable set to '/tmp/target/debug/winit-softbuffer' (arm64).
(lldb) run
Process 17456 launched: '/tmp/target/debug/winit-softbuffer' (arm64)
2024-01-15 14:10:35.208451-0500 winit-softbuffer[17456:16840330] [Window] Warning: Window WinitWindow 0x1005066f0 ordered front from a non-active application and may order beneath the active application's windows.
2024-01-15 14:10:35.248207-0500 winit-softbuffer[17456:16840330] [Window] Warning: Window WinitWindow 0x1005066f0 ordered front from a non-active application and may order beneath the active application's windows.
2024-01-15 14:10:38.903335-0500 winit-softbuffer[17456:16840368] [client] No error handler for XPC error: Connection invalid
Process 17456 exited with status = 0 (0x00000000)
madsmtm commented 8 months ago

Hmm, just to explore that path, perhaps you could try creating the window, context and surface inside of Event::NewEvents(StartCause::Init)?

apps4uco commented 8 months ago

... sure. I delayed the init of the surface as shown:

Event::NewEvents(StartCause::Init) => {
                    context = Some(softbuffer::Context::new(window.clone()).unwrap());
                    surface = Some(softbuffer::Surface::new(context.as_mut().unwrap(), window.clone()).unwrap());
                    // let s = objc2::rc::autoreleasepool(|_| {
                    //         softbuffer::Surface::new(context.as_mut().unwrap(), window.clone()).unwrap()
                    //     });
                    // surface = Some(s);
                }

Still get a segmentation fault.

Also using the code shown in comments also produces the same result.

Output

Set surface to None
Set context to None
Calling exit
zsh: segmentation fault  cargo run

Note: println Sleep is not called.

winit-softbuffer-delay-init.zip

madsmtm commented 8 months ago

Huh, with that example I get a segmentation fault too!

Hold on, let me try to figure it out.

apps4uco commented 8 months ago

Just realized that you can get a report on the process exiting on a Mac, (Im more of a Linux developer ...)

report.txt

madsmtm commented 8 months ago

Ugh, stupid me, I already fixed this in https://github.com/rust-windowing/softbuffer/pull/180, which was why I couldn't seem to find any problem with the code - and then I probably had trouble reproducing because my editor updated the lockfile or something...

Run cargo update to get softbuffer v0.4.1 ;)

apps4uco commented 8 months ago

Yep that solved it.... Cool thanks for looking into it ... And fixing it