From e8d766e1b2d5013e3f2c0a95d43b1dcb5eb00044 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 16 Jan 2007 17:00:00 +0000 Subject: [PATCH] Ensure we put the right number of items in a struct or message and add test cases. This avoids us getting kicked off the bus when trying to put the wrong number of things in a struct - this used to happen, but was masked by the fact that the tests ran with service activation, so the service was just killed and reactivated. Forthcoming changes to get_object make this automatic reactivation not happen (messages will be directed to the unique name by default, so stateful communication can work). --- _dbus_bindings/message-append.c | 55 +++++++++++++++++++++++++++-------------- test/test-standalone.py | 44 ++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 20 deletions(-) diff --git a/_dbus_bindings/message-append.c b/_dbus_bindings/message-append.c index 74faf9f..f629c57 100644 --- a/_dbus_bindings/message-append.c +++ b/_dbus_bindings/message-append.c @@ -410,7 +410,8 @@ dbus_py_Message_guess_signature(PyObject *unused UNUSED, PyObject *args) static int _message_iter_append_pyobject(DBusMessageIter *appender, DBusSignatureIter *sig_iter, - PyObject *obj); + PyObject *obj, + dbus_bool_t *more); static int _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj); @@ -522,6 +523,7 @@ _message_iter_append_dictentry(DBusMessageIter *appender, DBusMessageIter sub; int ret = -1; PyObject *value = PyObject_GetItem(dict, key); + dbus_bool_t more; if (!value) return -1; @@ -553,9 +555,9 @@ _message_iter_append_dictentry(DBusMessageIter *appender, PyErr_NoMemory(); goto out; } - ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key); + ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, key, &more); if (ret == 0) { - ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value); + ret = _message_iter_append_pyobject(&sub, &sub_sig_iter, value, &more); } DBG("%s", "Closing DICT_ENTRY container"); if (!dbus_message_iter_close_container(appender, &sub)) { @@ -581,6 +583,7 @@ _message_iter_append_multi(DBusMessageIter *appender, int container = mode; dbus_bool_t is_byte_array = DBusPyByteArray_Check(obj); int inner_type; + dbus_bool_t more; #ifdef USING_DBG fprintf(stderr, "Appending multiple: "); @@ -666,15 +669,27 @@ _message_iter_append_multi(DBusMessageIter *appender, Py_DECREF(byte); } else { + /* advances sub_sig_iter and sets more on success - for array + * this doesn't matter, for struct it's essential */ ret = _message_iter_append_pyobject(&sub_appender, &sub_sig_iter, - contents); + contents, &more); } + Py_DECREF(contents); if (ret < 0) { break; } } - if (PyErr_Occurred()) ret = -1; + + if (PyErr_Occurred()) { + ret = -1; + } + else if (mode == DBUS_TYPE_STRUCT && more) { + PyErr_Format(PyExc_TypeError, "More items found in struct's D-Bus " + "signature than in Python arguments "); + ret = -1; + } + /* This must be run as cleanup, even on failure. */ DBG("Closing %c container", container); if (!dbus_message_iter_close_container(appender, &sub_appender)) { @@ -730,6 +745,7 @@ _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj) PyObject *obj_sig; int ret; long variant_level; + dbus_bool_t dummy; /* Separate the object into the contained object, and the number of * variants it's wrapped in. */ @@ -777,7 +793,7 @@ _message_iter_append_variant(DBusMessageIter *appender, PyObject *obj) /* Put the object itself into the innermost variant */ ret = _message_iter_append_pyobject(&variant_iters[variant_level-1], - &obj_sig_iter, obj); + &obj_sig_iter, obj, &dummy); /* here we rely on i (and variant_level) being a signed long */ for (i = variant_level - 1; i >= 0; i--) { @@ -804,10 +820,12 @@ out: return ret; } +/* On success, *more is set to whether there's more in the signature. */ static int _message_iter_append_pyobject(DBusMessageIter *appender, DBusSignatureIter *sig_iter, - PyObject *obj) + PyObject *obj, + dbus_bool_t *more) { int sig_type = dbus_signature_iter_get_current_type(sig_iter); union { @@ -983,16 +1001,11 @@ _message_iter_append_pyobject(DBusMessageIter *appender, if (ret < 0) return -1; DBG("Advancing signature iter at %p", sig_iter); + *more = dbus_signature_iter_next(sig_iter); #ifdef USING_DBG - { - dbus_bool_t b = -#endif - dbus_signature_iter_next(sig_iter); -#ifdef USING_DBG - DBG("- result: %ld, type %02x '%c'", (long)b, - (int)dbus_signature_iter_get_current_type(sig_iter), - (int)dbus_signature_iter_get_current_type(sig_iter)); - } + DBG("- result: %ld, type %02x '%c'", (long)(*more), + (int)dbus_signature_iter_get_current_type(sig_iter), + (int)dbus_signature_iter_get_current_type(sig_iter)); #endif return 0; } @@ -1007,6 +1020,9 @@ dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs) DBusMessageIter appender; int i; static char *argnames[] = {"signature", NULL}; + /* must start FALSE for the case where there's nothing there and we + * never iterate at all */ + dbus_bool_t more; if (!self->msg) return DBusPy_RaiseUnusableMessage(); @@ -1040,14 +1056,15 @@ dbus_py_Message_append(Message *self, PyObject *args, PyObject *kwargs) } dbus_signature_iter_init(&sig_iter, signature); dbus_message_iter_init_append(self->msg, &appender); + more = (signature[0] != '\0'); for (i = 0; i < PyTuple_GET_SIZE(args); i++) { if (_message_iter_append_pyobject(&appender, &sig_iter, - PyTuple_GET_ITEM(args, i)) < 0) { + PyTuple_GET_ITEM(args, i), + &more) < 0) { goto hosed; } } - if (dbus_signature_iter_get_current_type(&sig_iter) - != DBUS_TYPE_INVALID) { + if (more) { PyErr_SetString(PyExc_TypeError, "More items found in D-Bus " "signature than in Python arguments"); goto hosed; diff --git a/test/test-standalone.py b/test/test-standalone.py index 3bd5716..d1c99db 100755 --- a/test/test-standalone.py +++ b/test/test-standalone.py @@ -1,6 +1,10 @@ #!/usr/bin/env python -# Copyright (C) 2006 Collabora Ltd. +"""Tests that don't need an active D-Bus connection to run, but can be +run in isolation. +""" + +# Copyright (C) 2006, 2007 Collabora Ltd. # # Licensed under the Academic Free License version 2.1 # @@ -129,6 +133,25 @@ class TestTypes(unittest.TestCase): class TestMessageMarshalling(unittest.TestCase): + def test_count(self): + from _dbus_bindings import SignalMessage + s = SignalMessage('/', 'foo.bar', 'baz') + try: + s.append('a', signature='ss') + except TypeError: + pass + else: + raise AssertionError('Appending too few things in a message ' + 'should fail') + s = SignalMessage('/', 'foo.bar', 'baz') + try: + s.append('a','b','c', signature='ss') + except TypeError: + pass + else: + raise AssertionError('Appending too many things in a message ' + 'should fail') + def test_append(self): aeq = self.assertEquals from _dbus_bindings import SignalMessage @@ -248,6 +271,25 @@ class TestMessageMarshalling(unittest.TestCase): s.append(MyObject()) self.assertEquals(s.get_args_list(), ['/foo', '/foo']) + def test_struct(self): + from _dbus_bindings import SignalMessage + s = SignalMessage('/', 'foo.bar', 'baz') + try: + s.append(('a',), signature='(ss)') + except TypeError: + pass + else: + raise AssertionError('Appending too few things in a struct ' + 'should fail') + s = SignalMessage('/', 'foo.bar', 'baz') + try: + s.append(('a','b','c'), signature='(ss)') + except TypeError: + pass + else: + raise AssertionError('Appending too many things in a struct ' + 'should fail') + if __name__ == '__main__': unittest.main() -- 2.11.4.GIT