crystal-lang / crystal

The Crystal Programming Language
https://crystal-lang.org
Apache License 2.0
19.41k stars 1.62k forks source link

Using `crystal tool unreachable` creates a stack overflow #13879

Open crimson-knight opened 1 year ago

crimson-knight commented 1 year ago

Bug Report

I have a small binary app I decided to try the new unreachable tool on, but it appears to be crashing.

Here are the last 25 lines:

sethtucker@sethtucker my_secret_app % crystal tool unreachable src/my_secret_app.cr 2>&1 | head -n 25
Stack overflow (e.g., infinite or very deep recursion)
[0x100cf4db4] *Exception::CallStack::print_backtrace:Nil +36 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100cf4d58] ~procProc(Int32, Pointer(LibC::SiginfoT), Pointer(Void), Nil)@src/crystal/system/unix/signal.cr:131 +488 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x1a0eb2a24] _sigtramp +56 in /usr/lib/system/libsystem_platform.dylib
[0x100dd921c] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +2964 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100dd97bc] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +4404 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100dd99ac] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +4900 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100dd921c] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +2964 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100dd97bc] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +4404 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal
[0x100dd8708] *Crystal::ASTNode+@Crystal::ASTNode#accept<Crystal::UnreachableVisitor>:Nil +128 in /opt/homebrew/Cellar/crystal/1.10.0/bin/crystal (2 times)

My specs pass and my app is currently compiling and working as expected.

Crystal 1.10.0 (2023-10-09)

LLVM: 15.0.7
Default target: aarch64-apple-darwin22.5.0

I cannot share any of the code, but I'll see if I can recreate with another app that I can share.

straight-shoota commented 1 year ago

You could build the compiler in non-release mode, then the stack trace might give some more helpful insight.

straight-shoota commented 11 months ago

@crimson-knight Could you try #13922 to see if that fixes it?

HertzDevil commented 11 months ago

I found some more snippets that seem to get stuck forever:

require "compiler/crystal/syntax"

Crystal::Parser.new("").parse
Crystal::Parser.new("").invalid_internal_name?("")

Reduced:

def foo(x)
  {% begin %}
    case x
    when Int32
      case x
      when {{ (0..env("N").to_i).to_a.splat }}
      end
    end
  {% end %}
end

foo("")

This takes around 5 seconds when N=26, and roughly doubles in time for each extra clause. So there is definitely exponential behavior that is resolved by #13922

straight-shoota commented 4 days ago

@crimson-knight If you can still reproduce this issue, maybe you could try if #15065 resolves it?