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

Same code involving Tuple upcast produces different results in release mode #13411

Open
HertzDevil opened this issue Apr 28, 2023 · 1 comment

Comments

@HertzDevil
Copy link
Contributor

The following:

class String
  def to_unsafe
    pointerof(@c)
  end
end

lib LibC
  fun printf(fmt : UInt8*, ...) : Int32
  fun exit(status : Int32) : NoReturn
  $environ : Char**
end

struct Stop
  def foo
    LibC.printf("0\n".to_unsafe)
  end
end

struct Tuple(*T)
  def foo
    LibC.printf("1\n".to_unsafe)
  end
end

struct Iter
  def initialize(@proc : (-> ({Int32, Int32} | Stop)) | (-> {Int32, Int32}))
  end

  def next
    @proc.call
  end
end

class Foo
  def initialize(@iterator : Iter)
  end
end

iterator = Iter.new( ->{ Stop.new.as(Stop | {Int32, Int32}) } )
x = Foo.new(iterator)
y = LibC.environ ? x.@iterator.next : Stop.new.as(Stop | {Int32, Bool | Int32})
y.foo

prints 0 in non-release builds and 1 in release builds. A higher-level reproduction is:

# does not terminate
[{true}].each.chain([{1}].each).each { |v| p v }
# {true}
# {1}
# {-2071293984}
# {-2071293984}
# {-2071293984}
# {-2071293984}
# ...

Here the type of the #chain'ed iterator's #next features a similar Tuple upcast.

It is broken since Crystal 1.6.2, which is also the version that switched from LLVM 10 to 13. I suspect the difference in behavior is a consequence of reaching an unreachable instruction, but so far I have no clue why LLVM thinks that it is possible.

@straight-shoota
Copy link
Member

I've submitted #13412 with a mitigation for the immediate effect in Iterator#each.

Iterator.chain is not affected. Doing the same (or rather similar) operation with that method works fine.

Iterator.chain({[{true}].each, [{1}].each}).each { |v| p v }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants