Mercurial
view third_party/luajit/src/lj_clib.c @ 279:b3b547563ec7
Add Google connector service and agent wiki
Implement the C/Seobeo Google Drive and Gmail connector with encrypted OAuth storage, Zenbu authentication, browser testing, AI tool discovery, chunked HTTP decoding, and Bazel coverage. Consolidate repository guidance into progressive wiki documentation and enforce arena-first allocation for new first-party C code.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: 84c338fd-0939-4bb3-b7f3-1062eb213e5d
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 22:22:36 -0700 |
| parents | 94705b5986b3 |
| children |
line wrap: on
line source
/* ** FFI C library loader. ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h */ #include "lj_obj.h" #if LJ_HASFFI #include "lj_gc.h" #include "lj_err.h" #include "lj_tab.h" #include "lj_str.h" #include "lj_udata.h" #include "lj_ctype.h" #include "lj_cconv.h" #include "lj_cdata.h" #include "lj_clib.h" #include "lj_strfmt.h" /* -- OS-specific functions ----------------------------------------------- */ #if LJ_TARGET_DLOPEN #include <dlfcn.h> #include <stdio.h> #if defined(RTLD_DEFAULT) && !defined(NO_RTLD_DEFAULT) #define CLIB_DEFHANDLE RTLD_DEFAULT #elif LJ_TARGET_OSX || LJ_TARGET_BSD #define CLIB_DEFHANDLE ((void *)(intptr_t)-2) #else #define CLIB_DEFHANDLE NULL #endif LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L) { lj_err_callermsg(L, dlerror()); } #define clib_error(L, fmt, name) clib_error_(L) #if LJ_TARGET_CYGWIN #define CLIB_SOPREFIX "cyg" #else #define CLIB_SOPREFIX "lib" #endif #if LJ_TARGET_OSX #define CLIB_SOEXT "%s.dylib" #elif LJ_TARGET_CYGWIN #define CLIB_SOEXT "%s.dll" #else #define CLIB_SOEXT "%s.so" #endif static const char *clib_extname(lua_State *L, const char *name) { if (!strchr(name, '/') #if LJ_TARGET_CYGWIN && !strchr(name, '\\') #endif ) { if (!strchr(name, '.')) { name = lj_strfmt_pushf(L, CLIB_SOEXT, name); L->top--; #if LJ_TARGET_CYGWIN } else { return name; #endif } if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] && name[2] == CLIB_SOPREFIX[2])) { name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name); L->top--; } } return name; } /* Check for a recognized ld script line. */ static const char *clib_check_lds(lua_State *L, const char *buf) { char *p, *e; if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) && (p = strchr(buf, '('))) { while (*++p == ' ') ; for (e = p; *e && *e != ' ' && *e != ')'; e++) ; return strdata(lj_str_new(L, p, e-p)); } return NULL; } /* Quick and dirty solution to resolve shared library name from ld script. */ static const char *clib_resolve_lds(lua_State *L, const char *name) { FILE *fp = fopen(name, "r"); const char *p = NULL; if (fp) { char buf[256]; if (fgets(buf, sizeof(buf), fp)) { if (!strncmp(buf, "/* GNU ld script", 16)) { /* ld script magic? */ while (fgets(buf, sizeof(buf), fp)) { /* Check all lines. */ p = clib_check_lds(L, buf); if (p) break; } } else { /* Otherwise check only the first line. */ p = clib_check_lds(L, buf); } } fclose(fp); } return p; } static void *clib_loadlib(lua_State *L, const char *name, int global) { void *h = dlopen(clib_extname(L, name), RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); if (!h) { const char *e, *err = dlerror(); if (err && *err == '/' && (e = strchr(err, ':')) && (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) { h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL)); if (h) return h; err = dlerror(); } if (!err) err = "dlopen failed"; lj_err_callermsg(L, err); } return h; } static void clib_unloadlib(CLibrary *cl) { if (cl->handle && cl->handle != CLIB_DEFHANDLE) dlclose(cl->handle); } static void *clib_getsym(CLibrary *cl, const char *name) { void *p = dlsym(cl->handle, name); return p; } #elif LJ_TARGET_WINDOWS #define WIN32_LEAN_AND_MEAN #include <windows.h> #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 4 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 2 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*); #endif #define CLIB_DEFHANDLE ((void *)-1) /* Default libraries. */ enum { CLIB_HANDLE_EXE, #if !LJ_TARGET_UWP CLIB_HANDLE_DLL, CLIB_HANDLE_CRT, CLIB_HANDLE_KERNEL32, CLIB_HANDLE_USER32, CLIB_HANDLE_GDI32, #endif CLIB_HANDLE_MAX }; static void *clib_def_handle[CLIB_HANDLE_MAX]; LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, const char *name) { DWORD err = GetLastError(); #if LJ_TARGET_XBOXONE wchar_t wbuf[128]; char buf[128*2]; if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) || !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL)) #else char buf[128]; if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buf, sizeof(buf), NULL)) #endif buf[0] = '\0'; lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf)); } static int clib_needext(const char *s) { while (*s) { if (*s == '/' || *s == '\\' || *s == '.') return 0; s++; } return 1; } static const char *clib_extname(lua_State *L, const char *name) { if (clib_needext(name)) { name = lj_strfmt_pushf(L, "%s.dll", name); L->top--; } return name; } static void *clib_loadlib(lua_State *L, const char *name, int global) { DWORD oldwerr = GetLastError(); void *h = LJ_WIN_LOADLIBA(clib_extname(L, name)); if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name); SetLastError(oldwerr); UNUSED(global); return h; } static void clib_unloadlib(CLibrary *cl) { if (cl->handle == CLIB_DEFHANDLE) { #if !LJ_TARGET_UWP MSize i; for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) { void *h = clib_def_handle[i]; if (h) { clib_def_handle[i] = NULL; FreeLibrary((HINSTANCE)h); } } #endif } else if (cl->handle) { FreeLibrary((HINSTANCE)cl->handle); } } #if LJ_TARGET_UWP EXTERN_C IMAGE_DOS_HEADER __ImageBase; #endif static void *clib_getsym(CLibrary *cl, const char *name) { void *p = NULL; if (cl->handle == CLIB_DEFHANDLE) { /* Search default libraries. */ MSize i; for (i = 0; i < CLIB_HANDLE_MAX; i++) { HINSTANCE h = (HINSTANCE)clib_def_handle[i]; if (!(void *)h) { /* Resolve default library handles (once). */ #if LJ_TARGET_UWP h = (HINSTANCE)&__ImageBase; #else switch (i) { case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break; case CLIB_HANDLE_DLL: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)clib_def_handle, &h); break; case CLIB_HANDLE_CRT: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (const char *)&_fmode, &h); break; case CLIB_HANDLE_KERNEL32: h = LJ_WIN_LOADLIBA("kernel32.dll"); break; case CLIB_HANDLE_USER32: h = LJ_WIN_LOADLIBA("user32.dll"); break; case CLIB_HANDLE_GDI32: h = LJ_WIN_LOADLIBA("gdi32.dll"); break; } if (!h) continue; #endif clib_def_handle[i] = (void *)h; } p = (void *)GetProcAddress(h, name); if (p) break; } } else { p = (void *)GetProcAddress((HINSTANCE)cl->handle, name); } return p; } #else #define CLIB_DEFHANDLE NULL LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt, const char *name) { lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS")); } static void *clib_loadlib(lua_State *L, const char *name, int global) { lj_err_callermsg(L, "no support for loading dynamic libraries for this OS"); UNUSED(name); UNUSED(global); return NULL; } static void clib_unloadlib(CLibrary *cl) { UNUSED(cl); } static void *clib_getsym(CLibrary *cl, const char *name) { UNUSED(cl); UNUSED(name); return NULL; } #endif /* -- C library indexing -------------------------------------------------- */ #if LJ_TARGET_X86 && LJ_ABI_WIN /* Compute argument size for fastcall/stdcall functions. */ static CTSize clib_func_argsize(CTState *cts, CType *ct) { CTSize n = 0; while (ct->sib) { CType *d; ct = ctype_get(cts, ct->sib); if (ctype_isfield(ct->info)) { d = ctype_rawchild(cts, ct); n += ((d->size + 3) & ~3); } } return n; } #endif /* Get redirected or mangled external symbol. */ static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name) { if (ct->sib) { CType *ctf = ctype_get(cts, ct->sib); if (ctype_isxattrib(ctf->info, CTA_REDIR)) return strdata(gco2str(gcref(ctf->name))); } return strdata(name); } /* Index a C library by name. */ TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name) { TValue *tv = lj_tab_setstr(L, cl->cache, name); if (LJ_UNLIKELY(tvisnil(tv))) { CTState *cts = ctype_cts(L); CType *ct; CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX); if (!id) lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name)); if (ctype_isconstval(ct->info)) { CType *ctt = ctype_child(cts, ct); lj_assertCTS(ctype_isinteger(ctt->info) && ctt->size <= 4, "only 32 bit const supported"); /* NYI */ if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0) setnumV(tv, (lua_Number)(uint32_t)ct->size); else setintV(tv, (int32_t)ct->size); } else { const char *sym = clib_extsym(cts, ct, name); #if LJ_TARGET_WINDOWS DWORD oldwerr = GetLastError(); #endif void *p = clib_getsym(cl, sym); GCcdata *cd; lj_assertCTS(ctype_isfunc(ct->info) || ctype_isextern(ct->info), "unexpected ctype %08x in clib", ct->info); #if LJ_TARGET_X86 && LJ_ABI_WIN /* Retry with decorated name for fastcall/stdcall functions. */ if (!p && ctype_isfunc(ct->info)) { CTInfo cconv = ctype_cconv(ct->info); if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) { CTSize sz = clib_func_argsize(cts, ct); const char *symd = lj_strfmt_pushf(L, cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d", sym, sz); L->top--; p = clib_getsym(cl, symd); } } #endif if (!p) clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym); #if LJ_TARGET_WINDOWS SetLastError(oldwerr); #endif cd = lj_cdata_new(cts, id, CTSIZE_PTR); *(void **)cdataptr(cd) = p; setcdataV(L, tv, cd); lj_gc_anybarriert(L, cl->cache); } } return tv; } /* -- C library management ------------------------------------------------ */ /* Create a new CLibrary object and push it on the stack. */ static CLibrary *clib_new(lua_State *L, GCtab *mt) { GCtab *t = lj_tab_new(L, 0, 0); GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t); CLibrary *cl = (CLibrary *)uddata(ud); cl->cache = t; ud->udtype = UDTYPE_FFI_CLIB; /* NOBARRIER: The GCudata is new (marked white). */ setgcref(ud->metatable, obj2gco(mt)); setudataV(L, L->top++, ud); return cl; } /* Load a C library. */ void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global) { void *handle = clib_loadlib(L, strdata(name), global); CLibrary *cl = clib_new(L, mt); cl->handle = handle; } /* Unload a C library. */ void lj_clib_unload(CLibrary *cl) { clib_unloadlib(cl); cl->handle = NULL; } /* Create the default C library object. */ void lj_clib_default(lua_State *L, GCtab *mt) { CLibrary *cl = clib_new(L, mt); cl->handle = CLIB_DEFHANDLE; } #endif