pidl: Avoid leaving array_length NDR tokens around
authorAndrew Bartlett <abartlet@samba.org>
Fri, 21 May 2021 22:17:49 +0000 (10:17 +1200)
committerDouglas Bagnall <dbagnall@samba.org>
Wed, 2 Jun 2021 03:56:36 +0000 (03:56 +0000)
In many cases these can and should be consumed as soon as
they are used.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=14710

Signed-off-by: Andrew Bartlett <abartlet@samba.org>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
librpc/ABI/ndr-2.0.0.sigs
librpc/ndr/libndr.h
librpc/ndr/ndr.c
pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm

index 017b9b3500d434361027fd78dbd572accc458cf1..dbd65360eb80dcb46ddefc8938a10c5596083e44 100644 (file)
@@ -16,10 +16,10 @@ _ndr_pull_error: enum ndr_err_code (struct ndr_pull *, enum ndr_err_code, const
 _ndr_push_error: enum ndr_err_code (struct ndr_push *, enum ndr_err_code, const char *, const char *, const char *, ...)
 ndr_align_size: size_t (uint32_t, size_t)
 ndr_charset_length: uint32_t (const void *, charset_t)
-ndr_check_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
 ndr_check_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
 ndr_check_padding: void (struct ndr_pull *, size_t)
 ndr_check_pipe_chunk_trailer: enum ndr_err_code (struct ndr_pull *, int, uint32_t)
+ndr_check_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t)
 ndr_check_string_terminator: enum ndr_err_code (struct ndr_pull *, uint32_t, uint32_t)
 ndr_get_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
 ndr_get_array_size: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
@@ -249,6 +249,7 @@ ndr_size_string_array: size_t (const char **, uint32_t, int)
 ndr_size_struct: size_t (const void *, int, ndr_push_flags_fn_t)
 ndr_size_union: size_t (const void *, int, uint32_t, ndr_push_flags_fn_t)
 ndr_size_winreg_Data_GPO: size_t (const union winreg_Data_GPO *, uint32_t, int)
+ndr_steal_array_length: enum ndr_err_code (struct ndr_pull *, const void *, uint32_t *)
 ndr_string_array_size: size_t (struct ndr_push *, const char *)
 ndr_string_length: uint32_t (const void *, uint32_t)
 ndr_syntax_id_buf_string: char *(const struct ndr_syntax_id *, struct ndr_syntax_id_buf *)
index 156f70216c2e0e47bfa79852cedb2022679547b4..58b04e983710626ff7f1387d0960348a49379c7c 100644 (file)
@@ -659,7 +659,9 @@ enum ndr_err_code ndr_get_array_size(struct ndr_pull *ndr, const void *p, uint32
 enum ndr_err_code ndr_check_array_size(struct ndr_pull *ndr, const void *p, uint32_t size);
 enum ndr_err_code ndr_pull_array_length(struct ndr_pull *ndr, const void *p);
 enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length);
+enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length);
 enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length);
+enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length);
 enum ndr_err_code ndr_push_pipe_chunk_trailer(struct ndr_push *ndr, int ndr_flags, uint32_t count);
 enum ndr_err_code ndr_check_pipe_chunk_trailer(struct ndr_pull *ndr, int ndr_flags, uint32_t count);
 enum ndr_err_code ndr_push_set_switch_value(struct ndr_push *ndr, const void *p, uint32_t val);
index f5502b7c7054bcb144b5f9d5a0c82e3192296608..eaeb3b0e0948d197a58ded96e8fcb3adabc36826 100644 (file)
@@ -1143,12 +1143,21 @@ _PUBLIC_ enum ndr_err_code ndr_get_array_length(struct ndr_pull *ndr, const void
 }
 
 /*
-  check the stored array length field
+ * check the stored array length field and remove from the stored list
+ * (the array_size NDR token list).  We try to remove when possible to
+ * avoid the list growing towards the bounds check
+ */
+_PUBLIC_ enum ndr_err_code ndr_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t *length)
+{
+       return ndr_token_retrieve(&ndr->array_length_list, p, length);
+}
+/*
+  check the stored array length field, removing it from the list
 */
-_PUBLIC_ enum ndr_err_code ndr_check_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
+_PUBLIC_ enum ndr_err_code ndr_check_steal_array_length(struct ndr_pull *ndr, const void *p, uint32_t length)
 {
        uint32_t stored;
-       NDR_CHECK(ndr_token_peek(&ndr->array_length_list, p, &stored));
+       NDR_CHECK(ndr_steal_array_length(ndr, p, &stored));
        if (stored != length) {
                return ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE,
                                      "Bad array length - got %u expected %u\n",
index 011fd3fa0c4efa6e588b0e64221ca25b8f7ad35d..5927e973c32d6b91b1f10fc0e4cab080a5770933 100644 (file)
@@ -387,8 +387,12 @@ sub ParseArrayPullGetLength($$$$$$;$)
        }
 
        my $array_length = "length_$e->{NAME}_$l->{LEVEL_INDEX}";
-
-       $self->pidl("NDR_CHECK(ndr_get_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));");
+       if ($l->{IS_VARYING} and (defined($l->{LENGTH_IS}) or not $l->{IS_ZERO_TERMINATED})) {
+               $self->pidl("NDR_CHECK(ndr_get_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));");
+       } else {
+               # This will be the last use of the array_length token
+               $self->pidl("NDR_CHECK(ndr_steal_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", &$array_length));");
+       }
 
        if (my $range = has_property($e, "range")) {
                my ($low, $high) = parse_range($range);
@@ -451,7 +455,8 @@ sub ParseArrayPullHeader($$$$$$)
                        check_null_pointer($e, $env, sub { $self->defer(shift); },
                                           "return ndr_pull_error($ndr, NDR_ERR_INVALID_POINTER, \"NULL Pointer for length_is()\");"),
                        check_fully_dereferenced($e, $env));
-               $self->defer("NDR_CHECK(ndr_check_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));");
+               # This will be deferred until after the last ndr_get_array_length()
+               $self->defer("NDR_CHECK(ndr_check_steal_array_length($ndr, (void*)" . get_pointer_to($var_name) . ", $length));");
                $self->defer_deindent;
                $self->defer("}");
        }