Crystal: Including JSON::Serializable or YAML::Serializable lets you invoke a default constructor

Created on 29 Oct 2018  路  6Comments  路  Source: crystal-lang/crystal

https://play.crystal-lang.org/#/r/5dii

require "json"

class Foo
  include JSON::Serializable

  property name : String
end

pp Foo.new

Invalid memory access (signal 11) at address 0x4
[0x55679ffc5476] *CallStack::print_backtrace:Int32 +118
[0x55679ffb9b0d] __crystal_sigfault_handler +61
[0x7f56342143c0] ???
[0x55679ffc9e60] *String#chomp:String +352
[0x55679ffcb6f3] *String#pretty_print<PrettyPrint>:Nil +275
[0x5567a000496b] *Foo +1419
[0x5567a0004c95] *PrettyPrint::format<Foo, IO::FileDescriptor, Int32, String, Int32>:IO::FileDescriptor +117
[0x5567a0004c13] *PrettyPrint::format<Foo, IO::FileDescriptor, Int32>:IO::FileDescriptor +67
[0x55679ffb9b60] *pp<Foo>:Foo +32
[0x55679ffacaab] __crystal_main +1515
[0x5567a000b016] *Crystal::main_user_code<Int32, Pointer(Pointer(UInt8))>:Nil +6
[0x5567a000af79] *Crystal::main<Int32, Pointer(Pointer(UInt8))>:Int32 +41
[0x55679ffb7a66] main +6
[0x7f5633de1223] __libc_start_main +243
[0x55679ffac3ee] _start +46
[0x0] ???
bug compiler

Most helpful comment

I tried to debug this and I reduced it to this 馃檧

module Base
  def initialize(x)
  end
end

class Foo
  include Base
end

Foo.new # Works!

So it had nothing to do with JSON::Serializable and the {% @type %} rule, which works perfectly fine.

And I think I have a fix for this, but we'll see.

All 6 comments

Reduced:

require "json"

class Foo
  include JSON::Serializable

  property name : String
end

Foo.new.inspect

It's happening because of this line:

https://github.com/crystal-lang/crystal/blob/391785249f66aaf5929b787b29810aeb4af0e1e8/src/reference.cr#L69

because of the @{{ivar.id}}. When replacing the line with @{{ivar.id}}, it still happens.

And since the example is working without include JSON::Serializable and with assigning a value to name, it probably also has to do with this line:

https://github.com/crystal-lang/crystal/blob/391785249f66aaf5929b787b29810aeb4af0e1e8/src/json/serialization.cr#L138

or/and this line:

https://github.com/crystal-lang/crystal/blob/391785249f66aaf5929b787b29810aeb4af0e1e8/src/json/serialization.cr#L250

This is bug in compilation + JSON::Serializable magick. actually it should not compile.

hacks:

class Foo
  include JSON::Serializable

  property name : String = ""
end
pp Foo.new
class Foo
  include JSON::Serializable

  property name : String

  def initialize(@name)
  end
end
pp Foo.new("")

It's a bug in the compiler, I already mentioned it here

Oh. The invalid memory access can actually be fixed by replacing @{{ivar.id}}.inspect io in Reference#inspect by:

        {% if ivar.has_default_value? %}
          @{{ivar.id}}.inspect io
        {% else %}
          io << "nil"
        {% end %}

Kinda late, but I checked out that solution @r00ster91. It solves the problem if the ivar has a default value. But would cause the value to be skipped even if its set when it does _not_ have a default value.

require "json"

class Foo
  include JSON::Serializable

  property name : String
end

f = Foo.new
f.name = "jim"
f.inspect # => #<Foo:0x55ebe8e9af20 @name=nil>

I tried to debug this and I reduced it to this 馃檧

module Base
  def initialize(x)
  end
end

class Foo
  include Base
end

Foo.new # Works!

So it had nothing to do with JSON::Serializable and the {% @type %} rule, which works perfectly fine.

And I think I have a fix for this, but we'll see.

Was this page helpful?
0 / 5 - 0 ratings