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

Crash when upcasting complete Range to Enumerable #10518

Open
HertzDevil opened this issue Mar 18, 2021 · 4 comments
Open

Crash when upcasting complete Range to Enumerable #10518

HertzDevil opened this issue Mar 18, 2021 · 4 comments
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:generics topic:compiler:semantic

Comments

@HertzDevil
Copy link
Contributor

HertzDevil commented Mar 18, 2021

This was discovered while trying to recreate #4684 (comment). The following code started crashing since 0.36.0:

puts (0..0).as(Enumerable(Int32))
Invalid memory access (signal 11) at address 0x17600000176
[0x56058ea71366] print_backtrace at /usr/lib/crystal/exception/call_stack.cr:129:5
[0x56058ea64c4c] __crystal_sigfault_handler at /usr/lib/crystal/signal.cr:347:3
Program exited because of a segmentation fault (11)

0x176 is Range(Int32, Int32).crystal_instance_type_id.

Range(Int64, Int64), Range(UInt8, UInt8), and Range(UInt64, UInt64) have a similar issue, when the integer literals and the as argument are modified. On the other hand, Range(UInt32, UInt32) and Range(UInt16, UInt16) produce:

Module validation failed: Invalid bitcast
  %163 = bitcast %"Range(UInt32, UInt32)"* %10 to [4 x i32], !dbg !41
Load operand must be a pointer.
  %164 = load i32, [4 x i32] %163, !dbg !41
Call parameter type does not match function signature!
  %164 = load i32, [4 x i32] %163, !dbg !41
 [4 x i32]  call void @"*puts<Enumerable(UInt32)>:Nil"(i32 %164), !dbg !44
 (Exception)

Range(Int16, Int16) produces the following on e572b56:

BUG: trying to upcast Enumerable(Int16) <- Range(Int16, Int16) (Exception)
  from /crystal/src/compiler/crystal/codegen/cast.cr:672:5 in 'upcast_distinct'
  from /crystal/src/compiler/crystal/codegen/cast.cr:527:15 in 'upcast'
  from /crystal/src/compiler/crystal/codegen/codegen.cr:1219:19 in 'accept'
  from /crystal/src/compiler/crystal/codegen/codegen.cr:2184:7 in 'prepare_call_args_non_external'
  from /crystal/src/compiler/crystal/codegen/call.cr:57:7 in 'visit'
  from /crystal/src/compiler/crystal/syntax/visitor.cr:27:12 in 'accept'
  from /crystal/src/compiler/crystal/codegen/codegen.cr:619:9 in 'accept'
  from /crystal/src/compiler/crystal/codegen/codegen.cr:2149:7 in 'codegen'
  from /crystal/src/compiler/crystal/compiler.cr:172:16 in 'compile'
  from /crystal/src/compiler/crystal/command.cr:210:5 in 'run_command'
  from /crystal/src/compiler/crystal/command.cr:117:7 in 'run'
  from /crystal/src/compiler/crystal.cr:11:1 in '__crystal_main'
  from /crystal/src/crystal/main.cr:110:5 in 'main'
  from src/env/__libc_start_main.c:94:2 in 'libc_start_main_stage2'

Range(Int8, Int8) works. Floating-point ranges and ranges with mixed integer types also seem to work.

@HertzDevil HertzDevil added the kind:bug A bug in the code. Does not apply to documentation, specs, etc. label Mar 18, 2021
@HertzDevil
Copy link
Contributor Author

It seems Crystal::GenericModuleInstanceType#@including_types isn't properly populated when a generic type includes a generic module.

@HertzDevil
Copy link
Contributor Author

HertzDevil commented Mar 21, 2021

Reduced:

class Bar(T) # -> Range
end

module Foo(T) # -> Enumerable
end

def foo(x : Bar(Int64))
end

def foo(x : Bar(Int32))
end

class Bar(T)
  include Foo(T)
end

Bar(Int32).new.as(Foo(Int32)) # BUG: trying to upcast Foo(Int32) <- Bar(Int32) (Exception)

This happens because a bunch of Ranges are instantiated in Random#rand_range during overload ordering, but prelude.cr requires random.cr before range.cr. Swapping the order of the require statements fixes the standard library but not this reduced snippet. The include Foo(T) statement should do something similar to Type#after_initialize on any instantiations prior to the include.

Note that Range is defined internally by Crystal::Program, not by range.cr; if we move the include to above then nothing breaks.

@hutou
Copy link
Contributor

hutou commented Oct 6, 2022

A segmentation fault occurs when running the following code.
(note that Range printing is Ok outside class definition),
Is this the same issue ?

class Table(T)
  def initialize(@sources : Enumerable(T))
    p @sources
  end
end

data = 1..3
p data
puts "---"
t = Table.new(data)
1..3
---
Invalid memory access (signal 11) at address 0x0
[0x562ccbaa54b6] *Exception::CallStack::print_backtrace:Nil +118 in /home/hubert/.cache/crystal/crystal-run-test_range.tmp
[0x562ccba94ac6] ~procProc(Int32, Pointer(LibC::SiginfoT), Pointer(Void), Nil) +310 in /home/hubert/.cache/crystal/crystal-run-test_range.tmp
[0x7f4e78dfea00] ?? +139975012116992 in /usr/lib/libc.so.6
[0x562ccba9a7a7] *Exception::CallStack::new:Exception::CallStack +7 in /home/hubert/.cache/crystal/crystal-run-test_range.tmp
Program exited because of a segmentation fault (11)

@straight-shoota
Copy link
Member

Yes, that appears to be the same issue.
Thanks for reporting anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind:bug A bug in the code. Does not apply to documentation, specs, etc. topic:compiler:generics topic:compiler:semantic
Projects
None yet
Development

No branches or pull requests

3 participants