summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-19 19:40:24 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-05-19 19:40:24 -0700
commita047e7f97db2c9947d0b017eeb8de126e656e1a4 (patch)
treee63e5a28cb7a77b8c97309dc7033dc010ceeb941
parent60793497c9d4c6f832c10408a9f390a1f2487a9a (diff)
downloadtxr-a047e7f97db2c9947d0b017eeb8de126e656e1a4.tar.gz
txr-a047e7f97db2c9947d0b017eeb8de126e656e1a4.tar.bz2
txr-a047e7f97db2c9947d0b017eeb8de126e656e1a4.zip
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.
-rw-r--r--ffi.c12
1 files 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