slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
17.48k stars 599 forks source link

STATUS_STACK_OVERFLOW with multiple ComboBox on different styles #4586

Open Toyz opened 8 months ago

Toyz commented 8 months ago

When using Slint bindings for rust with the Slint builder, you will cause a STATUS_STACK_OVERFLOW when you have more than 1 combo box within the project.

main.slint

export component MainWindow inherits Window {
      ComboBox {
          model: ["First", "Second" "Third"];
          current-index: 0
        }

              ComboBox {
          model: ["First", "Second" "Third"];
          current-index: 0
        }
}

build.rs

fn main() {
    let config = slint_build::CompilerConfiguration::new().with_style("cosmic".into());

    slint_build::compile_with_config("ui/main.slint", config).unwrap();
}

main.rs

slint::include_modules!();

fn main() {
       MainWindow::new().expect("MainWindow::new() failed").run().expect("MainWindow::run() failed");
}

When running this on the latest (1.4.1 and including main) it will trigger a stack overflow on windows.

--- Notes ---

When using native styles the combo boxes work fine and don't trigger a panic

ogoffart commented 8 months ago

Thanks for posting a bug.

I tried to reproduce, but I cannot reproduce the problem.

Note that your code doesn't compile (missing comas and semicolon), but even when i add that and put the combobox next to each other, it works as expected.

Is there a backtrace available?

What exactly is crashing? Is it when running your program or when building, or the preview?

Toyz commented 8 months ago

Here is a backtrace from the program that is triggering it (sadly i can't share this projects code and wildly enough I can't reproduce it in my own example code for some odd reason)

* thread #1, name = 'main', stop reason = Exception 0xc00000fd encountered at address 0x7ff73506a227: Stack overflow
  * frame #0: 0x00007ff73506a227 test_project_code.exe`__chkstk() at chkstk.asm:109
    frame #1: 0x00007ff7344c094b test_project_code.exe`test_project_code::slint_generatedMainWindow::InnerMainWindow::init(root=<unavailable>, tree_index=<unavailable>, tree_index_of_first_child=<unavailable>) at main.rs:3843
    frame #2: 0x00007ff7345c7237 test_project_code.exe`test_project_code::slint_generatedMainWindow::InnerMainWindow::new() at main.rs:49192
    frame #3: 0x00007ff7345c7c1c test_project_code.exe`test_project_code::slint_generatedMainWindow::MainWindow::new() at main.rs:50582
    frame #4: 0x00007ff73435f9ab test_project_code.exe`test_project_code::main() at main.rs:44
    frame #5: 0x00007ff7344185db test_project_code.exe`core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >(=0x00007ff73435f5e0) at function.rs:250
    frame #6: 0x00007ff7344a8cee test_project_code.exe`std::sys_common::backtrace::__rust_begin_short_backtrace<void (*)(),tuple$<> >(*mut ) [inlined] core::hint::black_box(tuple$<>) at hint.rs:286
    frame #7: 0x00007ff73433dea1 test_project_code.exe`std::rt::lang_start::closure$0<tuple$<> >(*mut std::rt::lang_start::closure_env$0<tuple$<> >) at rt.rs:166
    frame #8: 0x00007ff73501e478 test_project_code.exe`std::rt::lang_start_internal() [inlined] std::rt::lang_start_internal::closure$2() at rt.rs:148
    frame #9: 0x00007ff73501e46d test_project_code.exe`std::rt::lang_start_internal() [inlined] std::panicking::try::do_call() at panicking.rs:504
    frame #10: 0x00007ff73501e46d test_project_code.exe`std::rt::lang_start_internal() [inlined] std::panicking::try() at panicking.rs:468
    frame #11: 0x00007ff73501e46d test_project_code.exe`std::rt::lang_start_internal() [inlined] std::panic::catch_unwind() at panic.rs:142
    frame #12: 0x00007ff73501e46d test_project_code.exe`std::rt::lang_start_internal() at rt.rs:148
    frame #13: 0x00007ff73433de7a test_project_code.exe`std::rt::lang_start<tuple$<> >(main=0x00007ff73435f5e0, argc=1, argv=0x00000236d5a89800, sigpipe=0) at rt.rs:165
    frame #14: 0x00007ff734360aa9 test_project_code.exe`main + 25
    frame #15: 0x00007ff73506a430 test_project_code.exe`__scrt_common_main_seh() [inlined] invoke_main() at exe_common.inl:78
    frame #16: 0x00007ff73506a40e test_project_code.exe`__scrt_common_main_seh() at exe_common.inl:288
    frame #17: 0x00007ff84d6e257d kernel32.dll
    frame #18: 0x00007ff84f0eaa58 ntdll.dll
  thread #2, name = 'ntdll.dll thread'
    frame #0: 0x00007ff84f132fc4 ntdll.dll
    frame #1: 0x00007ff84f0c537e ntdll.dll
    frame #2: 0x00007ff84d6e257d kernel32.dll
    frame #3: 0x00007ff84f0eaa58 ntdll.dll
  thread #3, name = 'ntdll.dll thread'
    frame #0: 0x00007ff84f132fc4 ntdll.dll
    frame #1: 0x00007ff84f0c537e ntdll.dll
    frame #2: 0x00007ff84d6e257d kernel32.dll
    frame #3: 0x00007ff84f0eaa58 ntdll.dll
  thread #4, name = 'ntdll.dll thread'
    frame #0: 0x00007ff84f132fc4 ntdll.dll
    frame #1: 0x00007ff84f0c537e ntdll.dll
    frame #2: 0x00007ff84d6e257d kernel32.dll
    frame #3: 0x00007ff84f0eaa58 ntdll.dll
  thread #5, name = 'test_project_code.exe!std::sys::windows::thread::impl$0::new::thread_start()'
    frame #0: 0x00007ff84f132f64 ntdll.dll
    frame #1: 0x00007ff84f0c39d5 ntdll.dll
    frame #2: 0x00007ff84f0df9cc ntdll.dll
    frame #3: 0x00007ff84f0dba93 ntdll.dll
    frame #4: 0x00007ff84ca92df3 KernelBase.dll
    frame #5: 0x00007ff73501ee5e test_project_code.exe`std::thread::park_timeout() [inlined] std::sys::windows::thread_parking::Parker::park_timeout() at thread_parking.rs:149
    frame #6: 0x00007ff73501edf7 test_project_code.exe`std::thread::park_timeout() at mod.rs:1135
    frame #7: 0x00007ff734fd9edb test_project_code.exe`std::sync::mpmc::context::Context::wait_until(self=0x000000f0566fe820) at context.rs:130
    frame #8: 0x00007ff734fe15f0 test_project_code.exe`std::sync::mpmc::list::impl$3::recv::closure$1<enum2$<log2::Action> >(cx=0x000000f0566fe820) at list.rs:444
    frame #9: 0x00007ff734fdad0c test_project_code.exe`std::sync::mpmc::context::impl$0::with::closure$0<std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> >,tuple$<> >(cx=0x000000f0566fe820) at context.rs:50
    frame #10: 0x00007ff734fdb0b6 test_project_code.exe`std::sync::mpmc::context::impl$0::with::closure$1<std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> >,tuple$<> >(cell=0x00000236d5aae5c8) at context.rs:58
    frame #11: 0x00007ff734fdb8c3 test_project_code.exe`std::thread::local::LocalKey<core::cell::Cell<enum2$<core::option::Option<std::sync::mpmc::context::Context> > > >::try_with<core::cell::Cell<enum2$<core::option::Option<std::sync::mpmc::context::Context> > >,std::sync::mpmc::context::impl$0::with::closure_env$1<std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> >,tuple$<> >,tuple$<> >(self=0x00007ff735190998, f=std::sync::mpmc::context::impl$0::with::closure_env$1<std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> >,tuple$<> > @ 0x000000f0566fe8f8) at local.rs:270
    frame #12: 0x00007ff734fd9f71 test_project_code.exe`std::sync::mpmc::context::Context::with<std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> >,tuple$<> >(f=std::sync::mpmc::list::impl$3::recv::closure_env$1<enum2$<log2::Action> > @ 0x000000f0566fe960) at context.rs:53
    frame #13: 0x00007ff734fe1478 test_project_code.exe`std::sync::mpmc::list::Channel<enum2$<log2::Action> >::recv<enum2$<log2::Action> >(self=0x00000236d5a90100) at list.rs:434
    frame #14: 0x00007ff734fd6b28 test_project_code.exe`std::sync::mpmc::Receiver<enum2$<log2::Action> >::recv_deadline<enum2$<log2::Action> >(self=0x000000f0566ff300) at mod.rs:340
    frame #15: 0x00007ff734fd6a57 test_project_code.exe`std::sync::mpmc::Receiver<enum2$<log2::Action> >::recv_timeout<enum2$<log2::Action> >(self=0x000000f0566ff300) at mod.rs:323
    frame #16: 0x00007ff734fd6dd0 test_project_code.exe`std::sync::mpsc::Receiver<enum2$<log2::Action> >::recv_timeout<enum2$<log2::Action> >(self=0x000000f0566ff300) at mod.rs:909
    frame #17: 0x00007ff734fd4d48 test_project_code.exe`log2::worker(ctx=0x00000000566ff300) at lib.rs:360
    frame #18: 0x00007ff734fd5da7 test_project_code.exe`log2::start_log2::closure$0(log2::start_log2::closure_env$0) at lib.rs:456
    frame #19: 0x00007ff734fd94f9 test_project_code.exe`std::sys_common::backtrace::__rust_begin_short_backtrace<log2::start_log2::closure_env$0,tuple$<> >(log2::start_log2::closure_env$0) [inlined] core::hint::black_box(tuple$<>) at hint.rs:286
    frame #20: 0x00007ff734fd7e71 test_project_code.exe`std::thread::impl$0::spawn_unchecked_::closure$1::closure$0<log2::start_log2::closure_env$0,tuple$<> >(std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<log2::start_log2::closure_env$0,tuple$<> >) at mod.rs:529
    frame #21: 0x00007ff734fd0d01 test_project_code.exe`core::panic::unwind_safe::impl$23::call_once<tuple$<>,std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<log2::start_log2::closure_env$0,tuple$<> > >(self=<unavailable>, =tuple$<> @ 0x000000f0566ff47f) at unwind_safe.rs:271
    frame #22: 0x00007ff734fdcd6b test_project_code.exe`std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<log2::start_log2::closure_env$0,tuple$<> > >,tuple$<> >(data=0x000000f0566ff5c0) at panicking.rs:504
    frame #23: 0x00007ff734fdf893 test_project_code.exe
    frame #24: 0x00007ff734fdcc04 test_project_code.exe`std::panicking::try<tuple$<>,core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<log2::start_log2::closure_env$0,tuple$<> > > >(f=<unavailable>) at panicking.rs:468
    frame #25: 0x00007ff734fd7cb3 test_project_code.exe`std::thread::impl$0::spawn_unchecked_::closure$1<log2::start_log2::closure_env$0,tuple$<> >(std::thread::impl$0::spawn_unchecked_::closure_env$1<log2::start_log2::closure_env$0,tuple$<> >) [inlined] std::panic::catch_unwind(f=core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked_::closure$1::closure_env$0<log2::start_log2::closure_env$0,tuple$<> > > @ 0x000000f0566ff750) at panic.rs:142
    frame #26: 0x00007ff734fd7caa test_project_code.exe`std::thread::impl$0::spawn_unchecked_::closure$1<log2::start_log2::closure_env$0,tuple$<> >(std::thread::impl$0::spawn_unchecked_::closure_env$1<log2::start_log2::closure_env$0,tuple$<> >) at mod.rs:528
    frame #27: 0x00007ff734fcb08e test_project_code.exe`core::ops::function::FnOnce::call_once<std::thread::impl$0::spawn_unchecked_::closure_env$1<log2::start_log2::closure_env$0,tuple$<> >,tuple$<> >(=0x00000236d5aad710) at function.rs:250
    frame #28: 0x00007ff73502ec5c test_project_code.exe`std::sys::windows::thread::impl$0::new::thread_start() at thread.rs:57
    frame #29: 0x00007ff84d6e257d kernel32.dll
    frame #30: 0x00007ff84f0eaa58 ntdll.dll

But the exact line it's being triggered at is the following.

        let win = MainWindow::new().expect("MainWindow::new() failed");

Above this line is just HIDAPI calls which are all returning fine as they are debug logging the actual result(s) I have been working with.

My guess is this looks to be when it is walking the tree on run it might be triggering it, this project has 4 files total 3 of which extend a gridlayout and 1 which is the main.slint. From there the main tab in the tab layout when it wasn't in native contained 1 Combobox and then another tab contained another combobox the stack overflow occures.

Each page also exports a "Global" they control that page's state for communication back to the rust code as a struct bound as an in-out

Other information as well: Cargo Version: cargo 1.76.0 (c84b36747 2024-01-18) Windows Version: Microsoft Windows [Version 10.0.22635.2921] (Windows 11)

ogoffart commented 8 months ago

Is there a difference between debug mode and release mode? We had this bug before in which trying to allocate big structure on the heap would first do a few copies on the stack that would cause a stack overflow: https://github.com/slint-ui/slint/issues/133 Is that a regresion from previous version of Slint or of Rust?

Toyz commented 8 months ago

Sorry for the late reply on this.

Just verified that this is only happening in DEBUG build. RELEASE builds work just fine

ogoffart commented 4 months ago

https://github.com/slint-ui/slint/pull/5415 fixes a stack overflow, but that's not really fitting with the backtrace

tronical commented 1 month ago

The default stack size on Windows is IIRC 1MB (see https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations?view=msvc-170 ). I'm not sure there's much that we can do here. Ideas:

Any other ideas what we could do?

Enyium commented 1 month ago

I now use the following code in my build.rs:

    // Increase stack size to prevent Slint issue <https://github.com/slint-ui/slint/issues/6299>.
    const STACK_SIZE_MIB_DEBUG: f64 = 2.;
    const STACK_SIZE_MIB_RELEASE: f64 = 1.;
    //i 1 MB is MSVC's default (as of Visual Studio 2022): <https://learn.microsoft.com/en-us/cpp/build/reference/stack-stack-allocations>.

    print!("cargo::rustc-link-arg=");

    match env::var("TARGET").unwrap().as_str() {
        "x86_64-pc-windows-msvc" => print!("/STACK:"),
        "x86_64-pc-windows-gnu" => print!("-Wl,--stack,"),
        //i Source: <https://users.rust-lang.org/t/stack-overflow-when-compiling-on-windows-10/50818/8>.
        _ => panic!("unexpected target"),
    }

    let stack_size_bytes = (match env::var("PROFILE").unwrap().as_str() {
        "debug" => STACK_SIZE_MIB_DEBUG,
        "release" => STACK_SIZE_MIB_RELEASE,
        _ => panic!("unexpected profile"),
    } * 1024f64.powi(2))
    .round() as u64;

    println!("{stack_size_bytes}");

Can that it bad, though, to just increase the stack when building for mobile (currently only Android), because resources are more limited?

tronical commented 1 month ago

In times where mobile phones measure ram in gigabytes I'm less concerned about 1-5 MB.

ogoffart commented 1 month ago

Any other ideas what we could do?

tronical commented 1 month ago

Among those (docs, templates, above bullet points), what's your preference?