r9373: - create a hierachical memory tree with recursiv ndr_pull_* functions
authorStefan Metzmacher <metze@samba.org>
Thu, 18 Aug 2005 01:24:08 +0000 (01:24 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:33:29 +0000 (13:33 -0500)
- 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
source4/librpc/ndr/libndr.h
source4/librpc/ndr/ndr.c
source4/librpc/ndr/ndr_compression.c
source4/librpc/ndr/ndr_krb5pac.c
source4/librpc/ndr/ndr_sec.c

index 8692fbb0f4977a2e248dd2ebe9b909f23ed687d5..d456bd58985c4d517752574c4502ba10ffd6315f 100644 (file)
@@ -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};";
index b7e06087a7f0560e7ae65930be84df813fcb2570..a319a44102c5a1dd5d1ac98a1387ecee70f0e2a1 100644 (file)
@@ -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)))
index a84049a3b070be46a70c88825efd994123078127..6bc4198de1d51a39268acb6327ba7c99f4d2bb13 100644 (file)
@@ -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;
index 097f76c90a733272dbea59d7cacd77a998bb1442..def194634f08d1e459222aacc7fe85301c793449 100644 (file)
@@ -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;
index 7d7e105e3ecd39d6f5a6d74f8a0586c0496bb72b..92e3d777072e5a9cfb9139b4848289ef0b5c2151 100644 (file)
@@ -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;
index c6eb98c58a09a5e47d1354e5cee3e495aca87c3a..fb18d48909d8b65da37a90898687f6ac67b0b713 100644 (file)
@@ -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;