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

tarantool / luajit / 9873466312

10 Jul 2024 11:36AM UTC coverage: 92.772% (+0.03%) from 92.745%
9873466312

push

github

ligurio
FFI: Turn FFI finalizer table into a proper GC root.

Reported by Sergey Bronnikov.

(cherry picked from commit f5affaa6c)

Previous patch fixes the problem partially because the introduced
GC root may not exist at the start phase of the GC cycle. In that
case, the cdata finalizer table will be collected at the end of
the cycle. Access to the cdata finalizer table exhibits heap use
after free. The patch turns the finalizer table into a proper
GC root. Note, that finalizer table is created on the
initialization of the main Lua State instead of loading the FFI
library.

Sergey Bronnikov:
* added the description and the tests for the problem

Part of tarantool/tarantool#10199

5674 of 6025 branches covered (94.17%)

Branch coverage included in aggregate %.

26 of 26 new or added lines in 5 files covered. (100.0%)

18 existing lines in 5 files now uncovered.

21653 of 23431 relevant lines covered (92.41%)

2941091.57 hits per line

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

92.51
/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)
609,517✔
40
{
41
  TValue *o = L->base;
609,517✔
42
  if (!(o < L->top)) {
609,517✔
43
  err_argtype:
×
44
    lj_err_argtype(L, 1, "C type");
×
45
  }
46
  if (tvisstr(o)) {  /* Parse an abstract C type declaration. */
609,517✔
47
    GCstr *s = strV(o);
604,336✔
48
    CPState cp;
604,336✔
49
    int errcode;
604,336✔
50
    cp.L = L;
604,336✔
51
    cp.cts = cts;
604,336✔
52
    cp.srcname = strdata(s);
604,336✔
53
    cp.p = strdata(s);
604,336✔
54
    cp.param = param;
604,336✔
55
    cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
604,336✔
56
    errcode = lj_cparse(&cp);
604,336✔
57
    if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
604,336✔
58
    return cp.val.id;
604,260✔
59
  } else {
60
    GCcdata *cd;
5,181✔
61
    if (!tviscdata(o)) goto err_argtype;
5,181✔
62
    if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
5,181✔
63
    cd = cdataV(o);
5,181✔
64
    return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
5,181✔
65
  }
66
}
67

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

77
/* Convert argument to C pointer. */
78
static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
796✔
79
{
80
  CTState *cts = ctype_cts(L);
796✔
81
  TValue *o = L->base + narg-1;
796✔
82
  void *p;
796✔
83
  if (o >= L->top)
796✔
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));
796✔
86
  return p;
796✔
87
}
88

89
/* Convert argument to int32_t. */
90
static int32_t ffi_checkint(lua_State *L, int narg)
58,269✔
91
{
92
  CTState *cts = ctype_cts(L);
58,269✔
93
  TValue *o = L->base + narg-1;
58,269✔
94
  int32_t i;
58,269✔
95
  if (o >= L->top)
58,269✔
96
    lj_err_arg(L, narg, LJ_ERR_NOVAL);
3✔
97
  lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
58,266✔
98
                 CCF_ARG(narg));
58,266✔
99
  return i;
58,266✔
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)
195✔
108
{
109
  CTypeID id = ctype_typeid(cts, ct);
195✔
110
  cTValue *tv = lj_ctype_meta(cts, id, mm);
195✔
111
  TValue *base = L->base;
195✔
112
  if (!tv) {
195✔
113
    const char *s;
6✔
114
  err_index:
4✔
115
    s = strdata(lj_ctype_repr(L, id, NULL));
6✔
116
    if (tvisstr(L->base+1)) {
6✔
117
      lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+1));
5✔
118
    } else {
119
      const char *key = tviscdata(L->base+1) ?
2✔
120
        strdata(lj_ctype_repr(L, cdataV(L->base+1)->ctypeid, NULL)) :
2✔
121
        lj_typename(L->base+1);
1✔
122
      lj_err_callerv(L, LJ_ERR_FFI_BADIDXW, s, key);
1✔
123
    }
124
  }
125
  if (!tvisfunc(tv)) {
191✔
126
    if (mm == MM_index) {
138✔
127
      cTValue *o = lj_meta_tget(L, tv, base+1);
135✔
128
      if (o) {
135✔
129
        if (tvisnil(o)) goto err_index;
133✔
130
        copyTV(L, L->top-1, o);
131✔
131
        return 1;
131✔
132
      }
133
    } else {
134
      TValue *o = lj_meta_tset(L, tv, base+1);
3✔
135
      if (o) {
3✔
136
        copyTV(L, o, base+2);
1✔
137
        return 0;
1✔
138
      }
139
    }
140
    copyTV(L, base, L->top);
4✔
141
    tv = L->top-1-LJ_FR2;
4✔
142
  }
143
  return lj_meta_tailcall(L, tv);
57✔
144
}
145

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

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

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

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

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

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

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

210
LJLIB_CF(ffi_meta___concat)        LJLIB_REC(cdata_arith MM_concat)
4✔
211
{
212
  return ffi_arith(L);
4✔
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)
67,921✔
219
{
220
  CTState *cts = ctype_cts(L);
67,921✔
221
  GCcdata *cd = ffi_checkcdata(L, 1);
67,921✔
222
  CTypeID id = cd->ctypeid;
67,921✔
223
  CType *ct;
67,921✔
224
  cTValue *tv;
67,921✔
225
  MMS mm = MM_call;
67,921✔
226
  if (cd->ctypeid == CTID_CTYPEID) {
67,921✔
227
    id = *(CTypeID *)cdataptr(cd);
3,383✔
228
    mm = MM_new;
3,383✔
229
  } else {
230
    int ret = lj_ccall_func(L, cd);
64,538✔
231
    if (ret >= 0)
64,529✔
232
      return ret;
233
  }
234
  /* Handle ctype __call/__new metamethod. */
235
  ct = ctype_raw(cts, id);
3,396✔
236
  if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
3,396✔
237
  tv = lj_ctype_meta(cts, id, mm);
3,396✔
238
  if (tv)
3,396✔
239
    return lj_meta_tailcall(L, tv);
14✔
240
  else if (mm == MM_call)
3,382✔
241
    lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
×
242
  return lj_cf_ffi_new(L);
3,382✔
243
}
244

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

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

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

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

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

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

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

281
LJLIB_CF(ffi_meta___tostring)
46✔
282
{
283
  GCcdata *cd = ffi_checkcdata(L, 1);
46✔
284
  const char *msg = "cdata<%s>: %p";
46✔
285
  CTypeID id = cd->ctypeid;
46✔
286
  void *p = cdataptr(cd);
46✔
287
  if (id == CTID_CTYPEID) {
46✔
288
    msg = "ctype<%s>";
5✔
289
    id = *(CTypeID *)p;
5✔
290
  } else {
291
    CTState *cts = ctype_cts(L);
41✔
292
    CType *ct = ctype_raw(cts, id);
41✔
293
    if (ctype_isref(ct->info)) {
41✔
294
      p = *(void **)p;
×
295
      ct = ctype_rawchild(cts, ct);
×
296
    }
297
    if (ctype_iscomplex(ct->info)) {
41✔
298
      setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
16✔
299
      goto checkgc;
16✔
300
    } else if (ct->size == 8 && ctype_isinteger(ct->info)) {
25✔
301
      setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
21✔
302
                                               (ct->info & CTF_UNSIGNED)));
21✔
303
      goto checkgc;
21✔
304
    } else if (ctype_isfunc(ct->info)) {
4✔
305
      p = *(void **)p;
×
306
    } else if (ctype_isenum(ct->info)) {
4✔
307
      msg = "cdata<%s>: %d";
×
308
      p = (void *)(uintptr_t)*(uint32_t **)p;
×
309
    } else {
310
      if (ctype_isptr(ct->info)) {
4✔
311
        p = cdata_getptr(p, ct->size);
1✔
312
        ct = ctype_rawchild(cts, ct);
1✔
313
      }
314
      if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
4✔
315
        /* Handle ctype __tostring metamethod. */
316
        cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
4✔
317
        if (tv)
4✔
318
          return lj_meta_tailcall(L, tv);
3✔
319
      }
320
    }
321
  }
322
  lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
6✔
323
checkgc:
43✔
324
  lj_gc_check(L);
43✔
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)
64,278✔
362
{
363
  TValue *o = L->base;
64,278✔
364
  CLibrary *cl;
64,278✔
365
  if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
64,278✔
366
    lj_err_argt(L, 1, LUA_TUSERDATA);
×
367
  cl = (CLibrary *)uddata(udataV(o));
64,278✔
368
  if (!(o+1 < L->top && tvisstr(o+1)))
64,278✔
369
    lj_err_argt(L, 2, LUA_TSTRING);
×
370
  return lj_clib_index(L, cl, strV(o+1));
64,278✔
371
}
372

373
LJLIB_CF(ffi_clib___index)        LJLIB_REC(clib_index 1)
64,276✔
374
{
375
  TValue *tv = ffi_clib_index(L);
64,276✔
376
  if (tviscdata(tv)) {
64,276✔
377
    CTState *cts = ctype_cts(L);
64,276✔
378
    GCcdata *cd = cdataV(tv);
64,276✔
379
    CType *s = ctype_get(cts, cd->ctypeid);
64,276✔
380
    if (ctype_isextern(s->info)) {
64,276✔
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);
64,275✔
390
  return 1;
64,275✔
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)
200✔
419
{
420
  TValue *o = L->base;
200✔
421
  if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
200✔
422
    lj_clib_unload((CLibrary *)uddata(udataV(o)));
200✔
423
  return 0;
200✔
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)
1,604✔
433
{
434
  GCcdata *cd = ffi_checkcdata(L, 1);
1,604✔
435
  CTState *cts = ctype_cts(L);
1,604✔
436
  CType *ct = ctype_raw(cts, cd->ctypeid);
1,604✔
437
  if (ctype_isptr(ct->info) && (LJ_32 || ct->size == 8)) {
1,604✔
438
    MSize slot = lj_ccallback_ptr2slot(cts, *(void **)cdataptr(cd));
1,604✔
439
    if (slot < cts->cb.sizeid && cts->cb.cbid[slot] != 0) {
1,604✔
440
      GCtab *t = cts->miscmap;
1,602✔
441
      TValue *tv = lj_tab_setint(L, t, (int32_t)slot);
1,602✔
442
      if (fn) {
1,602✔
443
        setfuncV(L, tv, fn);
1✔
444
        lj_gc_anybarriert(L, t);
1✔
445
      } else {
446
        setnilV(tv);
1,601✔
447
        cts->cb.cbid[slot] = 0;
1,601✔
448
        cts->cb.topid = slot < cts->cb.topid ? slot : cts->cb.topid;
1,601✔
449
      }
450
      return 0;
1,602✔
451
    }
452
  }
453
  lj_err_caller(L, LJ_ERR_FFI_BADCBACK);
2✔
454
  return 0;
455
}
456

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

462
LJLIB_CF(ffi_callback_set)
2✔
463
{
464
  GCfunc *fn = lj_lib_checkfunc(L, 2);
2✔
465
  return ffi_callback_set(L, fn);
2✔
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)
86✔
477
{
478
  GCstr *s = lj_lib_checkstr(L, 1);
86✔
479
  CPState cp;
86✔
480
  int errcode;
86✔
481
  cp.L = L;
86✔
482
  cp.cts = ctype_cts(L);
86✔
483
  cp.srcname = strdata(s);
86✔
484
  cp.p = strdata(s);
86✔
485
  cp.param = L->base+1;
86✔
486
  cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
86✔
487
  errcode = lj_cparse(&cp);
86✔
488
  if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
86✔
489
  lj_gc_check(L);
72✔
490
  return 0;
72✔
491
}
492

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

819
#include "lj_libdef.h"
820

821
/* ------------------------------------------------------------------------ */
822

823
/* Register FFI module as loaded. */
824
static void ffi_register_module(lua_State *L)
196✔
825
{
826
  cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
196✔
827
  if (tmp && tvistab(tmp)) {
196✔
828
    GCtab *t = tabV(tmp);
194✔
829
    copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
194✔
830
    lj_gc_anybarriert(L, t);
194✔
831
  }
832
}
196✔
833

834
LUALIB_API int luaopen_ffi(lua_State *L)
196✔
835
{
836
  CTState *cts = lj_ctype_init(L);
196✔
837
  settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
196✔
838
  LJ_LIB_REG(L, NULL, ffi_meta);
196✔
839
  /* NOBARRIER: basemt is a GC root. */
840
  setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
196✔
841
  LJ_LIB_REG(L, NULL, ffi_clib);
196✔
842
  LJ_LIB_REG(L, NULL, ffi_callback);
196✔
843
  /* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
844
  settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
196✔
845
  L->top--;
196✔
846
  lj_clib_default(L, tabV(L->top-1));  /* Create ffi.C default namespace. */
196✔
847
  lua_pushliteral(L, LJ_OS_NAME);
196✔
848
  lua_pushliteral(L, LJ_ARCH_NAME);
196✔
849
  LJ_LIB_REG(L, NULL, ffi);  /* Note: no global "ffi" created! */
196✔
850
  ffi_register_module(L);
196✔
851
  return 1;
196✔
852
}
853

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