Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow crash when chaining multiple decode.field calls #4287

Open
occlu opened this issue Feb 28, 2025 · 8 comments
Open

Stack overflow crash when chaining multiple decode.field calls #4287

occlu opened this issue Feb 28, 2025 · 8 comments
Labels
help wanted Contributions encouraged priority:high

Comments

@occlu
Copy link

occlu commented Feb 28, 2025

Gleam: 1.8.1
OS: Windows 11
Target: Both

Issue description

When chaining approximately 50 use x <- decode.field, gleam run crashes with the following error :

thread 'main' has overflowed its stack

Additionally, I am using VSCode, and saving the file causes the Gleam Language Server to crash immediately.

Steps to reproduce

  • Use the attached testing.gleam.txt file, which reliably reproduces the crash (requires simplifile and gleam_json libs).
  • The decoding succeeds if a certain number of decode.field calls are commented out.
  • The JSON file being decoded : characters.json.
@GearsDatapacks
Copy link
Member

I can't seem to reproduce this issue. With the same files as you, it decodes successfully when I run it (tried on both targets, with Gleam 1.8.1 and nightly, Ubuntu)

@occlu
Copy link
Author

occlu commented Feb 28, 2025

I can't seem to reproduce this issue on Ubuntu either.

@GearsDatapacks
Copy link
Member

Interesting. Can anyone else test on mac or windows to see what happens?

@lpil
Copy link
Member

lpil commented Feb 28, 2025

Oh dear! I wonder what this is.

It's not possible to produce that error message on Erlang as it has a stack of unbounded size. The nearest thing you can get is process heap size limits being hit, or OOM, but neither produces an error like that. Could you try again and include the errors each target+runtime pair produces please 🙏

@lpil
Copy link
Member

lpil commented Feb 28, 2025

@occlu shared this with me on discord:

gleam build -t javascript
  Compiling testing

thread 'main' has overflowed its stack

It's the compiler overflowing and not the compiled code! I had incorrectly assumed otherwise.

I presume that our stack usage grows with each use, and on Windows the stack size must be smaller.

@lpil lpil added help wanted Contributions encouraged priority:high labels Feb 28, 2025
@GearsDatapacks
Copy link
Member

Ah yes that makes sense. I wonder what we can do about this

@PgBiel
Copy link
Contributor

PgBiel commented Mar 2, 2025

FWIW, Typst uses stacker on each evaluated function call: https://github.com/typst/typst/blob/cfb3b1a2709107f0f06f89ea25cabc939cec15e5/crates/typst-eval/src/call.rs#L67-L68

Could be a last resort for highly recursive algorithms.

@Enderchief
Copy link
Contributor

Interesting. Can anyone else test on mac or windows to see what happens?

I can reproduce this. Windows 10 / VSCode / Gleam 1.8.1 freshly installed using Scoop.
As soon as I open VSCode, the LSP crashes. Below is a minimal example.

import gleam/dynamic/decode

pub fn main() {
  use n1 <- decode.field("n1", decode.string)
  use n2 <- decode.field("n2", decode.string)
  use n3 <- decode.field("n3", decode.string)
  use n4 <- decode.field("n4", decode.string)
  use n5 <- decode.field("n5", decode.string)
  use n6 <- decode.field("n6", decode.string)
  use n7 <- decode.field("n7", decode.string)
  use n8 <- decode.field("n8", decode.string)
  use n9 <- decode.field("n9", decode.string)
  use n10 <- decode.field("n10", decode.string)
  use n11 <- decode.field("n11", decode.string)
  use n12 <- decode.field("n12", decode.string)
  use n13 <- decode.field("n13", decode.string)
  use n14 <- decode.field("n14", decode.string)
  use n15 <- decode.field("n15", decode.string)
  use n16 <- decode.field("n16", decode.string)
  use n17 <- decode.field("n17", decode.string)
  use n18 <- decode.field("n18", decode.string)
  use n19 <- decode.field("n19", decode.string)
  use n20 <- decode.field("n20", decode.string)
  use n21 <- decode.field("n21", decode.string)
  use n22 <- decode.field("n22", decode.string)
  use n23 <- decode.field("n23", decode.string)
  use n24 <- decode.field("n24", decode.string)
  use n25 <- decode.field("n25", decode.string)
  use n26 <- decode.field("n26", decode.string)
  use n27 <- decode.field("n27", decode.string)
  use n28 <- decode.field("n28", decode.string)
  use n29 <- decode.field("n29", decode.string)
  use n30 <- decode.field("n30", decode.string)
  use n31 <- decode.field("n31", decode.string)
  use n32 <- decode.field("n32", decode.string)
  use n33 <- decode.field("n33", decode.string)
  use n34 <- decode.field("n34", decode.string)
  use n35 <- decode.field("n35", decode.string)
  use n36 <- decode.field("n36", decode.string)
  use n37 <- decode.field("n37", decode.string)
  use n38 <- decode.field("n38", decode.string)
  use n39 <- decode.field("n39", decode.string)
  use n40 <- decode.field("n40", decode.string)
  use n41 <- decode.field("n41", decode.string)
  use n42 <- decode.field("n42", decode.string)
  use n43 <- decode.field("n43", decode.string)
  use n44 <- decode.field("n44", decode.string)
  use n45 <- decode.field("n45", decode.string)
  use n46 <- decode.field("n46", decode.string)
  use n47 <- decode.field("n47", decode.string)
  use n48 <- decode.field("n48", decode.string)
  use n49 <- decode.field("n49", decode.string)
  use n50 <- decode.field("n50", decode.string)
  use n51 <- decode.field("n51", decode.string)
  use n52 <- decode.field("n52", decode.string)
  use n53 <- decode.field("n53", decode.string)
  use n54 <- decode.field("n54", decode.string)
  // crashes when next line is uncommented
  // use n55 <- decode.field("n55", decode.string)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Contributions encouraged priority:high
Projects
None yet
Development

No branches or pull requests

5 participants