fixed pointer argument handling issues when interfacing with libffi in mod/ffi.c

This commit is contained in:
hyunghwan.chung 2019-08-10 04:08:49 +00:00
parent 70c97f5ab5
commit 85eae9e78b
3 changed files with 76 additions and 26 deletions

View File

@ -210,3 +210,14 @@ what looks better as a shorthand expression for block value?
a->()? block value? a->()? block value?
``` ```
### FFI
```
ffi := FFI new: 'libc.so.6'.
(ffi call: #printf signature: 's|sl>i' arguments: #("[%s ffi test %ld]\n" "sloppy" 12345678)) dump.
(ffi call: #printf signature: 's>i' arguments: #("[%% ffi test %%]\n")) dump.
(ffi call: #puts signature: 's>i' arguments: #("this is ffi test")) dump.
(ffi call: #time signature: 'p>l' arguments: #(#\p0)) dump.
ffi close.
```

View File

@ -34,7 +34,8 @@ class FFI(Object)
self.name := name. self.name := name.
x := self.ffi open(name). x := self.ffi open(name).
(x isError) ifTrue: [^x]. //(x isError) ifTrue: [^x].
if (x isError) { FFIException signal: ('Unable to open %s' strfmt(name)) }.
^self. ^self.
} }

View File

@ -1,4 +1,4 @@
/* /*arg
* $Id$ * $Id$
* *
Copyright (c) 2014-2018 Chung, Hyung-Hwan. All rights reserved. Copyright (c) 2014-2018 Chung, Hyung-Hwan. All rights reserved.
@ -57,9 +57,9 @@
#define FMTC_INT 'i' #define FMTC_INT 'i'
#define FMTC_LONG 'l' #define FMTC_LONG 'l'
#define FMTC_LONGLONG 'L' #define FMTC_LONGLONG 'L'
#define FMTC_POINTER 'p'
#define FMTC_BCS 's' #define FMTC_BCS 's'
#define FMTC_UCS 'S' #define FMTC_UCS 'S'
#define FMTC_POINTER 'p'
typedef struct link_t link_t; typedef struct link_t link_t;
struct link_t struct link_t
@ -232,8 +232,7 @@ static moo_pfrc_t pf_close (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcFree (ffi->dc); dcFree (ffi->dc);
ffi->dc = MOO_NULL; ffi->dc = MOO_NULL;
#endif #elif defined(USE_LIBFFI)
#if defined(USE_LIBFFI)
if (ffi->arg_types) if (ffi->arg_types)
{ {
moo_freemem (moo, ffi->arg_types); moo_freemem (moo, ffi->arg_types);
@ -264,8 +263,7 @@ softfail:
return MOO_PF_SUCCESS; return MOO_PF_SUCCESS;
} }
static MOO_INLINE int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned, moo_oop_t arg)
static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned, moo_oop_t arg)
{ {
#if defined(USE_LIBFFI) #if defined(USE_LIBFFI)
if (ffi->arg_count >= ffi->arg_max) if (ffi->arg_count >= ffi->arg_max)
@ -294,7 +292,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
switch (fmtc) switch (fmtc)
{ {
case FMTC_CHAR: case FMTC_CHAR:
if (!MOO_OOP_IS_CHAR(arg)) goto inval; if (!MOO_OOP_IS_CHAR(arg)) goto inval_arg_value;
if (_unsigned) if (_unsigned)
{ {
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
@ -319,7 +317,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
if (_unsigned) if (_unsigned)
{ {
moo_oow_t v; moo_oow_t v;
if (moo_inttooow(moo, arg, &v) == 0) goto inval; if (moo_inttooow(moo, arg, &v) == 0) goto inval_arg_value;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgShort (ffi->dc, v); dcArgShort (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -330,7 +328,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
else else
{ {
moo_ooi_t v; moo_ooi_t v;
if (moo_inttoooi(moo, arg, &v) == 0) goto inval; if (moo_inttoooi(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgShort (ffi->dc, v); dcArgShort (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -344,7 +342,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
if (_unsigned) if (_unsigned)
{ {
moo_oow_t v; moo_oow_t v;
if (moo_inttooow(moo, arg, &v) == 0) goto inval; if (moo_inttooow(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgInt (ffi->dc, v); dcArgInt (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -355,7 +353,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
else else
{ {
moo_ooi_t v; moo_ooi_t v;
if (moo_inttoooi(moo, arg, &v) == 0) goto inval; if (moo_inttoooi(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgInt (ffi->dc, v); dcArgInt (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -370,7 +368,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
if (_unsigned) if (_unsigned)
{ {
moo_oow_t v; moo_oow_t v;
if (moo_inttooow(moo, arg, &v) == 0) goto inval; if (moo_inttooow(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgLong (ffi->dc, v); dcArgLong (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -381,7 +379,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
else else
{ {
moo_ooi_t v; moo_ooi_t v;
if (moo_inttoooi(moo, arg, &v) == 0) goto inval; if (moo_inttoooi(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgLong (ffi->dc, v); dcArgLong (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -399,7 +397,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
{ {
moo_oow_t v; moo_oow_t v;
/* TODO: if (MOO_SIZEOF_LONG_LONG > MOO_SIZEOF_OOI_T) use moo_inttointmax() or something */ /* TODO: if (MOO_SIZEOF_LONG_LONG > MOO_SIZEOF_OOI_T) use moo_inttointmax() or something */
if (moo_inttooow(moo, arg, &v) == 0) goto inval; if (moo_inttooow(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgLongLong (ffi->dc, v); dcArgLongLong (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -410,7 +408,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
else else
{ {
moo_ooi_t v; moo_ooi_t v;
if (moo_inttoooi(moo, arg, &v) == 0) goto inval; if (moo_inttoooi(moo, arg, &v) == 0) goto oops;
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgLongLong (ffi->dc, v); dcArgLongLong (ffi->dc, v);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
@ -428,7 +426,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
{ {
moo_bch_t* ptr; moo_bch_t* ptr;
if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
#if defined(MOO_OOCH_IS_UCH) #if defined(MOO_OOCH_IS_UCH)
ptr = moo_dupootobcharswithheadroom(moo, MOO_SIZEOF_VOID_P, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg), MOO_NULL); ptr = moo_dupootobcharswithheadroom(moo, MOO_SIZEOF_VOID_P, MOO_OBJ_GET_CHAR_SLOT(arg), MOO_OBJ_GET_SIZE(arg), MOO_NULL);
@ -443,7 +441,8 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgPointer (ffi->dc, ptr); dcArgPointer (ffi->dc, ptr);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
ffi->arg_values[ffi->arg_count] = ptr; ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
ffi->arg_svs[ffi->arg_count].p = ptr;
#endif #endif
break; break;
} }
@ -452,7 +451,7 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
{ {
moo_uch_t* ptr; moo_uch_t* ptr;
if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval; if (!MOO_OBJ_IS_CHAR_POINTER(arg)) goto inval_arg_value;
#if defined(MOO_OOCH_IS_UCH) #if defined(MOO_OOCH_IS_UCH)
ptr = MOO_OBJ_GET_CHAR_SLOT(arg); ptr = MOO_OBJ_GET_CHAR_SLOT(arg);
@ -467,14 +466,33 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcArgPointer (ffi->dc, ptr); dcArgPointer (ffi->dc, ptr);
#elif defined(USE_LIBFFI) #elif defined(USE_LIBFFI)
ffi->arg_values[ffi->arg_count] = ptr; ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
ffi->arg_svs[ffi->arg_count].p = ptr;
#endif
break;
}
case FMTC_POINTER:
{
void* ptr;
/* TODO: map nil to NULL? or should #\p0 be enough? */
if (!MOO_OOP_IS_SMPTR(arg)) goto inval_arg_value;
ptr = MOO_OOP_TO_SMPTR(arg);
#if defined(USE_DYNCALL)
dcArgPointer (ffic->dc, ptr);
#elif defined(USE_LIBFFI)
ffi->arg_values[ffi->arg_count] = &ffi->arg_svs[ffi->arg_count].p;
ffi->arg_svs[ffi->arg_count].p = ptr;
#endif #endif
break; break;
} }
default: default:
/* invalid argument signature specifier */ /* invalid argument signature specifier */
goto inval; moo_seterrbfmt (moo, MOO_EINVAL, "invalid signature character - %jc", fmtc);
goto oops;
} }
#if defined(USE_LIBFFI) #if defined(USE_LIBFFI)
@ -483,8 +501,8 @@ static int add_ffi_arg (moo_t* moo, ffi_t* ffi, moo_ooch_t fmtc, int _unsigned,
#endif #endif
return 0; return 0;
inval: inval_arg_value:
moo_seterrnum (moo, MOO_EINVAL); moo_seterrbfmt (moo, MOO_EINVAL, "invalid argument value - %O", arg);
oops: oops:
return -1; return -1;
@ -583,7 +601,6 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
fmtc = (i >= MOO_OBJ_GET_SIZE(sig)? FMTC_NULL: MOO_OBJ_GET_CHAR_VAL(sig, i)); fmtc = (i >= MOO_OBJ_GET_SIZE(sig)? FMTC_NULL: MOO_OBJ_GET_CHAR_VAL(sig, i));
#if defined(USE_LIBFFI) #if defined(USE_LIBFFI)
/* TODO: handle unsigned */ /* TODO: handle unsigned */
//printf ("XXXXXXXXXXXXXXXXXXXXXXXXXXXxAAAAAAAA %d %d %d %p %p [%s] [%s] %ld\n", (int)j, (int)nfixedargs, (int)ffi->arg_count, ffi->fmtc_to_type[0][fmtc], &ffi_type_sint32, ffi->arg_values[0], ffi->arg_values[1], *(long*)ffi->arg_values[2]);
fs = (nfixedargs == j)? ffi_prep_cif(&ffi->cif, FFI_DEFAULT_ABI, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types): fs = (nfixedargs == j)? ffi_prep_cif(&ffi->cif, FFI_DEFAULT_ABI, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types):
ffi_prep_cif_var(&ffi->cif, FFI_DEFAULT_ABI, nfixedargs, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types); ffi_prep_cif_var(&ffi->cif, FFI_DEFAULT_ABI, nfixedargs, j, ffi->fmtc_to_type[0][fmtc], ffi->arg_types);
if (fs != FFI_OK) if (fs != FFI_OK)
@ -685,7 +702,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
r = dcCallPointer(ffi->dc, f); r = dcCallPointer(ffi->dc, f);
#else #elif defined(USE_LIBFFI)
r = ffi->ret_sv.p; r = ffi->ret_sv.p;
#endif #endif
@ -711,7 +728,7 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
r = dcCallPointer(ffi->dc, f); r = dcCallPointer(ffi->dc, f);
#else #elif defined(USE_LIBFFI)
r = ffi->ret_sv.p; r = ffi->ret_sv.p;
#endif #endif
@ -730,6 +747,26 @@ static moo_pfrc_t pf_call (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs)
break; break;
} }
case FMTC_POINTER:
{
void* r;
#if defined(USE_DYNCALL)
r = dcCallPointer(ffi->dc, f);
#elif defined(USE_LIBFFI)
r = ffi->ret_sv.p;
#endif
if (!MOO_IN_SMPTR_RANGE(r))
{
/* the returned pointer is not aligned */
goto softfail;
}
MOO_STACK_SETRET (moo, nargs, MOO_SMPTR_TO_OOP(r));
break;
}
default: default:
#if defined(USE_DYNCALL) #if defined(USE_DYNCALL)
dcCallVoid (ffi->dc, f); dcCallVoid (ffi->dc, f);
@ -842,6 +879,7 @@ static moo_pfbase_t* query (moo_t* moo, moo_mod_t* mod, const moo_ooch_t* name,
static void unload (moo_t* moo, moo_mod_t* mod) static void unload (moo_t* moo, moo_mod_t* mod)
{ {
/* TODO: anything? close open open dll handles? For that, pf_open must store the value it returns to mod->ctx or somewhere..*/ /* TODO: anything? close open open dll handles? For that, pf_open must store the value it returns to mod->ctx or somewhere..*/
/* TODO: track all opened shared objects... clear all external memories/resources created but not cleared (for lacking the call to 'close') */
} }
int moo_mod_ffi (moo_t* moo, moo_mod_t* mod) int moo_mod_ffi (moo_t* moo, moo_mod_t* mod)