r4139: 2nd attempt at fixing the null ptr in size_is() problem.
[samba.git] / source4 / build / pidl / parser.pm
index c52be637ec5d42ef030cff44c5c3a3009a9a565c..8fb74b2e0ed882e7f650a7bdaa25ec6765f1f185 100644 (file)
@@ -8,7 +8,6 @@
 package IdlParser;
 
 use strict;
-use client;
 use needed;
 
 # the list of needed functions
@@ -107,6 +106,17 @@ sub find_size_var($$$)
        die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n";
 }
 
+#####################################################################
+# check that a variable we get from find_size_var isn't a null pointer
+sub check_null_pointer($)
+{
+       my $size = shift;
+       if ($size =~ /^\*/) {
+               my $size2 = substr($size, 1);
+               pidl "\tif ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;\n";
+       }
+}
+
 
 #####################################################################
 # work out is a parse function should be declared static or not
@@ -269,6 +279,31 @@ sub ParseArrayPrint($$)
        }
 }
 
+#####################################################################
+# check the size_is and length_is constraints
+sub CheckArraySizes($$)
+{
+       my $e = shift;
+       my $var_prefix = shift;
+
+       if (util::has_property($e, "size_is")) {
+               my $size = find_size_var($e, util::array_size($e), $var_prefix);
+               pidl "\tif ($var_prefix$e->{NAME}) {\n";
+               check_null_pointer($size);
+               pidl "\t\tNDR_CHECK(ndr_check_array_size(ndr, (void*)&$var_prefix$e->{NAME}, $size));\n";
+               pidl "\t}\n";
+       }
+
+       if (my $length = util::has_property($e, "length_is")) {
+               $length = find_size_var($e, $length, $var_prefix);
+               pidl "\tif ($var_prefix$e->{NAME}) {\n";
+               check_null_pointer($length);
+               pidl "\t\tNDR_CHECK(ndr_check_array_length(ndr, (void*)&$var_prefix$e->{NAME}, $length));\n";
+               pidl "\t}\n";
+       }
+}
+
+
 #####################################################################
 # parse an array - pull side
 sub ParseArrayPull($$$)
@@ -284,7 +319,7 @@ sub ParseArrayPull($$$)
        # we allocate enough to pull the elements
        if (defined $e->{CONFORMANT_SIZE}) {
                $alloc_size = $e->{CONFORMANT_SIZE};
-
+               check_null_pointer($size);
                pidl "\tif ($size > $alloc_size) {\n";
                pidl "\t\treturn ndr_pull_error(ndr, NDR_ERR_CONFORMANT_SIZE, \"Bad conformant size %u should be %u\", $alloc_size, $size);\n";
                pidl "\t}\n";
@@ -295,56 +330,36 @@ sub ParseArrayPull($$$)
                }
 
                # non fixed arrays encode the size just before the array
-               pidl "\t{\n";
-               pidl "\t\tuint32_t _array_size;\n";
-               pidl "\t\tNDR_CHECK(ndr_pull_uint32(ndr, &_array_size));\n";
-               if ($size =~ /r->in/) {
-                       pidl "\t\tif (!(ndr->flags & LIBNDR_FLAG_REF_ALLOC) && _array_size != $size) {\n";
-               } else {
-                       pidl "\t\tif ($size != _array_size) {\n";
-               }
-               pidl "\t\t\treturn ndr_pull_error(ndr, NDR_ERR_ARRAY_SIZE, \"Bad array size %u should be %u\", _array_size, $size);\n";
-               pidl "\t\t}\n";
-               if ($size =~ /r->in/) {
-                       pidl "else { $size = _array_size; }\n";
-               }
-               pidl "\t}\n";
+               pidl "\t\tNDR_CHECK(ndr_pull_array_size(ndr, &$var_prefix$e->{NAME}));\n";
+               $alloc_size = "ndr_get_array_size(ndr, &$var_prefix$e->{NAME})";
        }
 
        if ((util::need_alloc($e) && !util::is_fixed_array($e)) ||
            ($var_prefix eq "r->in." && util::has_property($e, "ref"))) {
                if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
-                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
+                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
                }
        }
 
        if (($var_prefix eq "r->out." && util::has_property($e, "ref"))) {
                if (!util::is_inline_array($e) || $ndr_flags eq "NDR_SCALARS") {
                        pidl "\tif (ndr->flags & LIBNDR_FLAG_REF_ALLOC) {";
-                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, MAX(1, $alloc_size));\n";
+                       pidl "\t\tNDR_ALLOC_N(ndr, $var_prefix$e->{NAME}, $alloc_size);\n";
                        pidl "\t}\n";
                }
        }
 
-       pidl "\t{\n";
-
        if (my $length = util::has_property($e, "length_is")) {
-               $length = find_size_var($e, $length, $var_prefix);
-               pidl "\t\tuint32_t _offset, _length;\n";
-               pidl "\t\tNDR_CHECK(ndr_pull_uint32(ndr, &_offset));\n";
-               pidl "\t\tNDR_CHECK(ndr_pull_uint32(ndr, &_length));\n";
-               pidl "\t\tif (_offset != 0) return ndr_pull_error(ndr, NDR_ERR_OFFSET, \"Bad array offset 0x%08x\", _offset);\n";
-               pidl "\t\tif (_length > $size || _length != $length) return ndr_pull_error(ndr, NDR_ERR_LENGTH, \"Bad array length 0x%08x > size 0x%08x\", _offset, $size);\n\n";
-               $size = "_length";
+               pidl "\t\tNDR_CHECK(ndr_pull_array_length(ndr, &$var_prefix$e->{NAME}));\n";
+               $size = "ndr_get_array_length(ndr, &$var_prefix$e->{NAME})";
        }
 
+       check_null_pointer($size);
        if (util::is_scalar_type($e->{TYPE})) {
                pidl "\t\tNDR_CHECK(ndr_pull_array_$e->{TYPE}(ndr, $ndr_flags, $var_prefix$e->{NAME}, $size));\n";
        } else {
                pidl "\t\tNDR_CHECK(ndr_pull_array(ndr, $ndr_flags, (void **)$var_prefix$e->{NAME}, sizeof($var_prefix$e->{NAME}\[0]), $size, (ndr_pull_flags_fn_t)ndr_pull_$e->{TYPE}));\n";
        }
-
-       pidl "\t}\n";
 }
 
 
@@ -434,6 +449,9 @@ sub ParseElementPullSwitch($$$$)
        my $cprefix = util::c_pull_prefix($e);
 
        my $utype = $structs{$e->{TYPE}};
+
+       check_null_pointer($switch_var);
+
        if (!defined $utype ||
            !util::has_property($utype->{DATA}, "nodiscriminant")) {
                my $e2 = find_sibling($e, $switch);
@@ -476,6 +494,8 @@ sub ParseElementPushSwitch($$$$)
        my $switch_var = find_size_var($e, $switch, $var_prefix);
        my $cprefix = util::c_push_prefix($e);
 
+       check_null_pointer($switch_var);
+
        my $utype = $structs{$e->{TYPE}};
        if (!defined $utype ||
            !util::has_property($utype->{DATA}, "nodiscriminant")) {
@@ -505,6 +525,8 @@ sub ParseElementPrintSwitch($$$)
        my $switch_var = find_size_var($e, $switch, $var_prefix);
        my $cprefix = util::c_push_prefix($e);
 
+       check_null_pointer($switch_var);
+
        pidl "\tndr_print_$e->{TYPE}(ndr, \"$e->{NAME}\", $switch_var, $cprefix$var_prefix$e->{NAME});\n";
 }
 
@@ -705,7 +727,6 @@ sub ParseElementPullBuffer($$$)
 sub ParseStructPush($)
 {
        my($struct) = shift;
-       my $conform_e;
        
        if (! defined $struct->{ELEMENTS}) {
                return;
@@ -722,10 +743,15 @@ sub ParseStructPush($)
        if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
                my $size = find_size_var($e, util::array_size($e), "r->");
                $e->{CONFORMANT_SIZE} = $size;
-               $conform_e = $e;
+               check_null_pointer($size);
                pidl "\tNDR_CHECK(ndr_push_uint32(ndr, $size));\n";
        }
 
+       if (defined $e->{TYPE} && $e->{TYPE} eq "string" 
+           &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
+               pidl "\tNDR_CHECK(ndr_push_uint32(ndr, ndr_string_array_size(ndr, r->$e->{NAME})));\n";
+       }
+
        pidl "\tif (!(ndr_flags & NDR_SCALARS)) goto buffers;\n";
 
        pidl "\tNDR_CHECK(ndr_push_struct_start(ndr));\n";
@@ -790,6 +816,15 @@ sub ParseStructPull($)
        my $e = $struct->{ELEMENTS}[-1];
        if (defined $e->{ARRAY_LEN} && $e->{ARRAY_LEN} eq "*") {
                $conform_e = $e;
+       }
+
+       if (defined $e->{TYPE} && $e->{TYPE} eq "string"
+           &&  util::property_matches($e, "flag", ".*LIBNDR_FLAG_STR_CONFORMANT.*")) {
+               $conform_e = $e;
+       }
+
+       if (defined $conform_e) {
+               $conform_e = $e;
                pidl "\tuint32_t _conformant_size;\n";
                $conform_e->{CONFORMANT_SIZE} = "_conformant_size";
        }
@@ -824,6 +859,10 @@ sub ParseStructPull($)
                ParseElementPullBuffer($e, "r->", "NDR_BUFFERS");
        }
 
+       foreach my $e (@{$struct->{ELEMENTS}}) {
+               CheckArraySizes($e, "r->");
+       }
+
        pidl "\tndr_pull_struct_end(ndr);\n";
 
        pidl "done:\n";
@@ -833,18 +872,16 @@ sub ParseStructPull($)
 
 #####################################################################
 # calculate size of ndr struct
-
 sub ParseStructNdrSize($)
 {
        my $t = shift;
        my $static = fn_prefix($t);
        my $sizevar;
 
-       pidl $static . "size_t ndr_size_$t->{NAME}(int ret, struct $t->{NAME} *r, int flags)\n";
+       pidl $static . "size_t ndr_size_$t->{NAME}(int ret, const struct $t->{NAME} *r, int flags)\n";
        pidl "{\n";
 
        if (util::has_property($t->{DATA}, "flag")) {
-               
                pidl "\tflags = flags | " . $t->{DATA}->{PROPERTIES}->{flag} . ";\n";   
        }
 
@@ -867,6 +904,7 @@ sub ParseStructNdrSize($)
                        pidl "\tret = ndr_size_ptr(ret, &r->$e->{NAME}, flags); \n";
                } elsif (util::is_inline_array($e)) {
                        $sizevar = find_size_var($e, util::array_size($e), "r->");
+                       check_null_pointer($sizevar);
                        pidl "\t{\n";
                        pidl "\t\tint i;\n";
                        pidl "\t\tfor(i = 0; i < $sizevar; i++) {\n";
@@ -1049,7 +1087,7 @@ sub ParseUnionNdrSize($)
        my $t = shift;
        my $static = fn_prefix($t);
 
-       pidl $static . "size_t ndr_size_$t->{NAME}(int ret, union $t->{NAME} *data, uint16 level, int flags)\n";
+       pidl $static . "size_t ndr_size_$t->{NAME}(int ret, const union $t->{NAME} *data, uint16 level, int flags)\n";
        pidl "{\n";
        if (util::has_property($t->{DATA}, "flag")) {
                pidl "\tflags = flags | " . $t->{DATA}->{PROPERTIES}->{flag} . ";\n";   
@@ -1303,6 +1341,7 @@ sub ParseFunctionPush($)
        pidl $static . "NTSTATUS ndr_push_$fn->{NAME}(struct ndr_push *ndr, int flags, struct $fn->{NAME} *r)\n{\n";
 
        pidl "\n\tif (!(flags & NDR_IN)) goto ndr_out;\n\n";
+
        foreach my $e (@{$fn->{DATA}}) {
                if (util::has_property($e, "in")) {
                        ParseFunctionElementPush($e, "in");
@@ -1311,6 +1350,7 @@ sub ParseFunctionPush($)
 
        pidl "\nndr_out:\n";
        pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
+
        foreach my $e (@{$fn->{DATA}}) {
                if (util::has_property($e, "out")) {
                        ParseFunctionElementPush($e, "out");
@@ -1335,6 +1375,7 @@ sub ParseFunctionElementPull($$)
        if (util::array_size($e)) {
                if (util::need_wire_pointer($e)) {
                        pidl "\tNDR_CHECK(ndr_pull_ptr(ndr, &_ptr_$e->{NAME}));\n";
+                       pidl "\tr->$inout.$e->{NAME} = NULL;\n";
                        pidl "\tif (_ptr_$e->{NAME}) {\n";
                } elsif ($inout eq "out" && util::has_property($e, "ref")) {
                        pidl "\tif (r->$inout.$e->{NAME}) {\n";
@@ -1385,7 +1426,8 @@ sub AllocateRefVars($)
 
        # its an array
        my $size = find_size_var($e, $asize, "r->out.");
-       pidl "\tNDR_ALLOC_N(ndr, r->out.$e->{NAME}, MAX(1, $size));\n";
+       check_null_pointer($size);
+       pidl "\tNDR_ALLOC_N(ndr, r->out.$e->{NAME}, $size);\n";
        if (util::has_property($e, "in")) {
                pidl "\tmemcpy(r->out.$e->{NAME},r->in.$e->{NAME},$size * sizeof(*r->in.$e->{NAME}));\n";
        } else {
@@ -1435,14 +1477,27 @@ sub ParseFunctionPull($)
                }
        }
 
+       foreach my $e (@{$fn->{DATA}}) {
+               if (util::has_property($e, "in")) {
+                       CheckArraySizes($e, "r->in.");
+               }
+       }
+
        pidl "\nndr_out:\n";
        pidl "\tif (!(flags & NDR_OUT)) goto done;\n\n";
+
        foreach my $e (@{$fn->{DATA}}) {
                if (util::has_property($e, "out")) {
                        ParseFunctionElementPull($e, "out");
                }
        }
 
+       foreach my $e (@{$fn->{DATA}}) {
+               if (util::has_property($e, "out")) {
+                       CheckArraySizes($e, "r->out.");
+               }
+       }
+
        if ($fn->{RETURN_TYPE} && $fn->{RETURN_TYPE} ne "void") {
                pidl "\tNDR_CHECK(ndr_pull_$fn->{RETURN_TYPE}(ndr, &r->out.result));\n";
        }
@@ -1464,9 +1519,7 @@ sub FunctionTable($)
                if ($d->{TYPE} eq "FUNCTION") { $count++; }
        }
 
-       if ($count == 0) {
-               return;
-       }
+       return if ($count == 0);
 
        pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {\n";
        foreach my $d (@{$data}) {
@@ -1509,8 +1562,12 @@ sub FunctionTable($)
        pidl "\t$interface->{NAME}\_calls,\n";
        pidl "\t&$interface->{NAME}\_endpoints\n";
        pidl "};\n\n";
-}
 
+       pidl "static NTSTATUS dcerpc_ndr_$interface->{NAME}_init(void)\n";
+       pidl "{\n";
+       pidl "\treturn librpc_register_interface(&dcerpc_table_$interface->{NAME});\n";
+       pidl "}\n\n";
+}
 
 #####################################################################
 # parse the interface definitions
@@ -1554,7 +1611,36 @@ sub ParseInterface($)
        }
 
        FunctionTable($interface);
+}
+
+sub RegistrationFunction($$)
+{
+       my $idl = shift;
+       my $filename = shift;
 
+       $filename =~ /.*\/ndr_(.*).c/;
+       my $basename = $1;
+       pidl "NTSTATUS dcerpc_$basename\_init(void)\n";
+       pidl "{\n";
+       pidl "\tNTSTATUS status = NT_STATUS_OK;\n";
+       foreach my $interface (@{$idl}) {
+               next if $interface->{TYPE} ne "INTERFACE";
+
+               my $data = $interface->{INHERITED_DATA};
+               my $count = 0;
+               foreach my $d (@{$data}) {
+                       if ($d->{TYPE} eq "FUNCTION") { $count++; }
+               }
+
+               next if ($count == 0);
+
+               pidl "\tstatus = dcerpc_ndr_$interface->{NAME}_init();\n";
+               pidl "\tif (NT_STATUS_IS_ERR(status)) {\n";
+               pidl "\t\treturn status;\n";
+               pidl "\t}\n\n";
+       }
+       pidl "\treturn status;\n";
+       pidl "}\n\n";
 }
 
 #####################################################################
@@ -1582,7 +1668,7 @@ sub Parse($$)
                }
        }
 
-       pidl IdlClient::Parse($idl);
+       RegistrationFunction($idl, $filename);
 
        close(OUT);
 }