crystal-lang / crystal

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

Backtraces involving blocks are missing information. #11878

Open yxhuvud opened 2 years ago

yxhuvud commented 2 years ago

Bug Report

Consider the following code:

def wat
  foo { huh }
end

def foo
  yield
end

def bar
  raise "the bar"
end

def huh
  bar
end

wat

This outputs:

Unhandled exception: the bar (Exception)
  from foo.cr:14:3 in 'huh'
  from foo.cr:2:9 in 'wat'
  from foo.cr:17:1 in '__crystal_main'
  from /usr/share/crystal/src/crystal/main.cr:115:5 in 'main_user_code'
  from /usr/share/crystal/src/crystal/main.cr:101:7 in 'main'
  from /usr/share/crystal/src/crystal/main.cr:127:3 in 'main'
  from /lib/x86_64-linux-gnu/libc.so.6 in '??'
  from /lib/x86_64-linux-gnu/libc.so.6 in '__libc_start_main'
  from /home/linus/.cache/crystal/crystal-run-foo.tmp in '_start'
  from ???

Here we can note that neither foo nor bar are present in the stack trace.

Compare to ruby output, which is more complete and helpful:

Traceback (most recent call last):
    5: from foo.cr:17:in `<main>'
    4: from foo.cr:2:in `wat'
    3: from foo.cr:6:in `foo'
    2: from foo.cr:2:in `block in wat'
    1: from foo.cr:14:in `huh'
foo.cr:10:in `bar': the bar (RuntimeError)
asterite commented 2 years ago

Right... the reason is that blocks are inlined, so there isn't a call at all.

If there's a way to tell LLVM to fake a stack trace element, then I think we might be able to do it. Otherwise, I don't think so.

yxhuvud commented 2 years ago

Well, that explains why row 2 from the ruby output (block in wat) isn't there, but does it also explain why foo and bar doesn't show up at all?

asterite commented 2 years ago

Ah, right... yeah, I think the bug is that bar doesn't show up. Backtraces have been working wrong since the beginning and they were never fixed. It's probably related to that.

foo doesn't show up because the call is inlined.

asterite commented 2 years ago

If you change it to this, bar appears 🤷

def wat
  foo { huh }
end

def foo
  yield
end

def bar
  a = 1
  raise "the bar"
end

def huh
  bar
end

# wat
bar

But that is unrelated to this issue (it reads "Back traces involving blocks are missing information" but this bar thing isn't related to blocks)

yxhuvud commented 2 years ago

foo doesn't show up because the call is inlined.

Oh, it inlines the whole of foo into wat?, not just the block into foo. Well, that makes it harder I suppose.

but this bar thing isn't related to blocks

Ah. Perhaps I should submit a separate issue for just that?

rdp commented 2 years ago

Possibly related discussion on inlined methods: https://github.com/crystal-lang/crystal/issues/10661