svn commit: samba r20637 - in branches/SAMBA_4_0/source/pidl: lib/Parse/Pidl lib/Parse/Pidl/Samba4/NDR tests

jelmer at samba.org jelmer at samba.org
Tue Jan 9 23:41:26 GMT 2007


Author: jelmer
Date: 2007-01-09 23:41:25 +0000 (Tue, 09 Jan 2007)
New Revision: 20637

WebSVN: http://websvn.samba.org/cgi-bin/viewcvs.cgi?view=rev&root=samba&rev=20637

Log:
Don't check for NULL pointers when the pointer is guaranteed to not be NULL 
(if it is a ref pointer).

Added:
   branches/SAMBA_4_0/source/pidl/tests/samba-ndr.pl
Modified:
   branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
   branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Util.pm


Changeset:
Modified: branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm
===================================================================
--- branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm	2007-01-09 20:04:46 UTC (rev 20636)
+++ branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Samba4/NDR/Parser.pm	2007-01-09 23:41:25 UTC (rev 20637)
@@ -10,12 +10,14 @@
 require Exporter;
 @ISA = qw(Exporter);
 @EXPORT = qw(is_charset_array);
+ at EXPORT_OK = qw(check_null_pointer);
 
 use strict;
 use Parse::Pidl::Typelist qw(hasType getType mapType);
-use Parse::Pidl::Util qw(has_property ParseExpr print_uuid);
+use Parse::Pidl::Util qw(has_property ParseExpr ParseExprExt print_uuid);
 use Parse::Pidl::NDR qw(GetPrevLevel GetNextLevel ContainsDeferred);
 use Parse::Pidl::Samba4 qw(is_intree choose_header);
+use Parse::Pidl qw(warning);
 
 use vars qw($VERSION);
 $VERSION = '0.01';
@@ -165,29 +167,6 @@
 }
 
 #####################################################################
-# check that a variable we get from ParseExpr isn't a null pointer
-sub check_null_pointer($)
-{
-	my $size = shift;
-	if ($size =~ /^\*/) {
-		my $size2 = substr($size, 1);
-		pidl "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
-	}
-}
-
-#####################################################################
-# check that a variable we get from ParseExpr isn't a null pointer, 
-# putting the check at the end of the structure/function
-sub check_null_pointer_deferred($)
-{
-	my $size = shift;
-	if ($size =~ /^\*/) {
-		my $size2 = substr($size, 1);
-		defer "if ($size2 == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
-	}
-}
-
-#####################################################################
 # declare a function public or static, depending on its attributes
 sub fn_declare($$$)
 {
@@ -325,6 +304,61 @@
 	return $length;
 }
 
+sub check_null_pointer($$$)
+{
+	my ($element, $env, $print_fn) = @_;
+
+	return sub ($) {
+		my $expandedvar = shift;
+		my $check = 0;
+
+		# Figure out the number of pointers in $ptr
+		$expandedvar =~ s/^(\**)//;
+		my $ptr = $1;
+
+		my $var = undef;
+		foreach (keys %$env) {
+			if ($env->{$_} eq $expandedvar) {
+				$var = $_;
+				last;
+			}
+		}
+		
+		if (defined($var)) {
+			my $e;
+			# lookup ptr in $e
+			foreach (@{$element->{PARENT}->{ELEMENTS}}) {
+				if ($_->{NAME} eq $var) {
+					$e = $_;
+					last;
+				}
+			}
+
+			$e or die("Environment doesn't match siblings");
+
+			# See if pointer at pointer level $level
+			# needs to be checked.
+			foreach my $l (@{$e->{LEVELS}}) {
+				if ($l->{TYPE} eq "POINTER" and 
+					$l->{POINTER_INDEX} == length($ptr)) {
+					# No need to check ref pointers
+					$check = ($l->{POINTER_TYPE} ne "ref");
+					last;
+				}
+
+				if ($l->{TYPE} eq "DATA") {
+					warning($element, "too much dereferences for `$var'");
+				}
+			}
+		} else {
+			warning($element, "unknown dereferenced expression `$expandedvar'");
+			$check = 1;
+		}
+		
+		$print_fn->("if ($ptr$expandedvar == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;") if $check;
+	}
+}
+
 #####################################################################
 # parse an array - pull side
 sub ParseArrayPullHeader($$$$$)
@@ -339,21 +373,19 @@
 	} elsif ($l->{IS_ZERO_TERMINATED}) { # Noheader arrays
 		$length = $size = "ndr_get_string_size($ndr, sizeof(*$var_name))";
 	} else {
-		$length = $size = ParseExpr($l->{SIZE_IS}, $env, $e);
+		$length = $size = ParseExprExt($l->{SIZE_IS}, $env, $e, 
+		                               check_null_pointer($e, $env, \&pidl));
 	}
 
 	if ((!$l->{IS_SURROUNDING}) and $l->{IS_CONFORMANT}) {
 		pidl "NDR_CHECK(ndr_pull_array_size(ndr, " . get_pointer_to($var_name) . "));";
 	}
 
-
 	if ($l->{IS_VARYING}) {
 		pidl "NDR_CHECK(ndr_pull_array_length($ndr, " . get_pointer_to($var_name) . "));";
 		$length = "ndr_get_array_length($ndr, " . get_pointer_to($var_name) .")";
 	}
 
-	check_null_pointer($length);
-
 	if ($length ne $size) {
 		pidl "if ($length > $size) {";
 		indent;
@@ -363,20 +395,18 @@
 	}
 
 	if ($l->{IS_CONFORMANT} and not $l->{IS_ZERO_TERMINATED}) {
-		my $size = ParseExpr($l->{SIZE_IS}, $env, $e);
 		defer "if ($var_name) {";
 		defer_indent;
-		check_null_pointer_deferred($size);
+		my $size = ParseExprExt($l->{SIZE_IS}, $env, $e, check_null_pointer($e, $env, \&defer));
 		defer "NDR_CHECK(ndr_check_array_size(ndr, (void*)" . get_pointer_to($var_name) . ", $size));";
 		defer_deindent;
 		defer "}";
 	}
 
 	if ($l->{IS_VARYING} and not $l->{IS_ZERO_TERMINATED}) {
-		my $length = ParseExpr($l->{LENGTH_IS}, $env, $e);
 		defer "if ($var_name) {";
 		defer_indent;
-		check_null_pointer_deferred($length);
+		my $length = ParseExprExt($l->{LENGTH_IS}, $env, $e, check_null_pointer($e, $env, \&defer));
 		defer "NDR_CHECK(ndr_check_array_length(ndr, (void*)" . get_pointer_to($var_name) . ", $length));";
 		defer_deindent;
 		defer "}"
@@ -661,7 +691,7 @@
 	my ($e,$l,$var_name) = @_;
 
 	if ($l->{POINTER_TYPE} eq "ref") {
-		check_null_pointer(get_value_of($var_name));
+		pidl "if ($var_name == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;";
 		if ($l->{LEVEL} eq "EMBEDDED") {
 			pidl "NDR_CHECK(ndr_push_ref_ptr(ndr));";
 		}
@@ -774,10 +804,8 @@
 sub ParseSwitchPull($$$$$$)
 {
 	my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
-	my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
+	my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e, check_null_pointer($e, $env, \&pidl));
 
-	check_null_pointer($switch_var);
-
 	$var_name = get_pointer_to($var_name);
 	pidl "NDR_CHECK(ndr_pull_set_switch_value($ndr, $var_name, $switch_var));";
 }
@@ -787,9 +815,8 @@
 sub ParseSwitchPush($$$$$$)
 {
 	my($e,$l,$ndr,$var_name,$ndr_flags,$env) = @_;
-	my $switch_var = ParseExpr($l->{SWITCH_IS}, $env, $e);
+	my $switch_var = ParseExprExt($l->{SWITCH_IS}, $env, $e, check_null_pointer($e, $env, \&pidl));
 
-	check_null_pointer($switch_var);
 	$var_name = get_pointer_to($var_name);
 	pidl "NDR_CHECK(ndr_push_set_switch_value($ndr, $var_name, $switch_var));";
 }
@@ -2014,7 +2041,6 @@
 
 	my $var = ParseExpr($e->{NAME}, $env, $e);
 
-	check_null_pointer($size);
 	my $pl = GetPrevLevel($e, $l);
 	if (defined($pl) and 
 	    $pl->{TYPE} eq "POINTER" and 
@@ -2093,8 +2119,7 @@
 			and   $e->{LEVELS}[1]->{IS_ZERO_TERMINATED});
 
 		if ($e->{LEVELS}[1]->{TYPE} eq "ARRAY") {
-			my $size = ParseExpr($e->{LEVELS}[1]->{SIZE_IS}, $env, $e);
-			check_null_pointer($size);
+			my $size = ParseExprExt($e->{LEVELS}[1]->{SIZE_IS}, $env, $e, check_null_pointer($e, $env, \&pidl));
 			
 			pidl "NDR_PULL_ALLOC_N(ndr, r->out.$e->{NAME}, $size);";
 

Modified: branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Util.pm
===================================================================
--- branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Util.pm	2007-01-09 20:04:46 UTC (rev 20636)
+++ branches/SAMBA_4_0/source/pidl/lib/Parse/Pidl/Util.pm	2007-01-09 23:41:25 UTC (rev 20637)
@@ -6,7 +6,7 @@
 
 require Exporter;
 @ISA = qw(Exporter);
- at EXPORT = qw(has_property property_matches ParseExpr is_constant make_str print_uuid MyDumper);
+ at EXPORT = qw(has_property property_matches ParseExpr ParseExprExt is_constant make_str print_uuid MyDumper);
 use vars qw($VERSION);
 $VERSION = '0.01';
 
@@ -115,4 +115,21 @@
 		undef);
 }
 
+sub ParseExprExt($$$$)
+{
+	my($expr, $varlist, $e, $deref) = @_;
+
+	die("Undefined value in ParseExpr") if not defined($expr);
+
+	my $x = new Parse::Pidl::Expr();
+	
+	return $x->Run($expr, sub { my $x = shift; error($e, $x); },
+		# Lookup fn 
+		sub { my $x = shift; 
+			  return($varlist->{$x}) if (defined($varlist->{$x})); 
+			  return $x;
+		  },
+		$deref);
+}
+
 1;

Added: branches/SAMBA_4_0/source/pidl/tests/samba-ndr.pl
===================================================================
--- branches/SAMBA_4_0/source/pidl/tests/samba-ndr.pl	2007-01-09 20:04:46 UTC (rev 20636)
+++ branches/SAMBA_4_0/source/pidl/tests/samba-ndr.pl	2007-01-09 23:41:25 UTC (rev 20637)
@@ -0,0 +1,135 @@
+#!/usr/bin/perl
+# (C) 2007 Jelmer Vernooij <jelmer at samba.org>
+# Published under the GNU General Public License
+use strict;
+use warnings;
+
+use Test::More tests => 10;
+use FindBin qw($RealBin);
+use lib "$RealBin";
+use Util;
+use Parse::Pidl::Util qw(MyDumper);
+use Parse::Pidl::Samba4::NDR::Parser qw(check_null_pointer);
+
+my $output;
+sub print_fn($) { my $x = shift; $output.=$x; }
+
+# Test case 1: Simple unique pointer dereference
+
+$output = "";
+my $fn = check_null_pointer({ 
+	PARENT => {
+		ELEMENTS => [
+			{ 
+				NAME => "bla",
+				LEVELS => [
+					{ TYPE => "POINTER",
+					  POINTER_INDEX => 0,
+					  POINTER_TYPE => "unique" },
+					{ TYPE => "DATA" }
+				],
+			},
+		]
+	}
+}, { bla => "r->in.bla" }, \&print_fn); 
+
+
+test_warnings("", sub { $fn->("r->in.bla"); });
+
+is($output, "if (r->in.bla == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;");
+
+# Test case 2: Simple ref pointer dereference
+
+$output = "";
+$fn = check_null_pointer({ 
+	PARENT => {
+		ELEMENTS => [
+			{ 
+				NAME => "bla",
+				LEVELS => [
+					{ TYPE => "POINTER",
+					  POINTER_INDEX => 0,
+					  POINTER_TYPE => "ref" },
+					{ TYPE => "DATA" }
+				],
+			},
+		]
+	}
+}, { bla => "r->in.bla" }, \&print_fn); 
+
+test_warnings("", sub { $fn->("r->in.bla"); });
+
+is($output, "");
+
+# Test case 3: Illegal dereference
+
+$output = "";
+$fn = check_null_pointer({ 
+	FILE => "nofile",
+	LINE => 1,
+	PARENT => {
+		ELEMENTS => [
+			{ 
+				NAME => "bla",
+				LEVELS => [
+					{ TYPE => "DATA" }
+				],
+			},
+		]
+	}
+}, { bla => "r->in.bla" }, \&print_fn); 
+
+test_warnings("nofile:1: too much dereferences for `bla'\n", 
+	          sub { $fn->("r->in.bla"); });
+
+is($output, "");
+
+# Test case 4: Double pointer dereference
+
+$output = "";
+$fn = check_null_pointer({ 
+	PARENT => {
+		ELEMENTS => [
+			{ 
+				NAME => "bla",
+				LEVELS => [
+					{ TYPE => "POINTER",
+					  POINTER_INDEX => 0,
+					  POINTER_TYPE => "unique" },
+					{ TYPE => "POINTER",
+					  POINTER_INDEX => 1,
+					  POINTER_TYPE => "unique" },
+					{ TYPE => "DATA" }
+				],
+			},
+		]
+	}
+}, { bla => "r->in.bla" }, \&print_fn); 
+
+test_warnings("",
+	          sub { $fn->("*r->in.bla"); });
+
+is($output, "if (*r->in.bla == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;");
+
+# Test case 5: Unknown variable
+
+$output = "";
+$fn = check_null_pointer({ 
+	FILE => "nofile",
+	LINE => 2,
+	PARENT => {
+		ELEMENTS => [
+			{ 
+				NAME => "bla",
+				LEVELS => [
+					{ TYPE => "DATA" }
+				],
+			},
+		]
+	}
+}, { }, \&print_fn); 
+
+test_warnings("nofile:2: unknown dereferenced expression `r->in.bla'\n",
+	          sub { $fn->("r->in.bla"); });
+
+is($output, "if (r->in.bla == NULL) return NT_STATUS_INVALID_PARAMETER_MIX;");


Property changes on: branches/SAMBA_4_0/source/pidl/tests/samba-ndr.pl
___________________________________________________________________
Name: svn:executable
   + *



More information about the samba-cvs mailing list