kikito/inspect.lua

.\inspect.lua:235: attempt to compare number with nil

LuminescentMoon opened this issue · 1 comments

Full error:

luajit: .\inspect.lua:235: attempt to compare number with nil
stack traceback:
        .\inspect.lua:235: in function 'putTable'
        .\inspect.lua:292: in function 'putValue'
        .\inspect.lua:262: in function 'f'
        .\inspect.lua:197: in function 'down'
        .\inspect.lua:243: in function 'putTable'
        .\inspect.lua:292: in function 'putValue'
        .\inspect.lua:323: in function 'inspect'
        test.lua:35: in main chunk
        [C]: at 0x7ff64c532000

Code I used to produce this error:

local createShim
createShim = function(options)
  options = options or {}
  local shim = {}
  local shimMetaTable = {
    __call = options.callFunc or function() end,
    __index = function(t, k)
      local newShim = createShim(options)
      t[k] = newShim
      return newShim
    end
  }
  if options.isWeak then shimMetaTable.__mode = 'kv' end
  setmetatable(shim, shimMetaTable)
  return shim
end

local shim = createShim({ isWeak = true })

local function getRandomLetter()
    return string.char(math.random(97, 122))
end

local inspect = require('inspect')

while true do
  local reference = shim
  for i = 1, math.random(1, 50) do
    local keyString = ''
    for i = 1, math.random(1, 20) do
      keyString = keyString .. getRandomLetter()
    end
    reference = reference[keyString]
  end
  print(inspect(shim))
end

Fixed by putting a guard in line 235:

----
  elseif self.level >= self.depth then
    self:puts('{...}')
  else
    -- BEFORE: if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
    if self.tableAppearances[t] and self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end

    local nonSequentialKeys = getNonSequentialKeys(t)
    local length            = rawlen(t)
----

It seems that a GC cycle runs before call to putValue. GC cleans out all shims inside t, because they are stored only in weak tables - parent shims and tableAppearances. Therefore, t[k] in self:putValue(t[k]) triggers __index shim metamethod, which returns a new table, not in tableAppearences, and that causes the error later inside putValue. A proper fix would be to not make tableAppearances weak, so that parts of inspected table can't be collected during inspection.