From ec96a742f7b6ce4cbb4f649dd8aba92ef80f0ff0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 18 Aug 2005 01:24:08 +0000 Subject: r9373: - create a hierachical memory tree with recursiv ndr_pull_* functions - with this it's also possible to talloc_free() the ndr_pull structure and talloc_steal(ndr->current_mem_ctx); to fetch the whole data of the hierachical tree - if the toplevel struct is a valid talloc pointer it's also possible to use NDR_PULL_SET_MEM_CTX(ndr, mem_ctx); to the the toplevel pointer with the struct pointer (NOTE: no callers are using this yet, but they shortly will) metze (This used to be commit 1a2b8369586642cc9bc15d015c1e4256c3a92732) --- source4/build/pidl/Parse/Pidl/Samba/NDR/Parser.pm | 137 ++++++++++++++++++++-- source4/librpc/ndr/libndr.h | 44 +++++-- source4/librpc/ndr/ndr.c | 2 + source4/librpc/ndr/ndr_compression.c | 1 + source4/librpc/ndr/ndr_krb5pac.c | 6 +- source4/librpc/ndr/ndr_sec.c | 2 + 6 files changed, 168 insertions(+), 24 deletions(-) diff --git a/source4/build/pidl/Parse/Pidl/Samba/NDR/Parser.pm b/source4/build/pidl/Parse/Pidl/Samba/NDR/Parser.pm index 8692fbb0f4..d456bd5898 100644 --- a/source4/build/pidl/Parse/Pidl/Samba/NDR/Parser.pm +++ b/source4/build/pidl/Parse/Pidl/Samba/NDR/Parser.pm @@ -836,6 +836,59 @@ sub CalcNdrFlags($$$) return undef; } +sub ParseMemCtxPullStart($$$) +{ + my $e = shift; + my $l = shift; + my $ptr_name = shift; + + my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}"; + my $mem_c_ctx = $ptr_name; + my $mem_c_flags = "0"; + + return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED}); + + if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) { + my $nl = GetNextLevel($e, $l); + my $next_is_array = ($nl->{TYPE} eq "ARRAY"); + my $next_is_string = (($nl->{TYPE} eq "DATA") and + ($nl->{DATA_TYPE} eq "string")); + if ($next_is_array or $next_is_string) { + return; + } else { + $mem_c_flags = "LIBNDR_FLAG_REF_ALLOC"; + } + } + + pidl "$mem_r_ctx = NDR_PULL_GET_MEM_CTX(ndr);"; + pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_c_ctx, $mem_c_flags);"; +} + +sub ParseMemCtxPullEnd($$) +{ + my $e = shift; + my $l = shift; + + my $mem_r_ctx = "_mem_save_$e->{NAME}_$l->{LEVEL_INDEX}"; + my $mem_r_flags = "0"; + + return if ($l->{TYPE} eq "ARRAY" and $l->{IS_FIXED}); + + if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) { + my $nl = GetNextLevel($e, $l); + my $next_is_array = ($nl->{TYPE} eq "ARRAY"); + my $next_is_string = (($nl->{TYPE} eq "DATA") and + ($nl->{DATA_TYPE} eq "string")); + if ($next_is_array or $next_is_string) { + return; + } else { + $mem_r_flags = "LIBNDR_FLAG_REF_ALLOC"; + } + } + + pidl "NDR_PULL_SET_MEM_CTX(ndr, $mem_r_ctx, $mem_r_flags);"; +} + sub ParseElementPullLevel { my($e,$l,$ndr,$var_name,$env,$primitives,$deferred) = @_; @@ -890,9 +943,13 @@ sub ParseElementPullLevel } } + ParseMemCtxPullStart($e,$l, $var_name); + $var_name = get_value_of($var_name); ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, 1, 1); + ParseMemCtxPullEnd($e,$l); + if ($l->{POINTER_TYPE} ne "ref") { if ($l->{POINTER_TYPE} eq "relative") { pidl "ndr_pull_restore(ndr, &_relative_save);"; @@ -904,9 +961,12 @@ sub ParseElementPullLevel not has_fast_array($e,$l) and not has_property($e, "charset")) { my $length = ParseExpr($l->{LENGTH_IS}, $env); my $counter = "cntr_$e->{NAME}_$l->{LEVEL_INDEX}"; + my $array_name = $var_name; $var_name = $var_name . "[$counter]"; + ParseMemCtxPullStart($e,$l, $array_name); + if (($primitives and not $l->{IS_DEFERRED}) or ($deferred and $l->{IS_DEFERRED})) { pidl "for ($counter = 0; $counter < $length; $counter++) {"; indent; @@ -927,6 +987,9 @@ sub ParseElementPullLevel deindent; pidl "}"; } + + ParseMemCtxPullEnd($e,$l); + } elsif ($l->{TYPE} eq "SWITCH") { ParseElementPullLevel($e,GetNextLevel($e,$l), $ndr, $var_name, $env, $primitives, $deferred); } @@ -969,7 +1032,7 @@ sub ParsePtrPull($$$$) unless ($next_is_array or $next_is_string) { pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; - pidl "\tNDR_ALLOC($ndr, $var_name);"; + pidl "\tNDR_PULL_ALLOC($ndr, $var_name);"; pidl "}"; } @@ -987,9 +1050,13 @@ sub ParsePtrPull($$$$) # Don't do this for arrays, they're allocated at the actual level # of the array unless ($next_is_array or $next_is_string) { - pidl "NDR_ALLOC($ndr, $var_name);"; + pidl "NDR_PULL_ALLOC($ndr, $var_name);"; } else { - pidl "NDR_ALLOC_SIZE($ndr, $var_name, 1);"; # FIXME: Yes, this is nasty. We allocate an array twice - once just to indicate that it's there, then the real allocation... + # FIXME: Yes, this is nasty. + # We allocate an array twice + # - once just to indicate that it's there, + # - then the real allocation... + pidl "NDR_PULL_ALLOC_SIZE($ndr, $var_name, 1);"; } #pidl "memset($var_name, 0, sizeof($var_name));"; @@ -1285,6 +1352,37 @@ sub DeclareArrayVariables($) } } +sub need_decl_mem_ctx($$) +{ + my $e = shift; + my $l = shift; + + return 0 if has_fast_array($e,$l); + return 0 if (has_property($e, "charset") and ($l->{TYPE} ne "POINTER")); + return 1 if (($l->{TYPE} eq "ARRAY") and not $l->{IS_FIXED}); + + if (($l->{TYPE} eq "POINTER") and ($l->{POINTER_TYPE} eq "ref")) { + my $nl = GetNextLevel($e, $l); + my $next_is_array = ($nl->{TYPE} eq "ARRAY"); + my $next_is_string = (($nl->{TYPE} eq "DATA") and + ($nl->{DATA_TYPE} eq "string")); + return 0 if ($next_is_array or $next_is_string); + } + return 1 if ($l->{TYPE} eq "POINTER"); + + return 0; +} + +sub DeclareMemCtxVariables($) +{ + my $e = shift; + foreach my $l (@{$e->{LEVELS}}) { + if (need_decl_mem_ctx($e, $l)) { + pidl "TALLOC_CTX *_mem_save_$e->{NAME}_$l->{LEVEL_INDEX};"; + } + } +} + ##################################################################### # parse a struct - pull side sub ParseStructPull($$) @@ -1299,6 +1397,7 @@ sub ParseStructPull($$) foreach my $e (@{$struct->{ELEMENTS}}) { DeclarePtrVariables($e); DeclareArrayVariables($e); + DeclareMemCtxVariables($e); } # save the old relative_base_offset @@ -1543,6 +1642,14 @@ sub ParseUnionPull($$) pidl Parse::Pidl::Typelist::mapType($switch_type) . " _level;"; } + my %double_cases = (); + foreach my $el (@{$e->{ELEMENTS}}) { + next if ($el->{TYPE} eq "EMPTY"); + next if ($double_cases{"$el->{NAME}"}); + DeclareMemCtxVariables($el); + $double_cases{"$el->{NAME}"} = 1; + } + start_flags($e); pidl "level = ndr_pull_get_switch_value(ndr, r);"; @@ -1846,12 +1953,12 @@ sub AllocateArrayLevel($$$$$) if (defined($pl) and $pl->{TYPE} eq "POINTER" and $pl->{POINTER_TYPE} eq "ref" - and not $l->{IS_ZERO_TERMINATED}) { - pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; - pidl "\tNDR_ALLOC_N($ndr, $var, $size);"; - pidl "}"; + and not $l->{IS_ZERO_TERMINATED}) { + pidl "if (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {"; + pidl "\tNDR_PULL_ALLOC_N($ndr, $var, $size);"; + pidl "}"; } else { - pidl "NDR_ALLOC_N($ndr, $var, $size);"; + pidl "NDR_PULL_ALLOC_N($ndr, $var, $size);"; } if (grep(/in/,@{$e->{DIRECTION}}) and @@ -1876,10 +1983,18 @@ sub ParseFunctionPull($) # declare any internal pointers we need foreach my $e (@{$fn->{ELEMENTS}}) { - DeclarePtrVariables($e); + DeclarePtrVariables($e); DeclareArrayVariables($e); } + my %double_cases = (); + foreach my $e (@{$fn->{ELEMENTS}}) { + next if ($e->{TYPE} eq "EMPTY"); + next if ($double_cases{"$e->{NAME}"}); + DeclareMemCtxVariables($e); + $double_cases{"$e->{NAME}"} = 1; + } + pidl "if (flags & NDR_IN) {"; indent; @@ -1917,7 +2032,7 @@ sub ParseFunctionPull($) my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env); check_null_pointer($size); - pidl "NDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);"; + pidl "NDR_PULL_ALLOC_N(ndr, r->out.$e->{NAME}, $size);"; if (grep(/in/, @{$e->{DIRECTION}})) { pidl "memcpy(r->out.$e->{NAME}, r->in.$e->{NAME}, $size * sizeof(*r->in.$e->{NAME}));"; @@ -1925,7 +2040,7 @@ sub ParseFunctionPull($) pidl "memset(r->out.$e->{NAME}, 0, $size * sizeof(*r->out.$e->{NAME}));"; } } else { - pidl "NDR_ALLOC(ndr, r->out.$e->{NAME});"; + pidl "NDR_PULL_ALLOC(ndr, r->out.$e->{NAME});"; if (grep(/in/, @{$e->{DIRECTION}})) { pidl "*r->out.$e->{NAME} = *r->in.$e->{NAME};"; diff --git a/source4/librpc/ndr/libndr.h b/source4/librpc/ndr/libndr.h index b7e06087a7..a319a44102 100644 --- a/source4/librpc/ndr/libndr.h +++ b/source4/librpc/ndr/libndr.h @@ -54,6 +54,8 @@ struct ndr_pull { struct ndr_token_list *array_length_list; struct ndr_token_list *switch_list; + TALLOC_CTX *current_mem_ctx; + /* this is used to ensure we generate unique reference IDs between request and reply */ uint32_t ptr_count; @@ -224,28 +226,46 @@ enum ndr_compression_alg { return _status; \ } while (0) +#define NDR_PULL_GET_MEM_CTX(ndr) (ndr->current_mem_ctx) -#define NDR_ALLOC_SIZE(ndr, s, size) do { \ - (s) = talloc_size(ndr, size); \ - if ((size) && !(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, \ - "Alloc %u failed\n", \ - (unsigned)size); \ - } while (0) +#define NDR_PULL_SET_MEM_CTX(ndr, mem_ctx, flgs) do {\ + if ( !(flgs) || (ndr->flags & flgs) ) {\ + if (!(mem_ctx)) {\ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "NDR_PULL_SET_MEM_CTX(NULL): %s\n", __location__); \ + }\ + ndr->current_mem_ctx = discard_const(mem_ctx);\ + }\ +} while(0) -#define NDR_ALLOC(ndr, s) NDR_ALLOC_SIZE(ndr, s, sizeof(*(s))) +#define _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr) do {\ + if (!ndr->current_mem_ctx) {\ + ndr->current_mem_ctx = talloc_new(ndr);\ + if (!ndr->current_mem_ctx) {\ + return ndr_pull_error(ndr, NDR_ERR_ALLOC, "_NDR_PULL_FIX_CURRENT_MEM_CTX() failed: %s\n", __location__); \ + }\ + }\ +} while(0) + +#define NDR_PULL_ALLOC_SIZE(ndr, s, size) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_size(ndr->current_mem_ctx, size); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u failed: %s\n",(unsigned)size, __location__); \ +} while (0) +#define NDR_PULL_ALLOC(ndr, s) NDR_PULL_ALLOC_SIZE(ndr, s, sizeof(*(s))) -#define NDR_ALLOC_N_SIZE(ndr, s, n, elsize) do { \ - (s) = talloc_array_size(ndr, elsize, n); \ - if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u * %u failed\n", (unsigned)n, (unsigned)elsize); \ +#define NDR_PULL_ALLOC_N_SIZE(ndr, s, n, elsize) do { \ + _NDR_PULL_FIX_CURRENT_MEM_CTX(ndr);\ + (s) = talloc_array_size(ndr->current_mem_ctx, elsize, n); \ + if (!(s)) return ndr_pull_error(ndr, NDR_ERR_ALLOC, "Alloc %u * %u failed: %s\n", (unsigned)n, (unsigned)elsize, __location__); \ } while (0) -#define NDR_ALLOC_N(ndr, s, n) NDR_ALLOC_N_SIZE(ndr, s, n, sizeof(*(s))) +#define NDR_PULL_ALLOC_N(ndr, s, n) NDR_PULL_ALLOC_N_SIZE(ndr, s, n, sizeof(*(s))) #define NDR_PUSH_ALLOC_SIZE(ndr, s, size) do { \ (s) = talloc_size(ndr, size); \ - if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %u failed\n", (unsigned)size); \ + if (!(s)) return ndr_push_error(ndr, NDR_ERR_ALLOC, "push alloc %u failed: %s\n", (unsigned)size, __location__); \ } while (0) #define NDR_PUSH_ALLOC(ndr, s) NDR_PUSH_ALLOC_SIZE(ndr, s, sizeof(*(s))) diff --git a/source4/librpc/ndr/ndr.c b/source4/librpc/ndr/ndr.c index a84049a3b0..6bc4198de1 100644 --- a/source4/librpc/ndr/ndr.c +++ b/source4/librpc/ndr/ndr.c @@ -50,6 +50,7 @@ struct ndr_pull *ndr_pull_init_blob(const DATA_BLOB *blob, TALLOC_CTX *mem_ctx) ndr = talloc_zero(mem_ctx, struct ndr_pull); if (!ndr) return NULL; + ndr->current_mem_ctx = mem_ctx; ndr->data = blob->data; ndr->data_size = blob->length; @@ -359,6 +360,7 @@ NTSTATUS ndr_pull_subcontext_start(struct ndr_pull *ndr, subndr = talloc_zero(ndr, struct ndr_pull); NT_STATUS_HAVE_NO_MEMORY(subndr); subndr->flags = ndr->flags; + subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->offset = 0; diff --git a/source4/librpc/ndr/ndr_compression.c b/source4/librpc/ndr/ndr_compression.c index 097f76c90a..def194634f 100644 --- a/source4/librpc/ndr/ndr_compression.c +++ b/source4/librpc/ndr/ndr_compression.c @@ -105,6 +105,7 @@ static NTSTATUS ndr_pull_compression_mszip(struct ndr_pull *subndr, comndr = talloc_zero(subndr, struct ndr_pull); NT_STATUS_HAVE_NO_MEMORY(comndr); comndr->flags = subndr->flags; + comndr->current_mem_ctx = subndr->current_mem_ctx; comndr->data = uncompressed.data; comndr->data_size = uncompressed.length; diff --git a/source4/librpc/ndr/ndr_krb5pac.c b/source4/librpc/ndr/ndr_krb5pac.c index 7d7e105e3e..92e3d77707 100644 --- a/source4/librpc/ndr/ndr_krb5pac.c +++ b/source4/librpc/ndr/ndr_krb5pac.c @@ -78,6 +78,7 @@ NTSTATUS ndr_push_PAC_BUFFER(struct ndr_push *ndr, int ndr_flags, const struct P NTSTATUS ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUFFER *r) { uint32_t _ptr_info; + TALLOC_CTX *_mem_save_info_0; if (ndr_flags & NDR_SCALARS) { NDR_CHECK(ndr_pull_align(ndr, 4)); NDR_CHECK(ndr_pull_PAC_TYPE(ndr, NDR_SCALARS, &r->type)); @@ -87,7 +88,7 @@ NTSTATUS ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUF ndr_set_flags(&ndr->flags, LIBNDR_FLAG_ALIGN8); NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_info)); if (_ptr_info) { - NDR_ALLOC(ndr, r->info); + NDR_PULL_ALLOC(ndr, r->info); NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->info, _ptr_info)); } else { r->info = NULL; @@ -104,6 +105,8 @@ NTSTATUS ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUF struct ndr_pull_save _relative_save; ndr_pull_save(ndr, &_relative_save); NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->info)); + _mem_save_info_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->info, 0); { struct ndr_pull *_ndr_info; NDR_CHECK(ndr_pull_subcontext_start(ndr, &_ndr_info, 0, r->_ndr_size)); @@ -111,6 +114,7 @@ NTSTATUS ndr_pull_PAC_BUFFER(struct ndr_pull *ndr, int ndr_flags, struct PAC_BUF NDR_CHECK(ndr_pull_PAC_INFO(_ndr_info, NDR_SCALARS|NDR_BUFFERS, r->info)); NDR_CHECK(ndr_pull_subcontext_end(ndr, _ndr_info, 0, r->_ndr_size)); } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_info_0, 0); ndr_pull_restore(ndr, &_relative_save); } ndr->flags = _flags_save_PAC_INFO; diff --git a/source4/librpc/ndr/ndr_sec.c b/source4/librpc/ndr/ndr_sec.c index c6eb98c58a..fb18d48909 100644 --- a/source4/librpc/ndr/ndr_sec.c +++ b/source4/librpc/ndr/ndr_sec.c @@ -70,6 +70,8 @@ NTSTATUS ndr_pull_dom_sid28(struct ndr_pull *ndr, int ndr_flags, struct dom_sid subndr = talloc_zero(ndr, struct ndr_pull); NT_STATUS_HAVE_NO_MEMORY(subndr); + subndr->flags = ndr->flags; + subndr->current_mem_ctx = ndr->current_mem_ctx; subndr->data = ndr->data + ndr->offset; subndr->data_size = 28; -- cgit