From 1a3ee5a8a18d3c1b7db54f3b4875e1dda9a0769f Mon Sep 17 00:00:00 2001 From: lihongyan Date: Fri, 7 Aug 2026 17:11:26 +0800 Subject: [PATCH] Fix tcc.load(): home_path variable, pcall handle, metatype idempotency Three bugs in tcc.load() made it unusable with a home_path and made repeated calls crash: 1. tcc.home_path was assigned the undefined variable `tccdir` instead of the `home_path` parameter, silently discarding the provided path. 2. clib = pcall(ffi.load(...)) stored the *boolean* success flag into tcc.clib instead of the library handle, so tcc.clib.tcc_new() failed with 'cannot convert bool to struct TCCState *'. 3. ffi.metatype("TCCState", ...) was called unconditionally on every load; the second call raises 'cannot change a protected metatable'. Guarded with pcall so tcc.load() is idempotent. Also fixed tcc.new(): the body referenced `tcc.tccdir` (undefined) and the parameter `addpaths` (typo, missing underscore), so the home path setup branch never ran. --- tcc.lua | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tcc.lua b/tcc.lua index a6e43d7..0188803 100644 --- a/tcc.lua +++ b/tcc.lua @@ -48,7 +48,7 @@ tcc.clib = nil --local tcc = require("tcc").load("tcc", "/lib/tcc") function tcc.load(lib, home_path) if home_path then - tcc.home_path = tccdir + tcc.home_path = home_path else tcc.home_path = os.getenv("CONFIG_TCCDIR") or tcc.home_path end @@ -78,11 +78,16 @@ function tcc.load(lib, home_path) int tcc_relocate(TCCState *s1, void *ptr); void *tcc_get_symbol(TCCState *s, const char *name); ]]) - ffi.metatype("TCCState", tcc.State) + -- ffi.metatype fails on the second call: once a metatype is set it becomes + -- protected and cannot be changed ("cannot change a protected metatable"). + -- Guard it so tcc.load() is idempotent and can be called more than once + -- (e.g. from several modules or after a failed first load). + pcall(ffi.metatype, "TCCState", tcc.State) local clib if tcc.home_path then - clib = pcall(ffi.load(("%s/%s"):format(tcc.home_path, lib))) + local ok_load, lib_handle = pcall(ffi.load, ("%s/%s"):format(tcc.home_path, lib)) + clib = ok_load and lib_handle or nil end if not clib then clib = ffi.load(lib) @@ -102,10 +107,10 @@ end function tcc.new(add_paths) local state = tcc.clib.tcc_new() ffi.gc(state, tcc.State.__gc) - if addpaths ~= false and tcc.tccdir then - state:set_home_path(tcc.tccdir) - state:add_sysinclude_path(tcc.tccdir .. "/include") - state:add_library_path(tcc.tccdir .. "/lib") + if add_paths ~= false and tcc.home_path then + state:set_home_path(tcc.home_path) + state:add_sysinclude_path(tcc.home_path .. "/include") + state:add_library_path(tcc.home_path .. "/lib") end return state end