1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-01 04:58:35 +03:00

pidl/lib: Add recursion detection logic to prevent looping.

Under some circumstances 'can_contain_deferred' & 'align_type functions' can
loop.

This prevents a hang when processing sample idl like

interface hang
{
	typedef [public] struct {
		wsp_cbasestoragevariant variant[NUM_ENTRIES];
	} vt_variant_wrap;

	typedef [public,nodiscriminant,switch_type(uint16)] union {
		[case(VT_I1)] int8 vt_i1;
		[case(VT_VARIANT)] vt_variant_wrap vt_variant_wrap;
	} variant_types;

	typedef [public] struct {
		[switch_is(vtype)] variant_types vvalue;
	} wsp_cbasestoragevariant;
};

which will hang with the following command

   pidl --header --ndr-parser -- foo.idl

Signed-off-by: Noel Power <noel.power@suse.com>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
Noel Power 2014-12-02 17:26:41 +00:00 committed by Andrew Bartlett
parent 171171565f
commit 3f3fccab05

View File

@ -394,10 +394,10 @@ sub GetTypedefLevelTable($$$$)
#####################################################################
# see if a type contains any deferred data
sub can_contain_deferred($)
sub can_contain_deferred
{
sub can_contain_deferred($);
my ($type) = @_;
sub can_contain_deferred;
my ($type, @types_visited) = @_;
return 1 unless (hasType($type)); # assume the worst
@ -405,15 +405,29 @@ sub can_contain_deferred($)
return 0 if (Parse::Pidl::Typelist::is_scalar($type));
return can_contain_deferred($type->{DATA}) if ($type->{TYPE} eq "TYPEDEF");
foreach (@types_visited) {
if ($_ == $type) {
# we have already encountered this
# type, avoid recursion loop here
# and return
return 0;
}
}
return can_contain_deferred($type->{DATA},
@types_visited) if ($type->{TYPE} eq "TYPEDEF");
return 0 unless defined($type->{ELEMENTS});
foreach (@{$type->{ELEMENTS}}) {
return 1 if ($_->{POINTERS});
return 1 if (can_contain_deferred ($_->{TYPE}));
push(@types_visited,$type);
if (can_contain_deferred ($_->{TYPE},@types_visited)) {
pop(@types_visited);
return 1;
}
pop(@types_visited);
}
return 0;
}
@ -436,14 +450,13 @@ sub pointer_type($)
#####################################################################
# work out the correct alignment for a structure or union
sub find_largest_alignment($)
sub find_largest_alignment
{
my $s = shift;
my ($s, @types_visited) = @_;
my $align = 1;
for my $e (@{$s->{ELEMENTS}}) {
my $a = 1;
if ($e->{POINTERS}) {
# this is a hack for NDR64
# the NDR layer translates this into
@ -452,9 +465,10 @@ sub find_largest_alignment($)
} elsif (has_property($e, "subcontext")) {
$a = 1;
} elsif (has_property($e, "transmit_as")) {
$a = align_type($e->{PROPERTIES}->{transmit_as});
$a = align_type($e->{PROPERTIES}->{transmit_as},
@types_visited);
} else {
$a = align_type($e->{TYPE});
$a = align_type($e->{TYPE}, @types_visited);
}
$align = $a if ($align < $a);
@ -465,11 +479,10 @@ sub find_largest_alignment($)
#####################################################################
# align a type
sub align_type($)
sub align_type
{
sub align_type($);
my ($e) = @_;
sub align_type;
my ($e, @types_visited) = @_;
if (ref($e) eq "HASH" and $e->{TYPE} eq "SCALAR") {
my $ret = $scalar_alignment->{$e->{NAME}};
if (not defined $ret) {
@ -486,21 +499,51 @@ sub align_type($)
# warning($e, "assuming alignment of unknown type '$e' is 4");
return 4;
}
my $dt = getType($e);
foreach (@types_visited) {
if ($_ == $dt) {
# Chapt 14 of the DCE 1.1: Remote Procedure Call
# specification (available from pubs.opengroup.org)
# states:
# "The alignment of a structure in the octet stream is
# the largest of the alignments of the fields it
# contains. These fields may also be constructed types.
# The same alignment rules apply recursively to
# nested constructed types. "
#
# in the worst case scenario
# struct c1 {
# membertypea mema;
# membertypeb memb;
# struct c1 memc;
# }
# the nested struct c1 memc when encountered
# returns 0 ensuring the alignment will be calculated
# based on the other fields
return 0;
}
}
if ($dt->{TYPE} eq "TYPEDEF") {
return align_type($dt->{DATA});
return align_type($dt->{DATA}, @types_visited);
} elsif ($dt->{TYPE} eq "CONFORMANCE") {
return $dt->{DATA}->{ALIGN};
} elsif ($dt->{TYPE} eq "ENUM") {
return align_type(Parse::Pidl::Typelist::enum_type_fn($dt));
return align_type(Parse::Pidl::Typelist::enum_type_fn($dt),
@types_visited);
} elsif ($dt->{TYPE} eq "BITMAP") {
return align_type(Parse::Pidl::Typelist::bitmap_type_fn($dt));
return align_type(Parse::Pidl::Typelist::bitmap_type_fn($dt),
@types_visited);
} elsif (($dt->{TYPE} eq "STRUCT") or ($dt->{TYPE} eq "UNION")) {
# Struct/union without body: assume 4
return 4 unless (defined($dt->{ELEMENTS}));
return find_largest_alignment($dt);
my $res;
push(@types_visited, $dt);
$res = find_largest_alignment($dt, @types_visited);
pop(@types_visited);
return $res
} elsif (($dt->{TYPE} eq "PIPE")) {
return 5;
}