Skip to content

Run the runtime on a large-stack thread to avoid a main-thread stack overflow on Windows - #246

Open
gimperioso wants to merge 1 commit into
EFForg:masterfrom
gimperioso:fix/windows-stack-overflow
Open

Run the runtime on a large-stack thread to avoid a main-thread stack overflow on Windows#246
gimperioso wants to merge 1 commit into
EFForg:masterfrom
gimperioso:fix/windows-stack-overflow

Conversation

@gimperioso

Copy link
Copy Markdown

Problem

On Windows, apkeep 1.0.0 aborts while downloading some apps from the google-play
source with:

Downloading org.telegram.messenger...

thread 'main' (10812) has overflowed its stack

The process exits with 0xC00000FD (STATUS_STACK_OVERFLOW) and nothing is written to
the output directory. It reproduces on e.g. org.telegram.messenger and
com.instagram.android. This is the crash reported in #238.

Root cause

main is annotated with #[tokio::main], so the whole program future is driven with
block_on on the process main thread. On Windows the main thread only gets a
1 MiB stack by default (Linux typically gives ~8 MiB).

Downloading goes through gpapi, which decodes the Google Play protobuf responses with
prost. Those responses (details/delivery, with their nested item/cluster trees) are
decoded recursively — one stack frame per level of message nesting — and the deeper
responses returned for some apps recurse far enough to overflow the 1 MiB main-thread
stack. The same binary runs fine on Linux because of the larger default stack, which is
why the crash is Windows-specific.

The depth of the response — not the size of the resulting APK — is what matters: some
larger apps download fine while a couple of mid-sized but "busy" listings overflow.

Fix

Host the Tokio runtime on a dedicated thread with a generous (64 MiB) stack, so the
download succeeds regardless of the platform's default main-thread stack size. Since the
work is still driven with block_on (not spawn), the existing non-Send (Rc) usage
in the download path is unaffected.

fn main() {
    const STACK_SIZE: usize = 64 * 1024 * 1024;
    let main_thread = std::thread::Builder::new()
        .name("apkeep-main".to_string())
        .stack_size(STACK_SIZE)
        .spawn(|| {
            tokio::runtime::Builder::new_multi_thread()
                .enable_all()
                .thread_stack_size(STACK_SIZE)
                .build()
                .expect("failed to build tokio runtime")
                .block_on(run());
        })
        .expect("failed to spawn main worker thread");
    main_thread.join().expect("main worker thread panicked");
}

async fn run() { /* former body of main */ }

Verification

Built from the 1.0.0 tag, Windows 10 (19045), x86_64-pc-windows-msvc, google-play
source with AAS-token auth.

Build org.telegram.messenger com.instagram.android
1.0.0, before fix thread 'main' has overflowed its stack, 0 bytes written same
1.0.0, with this fix downloaded OK (52,465,700 B) downloaded OK (227,702,231 B)

Note: an optimized release build compiled with a current rustc may not overflow, since
the recursion depth sits near the 1 MiB boundary and the outcome depends on
inlining/codegen. That fragility is exactly what this change removes; the crash is
reliably reproducible with a debug build of the same tag, which this fix resolves.

A more fundamental fix would bound the recursion depth when decoding the Play protobuf
responses (in gpapi/prost), but raising the runtime stack resolves the reported crash
without touching the parsing path and helps on any platform with a small default
main-thread stack.

On Windows the process main thread gets a 1 MiB stack (vs ~8 MiB on Linux).
Decoding deeply nested Google Play protobuf responses recurses per nesting
level and can overflow it, aborting with "thread 'main' has overflowed its
stack" before anything is written to disk. Host the Tokio runtime on a
dedicated thread with a 64 MiB stack so downloads succeed regardless of the
platform default.

Assisted-by: Claude (Anthropic)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants