From a047e7f97db2c9947d0b017eeb8de126e656e1a4 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Fri, 19 May 2017 19:40:24 -0700 Subject: ffi: release return value when aborting callback. Continuing on the topic of the previous commit, what if in a callback an error occurs in the put operation that produces the return value? In that case we end up clobbering with the abort_retval or nulling out with zero bytes, either way potentially leaking memory. * ffi.c (ffi_closure_dispatch_safe): If the return value type has release semantics, then as the very first thing, null out the return value buffer. Then later if a dynamic control transfer is intercepted, invoke the release semantics before doing anything to the return value buffer. --- ffi.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ffi.c b/ffi.c index 3140204d..ce97c2e4 100644 --- a/ffi.c +++ b/ffi.c @@ -2181,11 +2181,14 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, struct txr_ffi_call_desc *tfcd = tfcl->tfcd; val types = tfcd->argtypes; val rtype = tfcd->rettype; - struct txr_ffi_type *volatile rtft = 0; - val retval = nil; + struct txr_ffi_type *rtft = ffi_type_struct(rtype); + volatile val retval = nao; int out_pass_needed = 0; uw_frame_t cont_guard; + if (rtft->release != 0) + memset(cret, 0, rtft->size); + uw_push_guard(&cont_guard, 0); uw_simple_catch_begin; @@ -2193,7 +2196,6 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, { args_decl(args, tfcl->nparam); args_decl(args_cp, tfcl->nparam); - rtft = ffi_type_struct(rtype); for (i = 0; i < nargs; i++) { val type = pop(&types); @@ -2223,7 +2225,9 @@ static void ffi_closure_dispatch_safe(ffi_cif *cif, void *cret, uw_unwind { s_exit_point = uw_curr_exit_point; - if (s_exit_point && rtft != 0) { + if (s_exit_point) { + if (rtft->release != 0 && retval != nao) + rtft->release(rtft, retval, convert(mem_t *, cret)); if (!tfcl->abort_retval) memset(cret, 0, rtft->size); else -- cgit v1.2.3