From 64112074e9772aead31092c8713e077d1aff050b Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Sun, 20 Feb 2005 02:57:38 +0000 Subject: r5465: Add support to multiple levels of pointers in pidl. Also add a new function to echo.idl that tests this behaviour. (This used to be commit e5eb5e847e75f2b7b041a66f84d9b919ddf27739) --- source4/build/pidl/ndr.pm | 173 ++++++++++++++++++++----------------- source4/build/pidl/validator.pm | 4 - source4/librpc/idl/echo.idl | 2 + source4/rpc_server/echo/rpc_echo.c | 9 ++ source4/torture/rpc/echo.c | 44 ++++++++++ 5 files changed, 151 insertions(+), 81 deletions(-) (limited to 'source4') diff --git a/source4/build/pidl/ndr.pm b/source4/build/pidl/ndr.pm index 2d885ca455..4f78ca6888 100644 --- a/source4/build/pidl/ndr.pm +++ b/source4/build/pidl/ndr.pm @@ -170,7 +170,10 @@ sub need_wire_pointer($) my $n = $e->{POINTERS}; my $pt = pointer_type($e); - if (defined($pt) and $pt eq "ref") { + if ( defined($pt) + and $pt eq "ref" + and $e->{PARENT}->{TYPE} eq "FUNCTION") + { $n--; } @@ -182,11 +185,8 @@ sub need_wire_pointer($) sub is_pure_scalar($) { my $e = shift; - if (util::has_property($e, "ref")) { - return 1; - } if (is_scalar_type($e->{TYPE}) && - !$e->{POINTERS} && + need_wire_pointer($e) == 0 && !util::array_size($e)) { return 1; } @@ -198,17 +198,19 @@ sub need_alloc($) { my $e = shift; - if (util::has_property($e, "ref")) { - return 0; - } - - if ($e->{POINTERS} || util::array_size($e)) { - return 1; - } - + return 0 if (util::has_property($e, "ref")); + return 1 if ($e->{POINTERS} || util::array_size($e)); return 0; } +sub c_ptr_prefix($) +{ + my $e = shift; + my $pointers = ""; + foreach my $i (need_wire_pointer($e)..$e->{POINTERS}-1) { $pointers.="*"; } + return $pointers; +} + # determine the C prefix used to refer to a variable when passing to a push # function. This will be '*' for pointers to scalar types, '' for scalar # types and normal pointers and '&' for pass-by-reference structures @@ -216,20 +218,22 @@ sub c_push_prefix($) { my $e = shift; - if ($e->{TYPE} =~ "string") { - return ""; - } + my $ret = ""; - if (is_scalar_type($e->{TYPE}) && + if ($e->{TYPE} =~ "string") { + $ret = ""; + } elsif (is_scalar_type($e->{TYPE}) && $e->{POINTERS}) { - return "*"; - } - if (!is_scalar_type($e->{TYPE}) && + $ret = "*"; + } elsif (!is_scalar_type($e->{TYPE}) && !$e->{POINTERS} && !util::array_size($e)) { return "&"; } - return ""; + + foreach my $i (2..$e->{POINTERS}) { $ret.="*"; } + + return $ret; } # determine the C prefix used to refer to a variable when passing to a pull @@ -246,7 +250,9 @@ sub c_pull_prefix($) return "&"; } - return ""; + my $ret = ""; + foreach my $i (2..$e->{POINTERS}) { $ret.="*"; } + return $ret; } my $res = ""; my $tabs = ""; @@ -488,10 +494,9 @@ sub ParseArrayPrint($$) my $e = shift; my $var_prefix = shift; my $size = ParseExpr($e, util::array_size($e), $var_prefix); - my $length = util::has_property($e, "length_is"); - if (defined $length) { - $size = ParseExpr($e, $length, $var_prefix); + if (is_varying_array($e)) { + $size = ParseExpr($e, util::has_property($e, "length_is"), $var_prefix); } if (is_scalar_type($e->{TYPE})) { @@ -508,8 +513,7 @@ sub CheckArraySizes($$) my $e = shift; my $var_prefix = shift; - if (!is_surrounding_array($e) && - is_conformant_array($e)) { + if (!is_surrounding_array($e) && is_conformant_array($e)) { my $size = ParseExpr($e, util::array_size($e), $var_prefix); pidl "if ($var_prefix$e->{NAME}) {"; indent; @@ -592,12 +596,13 @@ sub ParseArrayPull($$$) } } - if (my $length = util::has_property($e, "length_is")) { + if (is_varying_array($e)) { pidl "NDR_CHECK(ndr_pull_array_length(ndr, &$var_prefix$e->{NAME}));"; $size = "ndr_get_array_length(ndr, &$var_prefix$e->{NAME})"; } check_null_pointer($size); + if (is_scalar_type($e->{TYPE})) { pidl "NDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));"; } else { @@ -613,6 +618,7 @@ sub ParseElementPushScalar($$$) my($var_prefix) = shift; my($ndr_flags) = shift; my $cprefix = c_push_prefix($e); + my $ptr_prefix = c_ptr_prefix($e); my $sub_size = util::has_property($e, "subcontext"); start_flags($e); @@ -622,11 +628,11 @@ sub ParseElementPushScalar($$$) } if (util::has_property($e, "relative")) { - pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $var_prefix$e->{NAME}));"; + pidl "NDR_CHECK(ndr_push_relative_ptr1(ndr, $ptr_prefix$var_prefix$e->{NAME}));"; + } elsif (need_wire_pointer($e)) { + ParseElementPushPtr($e, $ptr_prefix.$var_prefix, "NDR_SCALARS"); } elsif (is_inline_array($e)) { ParseArrayPush($e, "r->", "NDR_SCALARS"); - } elsif (need_wire_pointer($e)) { - ParseElementPushPtr($e, $var_prefix, $ndr_flags); } elsif (need_alloc($e)) { # no scalar component } elsif (my $switch = util::has_property($e, "switch_is")) { @@ -659,6 +665,7 @@ sub ParseElementPrint($$) my($e) = shift; my($var_prefix) = shift; my $cprefix = c_push_prefix($e); + my $ptr_prefix = c_ptr_prefix($e); return if (util::has_property($e, "noprint")); @@ -670,13 +677,16 @@ sub ParseElementPrint($$) pidl "}"; } - if (!is_fixed_array($e) and ($e->{POINTERS} or util::array_size($e))) { + my $l = $e->{POINTERS}; + $l++ if (util::array_size($e) and $l == 0 and !is_fixed_array($e)); + + foreach my $i (1..$l) { pidl "ndr_print_ptr(ndr, \"$e->{NAME}\", $var_prefix$e->{NAME});"; pidl "ndr->depth++;"; - } - if (need_wire_pointer($e)) { - pidl "if ($var_prefix$e->{NAME}) {"; - indent; + if ($i > $l-need_wire_pointer($e)) { + pidl "if ($ptr_prefix$var_prefix$e->{NAME}) {"; + indent; + } } if (util::array_size($e)) { @@ -690,11 +700,11 @@ sub ParseElementPrint($$) pidl "ndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $cprefix$var_prefix$e->{NAME});"; } - if (need_wire_pointer($e)) { - deindent; - pidl "}"; - } - if (!is_fixed_array($e) and ($e->{POINTERS} or util::array_size($e))) { + foreach my $i (1..$l) { + if ($i > $l-need_wire_pointer($e)) { + deindent; + pidl "}"; + } pidl "ndr->depth--;"; } } @@ -804,6 +814,7 @@ sub ParseElementPullScalar($$$) my($var_prefix) = shift; my($ndr_flags) = shift; my $cprefix = c_pull_prefix($e); + my $ptr_prefix = c_ptr_prefix($e); my $sub_size = util::has_property($e, "subcontext"); start_flags($e); @@ -811,9 +822,8 @@ sub ParseElementPullScalar($$$) if (is_inline_array($e)) { ParseArrayPull($e, "r->", "NDR_SCALARS"); } elsif (need_wire_pointer($e)) { - ParseElementPullPtr($e, $var_prefix, $ndr_flags); - } elsif (need_alloc($e)) { - # no scalar component + ParseElementPullPtr($e, $ptr_prefix.$var_prefix, "NDR_SCALARS"); + } elsif (is_surrounding_array($e)) { } elsif (my $switch = util::has_property($e, "switch_is")) { ParseElementPullSwitch($e, $var_prefix, $ndr_flags, $switch); } elsif (defined $sub_size) { @@ -821,6 +831,7 @@ sub ParseElementPullScalar($$$) } else { pidl "NDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; } + if (my $range = util::has_property($e, "range")) { my ($low, $high) = split(/ /, $range, 2); pidl "if ($var_prefix$e->{NAME} < $low || $var_prefix$e->{NAME} > $high) {"; @@ -862,18 +873,22 @@ sub ParseElementPushBuffer($$$) my $cprefix = c_push_prefix($e); my $sub_size = util::has_property($e, "subcontext"); - if (is_pure_scalar($e)) { - return; - } + return if (is_pure_scalar($e)); start_flags($e); - if (need_wire_pointer($e)) { - pidl "if ($var_prefix$e->{NAME}) {"; - indent; - if (util::has_property($e, "relative")) { - pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; + my $pointers = c_ptr_prefix($e); + for my $i (1..need_wire_pointer($e)) { + if ($i > 1) { + ParseElementPushPtr($e,$pointers.$var_prefix,$ndr_flags); } + pidl "if ($pointers$var_prefix$e->{NAME}) {"; + indent; + $pointers.="*"; + } + + if (util::has_property($e, "relative")) { + pidl "NDR_CHECK(ndr_push_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; } if (is_inline_array($e)) { @@ -896,10 +911,10 @@ sub ParseElementPushBuffer($$$) pidl "NDR_CHECK(ndr_push_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; } - if (need_wire_pointer($e)) { + for my $i (1..need_wire_pointer($e)) { deindent; pidl "}"; - } + } end_flags($e); } @@ -914,22 +929,26 @@ sub ParseElementPullBuffer($$$) my $cprefix = c_pull_prefix($e); my $sub_size = util::has_property($e, "subcontext"); - if (is_pure_scalar($e)) { - return; - } + return if (is_pure_scalar($e)); start_flags($e); - if (need_wire_pointer($e)) { - pidl "if ($var_prefix$e->{NAME}) {"; - indent; - if (util::has_property($e, "relative")) { - pidl "struct ndr_pull_save _relative_save;"; - pidl "ndr_pull_save(ndr, &_relative_save);"; - pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; - } - } - + my $pointers = c_ptr_prefix($e); + for my $i (1..need_wire_pointer($e)) { + if ($i > 1) { + ParseElementPullPtr($e,$pointers.$var_prefix,"NDR_SCALARS"); + } + pidl "if ($pointers$var_prefix$e->{NAME}) {"; + indent; + $pointers.="*"; + } + + if (util::has_property($e, "relative")) { + pidl "struct ndr_pull_save _relative_save;"; + pidl "ndr_pull_save(ndr, &_relative_save);"; + pidl "NDR_CHECK(ndr_pull_relative_ptr2(ndr, $var_prefix$e->{NAME}));"; + } + if (is_inline_array($e)) { ParseArrayPull($e, "r->", "NDR_BUFFERS"); } elsif (util::array_size($e)) { @@ -950,13 +969,13 @@ sub ParseElementPullBuffer($$$) pidl "NDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $cprefix$var_prefix$e->{NAME}));"; } - if (need_wire_pointer($e)) { - if (util::has_property($e, "relative")) { - pidl "ndr_pull_restore(ndr, &_relative_save);"; - } + if (util::has_property($e, "relative")) { + pidl "ndr_pull_restore(ndr, &_relative_save);"; + } + for my $i (1..need_wire_pointer($e)) { deindent; pidl "}"; - } + } end_flags($e); } @@ -1710,7 +1729,7 @@ sub ParseFunctionElementPush($$) } else { ParseElementPushScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - if ($e->{POINTERS}) { + if (need_wire_pointer($e)) { ParseElementPushBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); } } @@ -1769,14 +1788,12 @@ sub ParseFunctionElementPull($$) pidl "NDR_CHECK(ndr_pull_unique_ptr(ndr, &_ptr_$e->{NAME}));"; pidl "r->$inout.$e->{NAME} = NULL;"; pidl "if (_ptr_$e->{NAME}) {"; - indent; } elsif ($inout eq "out" && util::has_property($e, "ref")) { pidl "if (r->$inout.$e->{NAME}) {"; - indent; } else { pidl "{"; - indent; } + indent; ParseArrayPull($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); deindent; pidl "}"; @@ -1786,12 +1803,13 @@ sub ParseFunctionElementPull($$) pidl "\tNDR_ALLOC(ndr, r->out.$e->{NAME});"; pidl "}"; } + if ($inout eq "in" && util::has_property($e, "ref")) { pidl "NDR_ALLOC(ndr, r->in.$e->{NAME});"; } ParseElementPullScalar($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); - if ($e->{POINTERS}) { + if (need_wire_pointer($e)) { ParseElementPullBuffer($e, "r->$inout.", "NDR_SCALARS|NDR_BUFFERS"); } } @@ -2175,3 +2193,4 @@ sub Parse($$) RegisterPrimitives(); 1; + diff --git a/source4/build/pidl/validator.pm b/source4/build/pidl/validator.pm index c61c89392b..cf7df0dcb2 100644 --- a/source4/build/pidl/validator.pm +++ b/source4/build/pidl/validator.pm @@ -40,10 +40,6 @@ sub el_name($) sub ValidElement($) { my $e = shift; - if ($e->{POINTERS} && $e->{POINTERS} > 1) { - fatal(el_name($e) . " : pidl cannot handle multiple pointer levels. Use a sub-structure containing a pointer instead\n"); - } - if ($e->{POINTERS} && $e->{ARRAY_LEN}) { fatal(el_name($e) . " : pidl cannot handle pointers to arrays. Use a substructure instead\n"); } diff --git a/source4/librpc/idl/echo.idl b/source4/librpc/idl/echo.idl index c0a6943898..612cdb319e 100644 --- a/source4/librpc/idl/echo.idl +++ b/source4/librpc/idl/echo.idl @@ -128,4 +128,6 @@ interface rpcecho void echo_TestSurrounding( [in,out,ref] echo_Surrounding *data ); + + uint16 echo_TestDoublePointer([in,ref] uint16 ***data); } diff --git a/source4/rpc_server/echo/rpc_echo.c b/source4/rpc_server/echo/rpc_echo.c index a2d2e552d6..daf16e12d7 100644 --- a/source4/rpc_server/echo/rpc_echo.c +++ b/source4/rpc_server/echo/rpc_echo.c @@ -151,6 +151,15 @@ static NTSTATUS echo_TestSurrounding(struct dcesrv_call_state *dce_call, TALLOC_ return NT_STATUS_OK; } +static uint16_t echo_TestDoublePointer(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestDoublePointer *r) +{ + if (!*r->in.data) + return 0; + if (!**r->in.data) + return 0; + return ***r->in.data; +} + static long echo_TestSleep(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx, struct echo_TestSleep *r) { struct echo_TestSleep_private *p; diff --git a/source4/torture/rpc/echo.c b/source4/torture/rpc/echo.c index 35df96c897..8ef0b00eb2 100644 --- a/source4/torture/rpc/echo.c +++ b/source4/torture/rpc/echo.c @@ -352,6 +352,49 @@ static BOOL test_surrounding(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) return ret; } +/* + test multiple levels of pointers +*/ +static BOOL test_doublepointer(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) +{ + NTSTATUS status; + struct echo_TestDoublePointer r; + BOOL ret = True; + uint16_t value = 12; + uint16_t *pvalue = &value; + uint16_t **ppvalue = &pvalue; + + ZERO_STRUCT(r); + r.in.data = &ppvalue; + + printf("\nTesting TestDoublePointer\n"); + status = dcerpc_echo_TestDoublePointer(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("TestDoublePointer failed - %s\n", nt_errstr(status)); + ret = False; + } + + if (value != r.out.result) { + printf("TestSurrounding did not return original value\n"); + ret = False; + } + + pvalue = NULL; + + status = dcerpc_echo_TestDoublePointer(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("TestDoublePointer failed - %s\n", nt_errstr(status)); + ret = False; + } + + if (r.out.result != 0) { + printf("TestSurrounding did not return 0 when passed a NULL pointer\n"); + ret = False; + } + + return ret; +} + BOOL torture_rpc_echo(void) { NTSTATUS status; @@ -377,6 +420,7 @@ BOOL torture_rpc_echo(void) ret &= test_testcall2(p, mem_ctx); ret &= test_enum(p, mem_ctx); ret &= test_surrounding(p, mem_ctx); + ret &= test_doublepointer(p, mem_ctx); ret &= test_sleep(p, mem_ctx); printf("\n"); -- cgit