1 /*
2 ** FFI library.
3 ** Copyright (C) 2005-2021 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. */
ffi_checkctype(lua_State * L,CTState * cts,TValue * param)39 static CTypeID ffi_checkctype(lua_State *L, CTState *cts, TValue *param)
40 {
41   TValue *o = L->base;
42   if (!(o < L->top)) {
43   err_argtype:
44     lj_err_argtype(L, 1, "C type");
45   }
46   if (tvisstr(o)) {  /* Parse an abstract C type declaration. */
47     GCstr *s = strV(o);
48     CPState cp;
49     int errcode;
50     cp.L = L;
51     cp.cts = cts;
52     cp.srcname = strdata(s);
53     cp.p = strdata(s);
54     cp.param = param;
55     cp.mode = CPARSE_MODE_ABSTRACT|CPARSE_MODE_NOIMPLICIT;
56     errcode = lj_cparse(&cp);
57     if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
58     return cp.val.id;
59   } else {
60     GCcdata *cd;
61     if (!tviscdata(o)) goto err_argtype;
62     if (param && param < L->top) lj_err_arg(L, 1, LJ_ERR_FFI_NUMPARAM);
63     cd = cdataV(o);
64     return cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) : cd->ctypeid;
65   }
66 }
67 
68 /* Check argument for C data and return it. */
ffi_checkcdata(lua_State * L,int narg)69 static GCcdata *ffi_checkcdata(lua_State *L, int narg)
70 {
71   TValue *o = L->base + narg-1;
72   if (!(o < L->top && tviscdata(o)))
73     lj_err_argt(L, narg, LUA_TCDATA);
74   return cdataV(o);
75 }
76 
77 /* Convert argument to C pointer. */
ffi_checkptr(lua_State * L,int narg,CTypeID id)78 static void *ffi_checkptr(lua_State *L, int narg, CTypeID id)
79 {
80   CTState *cts = ctype_cts(L);
81   TValue *o = L->base + narg-1;
82   void *p;
83   if (o >= L->top)
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));
86   return p;
87 }
88 
89 /* Convert argument to int32_t. */
ffi_checkint(lua_State * L,int narg)90 static int32_t ffi_checkint(lua_State *L, int narg)
91 {
92   CTState *cts = ctype_cts(L);
93   TValue *o = L->base + narg-1;
94   int32_t i;
95   if (o >= L->top)
96     lj_err_arg(L, narg, LJ_ERR_NOVAL);
97   lj_cconv_ct_tv(cts, ctype_get(cts, CTID_INT32), (uint8_t *)&i, o,
98 		 CCF_ARG(narg));
99   return i;
100 }
101 
102 /* -- C type metamethods -------------------------------------------------- */
103 
104 #define LJLIB_MODULE_ffi_meta
105 
106 /* Handle ctype __index/__newindex metamethods. */
ffi_index_meta(lua_State * L,CTState * cts,CType * ct,MMS mm)107 static int ffi_index_meta(lua_State *L, CTState *cts, CType *ct, MMS mm)
108 {
109   CTypeID id = ctype_typeid(cts, ct);
110   cTValue *tv = lj_ctype_meta(cts, id, mm);
111   TValue *base = L->base;
112   if (!tv) {
113     const char *s;
114   err_index:
115     s = strdata(lj_ctype_repr(L, id, NULL));
116     if (tvisstr(L->base+1)) {
117       lj_err_callerv(L, LJ_ERR_FFI_BADMEMBER, s, strVdata(L->base+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)
147 {
148   CTState *cts = ctype_cts(L);
149   CTInfo qual = 0;
150   CType *ct;
151   uint8_t *p;
152   TValue *o = L->base;
153   if (!(o+1 < L->top && tviscdata(o)))  /* Also checks for presence of key. */
154     lj_err_argt(L, 1, LUA_TCDATA);
155   ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
156   if ((qual & 1))
157     return ffi_index_meta(L, cts, ct, MM_index);
158   if (lj_cdata_get(cts, ct, L->top-1, p))
159     lj_gc_check(L);
160   return 1;
161 }
162 
163 LJLIB_CF(ffi_meta___newindex)	LJLIB_REC(cdata_index 1)
164 {
165   CTState *cts = ctype_cts(L);
166   CTInfo qual = 0;
167   CType *ct;
168   uint8_t *p;
169   TValue *o = L->base;
170   if (!(o+2 < L->top && tviscdata(o)))  /* Also checks for key and value. */
171     lj_err_argt(L, 1, LUA_TCDATA);
172   ct = lj_cdata_index(cts, cdataV(o), o+1, &p, &qual);
173   if ((qual & 1)) {
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);
179   return 0;
180 }
181 
182 /* Common handler for cdata arithmetic. */
ffi_arith(lua_State * L)183 static int ffi_arith(lua_State *L)
184 {
185   MMS mm = (MMS)(curr_func(L)->c.ffid - (int)FF_ffi_meta___eq + (int)MM_eq);
186   return lj_carith_op(L, mm);
187 }
188 
189 /* The following functions must be in contiguous ORDER MM. */
LJLIB_REC(cdata_arith MM_eq)190 LJLIB_CF(ffi_meta___eq)		LJLIB_REC(cdata_arith MM_eq)
191 {
192   return ffi_arith(L);
193 }
194 
LJLIB_REC(cdata_arith MM_len)195 LJLIB_CF(ffi_meta___len)	LJLIB_REC(cdata_arith MM_len)
196 {
197   return ffi_arith(L);
198 }
199 
LJLIB_REC(cdata_arith MM_lt)200 LJLIB_CF(ffi_meta___lt)		LJLIB_REC(cdata_arith MM_lt)
201 {
202   return ffi_arith(L);
203 }
204 
LJLIB_REC(cdata_arith MM_le)205 LJLIB_CF(ffi_meta___le)		LJLIB_REC(cdata_arith MM_le)
206 {
207   return ffi_arith(L);
208 }
209 
LJLIB_REC(cdata_arith MM_concat)210 LJLIB_CF(ffi_meta___concat)	LJLIB_REC(cdata_arith MM_concat)
211 {
212   return ffi_arith(L);
213 }
214 
215 /* Forward declaration. */
216 static int lj_cf_ffi_new(lua_State *L);
217 
LJLIB_REC(cdata_call)218 LJLIB_CF(ffi_meta___call)	LJLIB_REC(cdata_call)
219 {
220   CTState *cts = ctype_cts(L);
221   GCcdata *cd = ffi_checkcdata(L, 1);
222   CTypeID id = cd->ctypeid;
223   CType *ct;
224   cTValue *tv;
225   MMS mm = MM_call;
226   if (cd->ctypeid == CTID_CTYPEID) {
227     id = *(CTypeID *)cdataptr(cd);
228     mm = MM_new;
229   } else {
230     int ret = lj_ccall_func(L, cd);
231     if (ret >= 0)
232       return ret;
233   }
234   /* Handle ctype __call/__new metamethod. */
235   ct = ctype_raw(cts, id);
236   if (ctype_isptr(ct->info)) id = ctype_cid(ct->info);
237   tv = lj_ctype_meta(cts, id, mm);
238   if (tv)
239     return lj_meta_tailcall(L, tv);
240   else if (mm == MM_call)
241     lj_err_callerv(L, LJ_ERR_FFI_BADCALL, strdata(lj_ctype_repr(L, id, NULL)));
242   return lj_cf_ffi_new(L);
243 }
244 
LJLIB_REC(cdata_arith MM_add)245 LJLIB_CF(ffi_meta___add)	LJLIB_REC(cdata_arith MM_add)
246 {
247   return ffi_arith(L);
248 }
249 
LJLIB_REC(cdata_arith MM_sub)250 LJLIB_CF(ffi_meta___sub)	LJLIB_REC(cdata_arith MM_sub)
251 {
252   return ffi_arith(L);
253 }
254 
LJLIB_REC(cdata_arith MM_mul)255 LJLIB_CF(ffi_meta___mul)	LJLIB_REC(cdata_arith MM_mul)
256 {
257   return ffi_arith(L);
258 }
259 
LJLIB_REC(cdata_arith MM_div)260 LJLIB_CF(ffi_meta___div)	LJLIB_REC(cdata_arith MM_div)
261 {
262   return ffi_arith(L);
263 }
264 
LJLIB_REC(cdata_arith MM_mod)265 LJLIB_CF(ffi_meta___mod)	LJLIB_REC(cdata_arith MM_mod)
266 {
267   return ffi_arith(L);
268 }
269 
LJLIB_REC(cdata_arith MM_pow)270 LJLIB_CF(ffi_meta___pow)	LJLIB_REC(cdata_arith MM_pow)
271 {
272   return ffi_arith(L);
273 }
274 
LJLIB_REC(cdata_arith MM_unm)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 
LJLIB_CF(ffi_meta___tostring)281 LJLIB_CF(ffi_meta___tostring)
282 {
283   GCcdata *cd = ffi_checkcdata(L, 1);
284   const char *msg = "cdata<%s>: %p";
285   CTypeID id = cd->ctypeid;
286   void *p = cdataptr(cd);
287   if (id == CTID_CTYPEID) {
288     msg = "ctype<%s>";
289     id = *(CTypeID *)p;
290   } else {
291     CTState *cts = ctype_cts(L);
292     CType *ct = ctype_raw(cts, id);
293     if (ctype_isref(ct->info)) {
294       p = *(void **)p;
295       ct = ctype_rawchild(cts, ct);
296     }
297     if (ctype_iscomplex(ct->info)) {
298       setstrV(L, L->top-1, lj_ctype_repr_complex(L, cdataptr(cd), ct->size));
299       goto checkgc;
300     } else if (ct->size == 8 && ctype_isinteger(ct->info)) {
301       setstrV(L, L->top-1, lj_ctype_repr_int64(L, *(uint64_t *)cdataptr(cd),
302 					       (ct->info & CTF_UNSIGNED)));
303       goto checkgc;
304     } else if (ctype_isfunc(ct->info)) {
305       p = *(void **)p;
306     } else if (ctype_isenum(ct->info)) {
307       msg = "cdata<%s>: %d";
308       p = (void *)(uintptr_t)*(uint32_t **)p;
309     } else {
310       if (ctype_isptr(ct->info)) {
311 	p = cdata_getptr(p, ct->size);
312 	ct = ctype_rawchild(cts, ct);
313       }
314       if (ctype_isstruct(ct->info) || ctype_isvector(ct->info)) {
315 	/* Handle ctype __tostring metamethod. */
316 	cTValue *tv = lj_ctype_meta(cts, ctype_typeid(cts, ct), MM_tostring);
317 	if (tv)
318 	  return lj_meta_tailcall(L, tv);
319       }
320     }
321   }
322   lj_strfmt_pushf(L, msg, strdata(lj_ctype_repr(L, id, NULL)), p);
323 checkgc:
324   lj_gc_check(L);
325   return 1;
326 }
327 
ffi_pairs(lua_State * L,MMS mm)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 
LJLIB_CF(ffi_meta___pairs)342 LJLIB_CF(ffi_meta___pairs)
343 {
344   return ffi_pairs(L, MM_pairs);
345 }
346 
LJLIB_CF(ffi_meta___ipairs)347 LJLIB_CF(ffi_meta___ipairs)
348 {
349   return ffi_pairs(L, MM_ipairs);
350 }
351 
LJLIB_SET(__metatable)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)
362 {
363   TValue *o = L->base;
364   CLibrary *cl;
365   if (!(o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB))
366     lj_err_argt(L, 1, LUA_TUSERDATA);
367   cl = (CLibrary *)uddata(udataV(o));
368   if (!(o+1 < L->top && tvisstr(o+1)))
369     lj_err_argt(L, 2, LUA_TSTRING);
370   return lj_clib_index(L, cl, strV(o+1));
371 }
372 
373 LJLIB_CF(ffi_clib___index)	LJLIB_REC(clib_index 1)
374 {
375   TValue *tv = ffi_clib_index(L);
376   if (tviscdata(tv)) {
377     CTState *cts = ctype_cts(L);
378     GCcdata *cd = cdataV(tv);
379     CType *s = ctype_get(cts, cd->ctypeid);
380     if (ctype_isextern(s->info)) {
381       CTypeID sid = ctype_cid(s->info);
382       void *sp = *(void **)cdataptr(cd);
383       CType *ct = ctype_raw(cts, sid);
384       if (lj_cconv_tv_ct(cts, ct, sid, L->top-1, sp))
385 	lj_gc_check(L);
386       return 1;
387     }
388   }
389   copyTV(L, L->top-1, tv);
390   return 1;
391 }
392 
393 LJLIB_CF(ffi_clib___newindex)	LJLIB_REC(clib_index 0)
394 {
395   TValue *tv = ffi_clib_index(L);
396   TValue *o = L->base+2;
397   if (o < L->top && tviscdata(tv)) {
398     CTState *cts = ctype_cts(L);
399     GCcdata *cd = cdataV(tv);
400     CType *d = ctype_get(cts, cd->ctypeid);
401     if (ctype_isextern(d->info)) {
402       CTInfo qual = 0;
403       for (;;) {  /* Skip attributes and collect qualifiers. */
404 	d = ctype_child(cts, d);
405 	if (!ctype_isattrib(d->info)) break;
406 	if (ctype_attrib(d->info) == CTA_QUAL) qual |= d->size;
407       }
408       if (!((d->info|qual) & CTF_CONST)) {
409 	lj_cconv_ct_tv(cts, d, *(void **)cdataptr(cd), o, 0);
410 	return 0;
411       }
412     }
413   }
414   lj_err_caller(L, LJ_ERR_FFI_WRCONST);
415   return 0;  /* unreachable */
416 }
417 
LJLIB_CF(ffi_clib___gc)418 LJLIB_CF(ffi_clib___gc)
419 {
420   TValue *o = L->base;
421   if (o < L->top && tvisudata(o) && udataV(o)->udtype == UDTYPE_FFI_CLIB)
422     lj_clib_unload((CLibrary *)uddata(udataV(o)));
423   return 0;
424 }
425 
426 #include "lj_libdef.h"
427 
428 /* -- Callback function metamethods --------------------------------------- */
429 
430 #define LJLIB_MODULE_ffi_callback
431 
ffi_callback_set(lua_State * L,GCfunc * fn)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 
LJLIB_CF(ffi_callback_free)457 LJLIB_CF(ffi_callback_free)
458 {
459   return ffi_callback_set(L, NULL);
460 }
461 
LJLIB_CF(ffi_callback_set)462 LJLIB_CF(ffi_callback_set)
463 {
464   GCfunc *fn = lj_lib_checkfunc(L, 2);
465   return ffi_callback_set(L, fn);
466 }
467 
LJLIB_SET(__index)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)
477 {
478   GCstr *s = lj_lib_checkstr(L, 1);
479   CPState cp;
480   int errcode;
481   cp.L = L;
482   cp.cts = ctype_cts(L);
483   cp.srcname = strdata(s);
484   cp.p = strdata(s);
485   cp.param = L->base+1;
486   cp.mode = CPARSE_MODE_MULTI|CPARSE_MODE_DIRECT;
487   errcode = lj_cparse(&cp);
488   if (errcode) lj_err_throw(L, errcode);  /* Propagate errors. */
489   lj_gc_check(L);
490   return 0;
491 }
492 
493 LJLIB_CF(ffi_new)	LJLIB_REC(.)
494 {
495   CTState *cts = ctype_cts(L);
496   CTypeID id = ffi_checkctype(L, cts, NULL);
497   CType *ct = ctype_raw(cts, id);
498   CTSize sz;
499   CTInfo info = lj_ctype_info(cts, id, &sz);
500   TValue *o = L->base+1;
501   GCcdata *cd;
502   if ((info & CTF_VLA)) {
503     o++;
504     sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
505   }
506   if (sz == CTSIZE_INVALID)
507     lj_err_arg(L, 1, LJ_ERR_FFI_INVSIZE);
508   cd = lj_cdata_newx(cts, id, sz, info);
509   setcdataV(L, o-1, cd);  /* Anchor the uninitialized cdata. */
510   lj_cconv_ct_init(cts, ct, sz, cdataptr(cd),
511 		   o, (MSize)(L->top - o));  /* Initialize cdata. */
512   if (ctype_isstruct(ct->info)) {
513     /* Handle ctype __gc metamethod. Use the fast lookup here. */
514     cTValue *tv = lj_tab_getinth(cts->miscmap, -(int32_t)id);
515     if (tv && tvistab(tv) && (tv = lj_meta_fast(L, tabV(tv), MM_gc))) {
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. */
526   lj_gc_check(L);
527   return 1;
528 }
529 
LJLIB_REC(ffi_new)530 LJLIB_CF(ffi_cast)	LJLIB_REC(ffi_new)
531 {
532   CTState *cts = ctype_cts(L);
533   CTypeID id = ffi_checkctype(L, cts, NULL);
534   CType *d = ctype_raw(cts, id);
535   TValue *o = lj_lib_checkany(L, 2);
536   L->top = o+1;  /* Make sure this is the last item on the stack. */
537   if (!(ctype_isnum(d->info) || ctype_isptr(d->info) || ctype_isenum(d->info)))
538     lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
539   if (!(tviscdata(o) && cdataV(o)->ctypeid == id)) {
540     GCcdata *cd = lj_cdata_new(cts, id, d->size);
541     lj_cconv_ct_tv(cts, d, cdataptr(cd), o, CCF_CAST);
542     setcdataV(L, o, cd);
543     lj_gc_check(L);
544   }
545   return 1;
546 }
547 
548 LJLIB_CF(ffi_typeof)	LJLIB_REC(.)
549 {
550   CTState *cts = ctype_cts(L);
551   CTypeID id = ffi_checkctype(L, cts, L->base+1);
552   GCcdata *cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
553   *(CTypeID *)cdataptr(cd) = id;
554   setcdataV(L, L->top-1, cd);
555   lj_gc_check(L);
556   return 1;
557 }
558 
559 /* Internal and unsupported API. */
LJLIB_CF(ffi_typeinfo)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       if (isdead(G(L), obj2gco(s))) flipwhite(obj2gco(s));
577       setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "name")), s);
578     }
579     lj_gc_check(L);
580     return 1;
581   }
582   return 0;
583 }
584 
585 LJLIB_CF(ffi_istype)	LJLIB_REC(.)
586 {
587   CTState *cts = ctype_cts(L);
588   CTypeID id1 = ffi_checkctype(L, cts, NULL);
589   TValue *o = lj_lib_checkany(L, 2);
590   int b = 0;
591   if (tviscdata(o)) {
592     GCcdata *cd = cdataV(o);
593     CTypeID id2 = cd->ctypeid == CTID_CTYPEID ? *(CTypeID *)cdataptr(cd) :
594 						cd->ctypeid;
595     CType *ct1 = lj_ctype_rawref(cts, id1);
596     CType *ct2 = lj_ctype_rawref(cts, id2);
597     if (ct1 == ct2) {
598       b = 1;
599     } else if (ctype_type(ct1->info) == ctype_type(ct2->info) &&
600 	       ct1->size == ct2->size) {
601       if (ctype_ispointer(ct1->info))
602 	b = lj_cconv_compatptr(cts, ct1, ct2, CCF_IGNQUAL);
603       else if (ctype_isnum(ct1->info) || ctype_isvoid(ct1->info))
604 	b = (((ct1->info ^ ct2->info) & ~(CTF_QUAL|CTF_LONG)) == 0);
605     } else if (ctype_isstruct(ct1->info) && ctype_isptr(ct2->info) &&
606 	       ct1 == ctype_rawchild(cts, ct2)) {
607       b = 1;
608     }
609   }
610   setboolV(L->top-1, b);
611   setboolV(&G(L)->tmptv2, b);  /* Remember for trace recorder. */
612   return 1;
613 }
614 
LJLIB_REC(ffi_xof FF_ffi_sizeof)615 LJLIB_CF(ffi_sizeof)	LJLIB_REC(ffi_xof FF_ffi_sizeof)
616 {
617   CTState *cts = ctype_cts(L);
618   CTypeID id = ffi_checkctype(L, cts, NULL);
619   CTSize sz;
620   if (LJ_UNLIKELY(tviscdata(L->base) && cdataisv(cdataV(L->base)))) {
621     sz = cdatavlen(cdataV(L->base));
622   } else {
623     CType *ct = lj_ctype_rawref(cts, id);
624     if (ctype_isvltype(ct->info))
625       sz = lj_ctype_vlsize(cts, ct, (CTSize)ffi_checkint(L, 2));
626     else
627       sz = ctype_hassize(ct->info) ? ct->size : CTSIZE_INVALID;
628     if (LJ_UNLIKELY(sz == CTSIZE_INVALID)) {
629       setnilV(L->top-1);
630       return 1;
631     }
632   }
633   setintV(L->top-1, (int32_t)sz);
634   return 1;
635 }
636 
LJLIB_REC(ffi_xof FF_ffi_alignof)637 LJLIB_CF(ffi_alignof)	LJLIB_REC(ffi_xof FF_ffi_alignof)
638 {
639   CTState *cts = ctype_cts(L);
640   CTypeID id = ffi_checkctype(L, cts, NULL);
641   CTSize sz = 0;
642   CTInfo info = lj_ctype_info(cts, id, &sz);
643   setintV(L->top-1, 1 << ctype_align(info));
644   return 1;
645 }
646 
LJLIB_REC(ffi_xof FF_ffi_offsetof)647 LJLIB_CF(ffi_offsetof)	LJLIB_REC(ffi_xof FF_ffi_offsetof)
648 {
649   CTState *cts = ctype_cts(L);
650   CTypeID id = ffi_checkctype(L, cts, NULL);
651   GCstr *name = lj_lib_checkstr(L, 2);
652   CType *ct = lj_ctype_rawref(cts, id);
653   CTSize ofs;
654   if (ctype_isstruct(ct->info) && ct->size != CTSIZE_INVALID) {
655     CType *fct = lj_ctype_getfield(cts, ct, name, &ofs);
656     if (fct) {
657       setintV(L->top-1, ofs);
658       if (ctype_isfield(fct->info)) {
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(.)
671 {
672   int err = errno;
673   if (L->top > L->base)
674     errno = ffi_checkint(L, 1);
675   setintV(L->top++, err);
676   return 1;
677 }
678 
679 LJLIB_CF(ffi_string)	LJLIB_REC(.)
680 {
681   CTState *cts = ctype_cts(L);
682   TValue *o = lj_lib_checkany(L, 1);
683   const char *p;
684   size_t len;
685   if (o+1 < L->top && !tvisnil(o+1)) {
686     len = (size_t)ffi_checkint(L, 2);
687     lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, o,
688 		   CCF_ARG(1));
689   } else {
690     lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CCHAR), (uint8_t *)&p, o,
691 		   CCF_ARG(1));
692     len = strlen(p);
693   }
694   L->top = o+1;  /* Make sure this is the last item on the stack. */
695   setstrV(L, o, lj_str_new(L, p, len));
696   lj_gc_check(L);
697   return 1;
698 }
699 
700 LJLIB_CF(ffi_copy)	LJLIB_REC(.)
701 {
702   void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
703   void *sp = ffi_checkptr(L, 2, CTID_P_CVOID);
704   TValue *o = L->base+1;
705   CTSize len;
706   if (tvisstr(o) && o+1 >= L->top)
707     len = strV(o)->len+1;  /* Copy Lua string including trailing '\0'. */
708   else
709     len = (CTSize)ffi_checkint(L, 3);
710   memcpy(dp, sp, len);
711   return 0;
712 }
713 
714 LJLIB_CF(ffi_fill)	LJLIB_REC(.)
715 {
716   void *dp = ffi_checkptr(L, 1, CTID_P_VOID);
717   CTSize len = (CTSize)ffi_checkint(L, 2);
718   int32_t fill = 0;
719   if (L->base+2 < L->top && !tvisnil(L->base+2)) fill = ffi_checkint(L, 3);
720   memset(dp, fill, len);
721   return 0;
722 }
723 
724 /* Test ABI string. */
725 LJLIB_CF(ffi_abi)	LJLIB_REC(.)
726 {
727   GCstr *s = lj_lib_checkstr(L, 1);
728   int b = lj_cparse_case(s,
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;
760   setboolV(L->top-1, b);
761   setboolV(&G(L)->tmptv2, b);  /* Remember for trace recorder. */
762   return 1;
763 }
764 
765 LJLIB_PUSH(top-8) LJLIB_SET(!)  /* Store reference to miscmap table. */
766 
LJLIB_CF(ffi_metatype)767 LJLIB_CF(ffi_metatype)
768 {
769   CTState *cts = ctype_cts(L);
770   CTypeID id = ffi_checkctype(L, cts, NULL);
771   GCtab *mt = lj_lib_checktab(L, 2);
772   GCtab *t = cts->miscmap;
773   CType *ct = ctype_get(cts, id);  /* Only allow raw types. */
774   TValue *tv;
775   GCcdata *cd;
776   if (!(ctype_isstruct(ct->info) || ctype_iscomplex(ct->info) ||
777 	ctype_isvector(ct->info)))
778     lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
779   tv = lj_tab_setinth(L, t, -(int32_t)id);
780   if (!tvisnil(tv))
781     lj_err_caller(L, LJ_ERR_PROTMT);
782   settabV(L, tv, mt);
783   lj_gc_anybarriert(L, t);
784   cd = lj_cdata_new(cts, CTID_CTYPEID, 4);
785   *(CTypeID *)cdataptr(cd) = id;
786   setcdataV(L, L->top-1, cd);
787   lj_gc_check(L);
788   return 1;
789 }
790 
791 LJLIB_PUSH(top-7) LJLIB_SET(!)  /* Store reference to finalizer table. */
792 
LJLIB_CF(ffi_gc)793 LJLIB_CF(ffi_gc)	LJLIB_REC(.)
794 {
795   GCcdata *cd = ffi_checkcdata(L, 1);
796   TValue *fin = lj_lib_checkany(L, 2);
797   CTState *cts = ctype_cts(L);
798   CType *ct = ctype_raw(cts, cd->ctypeid);
799   if (!(ctype_isptr(ct->info) || ctype_isstruct(ct->info) ||
800 	ctype_isrefarray(ct->info)))
801     lj_err_arg(L, 1, LJ_ERR_FFI_INVTYPE);
802   lj_cdata_setfin(L, cd, gcval(fin), itype(fin));
803   L->top = L->base+1;  /* Pass through the cdata object. */
804   return 1;
805 }
806 
807 LJLIB_PUSH(top-5) LJLIB_SET(!)  /* Store clib metatable in func environment. */
808 
LJLIB_CF(ffi_load)809 LJLIB_CF(ffi_load)
810 {
811   GCstr *name = lj_lib_checkstr(L, 1);
812   int global = (L->base+1 < L->top && tvistruecond(L->base+1));
813   lj_clib_load(L, tabref(curr_func(L)->c.env), name, global);
814   return 1;
815 }
816 
LJLIB_SET(C)817 LJLIB_PUSH(top-4) LJLIB_SET(C)
818 LJLIB_PUSH(top-3) LJLIB_SET(os)
819 LJLIB_PUSH(top-2) LJLIB_SET(arch)
820 
821 #include "lj_libdef.h"
822 
823 /* ------------------------------------------------------------------------ */
824 
825 /* Create special weak-keyed finalizer table. */
826 static GCtab *ffi_finalizer(lua_State *L)
827 {
828   /* NOBARRIER: The table is new (marked white). */
829   GCtab *t = lj_tab_new(L, 0, 1);
830   settabV(L, L->top++, t);
831   setgcref(t->metatable, obj2gco(t));
832   setstrV(L, lj_tab_setstr(L, t, lj_str_newlit(L, "__mode")),
833 	  lj_str_newlit(L, "k"));
834   t->nomm = (uint8_t)(~(1u<<MM_mode));
835   return t;
836 }
837 
838 /* Register FFI module as loaded. */
ffi_register_module(lua_State * L)839 static void ffi_register_module(lua_State *L)
840 {
841   cTValue *tmp = lj_tab_getstr(tabV(registry(L)), lj_str_newlit(L, "_LOADED"));
842   if (tmp && tvistab(tmp)) {
843     GCtab *t = tabV(tmp);
844     copyTV(L, lj_tab_setstr(L, t, lj_str_newlit(L, LUA_FFILIBNAME)), L->top-1);
845     lj_gc_anybarriert(L, t);
846   }
847 }
848 
luaopen_ffi(lua_State * L)849 LUALIB_API int luaopen_ffi(lua_State *L)
850 {
851   CTState *cts = lj_ctype_init(L);
852   settabV(L, L->top++, (cts->miscmap = lj_tab_new(L, 0, 1)));
853   cts->finalizer = ffi_finalizer(L);
854   LJ_LIB_REG(L, NULL, ffi_meta);
855   /* NOBARRIER: basemt is a GC root. */
856   setgcref(basemt_it(G(L), LJ_TCDATA), obj2gco(tabV(L->top-1)));
857   LJ_LIB_REG(L, NULL, ffi_clib);
858   LJ_LIB_REG(L, NULL, ffi_callback);
859   /* NOBARRIER: the key is new and lj_tab_newkey() handles the barrier. */
860   settabV(L, lj_tab_setstr(L, cts->miscmap, &cts->g->strempty), tabV(L->top-1));
861   L->top--;
862   lj_clib_default(L, tabV(L->top-1));  /* Create ffi.C default namespace. */
863   lua_pushliteral(L, LJ_OS_NAME);
864   lua_pushliteral(L, LJ_ARCH_NAME);
865   LJ_LIB_REG(L, NULL, ffi);  /* Note: no global "ffi" created! */
866   ffi_register_module(L);
867   return 1;
868 }
869 
870 #endif
871