summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-03-17 07:13:59 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-03-17 07:13:59 -0700
commit11bffd3fe034af0fbe6a9bab4c382dca5d945b9d (patch)
tree8b792e2dab00bc88a14b663d8bf6e261e9a30251
parentd259634cb2d65b73ae1715a4c361c58b0dc998ae (diff)
downloadtxr-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.c21
1 files changed, 10 insertions, 11 deletions
diff --git a/ffi.c b/ffi.c
index 1ecd6678..e8e673ab 100644
--- a/ffi.c
+++ b/ffi.c
@@ -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);
}