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

tarantool / luajit / 8062004225

27 Feb 2024 08:41AM UTC coverage: 92.591% (-0.007%) from 92.598%
8062004225

push

github

Buristan
test: enable CLI-related lua-Harness tests back

Tarantool supports -b and -j options to use LuaJIT modules since the
commit bf8b76a4d ("lua: proxy -j and -b
flags"), so 241-standalone.t and 411-luajit.t tests in the lua-Harness
suite, disabled in the commit 39a4db500
("test: support Tarantool in lua-Harness"), can be enabled back.

However, the -O option is still not implemented in Tarantool, so the
related part in the 411-luajit.t test chunk is still disabled.

Follows up tarantool/tarantool#5541

Reviewed-by: Maxim Kokryashkin <m.kokryashkin@tarantool.org>
Reviewed-by: Sergey Kaplun <skaplun@tarantool.org>
Signed-off-by: Sergey Kaplun <skaplun@tarantool.org>
(cherry picked from commit e316cbf0d)

5657 of 6016 branches covered (94.03%)

Branch coverage included in aggregate %.

21588 of 23409 relevant lines covered (92.22%)

2817149.02 hits per line

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

61.83
/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)
10✔
58
{
59
  if (!strchr(name, '/')
10✔
60
#if LJ_TARGET_CYGWIN
61
      && !strchr(name, '\\')
62
#endif
63
     ) {
64
    if (!strchr(name, '.')) {
10✔
65
      name = lj_strfmt_pushf(L, CLIB_SOEXT, name);
10✔
66
      L->top--;
10✔
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] &&
10✔
73
          name[2] == CLIB_SOPREFIX[2])) {
6✔
74
      name = lj_strfmt_pushf(L, CLIB_SOPREFIX "%s", name);
4✔
75
      L->top--;
4✔
76
    }
77
  }
78
  return name;
10✔
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)
10✔
117
{
118
  void *h = dlopen(clib_extname(L, name),
20✔
119
                   RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
120
  if (!h) {
10✔
121
    const char *e, *err = dlerror();
×
122
    if (*err == '/' && (e = strchr(err, ':')) &&
×
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
    lj_err_callermsg(L, err);
×
129
  }
130
  return h;
131
}
132

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

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

145
#elif LJ_TARGET_WINDOWS
146

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

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

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

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

171
static void *clib_def_handle[CLIB_HANDLE_MAX];
172

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

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

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

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

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

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

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

280
#else
281

282
#define CLIB_DEFHANDLE        NULL
283

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

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

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

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

308
#endif
309

310
/* -- C library indexing -------------------------------------------------- */
311

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

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

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

395
/* -- C library management ------------------------------------------------ */
396

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

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

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

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

433
#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