Search code examples
jsonsegmentation-faultjson-deserializationnim-langnorm

Jsony newHook has `SIGSEGV: Illegal storage access. (Attempt to read from nil?)` when deserializing into ref-objects


I am writing a web-application and am deserializing via jsony into norm-model-object types. Norm-model-types are always ref objects. Somehow my code which is very similar to the default example in jsony's github documentation does not compile. Instead I receive the error SIGSEGV: Illegal storage access. (Attempt to read from nil?).

See here my code sample

import std/[typetraits, times]
import norm/[pragmas, model]
import jsony

const OUTPUT_TIME_FORMAT* = "yyyy-MM-dd'T'HH:mm:ss'.'ffffff'Z'"
type Character* {.tableName: "wikientries_character".} = ref object of Model
    name*: string
    creation_datetime*: DateTime
    update_datetime*: DateTime

proc parseHook*(s: string, i: var int, v: var DateTime) =
    ##[ jsony-hook that is automatically called to convert a json-string to datetime
    
    ``s``: The full JSON string that needs to be serialized. Your type may only be a part of this
    ``i``: The index on the JSON string where the next section of it starts that needs to be serialized here
    ``v``: The variable to fill with a proper value]##
    var str: string
    s.parseHook(i, str)
    v = parse(s, OUTPUT_TIME_FORMAT, utc())

proc newHook*(entry: var Character) =
  let currentDateTime: DateTime = now()
  entry.creation_datetime = currentDateTime # <-- This line is listed as the reason for the sigsev
  entry.update_datetime = currentDateTime
  entry.name = ""
  
var input = """ {"name":"Test"} """

let c = input.fromJson(Character)

I don't understand what the issue appears to be here, as the jsony-example on its github page looks pretty similar:

type
  Foo5 = object
    visible: string
    id: string
proc newHook*(foo: var Foo5) =
  # Populates the object before its fully deserialized.
  foo.visible = "yes"

var s = """{"id":"123"}"""
var v = s.fromJson(Foo5)
doAssert v.id == "123"
doAssert v.visible == "yes"

How can I fix this?


Solution

  • The answer lies in the fact that norm-object-types are ref objects, not normal (value) objects (Thanks to ElegantBeef, Rika and Yardanico from the nim-discord to point this out)! If you do not explicitly 'create' a ref-type at one point, the memory for it is never allocated since the code doesn't do the memory allocation for you unlike with value types!

    Therefore, you must initialize/create a ref-object first before you can use it, and Jsony does not take over initialization for you!

    The correct way to write the above newHook thus looks like this:

    proc newHook*(entry: var Character) =
      entry = new(Character)
      let currentDateTime: DateTime = now()
      entry.creation_datetime = currentDateTime
      entry.update_datetime = currentDateTime
      entry.name = ""