diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2019-06-11 17:16:50 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2019-06-13 12:22:29 +0200 |
commit | 01a13882bb59a6960904a7a78ad608146a6dc510 (patch) | |
tree | 67e4d57beb48ea2ac87fc3f2371ec6ca54e6cc92 /src/datatype.c | |
parent | 29d0b6b0526ed9b661db9f1c8dbd2abbff11483a (diff) |
src: add reference counter for dynamic datatypes
There are two datatypes are using runtime datatype allocation:
* Concatenations.
* Integer, that require byteorder adjustment.
From the evaluation / postprocess step, transformations are common,
hence expressions may end up fetching (infering) datatypes from an
existing one.
This patch adds a reference counter to release the dynamic datatype
object when it is shared.
The API includes the following helper functions:
* datatype_set(expr, datatype), to assign a datatype to an expression.
This helper already deals with reference counting for dynamic
datatypes. This also drops the reference counter of any previous
datatype (to deal with the datatype replacement case).
* datatype_get(datatype) bumps the reference counter. This function also
deals with nul-pointers, that occurs when the datatype is unset.
* datatype_free() drops the reference counter, and it also releases the
datatype if there are not more clients of it.
Rule of thumb is: The reference counter of any newly allocated datatype
is set to zero.
This patch also updates every spot to use datatype_set() for non-dynamic
datatypes, for consistency. In this case, the helper just makes an
simple assignment.
Note that expr_alloc() has been updated to call datatype_get() on the
datatype that is assigned to this new expression. Moreover, expr_free()
calls datatype_free().
This fixes valgrind reports like this one:
==28352== 1,350 (440 direct, 910 indirect) bytes in 5 blocks are definitely lost in loss recor 3 of 3
==28352== at 0x4C2BBAF: malloc (vg_replace_malloc.c:299)
==28352== by 0x4E79558: xmalloc (utils.c:36)
==28352== by 0x4E7963D: xzalloc (utils.c:65)
==28352== by 0x4E6029B: dtype_alloc (datatype.c:1073)
==28352== by 0x4E6029B: concat_type_alloc (datatype.c:1127)
==28352== by 0x4E6D3B3: netlink_delinearize_set (netlink.c:578)
==28352== by 0x4E6D68E: list_set_cb (netlink.c:648)
==28352== by 0x5D74023: nftnl_set_list_foreach (set.c:780)
==28352== by 0x4E6D6F3: netlink_list_sets (netlink.c:669)
==28352== by 0x4E5A7A3: cache_init_objects (rule.c:159)
==28352== by 0x4E5A7A3: cache_init (rule.c:216)
==28352== by 0x4E5A7A3: cache_update (rule.c:266)
==28352== by 0x4E7E0EE: nft_evaluate (libnftables.c:388)
==28352== by 0x4E7EADD: nft_run_cmd_from_filename (libnftables.c:479)
==28352== by 0x109A53: main (main.c:310)
This patch also removes the DTYPE_F_CLONE flag which is broken and not
needed anymore since proper reference counting is in place.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/datatype.c')
-rw-r--r-- | src/datatype.c | 46 |
1 files changed, 36 insertions, 10 deletions
diff --git a/src/datatype.c b/src/datatype.c index 1d5ed6f7..43cf45bd 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -1076,6 +1076,25 @@ static struct datatype *dtype_alloc(void) return dtype; } +struct datatype *datatype_get(const struct datatype *ptr) +{ + struct datatype *dtype = (struct datatype *)ptr; + + if (!dtype) + return NULL; + if (!(dtype->flags & DTYPE_F_ALLOC)) + return dtype; + + dtype->refcnt++; + return dtype; +} + +void datatype_set(struct expr *expr, const struct datatype *dtype) +{ + datatype_free(expr->dtype); + expr->dtype = datatype_get(dtype); +} + static struct datatype *dtype_clone(const struct datatype *orig_dtype) { struct datatype *dtype; @@ -1084,18 +1103,26 @@ static struct datatype *dtype_clone(const struct datatype *orig_dtype) *dtype = *orig_dtype; dtype->name = xstrdup(orig_dtype->name); dtype->desc = xstrdup(orig_dtype->desc); - dtype->flags = DTYPE_F_ALLOC | DTYPE_F_CLONE; + dtype->flags = DTYPE_F_ALLOC; + dtype->refcnt = 0; return dtype; } -static void dtype_free(const struct datatype *dtype) +void datatype_free(const struct datatype *ptr) { - if (dtype->flags & DTYPE_F_ALLOC) { - xfree(dtype->name); - xfree(dtype->desc); - xfree(dtype); - } + struct datatype *dtype = (struct datatype *)ptr; + + if (!dtype) + return; + if (!(dtype->flags & DTYPE_F_ALLOC)) + return; + if (--dtype->refcnt > 0) + return; + + xfree(dtype->name); + xfree(dtype->desc); + xfree(dtype); } const struct datatype *concat_type_alloc(uint32_t type) @@ -1137,7 +1164,7 @@ const struct datatype *concat_type_alloc(uint32_t type) void concat_type_destroy(const struct datatype *dtype) { - dtype_free(dtype); + datatype_free(dtype); } const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype, @@ -1157,8 +1184,7 @@ const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype, void set_datatype_destroy(const struct datatype *dtype) { - if (dtype && dtype->flags & DTYPE_F_CLONE) - dtype_free(dtype); + datatype_free(dtype); } static struct error_record *time_unit_parse(const struct location *loc, |