能否在Lua字节码字符串中调用loadstring,其中包含对C函数的引用?

我们正在使用Love2d Lua游戏引擎,它向Lua提供了一个图形API。我们正在尝试序列化一个包含游戏世界的所有保存游戏数据的巨大哈希表。此哈希表包括一些函数,其中一些函数调用了Love2d C函数。

为了序列化哈希表中的函数,我们使用string.dump,并用loadstring把它们加载回来。这对纯Lua函数非常有效,但是当我们尝试序列化然后加载使用包装的C函数调用的函数时,例如在Love2d API中的函数,loadstring会返回nil。

考虑以下通过Love2d的图形引擎将“hello,world”绘制到屏幕上的简单程序:

function love.load()
    draw = function()
        love.graphics.print('hello, world', 10, 10)
    end
end
function love.draw()
    draw()
end

我们想能够这样做:

function love.load()
    draw_before_serialize = function()
        love.graphics.print('hello, world', 10, 10)
    end

    out = io.open("serialized.lua", "wb")
    out:write('draw = load([[' .. string.dump(draw_before_serialize) .. ']])')
    out:close()

    require "serialized"
end
function love.draw()
    draw()
end

这样做会写入到磁盘上一个包含非编译Lua和Lua字节码混合在一起的Lua文件,看起来像这样:

draw = load([[^[LJ^A^@
       @main.lua2^@^@^B^@^B^@^D^E^B^B4^@^@^@%^A^A^@>^@^B^AG^@^A^@^Qhello, world
       print^A^A^A^B^@^@]])

这种方法对不调用C模块的Lua函数是有效的。我们认为这是问题所在,因为以下示例是有效的:

function love.load()
    draw_before_serialize = function()
        print('hello, world')
    end

    out = io.open("serialized.lua", "wb")
    out:write('draw = load([[' .. string.dump(draw_before_serialize) .. ']])')
    out:close()

    require "serialized"
end
function love.draw()
    draw()
end

它不是调用Love2d图形方法,而是在控制台上进行打印。

经过更多测试,我们很困惑地发现此示例是有效的:

function love.load()
    draw_before_serialize = function()
        love.graphics.print('hello, world', 10, 10)
    end

    draw = load(string.dump(draw_before_serialize))
end
function love.draw()
    draw()
end

在这里,我们实际上没有将函数写入磁盘,而是仅转储并立即将其加载回来。我们认为罪魁祸首可能是没有设置二进制写模式标志("wb")来编写数据,但由于我们在Linux上,此标志无效。

有什么想法?

点赞