[Libguestfs] [libnbd PATCH 1/2] generator: Refactor handling of closures in unlocked functions
Richard W.M. Jones
rjones at redhat.com
Tue Sep 8 13:57:26 UTC 2020
On Mon, Sep 07, 2020 at 04:46:39PM -0500, Eric Blake wrote:
> We have a memory leak when a function with a closure exits early prior
> to registering that closure through some path that will guarantee
> cleanup. The easiest way to fix it is to guarantee that once a
> closure is passed into a public API, it will be cleaned regardless of
> whether that API succeeds or fails. But to avoid cleaning the closure
> more than once, we need to refactor our internal handling, in order to
> track when a closure has been handed off for later cleaning. The
> easiest way to do this is to pass closures by reference to all
> internal functions, so that helpers in the call stack can modify the
> incoming pointer rather than their own copy.
>
> This patch is just preparatory, with no semantic change. The public
> API still passes closures by copy, but the generator then operates on
> the address of that closure through all internal nbd_unlocked_*
> functions, rather than making further copies through each additional
> function call.
> ---
> generator/C.ml | 35 ++++++++++++-----------
> generator/C.mli | 1 +
> lib/debug.c | 6 ++--
> lib/opt.c | 26 ++++++++---------
> lib/rw.c | 76 ++++++++++++++++++++++++-------------------------
> 5 files changed, 73 insertions(+), 71 deletions(-)
>
> diff --git a/generator/C.ml b/generator/C.ml
> index deb77fa..280b319 100644
> --- a/generator/C.ml
> +++ b/generator/C.ml
> @@ -99,16 +99,17 @@ let rec name_of_arg = function
> | UInt64 n -> [n]
>
> let rec print_arg_list ?(wrap = false) ?maxcol ?handle ?types ?(parens = true)
> + ?(closure_mark) args optargs =
You don't need parens around here, you can just write ?closure_mark
> + if parens then pr "(";
> + if wrap then
> + pr_wrap ?maxcol ','
> + (fun () -> print_arg_list' ?handle ?types ?closure_mark args optargs)
> + else
> + print_arg_list' ?handle ?types ?closure_mark args optargs;
> + if parens then pr ")"
> +
> +and print_arg_list' ?(handle = false) ?(types = true) ?(closure_mark = "")
...
> args optargs =
> | Closure { cbname; cbargs } ->
> if types then pr "nbd_%s_callback " cbname;
> - pr "%s_callback" cbname
> + pr "%s%s_callback" closure_mark cbname
Perhaps make it type safe?
type closure_mark = AddressOf | Dereference
And then:
pr "%s%c_callback"
(match closure_mark with AddressOf -> '&' | Dereference -> '*')
cbname
...
> @@ -385,7 +386,7 @@ let generate_lib_unlocked_h () =
> pr "\n";
> List.iter (
> fun (name, { args; optargs; ret }) ->
> - print_extern ~wrap:true ("unlocked_" ^ name) args optargs ret
> + print_extern ~wrap:true ~closure_mark:"*" ("unlocked_" ^ name) args optargs ret
And at call sites like this one you'd use ~closure_mark:Dereference
Rest is fine.
ACK but definitely remove the superfluous parentheses above.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v
More information about the Libguestfs
mailing list