Files
neovim/src/nvim/generators/gen_keysets.lua
Arnout Engelen cb757f2663 build: make generated source files reproducible #21586
Problem:
Build is not reproducible, because generated source files (.c/.h/) are not
deterministic, mostly because Lua pairs() is unordered by design (for security).

https://github.com/LuaJIT/LuaJIT/issues/626#issuecomment-707005671
https://www.lua.org/manual/5.1/manual.html#pdf-next
> The order in which the indices are enumerated is not specified [...]
>
>> The hardening of the VM deliberately randomizes string hashes. This in
>> turn randomizes the iteration order of tables with string keys.

Solution:
- Update the code generation scripts to be deterministic.
    - That is only a partial solution: the exported function
      (funcs_metadata.generated.h) and ui event
      (ui_events_metadata.generated.h) metadata have some mpack'ed
      tables, which are not serialized deterministically.
    - As a workaround, introduce `PRG_GEN_LUA` cmake setting, so you can
      inject a modified build of luajit (with LUAJIT_SECURITY_PRN=0)
      that preserves table order.
    - Longer-term we should change the mpack'ed data structure so it no
      longer uses tables keyed by strings.

Closes #20124

Co-Authored-By: dundargoc <gocdundar@gmail.com>
Co-Authored-By: Arnout Engelen <arnout@bzzt.net>
2023-01-23 01:26:46 -08:00

81 lines
1.8 KiB
Lua

local nvimsrcdir = arg[1]
local shared_file = arg[2]
local funcs_file = arg[3]
local defs_file = arg[4]
_G.vim = loadfile(shared_file)()
if nvimsrcdir == '--help' then
print([[
Usage:
lua gen_keyset.lua TODOFIXUPDATETHIS
Will generate build/src/nvim/auto/keyset.generated.h with definition of functions
static const array.
]])
os.exit(0)
end
package.path = nvimsrcdir .. '/?.lua;' .. package.path
local hashy = require'generators.hashy'
local funcspipe = io.open(funcs_file, 'wb')
local defspipe = io.open(defs_file, 'wb')
local keysets = require'api.keysets'
local keywords = {
register = true;
default = true;
}
local function sanitize(key)
if keywords[key] then
return key .. "_"
end
return key
end
for _, v in ipairs(keysets) do
local name = v[1]
local keys = v[2]
local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx)
return name.."_table["..idx.."].str"
end)
defspipe:write("typedef struct {\n")
for _, key in ipairs(neworder) do
defspipe:write(" Object "..sanitize(key)..";\n")
end
defspipe:write("} KeyDict_"..name..";\n\n")
defspipe:write("extern KeySetLink "..name.."_table[];\n")
funcspipe:write("KeySetLink "..name.."_table[] = {\n")
for _, key in ipairs(neworder) do
funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..sanitize(key)..")},\n")
end
funcspipe:write(' {NULL, 0},\n')
funcspipe:write("};\n\n")
funcspipe:write(hashfun)
funcspipe:write([[
Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len)
{
int hash = ]]..name..[[_hash(str, len);
if (hash == -1) {
return NULL;
}
return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off);
}
]])
defspipe:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n")
end
funcspipe:close()
defspipe:close()