Skip to content

Commit

Permalink
odict: fix ffi.new('void *') as a key
Browse files Browse the repository at this point in the history
The problem is found by @ochaton.
  • Loading branch information
Totktonada committed Mar 12, 2024
1 parent 6dbbd41 commit dd1a8e0
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
8 changes: 4 additions & 4 deletions algo/odict.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ local function gen(od, prev_key)

-- The previous key is nil only on the first call of the
-- generator function.
local id = prev_key == nil and 0 or ctx.key2id[prev_key]
local id = type(prev_key) == 'nil' and 0 or ctx.key2id[prev_key]
-- NB: This assert doesn't catch all the kinds of changes
-- during an iteration. It rather verifies a precondition
-- for the following cycle.
Expand All @@ -25,7 +25,7 @@ local function gen(od, prev_key)
-- id2key may contain a stalled entry, because __newindex
-- is not called on assignment of an existing field,
-- including assignment to nil.
if key ~= nil and od[key] ~= nil then
if type(key) ~= 'nil' and od[key] ~= nil then
return key, od[key]
end
end
Expand Down Expand Up @@ -93,11 +93,11 @@ local function reindex(od, ctx)
for id = 1, old_max_id do
local key = ctx.id2key[id]
-- Drop the given key-id pair from the key<->id mappings.
if key ~= nil then
if type(key) ~= 'nil' then
release(ctx, key)
end
-- Add the new key-id pair into the key<->id mappings.
if key ~= nil and od[key] ~= nil then
if type(key) ~= 'nil' and od[key] ~= nil then
track(ctx, key)
end
end
Expand Down
36 changes: 36 additions & 0 deletions test/004_odict_test.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ local t = require 'luatest' --[[@as luatest]]
local g = t.group('odict')

local fun = require 'fun'
local ffi = require 'ffi'
local odict = require 'algo.odict'

g.test_set_get = function()
Expand Down Expand Up @@ -117,6 +118,41 @@ g.test_pairs_delete_and_set = function()
})
end

-- Using cdata as a key is unusual, but it is legal in LuaJIT.
--
-- There is a potential pitfall: ffi.new('void *') == nil. Let's
-- verify that we handle such a key correctly.
g.test_null_as_key = function()
local od = odict.new()

local nulls = {
ffi.new('void *'),
ffi.new('void *'),
ffi.new('void *'),
}

od[nulls[1]] = 1
od[nulls[2]] = 2
od[nulls[3]] = 3

local res = {}
for k, v in odict.pairs(od) do
table.insert(res, {k, v})
end

-- It doesn't differentiate nulls.
t.assert_equals(res, {
{nulls[1], 1},
{nulls[2], 2},
{nulls[3], 3},
})

-- It does.
t.assert(rawequal(res[1][1], nulls[1]))
t.assert(rawequal(res[2][1], nulls[2]))
t.assert(rawequal(res[3][1], nulls[3]))
end

-- {{{ Helpers for reindexing test cases

-- Parse a range expressed like Python's slice operator.
Expand Down

0 comments on commit dd1a8e0

Please sign in to comment.