From f6c79072ca50e05a68b73a80a0ebd635a9bac068 Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Thu, 21 Apr 2016 21:44:56 +1200 Subject: [PATCH] pidl: Correct string handling to use talloc and be in common The previous string handling assumed the python variables referenced by PyString_AS_STRING had infinite life. When they were re-used the C structure started to point at unexpected things. We now check correctly for Unicode in every case, and we always duplicate the string with talloc_strdup() Signed-off-by: Andrew Bartlett Reviewed-by: Douglas Bagnall --- pidl/lib/Parse/Pidl/Samba4/Python.pm | 103 ++++++++++++++++----------- 1 file changed, 61 insertions(+), 42 deletions(-) diff --git a/pidl/lib/Parse/Pidl/Samba4/Python.pm b/pidl/lib/Parse/Pidl/Samba4/Python.pm index 6488ac9c73b..9e39167eb7e 100644 --- a/pidl/lib/Parse/Pidl/Samba4/Python.pm +++ b/pidl/lib/Parse/Pidl/Samba4/Python.pm @@ -960,6 +960,55 @@ sub assign($$$) } } +sub ConvertStringFromPythonData($$$$$) +{ + my ($self, $mem_ctx, $py_var, $target, $fail) = @_; + + $self->pidl("{"); + $self->indent; + $self->pidl("const char *test_str;"); + $self->pidl("const char *talloc_str;"); + $self->pidl("PyObject *unicode = NULL;"); + $self->pidl("if (PyUnicode_Check($py_var)) {"); + $self->indent; + # FIXME: Use Unix charset setting rather than utf-8 + $self->pidl("unicode = PyUnicode_AsEncodedString($py_var, \"utf-8\", \"ignore\");"); + $self->pidl("if (unicode == NULL) {"); + $self->indent; + $self->pidl("PyErr_NoMemory();"); + $self->pidl("$fail"); + $self->deindent; + $self->pidl("}"); + + $self->pidl("test_str = PyString_AS_STRING(unicode);"); + $self->deindent; + $self->pidl("} else if (PyString_Check($py_var)) {"); + $self->indent; + $self->pidl("test_str = PyString_AS_STRING($py_var);"); + $self->deindent; + $self->pidl("} else {"); + $self->indent; + $self->pidl("PyErr_Format(PyExc_TypeError, \"Expected string or unicode object, got %s\", Py_TYPE($py_var)->tp_name);"); + $self->pidl("$fail"); + $self->deindent; + $self->pidl("}"); + $self->pidl("talloc_str = talloc_strdup($mem_ctx, test_str);"); + $self->pidl("if (unicode != NULL) {"); + $self->indent; + $self->pidl("Py_DECREF(unicode);"); + $self->deindent; + $self->pidl("}"); + $self->pidl("if (talloc_str == NULL) {"); + $self->indent; + $self->pidl("PyErr_NoMemory();"); + $self->pidl("$fail"); + $self->deindent; + $self->pidl("}"); + $self->pidl("$target = talloc_str;"); + $self->deindent; + $self->pidl("}"); +} + sub ConvertObjectFromPythonData($$$$$$;$) { my ($self, $mem_ctx, $cvar, $ctype, $target, $fail, $location) = @_; @@ -1114,33 +1163,17 @@ sub ConvertObjectFromPythonData($$$$$$;$) } if ($actual_ctype->{TYPE} eq "SCALAR" and - ($actual_ctype->{NAME} eq "string" or $actual_ctype->{NAME} eq "nbt_string" or $actual_ctype->{NAME} eq "nbt_name" or $actual_ctype->{NAME} eq "wrepl_nbt_name")) { - $self->pidl("$target = talloc_strdup($mem_ctx, PyString_AS_STRING($cvar));"); - return; - } - - if ($actual_ctype->{TYPE} eq "SCALAR" and ($actual_ctype->{NAME} eq "dns_string" or $actual_ctype->{NAME} eq "dns_name")) { - $self->pidl("$target = talloc_strdup($mem_ctx, PyString_AS_STRING($cvar));"); - return; - } - - if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "ipv4address") { - $self->pidl("$target = PyString_AS_STRING($cvar);"); - return; - } - - if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "ipv6address") { - $self->pidl("$target = PyString_AsString($cvar);"); - return; - } - - if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "dnsp_name") { - $self->pidl("$target = PyString_AS_STRING($cvar);"); - return; - } - - if ($actual_ctype->{TYPE} eq "SCALAR" and $actual_ctype->{NAME} eq "dnsp_string") { - $self->pidl("$target = PyString_AS_STRING($cvar);"); + ($actual_ctype->{NAME} eq "string" + or $actual_ctype->{NAME} eq "nbt_string" + or $actual_ctype->{NAME} eq "nbt_name" + or $actual_ctype->{NAME} eq "wrepl_nbt_name" + or $actual_ctype->{NAME} eq "dns_string" + or $actual_ctype->{NAME} eq "dnsp_string" + or $actual_ctype->{NAME} eq "dns_name" + or $actual_ctype->{NAME} eq "ipv4address" + or $actual_ctype->{NAME} eq "ipv6address" + or $actual_ctype->{NAME} eq "dnsp_name")) { + $self->ConvertStringFromPythonData($mem_ctx, $cvar, $target, $fail); return; } @@ -1218,21 +1251,7 @@ sub ConvertObjectFromPythonLevel($$$$$$$$) } if (is_charset_array($e, $l)) { - $self->pidl("if (PyUnicode_Check($py_var)) {"); - $self->indent; - # FIXME: Use Unix charset setting rather than utf-8 - $self->pidl($var_name . " = PyString_AS_STRING(PyUnicode_AsEncodedString($py_var, \"utf-8\", \"ignore\"));"); - $self->deindent; - $self->pidl("} else if (PyString_Check($py_var)) {"); - $self->indent; - $self->pidl($var_name . " = PyString_AS_STRING($py_var);"); - $self->deindent; - $self->pidl("} else {"); - $self->indent; - $self->pidl("PyErr_Format(PyExc_TypeError, \"Expected string or unicode object, got %s\", Py_TYPE($py_var)->tp_name);"); - $self->pidl("$fail"); - $self->deindent; - $self->pidl("}"); + $self->ConvertStringFromPythonData($mem_ctx, $py_var, $var_name, $fail); } else { my $counter = "$e->{NAME}_cntr_$l->{LEVEL_INDEX}"; $self->pidl("PY_CHECK_TYPE(&PyList_Type, $py_var, $fail);");