diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2022-03-17 07:13:59 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2022-03-17 07:13:59 -0700 |
commit | 11bffd3fe034af0fbe6a9bab4c382dca5d945b9d (patch) | |
tree | 8b792e2dab00bc88a14b663d8bf6e261e9a30251 | |
parent | d259634cb2d65b73ae1715a4c361c58b0dc998ae (diff) | |
download | txr-11bffd3fe034af0fbe6a9bab4c382dca5d945b9d.tar.gz txr-11bffd3fe034af0fbe6a9bab4c382dca5d945b9d.tar.bz2 txr-11bffd3fe034af0fbe6a9bab4c382dca5d945b9d.zip |
ffi: after call, process args in reverse order.
In FFI foreign function and closure calls, it behooves us to
iterate over the arguments in the opposite order after the
call is done. By doing that, any freeing of memory that will
be done will be in the opposite order. And that is necessary
if some left argument allocates a pointer that is shared with
a right argument. An example of this occurs in the strtol
function:
long int strtol(const char *nptr, char **endptr, int base);
Here, the function sets *endptr to a value derived by
displacing ptr. If we call this function via FFI, then FFI
will allocate memory for nptr. When the function returns,
if we destroy that memory before processing *endptr
then *endptr contains an invalid pointer.
* ffi.c (ffi_call_wrap): In the in pass, iterate arguments
in reverse.
(ffi_closure_dispatch, ffi_closure_dispatch_safe):
Stack-allocate an array for the argument types, so we don't
have to pop the list twice, and to allow access in reverse
order. In the out pass, iterate arguments in reverse.
-rw-r--r-- | ffi.c | 21 |
1 files changed, 10 insertions, 11 deletions
@@ -4948,7 +4948,7 @@ val ffi_call_wrap(val fptr, val ffi_call_desc, struct args *args) ret = ifbe2(rtft->rget, rtft->get)(rtft, convert(mem_t *, rc), self); if (in_pass_needed) { - for (i = 0; i < n; i++) { + for (i = n - 1; i >= 0; i--) { struct txr_ffi_type *mtft = type[i]; if (mtft->by_value_in) mtft->in(mtft, 0, convert(mem_t *, values[i]), args->arg[i], self); @@ -4977,14 +4977,15 @@ static void ffi_closure_dispatch(ffi_cif *cif, void *cret, struct txr_ffi_type *rtft = ffi_type_struct(rtype); val retval = nil; int out_pass_needed = 0; + val *type = convert(val *, alloca(nargs * sizeof *type)); args_decl(args, nargs); args_decl(args_cp, nargs); + (void) cif; for (i = 0; i < nargs; i++) { - val type = pop(&types); - struct txr_ffi_type *mtft = ffi_type_struct(type); + struct txr_ffi_type *mtft = ffi_type_struct((type[i] = pop(&types))); val arg = mtft->get(mtft, convert(mem_t *, cargs[i]), self); args_add(args, arg); if (mtft->out != 0) @@ -4996,10 +4997,9 @@ static void ffi_closure_dispatch(ffi_cif *cif, void *cret, retval = generic_funcall(tfcl->fun, args); if (out_pass_needed) { - for (types = tfcd->argtypes, i = 0; i < nargs; i++) { - val type = pop(&types); + for (types = tfcd->argtypes, i = nargs - 1; i >= 0; i--) { val arg = args_at(args_cp, i); - struct txr_ffi_type *mtft = ffi_type_struct(type); + struct txr_ffi_type *mtft = ffi_type_struct(type[i]); if (mtft->out != 0) mtft->out(mtft, 0, arg, convert(mem_t *, cargs[i]), self); } @@ -5038,10 +5038,10 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, { args_decl(args, nargs); args_decl(args_cp, nargs); + val *type = convert(val *, alloca(nargs * sizeof *type)); for (i = 0; i < nargs; i++) { - val type = pop(&types); - struct txr_ffi_type *mtft = ffi_type_struct(type); + struct txr_ffi_type *mtft = ffi_type_struct((type[i] = pop(&types))); val arg = mtft->get(mtft, convert(mem_t *, cargs[i]), self); args_add(args, arg); if (mtft->out != 0) @@ -5053,10 +5053,9 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, retval = generic_funcall(tfcl->fun, args); if (out_pass_needed) { - for (types = tfcd->argtypes, i = 0; i < nargs; i++) { - val type = pop(&types); + for (types = tfcd->argtypes, i = nargs - 1; i >= 0; i--) { val arg = args_at(args_cp, i); - struct txr_ffi_type *mtft = ffi_type_struct(type); + struct txr_ffi_type *mtft = ffi_type_struct(type[i]); if (mtft->out != 0) mtft->out(mtft, 0, arg, convert(mem_t *, cargs[i]), self); } |