pidl/Python: improve error handling in PythonFunctionUnpackOut() results
authorStefan Metzmacher <metze@samba.org>
Tue, 9 May 2017 13:02:02 +0000 (15:02 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 18 Feb 2019 11:48:38 +0000 (12:48 +0100)
Signed-off-by: Stefan Metzmacher <metze@samba.org>
pidl/lib/Parse/Pidl/Samba4/Python.pm

index efb3265a5da17d6c414afa73221f590b84c452c1..a46bebe51d0814ab0f6dec0bcf5252536b0818dc 100644 (file)
@@ -938,57 +938,86 @@ sub PythonFunctionUnpackOut($$$)
        $self->pidl("static PyObject *$outfnname(struct $fn->{NAME} *r)");
        $self->pidl("{");
        $self->indent;
-       $self->pidl("PyObject *result;");
+       $self->pidl("PyObject *result = NULL;");
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next unless (grep(/out/,@{$e->{DIRECTION}}));
                next if (($metadata_args->{in}->{$e->{NAME}} and grep(/in/, @{$e->{DIRECTION}})) or
                         ($metadata_args->{out}->{$e->{NAME}}) and grep(/out/, @{$e->{DIRECTION}}));
-               $self->pidl("PyObject *py_$e->{NAME};");
+               $self->pidl("PyObject *py_$e->{NAME} = NULL;");
                $result_size++;
        }
 
        if ($fn->{RETURN_TYPE}) {
-               $result_size++ unless ($fn->{RETURN_TYPE} eq "WERROR" or $fn->{RETURN_TYPE} eq "NTSTATUS");
+               if ($fn->{RETURN_TYPE} ne "WERROR" and $fn->{RETURN_TYPE} ne "NTSTATUS") {
+                       $self->pidl("PyObject *py_result = NULL;");
+                       $result_size++;
+               }
        }
 
        my $i = 0;
 
+       my $fail = "return NULL;";
+
        if ($result_size > 1) {
+               $self->pidl("int ret;");
+               $self->pidl("");
                $self->pidl("result = PyTuple_New($result_size);");
+               $self->fail_on_null("result", $fail);
+               $fail = "Py_DECREF(result); " . $fail;
+
                $signature .= "(";
        } elsif ($result_size == 0) {
+               $self->pidl("");
                $self->pidl("result = Py_None;");
                $self->pidl("Py_INCREF(result);");
                $signature .= "None";
        }
 
+       $self->pidl("");
+
        foreach my $e (@{$fn->{ELEMENTS}}) {
                next if ($metadata_args->{out}->{$e->{NAME}});
                my $py_name = "py_$e->{NAME}";
                if (grep(/out/,@{$e->{DIRECTION}})) {
-                       $self->ConvertObjectToPython("r", $env, $e, "r->out.$e->{NAME}", $py_name, "return NULL;");
+                       $self->ConvertObjectToPython("r", $env, $e, "r->out.$e->{NAME}", $py_name, $fail);
                        if ($result_size > 1) {
-                               $self->pidl("PyTuple_SetItem(result, $i, $py_name);");
+                               $self->pidl("ret = PyTuple_SetItem(result, $i, $py_name);");
+                               $self->pidl("if (ret != 0) {");
+                               $self->indent;
+                               $self->pidl($fail);
+                               $self->deindent;
+                               $self->pidl("}");
                                $i++;
                                $signature .= "$e->{NAME}, ";
                        } else {
                                $self->pidl("result = $py_name;");
                                $signature .= $e->{NAME};
                        }
+                       $self->pidl("");
                }
        }
 
        if (defined($fn->{RETURN_TYPE}) and $fn->{RETURN_TYPE} eq "NTSTATUS") {
                $self->handle_ntstatus("r->out.result", "NULL", undef);
+               $self->pidl("");
        } elsif (defined($fn->{RETURN_TYPE}) and $fn->{RETURN_TYPE} eq "WERROR") {
                $self->handle_werror("r->out.result", "NULL", undef);
+               $self->pidl("");
        } elsif (defined($fn->{RETURN_TYPE})) {
                my $conv = $self->ConvertObjectToPythonData("r", $fn->{RETURN_TYPE}, "r->out.result", $fn);
+               $self->pidl("py_result = $conv;");
+               $self->fail_on_null("py_result", $fail);
                if ($result_size > 1) {
-                       $self->pidl("PyTuple_SetItem(result, $i, $conv);");
+                       $self->pidl("ret = PyTuple_SetItem(result, $i, py_result);");
+                       $self->pidl("if (ret != 0) {");
+                       $self->indent;
+                       $self->pidl($fail);
+                       $self->deindent;
+                       $self->pidl("}");
                } else {
-                       $self->pidl("result = $conv;");
+                       $self->pidl("result = py_result;");
                }
+               $self->pidl("");
                $signature .= "result";
        }