diff options
author | Andrew Tridgell <tridge@samba.org> | 2003-11-19 22:11:17 +0000 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2003-11-19 22:11:17 +0000 |
commit | 5d4bfbd30d73274684bfb91c9c40df156244b267 (patch) | |
tree | ddefe52f3fa65bf02687d381fffa945068820fb1 /source4 | |
parent | 10ee36bede1337d73feec575cc840957090b30b2 (diff) | |
download | samba-5d4bfbd30d73274684bfb91c9c40df156244b267.tar.gz samba-5d4bfbd30d73274684bfb91c9c40df156244b267.tar.bz2 samba-5d4bfbd30d73274684bfb91c9c40df156244b267.zip |
switched to a new way of handling unions, so that we can handle
alignment correctly for unions that have non-uint16 discriminants
added recursive structure alignment. This gets quite hairy, but I
think I've got it mostly right.
(This used to be commit c0d96f87ea633b1372a383f705aaf4ed3099b4a7)
Diffstat (limited to 'source4')
-rw-r--r-- | source4/build/pidl/parser.pm | 149 | ||||
-rw-r--r-- | source4/build/pidl/util.pm | 4 |
2 files changed, 123 insertions, 30 deletions
diff --git a/source4/build/pidl/parser.pm b/source4/build/pidl/parser.pm index e227d0d374..a5cf68669a 100644 --- a/source4/build/pidl/parser.pm +++ b/source4/build/pidl/parser.pm @@ -12,6 +12,7 @@ my($res); # the list of needed functions my %needed; +my %structs; ##################################################################### # parse a properties list @@ -29,6 +30,30 @@ sub ParseProperties($) } } +################################### +# find a sibling var in a structure +sub find_sibling($$) +{ + my($e) = shift; + my($name) = shift; + my($fn) = $e->{PARENT}; + + if ($fn->{TYPE} eq "FUNCTION") { + for my $e2 (@{$fn->{DATA}}) { + if ($e2->{NAME} eq $name) { + return $e2; + } + } + } + + for my $e2 (@{$fn->{ELEMENTS}}) { + if ($e2->{NAME} eq $name) { + return $e2; + } + } + die "invalid sibling '$name'"; +} + #################################################################### # work out the name of a size_is() variable sub find_size_var($$) @@ -49,16 +74,15 @@ sub find_size_var($$) return "r->$size"; } - for my $e2 (@{$fn->{DATA}}) { - if ($e2->{NAME} eq $size) { - if (util::has_property($e2, "in")) { - return "r->in.$size"; - } - if (util::has_property($e2, "out")) { - return "r->out.$size"; - } - } + my $e2 = find_sibling($e, $size); + + if (util::has_property($e2, "in")) { + return "r->in.$size"; + } + if (util::has_property($e2, "out")) { + return "r->out.$size"; } + die "invalid variable in $size for element $e->{NAME} in $fn->{NAME}\n"; } @@ -77,15 +101,61 @@ sub fn_prefix($) ##################################################################### # work out the correct alignment for a structure -sub struct_alignment($) +sub struct_alignment { my $s = shift; + my $align = 1; for my $e (@{$s->{ELEMENTS}}) { - if ($align < util::type_align($e)) { - $align = util::type_align($e); + my $a = 1; + + if (!util::need_wire_pointer($e) + && defined $structs{$e->{TYPE}}) { + if ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "STRUCT") { + $a = struct_alignment($structs{$e->{TYPE}}->{DATA}); + } elsif ($structs{$e->{TYPE}}->{DATA}->{TYPE} eq "UNION") { + $a = union_alignment($structs{$e->{TYPE}}->{DATA}); + } + } else { + $a = util::type_align($e); + } + + if ($align < $a) { + $align = $a; + } + } + + return $align; +} + +##################################################################### +# work out the correct alignment for a union +sub union_alignment +{ + my $u = shift; + + my $align = 1; + + foreach my $e (@{$u->{DATA}}) { + my $a = 1; + + if (!util::need_wire_pointer($e) + && defined $structs{$e->{DATA}->{TYPE}}) { + my $s = $structs{$e->{DATA}->{TYPE}}; + if ($s->{DATA}->{TYPE} eq "STRUCT") { + $a = struct_alignment($s->{DATA}); + } elsif ($s->{DATA}->{TYPE} eq "UNION") { + $a = union_alignment($s->{DATA}); + } + } else { + $a = util::type_align($e->{DATA}); + } + + if ($align < $a) { + $align = $a; } } + return $align; } @@ -256,17 +326,24 @@ sub ParseElementPullSwitch($$$$) my $cprefix = util::c_pull_prefix($e); - $res .= "\t{ uint16 _level = $switch_var;\n"; + my $utype = $structs{$e->{TYPE}}; + if (!defined $utype || + !util::has_property($utype->{DATA}, "nodiscriminant")) { + my $e2 = find_sibling($e, $switch); + $res .= "\tif (($ndr_flags) & NDR_SCALARS) {\n"; + $res .= "\t\t $e2->{TYPE} _level;\n"; + $res .= "\t\tNDR_CHECK(ndr_pull_$e2->{TYPE}(ndr, &_level));\n"; + $res .= "\t\tif (_level != $switch_var) return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\");\n"; + $res .= "\t}\n"; + } if (util::has_property($e, "subcontext")) { - $res .= "\tNDR_CHECK(ndr_pull_subcontext_union_fn(ndr, &_level, $cprefix$var_prefix$e->{NAME}, (ndr_pull_union_fn_t) ndr_pull_$e->{TYPE}));\n"; + $res .= "\tNDR_CHECK(ndr_pull_subcontext_union_fn(ndr, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_pull_union_fn_t) ndr_pull_$e->{TYPE}));\n"; } else { - $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, &_level, $cprefix$var_prefix$e->{NAME}));\n"; + $res .= "\tNDR_CHECK(ndr_pull_$e->{TYPE}(ndr, $ndr_flags, $switch_var, $cprefix$var_prefix$e->{NAME}));\n"; } - $res .= "\tif ((($ndr_flags) & NDR_SCALARS) && (_level != $switch_var)) return ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value %u in $e->{NAME}\");\n"; - $res .= "\t}\n"; } ##################################################################### @@ -280,6 +357,13 @@ sub ParseElementPushSwitch($$$$) my $switch_var = find_size_var($e, $switch); my $cprefix = util::c_push_prefix($e); + my $utype = $structs{$e->{TYPE}}; + if (!defined $utype || + !util::has_property($utype->{DATA}, "nodiscriminant")) { + my $e2 = find_sibling($e, $switch); + $res .= "\tNDR_CHECK(ndr_push_$e2->{TYPE}(ndr, $switch_var));\n"; + } + if (util::has_property($e, "subcontext")) { $res .= "\tNDR_CHECK(ndr_push_subcontext_union_fn(ndr, $switch_var, $cprefix$var_prefix$e->{NAME}, (ndr_push_union_fn_t) ndr_pull_$e->{TYPE}));\n"; } else { @@ -590,9 +674,9 @@ sub ParseUnionPush($) $res .= "\tNDR_CHECK(ndr_push_struct_start(ndr));\n"; - if (!util::has_property($e, "nodiscriminant")) { - $res .= "\tNDR_CHECK(ndr_push_uint16(ndr, level));\n"; - } +# my $align = union_alignment($e); +# $res .= "\tNDR_CHECK(ndr_push_align(ndr, $align));\n"; + $res .= "\tswitch (level) {\n"; foreach my $el (@{$e->{DATA}}) { if ($el->{CASE} eq "default") { @@ -665,10 +749,10 @@ sub ParseUnionPull($) $res .= "\tNDR_CHECK(ndr_pull_struct_start(ndr));\n"; - if (!util::has_property($e, "nodiscriminant")) { - $res .= "\tNDR_CHECK(ndr_pull_uint16(ndr, level));\n"; - } - $res .= "\tswitch (*level) {\n"; +# my $align = union_alignment($e); +# $res .= "\tNDR_CHECK(ndr_pull_align(ndr, $align));\n"; + + $res .= "\tswitch (level) {\n"; foreach my $el (@{$e->{DATA}}) { if ($el->{CASE} eq "default") { $res .= "\tdefault: {\n"; @@ -685,13 +769,13 @@ sub ParseUnionPull($) } if (! $have_default) { $res .= "\tdefault:\n"; - $res .= "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", *level);\n"; + $res .= "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n"; } $res .= "\t}\n"; $res .= "\tndr_pull_struct_end(ndr);\n"; $res .= "buffers:\n"; $res .= "\tif (!(ndr_flags & NDR_BUFFERS)) goto done;\n"; - $res .= "\tswitch (*level) {\n"; + $res .= "\tswitch (level) {\n"; foreach my $el (@{$e->{DATA}}) { if ($el->{CASE} eq "default") { $res .= "\tdefault:\n"; @@ -703,7 +787,7 @@ sub ParseUnionPull($) } if (! $have_default) { $res .= "\tdefault:\n"; - $res .= "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", *level);\n"; + $res .= "\t\treturn ndr_pull_error(ndr, NDR_ERR_BAD_SWITCH, \"Bad switch value \%u\", level);\n"; } $res .= "\t}\n"; $res .= "done:\n"; @@ -802,7 +886,7 @@ sub ParseTypedefPull($) } if ($e->{DATA}->{TYPE} eq "UNION") { - $res .= "$static" . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, uint16 *level, union $e->{NAME} *r)"; + $res .= "$static" . "NTSTATUS ndr_pull_$e->{NAME}(struct ndr_pull *ndr, int ndr_flags, uint16 level, union $e->{NAME} *r)"; $res .= "\n{\n"; ParseTypePull($e->{DATA}); $res .= "\treturn NT_STATUS_OK;\n"; @@ -959,6 +1043,15 @@ sub ParseInterface($) { my($interface) = shift; my($data) = $interface->{DATA}; + + foreach my $d (@{$data}) { + if ($d->{TYPE} eq "TYPEDEF") { + $structs{$d->{NAME}} = $d; + } + } + + + foreach my $d (@{$data}) { ($d->{TYPE} eq "TYPEDEF") && ParseTypedefPush($d); diff --git a/source4/build/pidl/util.pm b/source4/build/pidl/util.pm index 244a78af09..c18fe031f9 100644 --- a/source4/build/pidl/util.pm +++ b/source4/build/pidl/util.pm @@ -198,8 +198,7 @@ sub type_align($) my($e) = shift; my $type = $e->{TYPE}; - if ($e->{POINTERS} || array_size($e)) { - # FIXME: we really should recurse here + if (need_wire_pointer($e)) { return 4; } @@ -214,6 +213,7 @@ sub type_align($) return 2, if ($type eq "wchar_t"); return 4, if ($type eq "DATA_BLOB"); + # it must be an external type - all we can do is guess return 4; } |