denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
93.39k stars 5.18k forks source link

thread 'tokio-runtime-worker' has overflowed its stack #24325

Open begoon opened 1 week ago

begoon commented 1 week ago

Version: Deno 1.44.4

I have a complex CLI application to generate PDF's with pdfkit and a few extra libraries.

After the latest Deno update:

deno --version
deno 1.44.4 (release, aarch64-apple-darwin)
v8 12.6.228.9
typescript 5.4.5

everything crashes no matter what with:

cd src/pdf && \
        deno run -A --watch \
        pdf-cli.ts
Watcher Process started.

thread 'tokio-runtime-worker' has overflowed its stack
fatal runtime error: stack overflow

I'm puzzled about how to raise a bug report because I don't know how to supply a simple, reproducible test case.

Also, when I run this project AS IS but with Bun, it works as expected, with no crashes.

Any advice?

I have also realised that in the dockerfile, there is a version of Deno which I didn't upgrade. The application DOES work with that version:

deno --version
deno 1.43.1 (release, aarch64-apple-darwin)
v8 12.4.254.12
typescript 5.4.3

I have downgraded my main CLI deno to 1.43.1, and... the crash is gone.

Something had been broken between 1.43.1 and 1.44.4.

begoon commented 1 week ago

I have bisected the releases and found that the last working release for me is 1.43.5.

In 1.43.6, the application starts crashing because of the error above.

yazan-abdalrahman commented 1 week ago

Hello, can you explain how I can re-produce this bug?

What's the script in pdf-cli.ts? image

begoon commented 1 week ago

I have isolated the code causing the crash.

I have attached a single file, called crash.ts.

1.43.5 works okay with this file:

// deno upgrade --version 1.43.5
Downloading https://github.com/denoland/deno/releases/download/v1.43.5/deno-aarch64-apple-darwin.zip
Deno is upgrading to version 1.43.5
Archive:  /var/folders/yt/48q9hkh95x7fg1ps8sr95wd40000gn/T/.tmpV6kgiH/deno.zip
  inflating: deno                    
Upgraded successfully

// deno run -A src/pdf/crash.ts 

Warning Sloppy imports are not recommended and have a negative impact on performance.

1.43.6 crashes.

// deno upgrade --version 1.43.6
Downloading https://github.com/denoland/deno/releases/download/v1.43.6/deno-aarch64-apple-darwin.zip
Deno is upgrading to version 1.43.6
Archive:  /var/folders/yt/48q9hkh95x7fg1ps8sr95wd40000gn/T/.tmpi9CFkS/deno.zip
  inflating: deno                    
Upgraded successfully

// deno run -A src/pdf/crash.ts 
Warning Sloppy imports are not recommended and have a negative impact on performance.

thread 'tokio-runtime-worker' has overflowed its stack
fatal runtime error: stack overflow
zsh: abort      deno run -A src/pdf/crash.ts

crash.ts is attached. crash.zip

begoon commented 1 week ago

I have checked on linux/amd64 too. The behaviour is the same. It crashes on 1.43.6, but 1.43.5 works.

deno --version
deno 1.43.6 (release, x86_64-unknown-linux-gnu)
v8 12.4.254.13
typescript 5.4.5
yazan-abdalrahman commented 3 days ago

Hi @begoon, @dsherret, @bartlomieju

I've spent some time debugging the recent stack overflow issue we encountered while running our Deno script. After thorough investigation, I couldn't pinpoint any recursive asynchronous operations causing the problem. Instead, it appears that the issue stemmed from insufficient stack memory, exacerbated by recent updates in Deno's behavior complexity.

To address this, I explored increasing the stack memory allocation, which successfully resolved the issue on my WindowsPowerShell . Here's the command I used:

$env:RUST_MIN_STACK=9999999999 ; this for increase stack size try to increase the stack size until it work

see example: image

for linux the equivalent command for environments would be export RUST_MIN_STACK=9999999999

yazan-abdalrahman commented 2 days ago

Hi @begoon, @dsherret, @bartlomieju

I've spent some time debugging the recent stack overflow issue we encountered while running our Deno script. After thorough investigation, I couldn't pinpoint any recursive asynchronous operations causing the problem. Instead, it appears that the issue stemmed from insufficient stack memory, exacerbated by recent updates in Deno's behavior complexity.

To address this, I explored increasing the stack memory allocation, which successfully resolved the issue on my WindowsPowerShell . Here's the command I used:

$env:RUST_MIN_STACK=9999999999 ; this for increase stack size try to increase the stack size until it work

see example: image

for linux the equivalent command for environments would be export RUST_MIN_STACK=9999999999

and it worked when I tried it on Ubuntu without rust.

image

yazan-abdalrahman commented 2 days ago

@lucacasonato

Hello, my conclusion is that the issue is a memory issue, so what should we do? I believe we can add a flag to indicate the stack size of a thread, which would alleviate the issue if we didn't need to use env. RUST_MIN_STACK but env. RUST_MIN_STACK it resolves the issue

image

nathanwhit commented 1 day ago

Hello! I looked into this and the cause is an overflow in swc's resolver transform, you can see this from the backtrace:

Backtrace ``` frame #0: 0x00000001014023fc deno`OUTLINED_FUNCTION_6399 + 4 frame #1: 0x000000010126977c deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 28 frame #2: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3849: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3850: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3851: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3852: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3853: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3854: 0x00000001012699a0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 576 frame #3855: 0x0000000101269dfc deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_object_lit::h0f7e263a305fac74 + 324 frame #3856: 0x00000001012699f0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 656 frame #3857: 0x0000000101269dfc deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_object_lit::h0f7e263a305fac74 + 324 frame #3858: 0x00000001012699f0 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_expr::h144833a51f384f9c + 656 frame #3859: 0x000000010126c870 deno`swc_ecma_visit::visit_mut_var_declarators::h4d727e26ae807b9a + 60 frame #3860: 0x000000010126b12c deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_var_decl::h0015df53982443c0 + 40 frame #3861: 0x000000010126b60c deno`swc_ecma_visit::visit_mut_module_items::hb666b1afac57ec7e + 536 frame #3862: 0x000000010126b3c4 deno`_$LT$swc_ecma_transforms_base..resolver..Resolver$u20$as$u20$swc_ecma_visit..VisitMut$GT$::visit_mut_module_items::h65186121c5335ac6 + 356 frame #3863: 0x000000010047b238 deno`_$LT$swc_ecma_visit..Folder$LT$V$GT$$u20$as$u20$swc_ecma_visit..Fold$GT$::fold_program::h21c53df4d6ee7c9e + 68 frame #3864: 0x000000010047b5c4 deno`_$LT$swc_ecma_ast..module..Program$u20$as$u20$swc_ecma_visit..FoldWith$LT$V$GT$$GT$::fold_with::h8009075f52177431 + 856 frame #3865: 0x0000000100496624 deno`deno_ast::transpiling::fold_program::h322f01473dc57f71 + 3224 frame #3866: 0x00000001004df7b4 deno`deno_ast::transpiling::transpile::hfddfb5000f782f11 + 256 frame #3867: 0x00000001004df268 deno`deno_ast::transpiling::_$LT$impl$u20$deno_ast..parsed_source..ParsedSource$GT$::transpile::h69e7bfb372b7563f + 340 frame #3868: 0x00000001001fea60 deno`deno::emit::EmitParsedSourceHelper::transpile::hdd54dbbc6834d005 + 68 frame #3869: 0x000000010010074c deno`tokio::runtime::task::raw::poll::hd4fa1a1a0119c459 + 160 frame #3870: 0x00000001012e95c0 deno`std::sys_common::backtrace::__rust_begin_short_backtrace::h19cf7b946178ce3c + 400 frame #3871: 0x00000001012e9304 deno`core::ops::function::FnOnce::call_once$u7b$$u7b$vtable.shim$u7d$$u7d$::ha9ce68b6d6219635 + 148 frame #3872: 0x00000001011e1d3c deno`std::sys::pal::unix::thread::Thread::new::thread_start::h50a0ef5291b272f3 + 52 frame #3873: 0x0000000182f7ef94 libsystem_pthread.dylib`_pthread_start + 136 ```

The immediate cause (in your code) is the very large string concatenation

            "AAEAAAASAQAABAAgR0RFRrRCsIIAAir4AAACYkdQT1Or8IZpAAItXAAAZS5H" +
            "U1VCeoGFdwACkowAABWQT1MvMpl2sYAAAhh4AAAAYGNtYXDG7lFtAAId8AAA" +
            "BoJjdnQgBg4uPQACJ2gAAABaZnBnbYP7I6sAAiR0AAABvGdhc3AACAATAAIq" +
            "7AAAAAxnbHlm1d+kywAAASwAAfh4aGRteHmPiKEAAhjYAAAFGGhlYWT9R9JX" +
            "AAID5AAAADZoaGVhDUgS1wACGFQAAAAkaG10eN7XI9kAAgQcAAAUOGxvY2HG" +
            // <continues for ~3864 more lines

That effectively creates one big expression with thousands of subexpressions (each + creates a subexpression). When swc tries to visit this, it does one recursive function call per subexpression. Since there are so many subexpressions, that leads to a very deep call stack, which causes the stack overflow.


I'd recommend using escaped newlines or a template string instead of the string concatenation.

Escaped newlines (note the backslash at the end of each line, and the fact that the following line is not indented):

            "AAEAAAASAQAABAAgR0RFRrRCsIIAAhNYAAACYkdQT1Or8IZpAAIVvAAAZS5H\
U1VCeoGFdwACeuwAABWQT1MvMpl2sdgAAgEYAAAAYGNtYXDG7lFtAAIGkAAA\
BoJjdnQgBg0uPQACEAgAAABaZnBnbYP7I6sAAg0UAAABvGdhc3AACAATAAIT\
TAAAAAxnbHlmVocNBQAAASwAAeEYaGRteI6hoLIAAgF4AAAFGGhlYWT9DdJS\
// etc
ADAAmACbADEA0ADQADUAAQABAEoAAQADAEoAVwCV"

Or a template string, with a helper to strip out the newlines and leading whitespace


const stripIndent = (s: string) => s.split("\n").map((l) => l.trimStart()).join("");

// later

stripIndent( `AAEAAAASAQAABAAgR0RFRrRCsIIAAhNYAAACYkdQT1Or8IZpAAIVvAAAZS5H
            U1VCeoGFdwACeuwAABWQT1MvMpl2sdgAAgEYAAAAYGNtYXDG7lFtAAIGkAAA
            BoJjdnQgBg0uPQACEAgAAABaZnBnbYP7I6sAAg0UAAABvGdhc3AACAATAAIT
            TAAAAAxnbHlmVocNBQAAASwAAeEYaGRteI6hoLIAAgF4AAAFGGhlYWT9DdJS
            ADAAmACbADEA0ADQADUAAQABAEoAAQADAEoAVwCV`)