• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tarantool / luajit / 11774765987

11 Nov 2024 08:22AM UTC coverage: 92.931% (-0.008%) from 92.939%
11774765987

push

github

mandesero
tmp commit for ci check

5694 of 6033 branches covered (94.38%)

Branch coverage included in aggregate %.

21704 of 23449 relevant lines covered (92.56%)

2961521.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

65.41
/src/lj_clib.c
1
/*
2
** FFI C library loader.
3
** Copyright (C) 2005-2017 Mike Pall. See Copyright Notice in luajit.h
4
*/
5

6
#include "lj_obj.h"
7

8
#if LJ_HASFFI
9

10
#include "lj_gc.h"
11
#include "lj_err.h"
12
#include "lj_tab.h"
13
#include "lj_str.h"
14
#include "lj_udata.h"
15
#include "lj_ctype.h"
16
#include "lj_cconv.h"
17
#include "lj_cdata.h"
18
#include "lj_clib.h"
19
#include "lj_strfmt.h"
20

21
/* -- OS-specific functions ----------------------------------------------- */
22

23
#if LJ_TARGET_DLOPEN
24

25
#include <dlfcn.h>
26
#include <stdio.h>
27

28
#if defined(RTLD_DEFAULT)
29
#define CLIB_DEFHANDLE        RTLD_DEFAULT
30
#elif LJ_TARGET_OSX || LJ_TARGET_BSD
31
#define CLIB_DEFHANDLE        ((void *)(intptr_t)-2)
32
#else
33
#define CLIB_DEFHANDLE        NULL
34
#endif
35

36
LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
×
37
{
38
  lj_err_callermsg(L, dlerror());
×
39
}
40

41
#define clib_error(L, fmt, name)        clib_error_(L)
42

43
#if LJ_TARGET_CYGWIN
44
#define CLIB_SOPREFIX        "cyg"
45
#else
46
#define CLIB_SOPREFIX        "lib"
47
#endif
48

49
#if LJ_TARGET_OSX
50
#define CLIB_SOEXT        "%s.dylib"
51
#elif LJ_TARGET_CYGWIN
52
#define CLIB_SOEXT        "%s.dll"
53
#else
54
#define CLIB_SOEXT        "%s.so"
55
#endif
56

57
static const char *clib_extname(lua_State *L, const char *name)
11✔
58
{
59
  if (!strchr(name, '/')
11✔
60
#if LJ_TARGET_CYGWIN
61
      && !strchr(name, '\\')
62
#endif
63
     ) {
64
    if (!strchr(name, '.')) {
11✔
65
      name = lj_strfmt_pushf(L, CLIB_SOEXT, name);
11✔
66
      L->top--;
11✔
67
#if LJ_TARGET_CYGWIN
68
    } else {
69
      return name;
70
#endif
71
    }
72
    if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
11✔
73
          name[2] == CLIB_SOPREFIX[2])) {
6✔
74
      name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name);
5✔
75
      L->top--;
5✔
76
    }
77
  }
78
  return name;
11✔
79
}
80

81
/* Check for a recognized ld script line. */
82
static const char *clib_check_lds(lua_State *L, const char *buf)
×
83
{
84
  char *p, *e;
×
85
  if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
×
86
      (p = strchr(buf, '('))) {
×
87
    while (*++p == ' ') ;
×
88
    for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
×
89
    return strdata(lj_str_new(L, p, e-p));
×
90
  }
91
  return NULL;
92
}
93

94
/* Quick and dirty solution to resolve shared library name from ld script. */
95
static const char *clib_resolve_lds(lua_State *L, const char *name)
×
96
{
97
  FILE *fp = fopen(name, "r");
×
98
  const char *p = NULL;
×
99
  if (fp) {
×
100
    char buf[256];
×
101
    if (fgets(buf, sizeof(buf), fp)) {
×
102
      if (!strncmp(buf, "/* GNU ld script", 16)) {  /* ld script magic? */
×
103
        while (fgets(buf, sizeof(buf), fp)) {  /* Check all lines. */
×
104
          p = clib_check_lds(L, buf);
×
105
          if (p) break;
×
106
        }
107
      } else {  /* Otherwise check only the first line. */
108
        p = clib_check_lds(L, buf);
×
109
      }
110
    }
111
    fclose(fp);
×
112
  }
113
  return p;
×
114
}
115

116
static void *clib_loadlib(lua_State *L, const char *name, int global)
11✔
117
{
118
  void *h = dlopen(clib_extname(L, name),
22✔
119
                   RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
120
  if (!h) {
11✔
121
    const char *e, *err = dlerror();
1✔
122
    if (err && *err == '/' && (e = strchr(err, ':')) &&
1✔
123
        (name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
×
124
      h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
×
125
      if (h) return h;
×
126
      err = dlerror();
×
127
    }
128
    if (!err) err = "dlopen failed";
1✔
129
    lj_err_callermsg(L, err);
1✔
130
  }
131
  return h;
132
}
133

134
static void clib_unloadlib(CLibrary *cl)
216✔
135
{
136
  if (cl->handle && cl->handle != CLIB_DEFHANDLE)
216✔
137
    dlclose(cl->handle);
8✔
138
}
139

140
static void *clib_getsym(CLibrary *cl, const char *name)
156✔
141
{
142
  void *p = dlsym(cl->handle, name);
312✔
143
  return p;
156✔
144
}
145

146
#elif LJ_TARGET_WINDOWS
147

148
#define WIN32_LEAN_AND_MEAN
149
#include <windows.h>
150

151
#ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
152
#define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS        4
153
#define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT        2
154
BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
155
#endif
156

157
#define CLIB_DEFHANDLE        ((void *)-1)
158

159
/* Default libraries. */
160
enum {
161
  CLIB_HANDLE_EXE,
162
#if !LJ_TARGET_UWP
163
  CLIB_HANDLE_DLL,
164
  CLIB_HANDLE_CRT,
165
  CLIB_HANDLE_KERNEL32,
166
  CLIB_HANDLE_USER32,
167
  CLIB_HANDLE_GDI32,
168
#endif
169
  CLIB_HANDLE_MAX
170
};
171

172
static void *clib_def_handle[CLIB_HANDLE_MAX];
173

174
LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
175
                                            const char *name)
176
{
177
  DWORD err = GetLastError();
178
#if LJ_TARGET_XBOXONE
179
  wchar_t wbuf[128];
180
  char buf[128*2];
181
  if (!FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
182
                      NULL, err, 0, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL) ||
183
      !WideCharToMultiByte(CP_ACP, 0, wbuf, 128, buf, 128*2, NULL, NULL))
184
#else
185
  char buf[128];
186
  if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
187
                      NULL, err, 0, buf, sizeof(buf), NULL))
188
#endif
189
    buf[0] = '\0';
190
  lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, buf));
191
}
192

193
static int clib_needext(const char *s)
194
{
195
  while (*s) {
196
    if (*s == '/' || *s == '\\' || *s == '.') return 0;
197
    s++;
198
  }
199
  return 1;
200
}
201

202
static const char *clib_extname(lua_State *L, const char *name)
203
{
204
  if (clib_needext(name)) {
205
    name = lj_strfmt_pushf(L, "%s.dll", name);
206
    L->top--;
207
  }
208
  return name;
209
}
210

211
static void *clib_loadlib(lua_State *L, const char *name, int global)
212
{
213
  DWORD oldwerr = GetLastError();
214
  void *h = LJ_WIN_LOADLIBA(clib_extname(L, name));
215
  if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
216
  SetLastError(oldwerr);
217
  UNUSED(global);
218
  return h;
219
}
220

221
static void clib_unloadlib(CLibrary *cl)
222
{
223
  if (cl->handle == CLIB_DEFHANDLE) {
224
#if !LJ_TARGET_UWP
225
    MSize i;
226
    for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
227
      void *h = clib_def_handle[i];
228
      if (h) {
229
        clib_def_handle[i] = NULL;
230
        FreeLibrary((HINSTANCE)h);
231
      }
232
    }
233
#endif
234
  } else if (cl->handle) {
235
    FreeLibrary((HINSTANCE)cl->handle);
236
  }
237
}
238

239
#if LJ_TARGET_UWP
240
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
241
#endif
242

243
static void *clib_getsym(CLibrary *cl, const char *name)
244
{
245
  void *p = NULL;
246
  if (cl->handle == CLIB_DEFHANDLE) {  /* Search default libraries. */
247
    MSize i;
248
    for (i = 0; i < CLIB_HANDLE_MAX; i++) {
249
      HINSTANCE h = (HINSTANCE)clib_def_handle[i];
250
      if (!(void *)h) {  /* Resolve default library handles (once). */
251
#if LJ_TARGET_UWP
252
        h = (HINSTANCE)&__ImageBase;
253
#else
254
        switch (i) {
255
        case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
256
        case CLIB_HANDLE_DLL:
257
          GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
258
                             (const char *)clib_def_handle, &h);
259
          break;
260
        case CLIB_HANDLE_CRT:
261
          GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
262
                             (const char *)&_fmode, &h);
263
          break;
264
        case CLIB_HANDLE_KERNEL32: h = LJ_WIN_LOADLIBA("kernel32.dll"); break;
265
        case CLIB_HANDLE_USER32: h = LJ_WIN_LOADLIBA("user32.dll"); break;
266
        case CLIB_HANDLE_GDI32: h = LJ_WIN_LOADLIBA("gdi32.dll"); break;
267
        }
268
        if (!h) continue;
269
#endif
270
        clib_def_handle[i] = (void *)h;
271
      }
272
      p = (void *)GetProcAddress(h, name);
273
      if (p) break;
274
    }
275
  } else {
276
    p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
277
  }
278
  return p;
279
}
280

281
#else
282

283
#define CLIB_DEFHANDLE        NULL
284

285
LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
286
                                            const char *name)
287
{
288
  lj_err_callermsg(L, lj_strfmt_pushf(L, fmt, name, "no support for this OS"));
289
}
290

291
static void *clib_loadlib(lua_State *L, const char *name, int global)
292
{
293
  lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
294
  UNUSED(name); UNUSED(global);
295
  return NULL;
296
}
297

298
static void clib_unloadlib(CLibrary *cl)
299
{
300
  UNUSED(cl);
301
}
302

303
static void *clib_getsym(CLibrary *cl, const char *name)
304
{
305
  UNUSED(cl); UNUSED(name);
306
  return NULL;
307
}
308

309
#endif
310

311
/* -- C library indexing -------------------------------------------------- */
312

313
#if LJ_TARGET_X86 && LJ_ABI_WIN
314
/* Compute argument size for fastcall/stdcall functions. */
315
static CTSize clib_func_argsize(CTState *cts, CType *ct)
316
{
317
  CTSize n = 0;
318
  while (ct->sib) {
319
    CType *d;
320
    ct = ctype_get(cts, ct->sib);
321
    if (ctype_isfield(ct->info)) {
322
      d = ctype_rawchild(cts, ct);
323
      n += ((d->size + 3) & ~3);
324
    }
325
  }
326
  return n;
327
}
328
#endif
329

330
/* Get redirected or mangled external symbol. */
331
static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
156✔
332
{
333
  if (ct->sib) {
156✔
334
    CType *ctf = ctype_get(cts, ct->sib);
135✔
335
    if (ctype_isxattrib(ctf->info, CTA_REDIR))
135✔
336
      return strdata(gco2str(gcref(ctf->name)));
19✔
337
  }
338
  return strdata(name);
137✔
339
}
340

341
/* Index a C library by name. */
342
TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
66,504✔
343
{
344
  TValue *tv = lj_tab_setstr(L, cl->cache, name);
66,504✔
345
  if (LJ_UNLIKELY(tvisnil(tv))) {
66,504✔
346
    CTState *cts = ctype_cts(L);
156✔
347
    CType *ct;
156✔
348
    CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
156✔
349
    if (!id)
156✔
350
      lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
×
351
    if (ctype_isconstval(ct->info)) {
156✔
352
      CType *ctt = ctype_child(cts, ct);
×
353
      lj_assertCTS(ctype_isinteger(ctt->info) && ctt->size <= 4,
×
354
                   "only 32 bit const supported");  /* NYI */
355
      if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
×
356
        setnumV(tv, (lua_Number)(uint32_t)ct->size);
×
357
      else
358
        setintV(tv, (int32_t)ct->size);
×
359
    } else {
360
      const char *sym = clib_extsym(cts, ct, name);
156✔
361
#if LJ_TARGET_WINDOWS
362
      DWORD oldwerr = GetLastError();
363
#endif
364
      void *p = clib_getsym(cl, sym);
156✔
365
      GCcdata *cd;
156✔
366
      lj_assertCTS(ctype_isfunc(ct->info) || ctype_isextern(ct->info),
156✔
367
                   "unexpected ctype %08x in clib", ct->info);
368
#if LJ_TARGET_X86 && LJ_ABI_WIN
369
      /* Retry with decorated name for fastcall/stdcall functions. */
370
      if (!p && ctype_isfunc(ct->info)) {
371
        CTInfo cconv = ctype_cconv(ct->info);
372
        if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
373
          CTSize sz = clib_func_argsize(cts, ct);
374
          const char *symd = lj_strfmt_pushf(L,
375
                               cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
376
                               sym, sz);
377
          L->top--;
378
          p = clib_getsym(cl, symd);
379
        }
380
      }
381
#endif
382
      if (!p)
156✔
383
        clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
×
384
#if LJ_TARGET_WINDOWS
385
      SetLastError(oldwerr);
386
#endif
387
      cd = lj_cdata_new(cts, id, CTSIZE_PTR);
156✔
388
      *(void **)cdataptr(cd) = p;
156✔
389
      setcdataV(L, tv, cd);
156✔
390
      lj_gc_anybarriert(L, cl->cache);
156✔
391
    }
392
  }
393
  return tv;
66,504✔
394
}
395

396
/* -- C library management ------------------------------------------------ */
397

398
/* Create a new CLibrary object and push it on the stack. */
399
static CLibrary *clib_new(lua_State *L, GCtab *mt)
222✔
400
{
401
  GCtab *t = lj_tab_new(L, 0, 0);
222✔
402
  GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
222✔
403
  CLibrary *cl = (CLibrary *)uddata(ud);
222✔
404
  cl->cache = t;
222✔
405
  ud->udtype = UDTYPE_FFI_CLIB;
222✔
406
  /* NOBARRIER: The GCudata is new (marked white). */
407
  setgcref(ud->metatable, obj2gco(mt));
222✔
408
  setudataV(L, L->top++, ud);
222✔
409
  return cl;
222✔
410
}
411

412
/* Load a C library. */
413
void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
11✔
414
{
415
  void *handle = clib_loadlib(L, strdata(name), global);
11✔
416
  CLibrary *cl = clib_new(L, mt);
10✔
417
  cl->handle = handle;
10✔
418
}
10✔
419

420
/* Unload a C library. */
421
void lj_clib_unload(CLibrary *cl)
216✔
422
{
423
  clib_unloadlib(cl);
216✔
424
  cl->handle = NULL;
216✔
425
}
216✔
426

427
/* Create the default C library object. */
428
void lj_clib_default(lua_State *L, GCtab *mt)
212✔
429
{
430
  CLibrary *cl = clib_new(L, mt);
212✔
431
  cl->handle = CLIB_DEFHANDLE;
212✔
432
}
212✔
433

434
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc