From: Thomas Haller <thaller@redhat.com>
To: Pablo Neira Ayuso <pablo@netfilter.org>
Cc: NetFilter <netfilter-devel@vger.kernel.org>
Subject: Re: [nft PATCH] datatype: fix leak and cleanup reference counting for struct datatype
Date: Tue, 12 Sep 2023 09:18:34 +0200 [thread overview]
Message-ID: <0c61700ba841fa0aed32e99476a675aa325ce97f.camel@redhat.com> (raw)
In-Reply-To: <ZP+JBMa83ArN1FQD@calendula>
Hi Pablo,
> > @@ -3806,37 +3833,43 @@ static int stmt_evaluate_nat_map(struct
> > eval_ctx *ctx, struct stmt *stmt)
> >
> > datatype_set(data, dtype);
>
> Note here above, dtype is set to data expression, then...
>
> >
> > - if (expr_ops(data)->type != EXPR_CONCAT)
> > - return __stmt_evaluate_arg(ctx, stmt, dtype, dtype-
> > >size,
> > + if (expr_ops(data)->type != EXPR_CONCAT) {
> > + r = __stmt_evaluate_arg(ctx, stmt, dtype, dtype-
> > >size,
> > BYTEORDER_BIG_ENDIAN,
> > &stmt->nat.addr);
> > + goto out;
>
> ... this goto is not needed anymore? dtype has been already set to
> data.
> So this patch can be simplified. Same things for goto below in the
> scope of this function.
After datatype_set(data, dtype) the reference to "dtype" must still be
released. The simple way is
datatype_set(data, dtype);
datatype_free(dtype);
dtype = NULL;
and make sure to not use "dtype" afterwards, but data->dtype.
But there are already "goto out" earlier. So this change of cleanup-
style halfway through is error prone. We could also drop the other
"goto out" and explicitly implement cleanup at the multiple exit points
of the function. But that's also error prone and redundant.
The safe thing is to be very clear which variable holds a reference
(dtype), and always+only release it at the end (goto out).
The real solution to all of this would be __attribute__((cleanup)) and
let the compiler help. Unless that is used, a consistent `goto out` is
the cleanest solution.
It's about consistently doing "goto out", and not that you could rework
one "goto-out" with something else to safe a few lines of code. Once we
do "goto out", there is no need trying to release references early or
do anything smart with transferring ownership.
> > @@ -978,7 +983,8 @@ struct set *netlink_delinearize_set(struct
> > netlink_ctx *ctx,
> > if (keytype == NULL) {
> > netlink_io_error(ctx, NULL, "Unknown data type in
> > set key %u",
> > key);
> > - return NULL;
> > + set = NULL;
> > + goto out;
>
> Why this goto out? Not really needed.
No, it's not needed for technical reasons. It's there for consistency
regarding the release of the pointers. Anyway, I drop this.
I will later propose a patch using __attribute__((cleanup)) for
comparison.
>
> > }
> >
> > flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
> > @@ -991,8 +997,8 @@ struct set *netlink_delinearize_set(struct
> > netlink_ctx *ctx,
> > netlink_io_error(ctx, NULL,
> > "Unknown data type in set
> > key %u",
> > data);
> > - datatype_free(keytype);
> > - return NULL;
> > + set = NULL;
> > + goto out;
> > }
> > }
> >
> > @@ -1030,19 +1036,18 @@ struct set *netlink_delinearize_set(struct
> > netlink_ctx *ctx,
> > if (datatype) {
>
> Move this code under this if (datatype) branch into function in a
> preparation patch.
>
> Please, call it:
>
> netlink_delinearize_set_typeof()
>
> or pick a better name if you like so there is no need for dtype2.
>
> It will help clean up this chunk that you are passing by here.
Not sure how to do that. For one, the if-block is only used at one
place. So the function isn't really reusable (or where can I also reuse
it)?. Also, it uses quite many local variables. If all those become
function parameters, it's confusing. If I move only a subset of the
block to the new function, it's not clear how it simplifies anything. I
think there is not a sufficiently isolated functionality, that warrants
a function.
netlink_delinearize_set() is large and allocates up to 4 datattypes
that we need to release (datatype, keytype, dtype2, dtype). With the
patch, the pattern is very simple, that those 4 variables get only
assigned at one place, and always released only at the end (goto out).
Moving the block to a separate function, at most safes dtype2 but
doesn't remove the general need for such release-at-end. If I really
wanted, I could move dtype2 inside the if-block. But that doesn't seem
useful, given there is a consistent RAII-like cleanup mechanism in
place.
Other points will be fixed in v2.
Thomas
prev parent reply other threads:[~2023-09-12 7:19 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-09-11 9:01 [nft PATCH] datatype: fix leak and cleanup reference counting for struct datatype Thomas Haller
2023-09-11 21:39 ` Pablo Neira Ayuso
2023-09-12 7:18 ` Thomas Haller [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0c61700ba841fa0aed32e99476a675aa325ce97f.camel@redhat.com \
--to=thaller@redhat.com \
--cc=netfilter-devel@vger.kernel.org \
--cc=pablo@netfilter.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).