crystal-lang / crystal

The Crystal Programming Language

Home Page:https://crystal-lang.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect recursive expression crashes the compiler

BrucePerens opened this issue · comments

I have an incorrect recursive expression that crashes the compiler.
Compiler version:

Crystal 1.12.1 [4cea10199] (2024-04-11)

LLVM: 15.0.7
Default target: x86_64-unknown-linux-gnu

Code:

struct Point
  x : Float64

  def x=(v)
    self.x = v # This is incorrect recursion.
  end

  def initialize(@x = 0.0)
  end
end

a = Array(Point).new(1)

p = (a.to_unsafe + 0).value.x = 

Result:

bruce@bruce16:~$ crystal foo.cr
Stack overflow (e.g., infinite or very deep recursion)
[0x55f6003b1bf6] *Exception::CallStack::print_backtrace:Nil +118 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x55f6003a06e6] ~procProc(Int32, Pointer(LibC::SiginfoT), Pointer(Void), Nil) +310 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x7f8a7f784510] ?? +140232820802832 in /lib/x86_64-linux-gnu/libc.so.6
[0x55f600453dd1] *Point#x=<Int32>:NoReturn +1 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x55f600453dd6] ?? +94515054853590 in /home/bruce/.cache/crystal/crystal-run-foo.tmp (523510 times)
[0x55f600390c8a] ?? +94515054054538 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x55f600454d06] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x55f600454c7a] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +58 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x55f60039e1a6] main +6 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x7f8a7f76f6ca] ?? +140232820717258 in /lib/x86_64-linux-gnu/libc.so.6
[0x7f8a7f76f785] __libc_start_main +133 in /lib/x86_64-linux-gnu/libc.so.6
[0x55f600390771] _start +33 in /home/bruce/.cache/crystal/crystal-run-foo.tmp
[0x0] ???

What is your expected result? To me it seems the crash is somewhat legitimate given the setter for x is calling the setter for x. Maybe you intended to do this instead?

def x=(v)
  @x = v
end

EDIT: Or even shorter:

def x=(@x); end

Or just:

setter x

I am just assuming the compiler should never crash no matter what
stupid thing I do.

Indeed, it should not.

But it's not the compiler crashing here. It's your program which runs out of memory due to stack exhaustion.
You can verify by separating building and running the exectuable. The compiler build step should complete just fine.

Oops. OK, closing the report.