Skip to content

Large stack size of yyParser::yy_reduce in debug builds #78

Description

@ignatz

Maybe you're aware of this already...

TL;DR: the sum of local variables in yy_reduce is larger than 1MB in debug builds. Which means that trivial parses will fail automatically for debug builds on some systems (e.g. Windows).

Context

I'm using sqlite3-parser and got a report by someone building on Windows that their default stack size of 1MB isn't enough. I don't have Windows and I found this quite curious but was able to reproduce by limiting stack size. I found that yyParser::yy_reduce was the culprit.

$ ulimit -S -s 1024
$ cargo run --example sql_cmd "CREATE TABLE _procedure(name text primary key, type text, body text)"
...
thread 'main' has overflowed its stack
0x0000555555599f11 in sqlite3_parser::parser::parse::yyParser::yy_reduce (self=<error reading variable: Cannot access memory at address 0x526>,
    yyruleno=<error reading variable: Cannot access memory at address 0x7fffffef760e>, yy_look_ahead=0, yy_lookahead_token=0x55555569c088 <log::MAX_LOG_LEVEL_FILTER>)
    at target/debug/build/sqlite3-parser-afeaa46f3a33d80e/out/parse.rs:4169
4169        fn yy_reduce(
(gdb) bt
#0  0x0000555555599f11 in sqlite3_parser::parser::parse::yyParser::yy_reduce (self=<error reading variable: Cannot access memory at address 0x526>,
    yyruleno=<error reading variable: Cannot access memory at address 0x7fffffef760e>, yy_look_ahead=0, yy_lookahead_token=0x55555569c088 <log::MAX_LOG_LEVEL_FILTER>)
    at target/debug/build/sqlite3-parser-afeaa46f3a33d80e/out/parse.rs:4169
#1  0x00005555555c68ba in sqlite3_parser::parser::parse::yyParser::sqlite3Parser (self=0x7fffffffc2d8, yymajor=sqlite3_parser::dialect::token::TokenType::TK_TABLE, yyminor=...)
    at target/debug/build/sqlite3-parser-afeaa46f3a33d80e/out/parse.rs:6571
#2  0x000055555558b542 in sqlite3_parser::lexer::sql::{impl#1}::next (self=0x7fffffffc2d8) at src/lexer/sql/mod.rs:205
#3  0x000055555556cd03 in sql_cmd::main () at examples/sql_cmd.rs:14

I looked at the generated code and was first a bit puzzled. It seems to be an instance of: https://internals.rust-lang.org/t/match-expressions-use-a-lot-of-stack-space-in-debug-mode/17173. (match expressions, ifs, local scopes... all the same). I was able to "verify" this behavior by removing stack allocations in unused branches until above program would eventually run. Feels like spooky action at a distance :)

Possible Solutions

  • My first instinct was to look for code-gen attributes to tell the rust compiler to always overlap local variables but didn't find anything. Hopefully, I'm just ignorant
  • Reduce local allocations, e.g. move branches into inlined functions, optimize stack size of AST types, ... 🤷
  • Ignore this issue

Curious to hear your thoughts

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions