From: Andrew Bartlett Date: Tue, 16 Feb 2016 01:06:28 +0000 (+1300) Subject: pidl: Fix our python reference handling X-Git-Tag: talloc-2.1.6~28 X-Git-Url: http://git.samba.org/?a=commitdiff_plain;h=9e07f3a13b41be1f019887581b2a2bd049039a3d;p=samba.git pidl: Fix our python reference handling The new talloc.BaseObject allow us to hold a talloc context per python object (there may be many referring to the same C object) and the talloc context that the actual object pointer is under. Another advantage is that talloc.BaseObject(), has less of an ABI surface. Signed-off-by: Andrew Bartlett Reviewed-by: Garming Sam --- diff --git a/pidl/lib/Parse/Pidl/Samba4/Python.pm b/pidl/lib/Parse/Pidl/Samba4/Python.pm index f2cb5387751..29fb6e00084 100644 --- a/pidl/lib/Parse/Pidl/Samba4/Python.pm +++ b/pidl/lib/Parse/Pidl/Samba4/Python.pm @@ -376,15 +376,16 @@ sub PythonStruct($$$$$$) } $self->pidl(".tp_methods = $py_methods,"); $self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,"); - $self->pidl(".tp_basicsize = sizeof(pytalloc_Object),"); $self->pidl(".tp_new = py_$name\_new,"); $self->deindent; $self->pidl("};"); $self->pidl(""); - my $talloc_typename = $self->import_type_variable("talloc", "Object"); - $self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;", ""]); + my $talloc_typename = $self->import_type_variable("talloc", "BaseObject"); + $self->register_module_prereadycode(["$name\_Type.tp_base = $talloc_typename;", + "$name\_Type.tp_basicsize = pytalloc_BaseObject_size();", + ""]); return "&$typeobject"; } @@ -810,7 +811,6 @@ sub Interface($$$) $self->indent; $self->pidl("PyObject_HEAD_INIT(NULL) 0,"); $self->pidl(".tp_name = \"$basename.$interface->{NAME}\","); - $self->pidl(".tp_basicsize = sizeof(pytalloc_Object),"); $self->pidl(".tp_doc = $docstring,"); $self->pidl(".tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,"); $self->pidl(".tp_new = syntax_$interface->{NAME}_new,"); @@ -821,7 +821,9 @@ sub Interface($$$) $self->register_module_typeobject("abstract_syntax", "&$syntax_typename"); my $ndr_typename = $self->import_type_variable("samba.dcerpc.misc", "ndr_syntax_id"); - $self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;", ""]); + $self->register_module_prereadycode(["$syntax_typename.tp_base = $ndr_typename;", + "$syntax_typename.tp_basicsize = pytalloc_BaseObject_size();", + ""]); } $self->pidl_hdr("\n"); diff --git a/python/samba/tests/dcerpc/array.py b/python/samba/tests/dcerpc/array.py new file mode 100644 index 00000000000..80c53c61e2a --- /dev/null +++ b/python/samba/tests/dcerpc/array.py @@ -0,0 +1,171 @@ +# Unix SMB/CIFS implementation. +# Copyright (C) Andrew Bartlett 2016 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +"""Tests for array handling in PIDL generated bindings samba.dcerpc.*""" + +from samba.dcerpc import drsblobs +import samba.tests +from samba.ndr import ndr_unpack, ndr_pack +import talloc +import gc + +class ArrayTests(samba.tests.TestCase): + + def setUp(self): + super(ArrayTests, self).setUp() + talloc.enable_null_tracking() + self.startup_blocks = talloc.total_blocks() + + def tearDown(self): + super(ArrayTests, self).tearDown() + self.assertEqual(talloc.total_blocks(), self.startup_blocks) + talloc.report_full() + + def test_array_from_python(self): + rmd = drsblobs.replPropertyMetaDataBlob() + + rmd.version = 1 + rmd.ctr = drsblobs.replPropertyMetaDataCtr1() + rmd.ctr.count = 3 + + rmd1 = drsblobs.replPropertyMetaData1() + rmd1.attid = 1 + rmd1.version = 2 + + rmd2 = drsblobs.replPropertyMetaData1() + rmd2.attid = 2 + rmd2.version = 2 + + rmd3 = drsblobs.replPropertyMetaData1() + rmd3.attid = 3 + rmd3.version = 2 + + rmd.ctr.array = [rmd1, rmd2, rmd3] + gc.collect() + + self.assertIsNotNone(rmd) + self.assertEqual(rmd.version, 1) + self.assertIsNotNone(rmd.ctr) + self.assertEqual(rmd.ctr.count, 3) + self.assertEqual(len(rmd.ctr.array), rmd.ctr.count) + self.assertIsNotNone(rmd.ctr.array[0]) + self.assertEqual(rmd.ctr.array[0].attid, 1) + + def test_array_with_exception(self): + try: + rmd = drsblobs.replPropertyMetaDataBlob() + + rmd.version = 1 + rmd.ctr = drsblobs.replPropertyMetaDataCtr1() + rmd.ctr.count = 3 + + rmd1 = drsblobs.replPropertyMetaData1() + rmd1.attid = 1 + rmd1.version = 2 + + rmd2 = drsblobs.replPropertyMetaData1() + rmd2.attid = 2 + rmd2.version = 2 + + rmd3 = drsblobs.replPropertyMetaData1() + rmd3.attid = 3 + rmd3.version = 2 + + rmd.ctr.array = [rmd1, rmd2, rmd3] + + gc.collect() + + self.assertIsNotNone(rmd) + self.assertEqual(rmd.version, 1) + self.assertIsNotNone(rmd.ctr) + self.assertEqual(rmd.ctr.count, 3) + self.assertEqual(len(rmd.ctr.array), rmd.ctr.count) + self.assertIsNotNone(rmd.ctr.array[0]) + self.assertEqual(rmd.ctr.array[0].attid, 1) + + raise Exception() + except: + pass + + def test_array_from_python_function(self): + def get_rmd(): + rmd = drsblobs.replPropertyMetaDataBlob() + + rmd.version = 1 + rmd.ctr = drsblobs.replPropertyMetaDataCtr1() + rmd.ctr.count = 3 + + rmd1 = drsblobs.replPropertyMetaData1() + rmd1.attid = 1 + rmd1.version = 2 + + rmd2 = drsblobs.replPropertyMetaData1() + rmd2.attid = 2 + rmd2.version = 2 + + rmd3 = drsblobs.replPropertyMetaData1() + rmd3.attid = 3 + rmd3.version = 2 + + rmd.ctr.array = [rmd1, rmd2, rmd3] + return rmd + + rmd = get_rmd() + gc.collect() + self.assertIsNotNone(rmd) + self.assertEqual(rmd.version, 1) + self.assertIsNotNone(rmd.ctr) + self.assertEqual(rmd.ctr.count, 3) + self.assertEqual(len(rmd.ctr.array), rmd.ctr.count) + self.assertIsNotNone(rmd.ctr.array[0]) + self.assertEqual(rmd.ctr.array[0].attid, 1) + + def test_array_from_ndr(self): + rmd = drsblobs.replPropertyMetaDataBlob() + + rmd.version = 1 + rmd.ctr = drsblobs.replPropertyMetaDataCtr1() + rmd.ctr.count = 3 + + rmd1 = drsblobs.replPropertyMetaData1() + rmd1.attid = 1 + rmd1.version = 2 + + rmd2 = drsblobs.replPropertyMetaData1() + rmd2.attid = 2 + rmd2.version = 2 + + rmd3 = drsblobs.replPropertyMetaData1() + rmd3.attid = 3 + rmd3.version = 2 + + rmd.ctr.array = [rmd1, rmd2, rmd3] + + packed = ndr_pack(rmd) + gc.collect() + + rmd_unpacked = ndr_unpack(drsblobs.replPropertyMetaDataBlob, packed) + self.assertIsNotNone(rmd_unpacked) + self.assertEqual(rmd_unpacked.version, 1) + self.assertIsNotNone(rmd_unpacked.ctr) + self.assertEqual(rmd_unpacked.ctr.count, 3) + self.assertEqual(len(rmd_unpacked.ctr.array), rmd_unpacked.ctr.count) + self.assertIsNotNone(rmd_unpacked.ctr.array[0]) + self.assertEqual(rmd_unpacked.ctr.array[0].attid, 1) + + self.assertEqual(rmd.ctr.array[0].attid, + rmd_unpacked.ctr.array[0].attid) diff --git a/python/samba/tests/dcerpc/rpc_talloc.py b/python/samba/tests/dcerpc/rpc_talloc.py index b1e2741d7de..191e70c9702 100644 --- a/python/samba/tests/dcerpc/rpc_talloc.py +++ b/python/samba/tests/dcerpc/rpc_talloc.py @@ -51,25 +51,27 @@ class TallocTests(samba.tests.TestCase): '''get a list of attributes for RODC replication''' partial_attribute_set = drsuapi.DsPartialAttributeSet() - # we expect one block for the object, and one for the structure - self.check_blocks(partial_attribute_set, 2) + # we expect one block for the object + self.check_blocks(partial_attribute_set, 1) attids = [1, 2, 3] partial_attribute_set.version = 1 partial_attribute_set.attids = attids partial_attribute_set.num_attids = len(attids) - # we expect one block object, a structure, an ARRAY, and a + # we expect one block for the object, a structure, and a # reference to the array - self.check_blocks(partial_attribute_set, 3) + self.check_blocks(partial_attribute_set, 2) return partial_attribute_set def pas_test(self): pas = self.get_rodc_partial_attribute_set() - self.check_blocks(pas, 3) + self.check_blocks(pas, 2) req8 = drsuapi.DsGetNCChangesRequest8() - self.check_blocks(req8, 2) + self.check_blocks(req8, 1) + + # We expect the pas and req8, plus one block for each python object self.check_blocks(None, 5) req8.partial_attribute_set = pas if req8.partial_attribute_set.attids[1] != 2: diff --git a/source4/librpc/rpc/pyrpc.c b/source4/librpc/rpc/pyrpc.c index f1bfc887871..948cad212f6 100644 --- a/source4/librpc/rpc/pyrpc.c +++ b/source4/librpc/rpc/pyrpc.c @@ -342,7 +342,6 @@ static PyObject *py_transfer_syntax_ndr_new(PyTypeObject *type, PyObject *args, static PyTypeObject py_transfer_syntax_ndr_SyntaxType = { PyObject_HEAD_INIT(NULL) 0, .tp_name = "base.transfer_syntax_ndr", - .tp_basicsize = sizeof(pytalloc_Object), .tp_doc = "transfer_syntax_ndr()\n", .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = py_transfer_syntax_ndr_new, @@ -356,7 +355,6 @@ static PyObject *py_transfer_syntax_ndr64_new(PyTypeObject *type, PyObject *args static PyTypeObject py_transfer_syntax_ndr64_SyntaxType = { PyObject_HEAD_INIT(NULL) 0, .tp_name = "base.transfer_syntax_ndr64", - .tp_basicsize = sizeof(pytalloc_Object), .tp_doc = "transfer_syntax_ndr64()\n", .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = py_transfer_syntax_ndr64_new, @@ -395,7 +393,6 @@ static PyObject *py_bind_time_features_syntax_new(PyTypeObject *type, PyObject * static PyTypeObject py_bind_time_features_syntax_SyntaxType = { PyObject_HEAD_INIT(NULL) 0, .tp_name = "base.bind_time_features_syntax", - .tp_basicsize = sizeof(pytalloc_Object), .tp_doc = "bind_time_features_syntax(features)\n", .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_new = py_bind_time_features_syntax_new, @@ -415,8 +412,11 @@ void initbase(void) return; py_transfer_syntax_ndr_SyntaxType.tp_base = ndr_syntax_id_Type; + py_transfer_syntax_ndr_SyntaxType.tp_basicsize = pytalloc_BaseObject_size(); py_transfer_syntax_ndr64_SyntaxType.tp_base = ndr_syntax_id_Type; + py_transfer_syntax_ndr64_SyntaxType.tp_basicsize = pytalloc_BaseObject_size(); py_bind_time_features_syntax_SyntaxType.tp_base = ndr_syntax_id_Type; + py_bind_time_features_syntax_SyntaxType.tp_basicsize = pytalloc_BaseObject_size(); if (PyType_Ready(&dcerpc_InterfaceType) < 0) return;