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

tarantool / luajit / 7262987147

19 Dec 2023 02:10PM UTC coverage: 88.225% (-0.4%) from 88.616%
7262987147

push

github

fckxorg
test: add tests for debugging extensions

This patch adds tests for LuaJIT debugging
extensions for lldb and gdb.

5336 of 5969 branches covered (0.0%)

Branch coverage included in aggregate %.

20475 of 23287 relevant lines covered (87.92%)

1285545.26 hits per line

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

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

6
#define lib_ffi_c
7
#define LUA_LIB
8

9
#include <errno.h>
10

11
#include "lua.h"
12
#include "lauxlib.h"
13
#include "lualib.h"
14

15
#include "lj_obj.h"
16

17
#if LJ_HASFFI
18

19
#include "lj_gc.h"
20
#include "lj_err.h"
21
#include "lj_str.h"
22
#include "lj_tab.h"
23
#include "lj_meta.h"
24
#include "lj_ctype.h"
25
#include "lj_cparse.h"
26
#include "lj_cdata.h"
27
#include "lj_cconv.h"
28
#include "lj_carith.h"
29
#include "lj_ccall.h"
30
#include "lj_ccallback.h"
31
#include "lj_clib.h"
32
#include "lj_strfmt.h"
33
#include "lj_ff.h"
34
#include "lj_lib.h"
35

36
/* -- C type checks ------------------------------------------------------- */
37

38
/* Check first argument for a C type and returns its ID. */
39
static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
443,782✔
40
{
41
  TValue *o = L->base;
443,782✔
42
  if (!(o < L->top)) {
443,782✔
43
  err_argtype:
×
44
    lj_err_argtype(L, 1, "C type");
×
45
  }
46
  if (tvisstr(o)) {  /* Parse an abstract C type declaration. */
443,782✔
47
    GCstr *s = strV(o);
441,544✔
48
    CPState cp;
441,544✔
49
    int errcode;
441,544✔
50
    cp.L = L;
441,544✔
51
    cp.cts = cts;
441,544✔
52
    cp.srcname = strdata(s);
441,544✔
53
    cp.p = strdata(s);
441,544✔
54
    cp.param = param;
441,544✔
55
    cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
441,544✔
56
    errcode = lj_cparse(&cp);
441,544✔
57
    if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
441,544✔
58
    return cp.val.id;
441,544✔
59
  } else {
60
    GCcdata *cd;
2,238✔
61
    if (!tviscdata(o)) goto err_argtype;
2,238✔
62
    if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
2,238✔
63
    cd = cdataV(o);
2,238✔
64
    return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
2,238✔
65
  }
66
}
67

68
/* Check argument for C data and return it. */
69
static GCcdata *ffi_checkcdata(lua_State *L, int narg)
44,938✔
70
{
71
  TValue *o = L->base + narg-1;
44,938✔
72
  if (!(o < L->top && tviscdata(o)))
44,938✔
73
    lj_err_argt(L, narg, LUA_TCDATA);
×
74
  return cdataV(o);
44,938✔
75
}
76

77
/* Convert argument to C pointer. */
78
static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
786✔
79
{
80
  CTState *cts = ctype_cts(L);
786✔
81
  TValue *o = L->base + narg-1;
786✔
82
  void *p;
786✔
83
  if (o >= L->top)
786✔
84
    lj_err_arg(L, narg, LJ_ERR_NOVAL);
×
85
  lj_cconv_ct_tv(cts, ctype_get(cts, id), (uint8_t *)&p, o, CCF_ARG(narg));
786✔
86
  return p;
786✔
87
}
88

89
/* Convert argument to int32_t. */
90
static int32_t ffi_checkint(lua_State *L, int narg)
45,253✔
91
{
92
  CTState *cts = ctype_cts(L);
45,253✔
93
  TValue *o = L->base + narg-1;
45,253✔
94
  int32_t i;
45,253✔
95
  if (o >= L->top)
45,253✔
96
    lj_err_arg(L, narg, LJ_ERR_NOVAL);
×
97
  lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
45,253✔
98
                 CCF_ARG(narg));
45,253✔
99
  return i;
45,253✔
100
}
101

102
/* -- C type metamethods -------------------------------------------------- */
103

104
#define LJLIB_MODULE_ffi_meta
105

106
/* Handle ctype __index/__newindex metamethods. */
107
static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
1✔
108
{
109
  CTypeID id = ctype_typeid(cts, ct);
1✔
110
  cTValue *tv = lj_ctype_meta(cts, id, mm);
1✔
111
  TValue *base = L->base;
1✔
112
  if (!tv) {
1✔
113
    const char *s;
1✔
114
  err_index:
1✔
115
    s = strdata(lj_ctype_repr(L, id, NULL));
1✔
116
    if (tvisstr(L->base+1)) {
1✔
117
      lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
1✔
118
    } else {
119
      const char *key = tviscdata(L->base+1) ?
×
120
        strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) :
×
121
        lj_typename(L->base+1);
×
122
      lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key);
×
123
    }
124
  }
125
  if (!tvisfunc(tv)) {
×
126
    if (mm == MM_index) {
×
127
      cTValue *o = lj_meta_tget(L, tv, base+1);
×
128
      if (o) {
×
129
        if (tvisnil(o)) goto err_index;
×
130
        copyTV(L, L->top-1, o);
×
131
        return 1;
×
132
      }
133
    } else {
134
      TValue *o = lj_meta_tset(L, tv, base+1);
×
135
      if (o) {
×
136
        copyTV(L, o, base+2);
×
137
        return 0;
×
138
      }
139
    }
140
    copyTV(L, base, L->top);
×
141
    tv = L->top-1-LJ_FR2;
×
142
  }
143
  return lj_meta_tailcall(L, tv);
×
144
}
145

146
LJLIB_CF(ffi_meta___index)        LJLIB_REC(cdata_index 0)
407,412✔
147
{
148
  CTState *cts = ctype_cts(L);
407,412✔
149
  CTInfo qual = 0;
407,412✔
150
  CType *ct;
407,412✔
151
  uint8_t *p;
407,412✔
152
  TValue *o = L->base;
407,412✔
153
  if (!(o+1 < L->top && tviscdata(o)))  /* Also checks for presence of key. */
407,412✔
154
    lj_err_argt(L, 1, LUA_TCDATA);
×
155
  ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
407,412✔
156
  if ((qual & 1))
407,412✔
157
    return ffi_index_meta(L, cts, ct, MM_index);
1✔
158
  if (lj_cdata_get(cts, ct, L->top-1, p))
407,411✔
159
    lj_gc_check(L);
3,526✔
160
  return 1;
161
}
162

163
LJLIB_CF(ffi_meta___newindex)        LJLIB_REC(cdata_index 1)
5,548✔
164
{
165
  CTState *cts = ctype_cts(L);
5,548✔
166
  CTInfo qual = 0;
5,548✔
167
  CType *ct;
5,548✔
168
  uint8_t *p;
5,548✔
169
  TValue *o = L->base;
5,548✔
170
  if (!(o+2 < L->top && tviscdata(o)))  /* Also checks for key and value. */
5,548✔
171
    lj_err_argt(L, 1, LUA_TCDATA);
×
172
  ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
5,548✔
173
  if ((qual & 1)) {
5,548✔
174
    if ((qual & CTF_CONST))
×
175
      lj_err_caller(L, LJ_ERR_FFI_WRCONST);
×
176
    return ffi_index_meta(L, cts, ct, MM_newindex);
×
177
  }
178
  lj_cdata_set(cts, ct, p, o+2, qual);
5,548✔
179
  return 0;
5,548✔
180
}
181

182
/* Common handler for cdata arithmetic. */
183
static int ffi_arith(lua_State *L)
1,672,550✔
184
{
185
  MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
1,672,550✔
186
  return lj_carith_op(L, mm);
1,672,550✔
187
}
188

189
/* The following functions must be in contiguous ORDER MM. */
190
LJLIB_CF(ffi_meta___eq)                LJLIB_REC(cdata_arith MM_eq)
43,850✔
191
{
192
  return ffi_arith(L);
43,850✔
193
}
194

195
LJLIB_CF(ffi_meta___len)        LJLIB_REC(cdata_arith MM_len)
×
196
{
197
  return ffi_arith(L);
×
198
}
199

200
LJLIB_CF(ffi_meta___lt)                LJLIB_REC(cdata_arith MM_lt)
69✔
201
{
202
  return ffi_arith(L);
69✔
203
}
204

205
LJLIB_CF(ffi_meta___le)                LJLIB_REC(cdata_arith MM_le)
439,298✔
206
{
207
  return ffi_arith(L);
439,298✔
208
}
209

210
LJLIB_CF(ffi_meta___concat)        LJLIB_REC(cdata_arith MM_concat)
1✔
211
{
212
  return ffi_arith(L);
1✔
213
}
214

215
/* Forward declaration. */
216
static int lj_cf_ffi_new(lua_State *L);
217

218
LJLIB_CF(ffi_meta___call)        LJLIB_REC(cdata_call)
44,896✔
219
{
220
  CTState *cts = ctype_cts(L);
44,896✔
221
  GCcdata *cd = ffi_checkcdata(L, 1);
44,896✔
222
  CTypeID id = cd->ctypeid;
44,896✔
223
  CType *ct;
44,896✔
224
  cTValue *tv;
44,896✔
225
  MMS mm = MM_call;
44,896✔
226
  if (cd->ctypeid == CTID_CTYPEID) {
44,896✔
227
    id = *(CTypeID *)cdataptr(cd);
1,044✔
228
    mm = MM_new;
1,044✔
229
  } else {
230
    int ret = lj_ccall_func(L, cd);
43,852✔
231
    if (ret >= 0)
43,850✔
232
      return ret;
233
  }
234
  /* Handle ctype __call/__new metamethod. */
235
  ct = ctype_raw(cts, id);
1,044✔
236
  if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
1,044✔
237
  tv = lj_ctype_meta(cts, id, mm);
1,044✔
238
  if (tv)
1,044✔
239
    return lj_meta_tailcall(L, tv);
×
240
  else if (mm == MM_call)
1,044✔
241
    lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
×
242
  return lj_cf_ffi_new(L);
1,044✔
243
}
244

245
LJLIB_CF(ffi_meta___add)        LJLIB_REC(cdata_arith MM_add)
397,594✔
246
{
247
  return ffi_arith(L);
397,594✔
248
}
249

250
LJLIB_CF(ffi_meta___sub)        LJLIB_REC(cdata_arith MM_sub)
439,909✔
251
{
252
  return ffi_arith(L);
439,909✔
253
}
254

255
LJLIB_CF(ffi_meta___mul)        LJLIB_REC(cdata_arith MM_mul)
351,828✔
256
{
257
  return ffi_arith(L);
351,828✔
258
}
259

260
LJLIB_CF(ffi_meta___div)        LJLIB_REC(cdata_arith MM_div)
1✔
261
{
262
  return ffi_arith(L);
1✔
263
}
264

265
LJLIB_CF(ffi_meta___mod)        LJLIB_REC(cdata_arith MM_mod)
×
266
{
267
  return ffi_arith(L);
×
268
}
269

270
LJLIB_CF(ffi_meta___pow)        LJLIB_REC(cdata_arith MM_pow)
×
271
{
272
  return ffi_arith(L);
×
273
}
274

275
LJLIB_CF(ffi_meta___unm)        LJLIB_REC(cdata_arith MM_unm)
×
276
{
277
  return ffi_arith(L);
×
278
}
279
/* End of contiguous ORDER MM. */
280

281
LJLIB_CF(ffi_meta___tostring)
22✔
282
{
283
  GCcdata *cd = ffi_checkcdata(L, 1);
22✔
284
  const char *msg = "cdata<%s>: %p";
22✔
285
  CTypeID id = cd->ctypeid;
22✔
286
  void *p = cdataptr(cd);
22✔
287
  if (id == CTID_CTYPEID) {
22✔
288
    msg = "ctype<%s>";
5✔
289
    id = *(CTypeID *)p;
5✔
290
  } else {
291
    CTState *cts = ctype_cts(L);
17✔
292
    CType *ct = ctype_raw(cts, id);
17✔
293
    if (ctype_isref(ct->info)) {
17✔
294
      p = *(void **)p;
×
295
      ct = ctype_rawchild(cts, ct);
×
296
    }
297
    if (ctype_iscomplex(ct->info)) {
17✔
298
      setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
8✔
299
      goto checkgc;
8✔
300
    } else if (ct->size == 8 && ctype_isinteger(ct->info)) {
9✔
301
      setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
8✔
302
                                               (ct->info & CTF_UNSIGNED)));
8✔
303
      goto checkgc;
8✔
304
    } else if (ctype_isfunc(ct->info)) {
1✔
305
      p = *(void **)p;
×
306
    } else if (ctype_isenum(ct->info)) {
1✔
307
      msg = "cdata<%s>: %d";
×
308
      p = (void *)(uintptr_t)*(uint32_t **)p;
×
309
    } else {
310
      if (ctype_isptr(ct->info)) {
1✔
311
        p = cdata_getptr(p, ct->size);
×
312
        ct = ctype_rawchild(cts, ct);
×
313
      }
314
      if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
1✔
315
        /* Handle ctype __tostring metamethod. */
316
        cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
1✔
317
        if (tv)
1✔
318
          return lj_meta_tailcall(L, tv);
×
319
      }
320
    }
321
  }
322
  lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
6✔
323
checkgc:
22✔
324
  lj_gc_check(L);
22✔
325
  return 1;
326
}
327

328
static int ffi_pairs(lua_State *L, MMS mm)
×
329
{
330
  CTState *cts = ctype_cts(L);
×
331
  CTypeID id = ffi_checkcdata(L, 1)->ctypeid;
×
332
  CType *ct = ctype_raw(cts, id);
×
333
  cTValue *tv;
×
334
  if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
×
335
  tv = lj_ctype_meta(cts, id, mm);
×
336
  if (!tv)
×
337
    lj_err_callerv(L, LJ_ERR_FFI_BADMM, strdata(lj_ctype_repr(L, id, NULL)),
×
338
                   strdata(mmname_str(G(L), mm)));
×
339
  return lj_meta_tailcall(L, tv);
×
340
}
341

342
LJLIB_CF(ffi_meta___pairs)
×
343
{
344
  return ffi_pairs(L, MM_pairs);
×
345
}
346

347
LJLIB_CF(ffi_meta___ipairs)
×
348
{
349
  return ffi_pairs(L, MM_ipairs);
×
350
}
351

352
LJLIB_PUSH("ffi") LJLIB_SET(__metatable)
353

354
#include "lj_libdef.h"
355

356
/* -- C library metamethods ----------------------------------------------- */
357

358
#define LJLIB_MODULE_ffi_clib
359

360
/* Index C library by a name. */
361
static TValue *ffi_clib_index(lua_State *L)
43,741✔
362
{
363
  TValue *o = L->base;
43,741✔
364
  CLibrary *cl;
43,741✔
365
  if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
43,741✔
366
    lj_err_argt(L, 1, LUA_TUSERDATA);
×
367
  cl = (CLibrary *)uddata(udataV(o));
43,741✔
368
  if (!(o+1 < L->top && tvisstr(o+1)))
43,741✔
369
    lj_err_argt(L, 2, LUA_TSTRING);
×
370
  return lj_clib_index(L, cl, strV(o+1));
43,741✔
371
}
372

373
LJLIB_CF(ffi_clib___index)        LJLIB_REC(clib_index 1)
43,739✔
374
{
375
  TValue *tv = ffi_clib_index(L);
43,739✔
376
  if (tviscdata(tv)) {
43,739✔
377
    CTState *cts = ctype_cts(L);
43,739✔
378
    GCcdata *cd = cdataV(tv);
43,739✔
379
    CType *s = ctype_get(cts, cd->ctypeid);
43,739✔
380
    if (ctype_isextern(s->info)) {
43,739✔
381
      CTypeID sid = ctype_cid(s->info);
1✔
382
      void *sp = *(void **)cdataptr(cd);
1✔
383
      CType *ct = ctype_raw(cts, sid);
1✔
384
      if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
1✔
385
        lj_gc_check(L);
×
386
      return 1;
1✔
387
    }
388
  }
389
  copyTV(L, L->top-1, tv);
43,738✔
390
  return 1;
43,738✔
391
}
392

393
LJLIB_CF(ffi_clib___newindex)        LJLIB_REC(clib_index 0)
2✔
394
{
395
  TValue *tv = ffi_clib_index(L);
2✔
396
  TValue *o = L->base+2;
2✔
397
  if (o < L->top && tviscdata(tv)) {
2✔
398
    CTState *cts = ctype_cts(L);
2✔
399
    GCcdata *cd = cdataV(tv);
2✔
400
    CType *d = ctype_get(cts, cd->ctypeid);
2✔
401
    if (ctype_isextern(d->info)) {
2✔
402
      CTInfo qual = 0;
403
      for (;;) {  /* Skip attributes and collect qualifiers. */
2✔
404
        d = ctype_child(cts, d);
2✔
405
        if (!ctype_isattrib(d->info)) break;
2✔
406
        if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
×
407
      }
408
      if (!((d->info|qual) & CTF_CONST)) {
2✔
409
        lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
2✔
410
        return 0;
2✔
411
      }
412
    }
413
  }
414
  lj_err_caller(L, LJ_ERR_FFI_WRCONST);
×
415
  return 0;  /* unreachable */
416
}
417

418
LJLIB_CF(ffi_clib___gc)
109✔
419
{
420
  TValue *o = L->base;
109✔
421
  if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
109✔
422
    lj_clib_unload((CLibrary *)uddata(udataV(o)));
109✔
423
  return 0;
109✔
424
}
425

426
#include "lj_libdef.h"
427

428
/* -- Callback function metamethods --------------------------------------- */
429

430
#define LJLIB_MODULE_ffi_callback
431

432
static int ffi_callback_set(lua_State *L, GCfunc *fn)
×
433
{
434
  GCcdata *cd = ffi_checkcdata(L, 1);
×
435
  CTState *cts = ctype_cts(L);
×
436
  CType *ct = ctype_raw(cts, cd->ctypeid);
×
437
  if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
×
438
    MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
×
439
    if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
×
440
      GCtab *t = cts->miscmap;
×
441
      TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
×
442
      if (fn) {
×
443
        setfuncV(L, tv, fn);
×
444
        lj_gc_anybarriert(L, t);
×
445
      } else {
446
        setnilV(tv);
×
447
        cts->cb.cbid[slot] = 0;
×
448
        cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
×
449
      }
450
      return 0;
×
451
    }
452
  }
453
  lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
×
454
  return 0;
455
}
456

457
LJLIB_CF(ffi_callback_free)
×
458
{
459
  return ffi_callback_set(L, NULL);
×
460
}
461

462
LJLIB_CF(ffi_callback_set)
×
463
{
464
  GCfunc *fn = lj_lib_checkfunc(L, 2);
×
465
  return ffi_callback_set(L, fn);
×
466
}
467

468
LJLIB_PUSH(top-1) LJLIB_SET(__index)
469

470
#include "lj_libdef.h"
471

472
/* -- FFI library functions ----------------------------------------------- */
473

474
#define LJLIB_MODULE_ffi
475

476
LJLIB_CF(ffi_cdef)
25✔
477
{
478
  GCstr *s = lj_lib_checkstr(L, 1);
25✔
479
  CPState cp;
25✔
480
  int errcode;
25✔
481
  cp.L = L;
25✔
482
  cp.cts = ctype_cts(L);
25✔
483
  cp.srcname = strdata(s);
25✔
484
  cp.p = strdata(s);
25✔
485
  cp.param = L->base+1;
25✔
486
  cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
25✔
487
  errcode = lj_cparse(&cp);
25✔
488
  if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
25✔
489
  lj_gc_check(L);
25✔
490
  return 0;
25✔
491
}
492

493
LJLIB_CF(ffi_new)        LJLIB_REC(.)
442,230✔
494
{
495
  CTState *cts = ctype_cts(L);
442,230✔
496
  CTypeID id = ffi_checkctype(L, cts, NULL);
442,230✔
497
  CType *ct = ctype_raw(cts, id);
442,230✔
498
  CTSize sz;
442,230✔
499
  CTInfo info = lj_ctype_info(cts, id, &sz);
442,230✔
500
  TValue *o = L->base+1;
442,230✔
501
  GCcdata *cd;
442,230✔
502
  if ((info & CTF_VLA)) {
442,230✔
503
    o++;
479✔
504
    sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
479✔
505
  }
506
  if (sz == CTSIZE_INVALID)
442,230✔
507
    lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
×
508
  cd = lj_cdata_newx(cts, id, sz, info);
442,230✔
509
  setcdataV(L, o-1, cd);  /* Anchor the uninitialized cdata. */
442,230✔
510
  lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
442,230✔
511
                   o, (MSize)(L->top - o));  /* Initialize cdata. */
442,230✔
512
  if (ctype_isstruct(ct->info)) {
442,230✔
513
    /* Handle ctype __gc metamethod. Use the fast lookup here. */
514
    cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
787✔
515
    if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
787✔
516
      GCtab *t = cts->finalizer;
×
517
      if (gcref(t->metatable)) {
×
518
        /* Add to finalizer table, if still enabled. */
519
        copyTV(L, lj_tab_set(L, t, o-1), tv);
×
520
        lj_gc_anybarriert(L, t);
×
521
        cd->marked |= LJ_GC_CDATA_FIN;
×
522
      }
523
    }
524
  }
525
  L->top = o;  /* Only return the cdata itself. */
442,230✔
526
  lj_gc_check(L);
442,230✔
527
  return 1;
442,230✔
528
}
529

530
LJLIB_CF(ffi_cast)        LJLIB_REC(ffi_new)
566✔
531
{
532
  CTState *cts = ctype_cts(L);
566✔
533
  CTypeID id = ffi_checkctype(L, cts, NULL);
566✔
534
  CType *d = ctype_raw(cts, id);
566✔
535
  TValue *o = lj_lib_checkany(L, 2);
566✔
536
  L->top = o+1;  /* Make sure this is the last item on the stack. */
566✔
537
  if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
566✔
538
    lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
×
539
  if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) {
566✔
540
    GCcdata *cd = lj_cdata_new(cts, id, d->size);
566✔
541
    lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
566✔
542
    setcdataV(L, o, cd);
566✔
543
    lj_gc_check(L);
566✔
544
  }
545
  return 1;
566✔
546
}
547

548
LJLIB_CF(ffi_typeof)        LJLIB_REC(.)
101✔
549
{
550
  CTState *cts = ctype_cts(L);
101✔
551
  CTypeID id = ffi_checkctype(L, cts, L->base+1);
101✔
552
  GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
101✔
553
  *(CTypeID *)cdataptr(cd) = id;
101✔
554
  setcdataV(L, L->top-1, cd);
101✔
555
  lj_gc_check(L);
101✔
556
  return 1;
101✔
557
}
558

559
/* Internal and unsupported API. */
560
LJLIB_CF(ffi_typeinfo)
×
561
{
562
  CTState *cts = ctype_cts(L);
×
563
  CTypeID id = (CTypeID)ffi_checkint(L, 1);
×
564
  if (id > 0 && id < cts->top) {
×
565
    CType *ct = ctype_get(cts, id);
×
566
    GCtab *t;
×
567
    lua_createtable(L, 0, 4);  /* Increment hash size if fields are added. */
×
568
    t = tabV(L->top-1);
×
569
    setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "info")), (int32_t)ct->info);
×
570
    if (ct->size != CTSIZE_INVALID)
×
571
      setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "size")), (int32_t)ct->size);
×
572
    if (ct->sib)
×
573
      setintV(lj_tab_setstr(L, t, lj_str_newlit(L, "sib")), (int32_t)ct->sib);
×
574
    if (gcref(ct->name)) {
×
575
      GCstr *s = gco2str(gcref(ct->name));
×
576
      setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "name")), s);
×
577
    }
578
    lj_gc_check(L);
×
579
    return 1;
×
580
  }
581
  return 0;
582
}
583

584
LJLIB_CF(ffi_istype)        LJLIB_REC(.)
195✔
585
{
586
  CTState *cts = ctype_cts(L);
195✔
587
  CTypeID id1 = ffi_checkctype(L, cts, NULL);
195✔
588
  TValue *o = lj_lib_checkany(L, 2);
195✔
589
  int b = 0;
195✔
590
  if (tviscdata(o)) {
195✔
591
    GCcdata *cd = cdataV(o);
183✔
592
    CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) :
183✔
593
                                                cd->ctypeid;
594
    CType *ct1 = lj_ctype_rawref(cts, id1);
183✔
595
    CType *ct2 = lj_ctype_rawref(cts, id2);
183✔
596
    if (ct1 == ct2) {
183✔
597
      b = 1;
598
    } else if (ctype_type(ct1->info) == ctype_type(ct2->info) &&
26✔
599
               ct1->size == ct2->size) {
23✔
600
      if (ctype_ispointer(ct1->info))
15✔
601
        b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL);
8✔
602
      else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info))
7✔
603
        b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0);
6✔
604
    } else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) &&
11✔
605
               ct1 == ctype_rawchild(cts, ct2)) {
1✔
606
      b = 1;
1✔
607
    }
608
  }
609
  setboolV(L->top-1, b);
195✔
610
  setboolV(&G(L)->tmptv2, b);  /* Remember for trace recorder. */
195✔
611
  return 1;
195✔
612
}
613

614
LJLIB_CF(ffi_sizeof)        LJLIB_REC(ffi_xof FF_ffi_sizeof)
685✔
615
{
616
  CTState *cts = ctype_cts(L);
685✔
617
  CTypeID id = ffi_checkctype(L, cts, NULL);
685✔
618
  CTSize sz;
685✔
619
  if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
685✔
620
    sz = cdatavlen(cdataV(L->base));
311✔
621
  } else {
622
    CType *ct = lj_ctype_rawref(cts, id);
374✔
623
    if (ctype_isvltype(ct->info))
374✔
624
      sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
311✔
625
    else
626
      sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
63✔
627
    if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
374✔
628
      setnilV(L->top-1);
×
629
      return 1;
×
630
    }
631
  }
632
  setintV(L->top-1, (int32_t)sz);
685✔
633
  return 1;
685✔
634
}
635

636
LJLIB_CF(ffi_alignof)        LJLIB_REC(ffi_xof FF_ffi_alignof)
×
637
{
638
  CTState *cts = ctype_cts(L);
×
639
  CTypeID id = ffi_checkctype(L, cts, NULL);
×
640
  CTSize sz = 0;
×
641
  CTInfo info = lj_ctype_info(cts, id, &sz);
×
642
  setintV(L->top-1, 1 << ctype_align(info));
×
643
  return 1;
×
644
}
645

646
LJLIB_CF(ffi_offsetof)        LJLIB_REC(ffi_xof FF_ffi_offsetof)
3✔
647
{
648
  CTState *cts = ctype_cts(L);
3✔
649
  CTypeID id = ffi_checkctype(L, cts, NULL);
3✔
650
  GCstr *name = lj_lib_checkstr(L, 2);
3✔
651
  CType *ct = lj_ctype_rawref(cts, id);
3✔
652
  CTSize ofs;
3✔
653
  if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
3✔
654
    CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
3✔
655
    if (fct) {
3✔
656
      setintV(L->top-1, ofs);
3✔
657
      if (ctype_isfield(fct->info)) {
3✔
658
        return 1;
659
      } else if (ctype_isbitfield(fct->info)) {
×
660
        setintV(L->top++, ctype_bitpos(fct->info));
×
661
        setintV(L->top++, ctype_bitbsz(fct->info));
×
662
        return 3;
×
663
      }
664
    }
665
  }
666
  return 0;
667
}
668

669
LJLIB_CF(ffi_errno)        LJLIB_REC(.)
60✔
670
{
671
  int err = errno;
60✔
672
  if (L->top > L->base)
60✔
673
    errno = ffi_checkint(L, 1);
2✔
674
  setintV(L->top++, err);
60✔
675
  return 1;
60✔
676
}
677

678
LJLIB_CF(ffi_string)        LJLIB_REC(.)
43,920✔
679
{
680
  CTState *cts = ctype_cts(L);
43,920✔
681
  TValue *o = lj_lib_checkany(L, 1);
43,920✔
682
  const char *p;
43,920✔
683
  size_t len;
43,920✔
684
  if (o+1 < L->top && !tvisnil(o+1)) {
43,920✔
685
    len = (size_t)ffi_checkint(L, 2);
43,852✔
686
    lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o,
43,852✔
687
                   CCF_ARG(1));
688
  } else {
689
    lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o,
68✔
690
                   CCF_ARG(1));
691
    len = strlen(p);
68✔
692
  }
693
  L->top = o+1;  /* Make sure this is the last item on the stack. */
43,920✔
694
  setstrV(L, o, lj_str_new(L, p, len));
43,920✔
695
  lj_gc_check(L);
43,920✔
696
  return 1;
43,920✔
697
}
698

699
LJLIB_CF(ffi_copy)        LJLIB_REC(.)
299✔
700
{
701
  void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
299✔
702
  void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
299✔
703
  TValue *o = L->base+1;
299✔
704
  CTSize len;
299✔
705
  if (tvisstr(o) && o+1 >= L->top)
299✔
706
    len = strV(o)->len+1;  /* Copy Lua string including trailing '\0'. */
65✔
707
  else
708
    len = (CTSize)ffi_checkint(L, 3);
234✔
709
  memcpy(dp, sp, len);
299✔
710
  return 0;
299✔
711
}
712

713
LJLIB_CF(ffi_fill)        LJLIB_REC(.)
188✔
714
{
715
  void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
188✔
716
  CTSize len = (CTSize)ffi_checkint(L, 2);
188✔
717
  int32_t fill = 0;
188✔
718
  if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3);
188✔
719
  memset(dp, fill, len);
188✔
720
  return 0;
188✔
721
}
722

723
/* Test ABI string. */
724
LJLIB_CF(ffi_abi)        LJLIB_REC(.)
270✔
725
{
726
  GCstr *s = lj_lib_checkstr(L, 1);
270✔
727
  int b = lj_cparse_case(s,
269✔
728
#if LJ_64
729
    "\00564bit"
730
#else
731
    "\00532bit"
732
#endif
733
#if LJ_ARCH_HASFPU
734
    "\003fpu"
735
#endif
736
#if LJ_ABI_SOFTFP
737
    "\006softfp"
738
#else
739
    "\006hardfp"
740
#endif
741
#if LJ_ABI_EABI
742
    "\004eabi"
743
#endif
744
#if LJ_ABI_WIN
745
    "\003win"
746
#endif
747
#if LJ_TARGET_UWP
748
    "\003uwp"
749
#endif
750
#if LJ_LE
751
    "\002le"
752
#else
753
    "\002be"
754
#endif
755
#if LJ_GC64
756
    "\004gc64"
757
#endif
758
  ) >= 0;
269✔
759
  setboolV(L->top-1, b);
269✔
760
  setboolV(&G(L)->tmptv2, b);  /* Remember for trace recorder. */
269✔
761
  return 1;
269✔
762
}
763

764
LJLIB_PUSH(top-8) LJLIB_SET(!)  /* Store reference to miscmap table. */
765

766
LJLIB_CF(ffi_metatype)
2✔
767
{
768
  CTState *cts = ctype_cts(L);
2✔
769
  CTypeID id = ffi_checkctype(L, cts, NULL);
2✔
770
  GCtab *mt = lj_lib_checktab(L, 2);
2✔
771
  GCtab *t = cts->miscmap;
2✔
772
  CType *ct = ctype_get(cts, id);  /* Only allow raw types. */
2✔
773
  TValue *tv;
2✔
774
  GCcdata *cd;
2✔
775
  if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
2✔
776
        ctype_isvector(ct->info)))
×
777
    lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
×
778
  tv = lj_tab_setinth(L, t, -(int32_t)id);
2✔
779
  if (!tvisnil(tv))
2✔
780
    lj_err_caller(L, LJ_ERR_PROTMT);
×
781
  settabV(L, tv, mt);
2✔
782
  lj_gc_anybarriert(L, t);
2✔
783
  cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
2✔
784
  *(CTypeID *)cdataptr(cd) = id;
2✔
785
  setcdataV(L, L->top-1, cd);
2✔
786
  lj_gc_check(L);
2✔
787
  return 1;
2✔
788
}
789

790
LJLIB_PUSH(top-7) LJLIB_SET(!)  /* Store reference to finalizer table. */
791

792
LJLIB_CF(ffi_gc)        LJLIB_REC(.)
20✔
793
{
794
  GCcdata *cd = ffi_checkcdata(L, 1);
20✔
795
  TValue *fin = lj_lib_checkany(L, 2);
20✔
796
  CTState *cts = ctype_cts(L);
20✔
797
  CType *ct = ctype_raw(cts, cd->ctypeid);
20✔
798
  if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
20✔
799
        ctype_isrefarray(ct->info)))
×
800
    lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
×
801
  lj_cdata_setfin(L, cd, gcval(fin), itype(fin));
20✔
802
  L->top = L->base+1;  /* Pass through the cdata object. */
20✔
803
  return 1;
20✔
804
}
805

806
LJLIB_PUSH(top-5) LJLIB_SET(!)  /* Store clib metatable in func environment. */
807

808
LJLIB_CF(ffi_load)
7✔
809
{
810
  GCstr *name = lj_lib_checkstr(L, 1);
7✔
811
  int global = (L->base+1 < L->top && tvistruecond(L->base+1));
7✔
812
  lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
7✔
813
  return 1;
7✔
814
}
815

816
LJLIB_PUSH(top-4) LJLIB_SET(C)
817
LJLIB_PUSH(top-3) LJLIB_SET(os)
818
LJLIB_PUSH(top-2) LJLIB_SET(arch)
819

820
#include "lj_libdef.h"
821

822
/* ------------------------------------------------------------------------ */
823

824
/* Create special weak-keyed finalizer table. */
825
static GCtab *ffi_finalizer(lua_State *L)
106✔
826
{
827
  /* NOBARRIER: The table is new (marked white). */
828
  GCtab *t = lj_tab_new(L, 0, 1);
106✔
829
  settabV(L, L->top++, t);
106✔
830
  setgcref(t->metatable, obj2gco(t));
106✔
831
  setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
106✔
832
          lj_str_newlit(L, "k"));
833
  t->nomm = (uint8_t)(~(1u<<MM_mode));
106✔
834
  return t;
106✔
835
}
836

837
/* Register FFI module as loaded. */
838
static void ffi_register_module(lua_State *L)
106✔
839
{
840
  cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
106✔
841
  if (tmp && tvistab(tmp)) {
106✔
842
    GCtab *t = tabV(tmp);
106✔
843
    copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
106✔
844
    lj_gc_anybarriert(L, t);
106✔
845
  }
846
}
106✔
847

848
LUALIB_API int luaopen_ffi(lua_State *L)
106✔
849
{
850
  CTState *cts = lj_ctype_init(L);
106✔
851
  settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
106✔
852
  cts->finalizer = ffi_finalizer(L);
106✔
853
  LJ_LIB_REG(L, NULL, ffi_meta);
106✔
854
  /* NOBARRIER: basemt is a GC root. */
855
  setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
106✔
856
  LJ_LIB_REG(L, NULL, ffi_clib);
106✔
857
  LJ_LIB_REG(L, NULL, ffi_callback);
106✔
858
  /* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
859
  settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
106✔
860
  L->top--;
106✔
861
  lj_clib_default(L, tabV(L->top-1));  /* Create ffi.C default namespace. */
106✔
862
  lua_pushliteral(L, LJ_OS_NAME);
106✔
863
  lua_pushliteral(L, LJ_ARCH_NAME);
106✔
864
  LJ_LIB_REG(L, NULL, ffi);  /* Note: no global "ffi" created! */
106✔
865
  ffi_register_module(L);
106✔
866
  return 1;
106✔
867
}
868

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