[patch] [python] Ensure we put the right number of items in a struct or message, and add test cases

Simon McVittie simon.mcvittie at collabora.co.uk
Tue Jan 16 09:28:51 PST 2007


From e8d766e1b2d5013e3f2c0a95d43b1dcb5eb00044 Mon Sep 17 00:00:00 2001
From: Simon McVittie <simon.mcvittie at collabora.co.uk>
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. <http://www.collabora.co.uk/>
+"""Tests that don't need an active D-Bus connection to run, but can be
+run in isolation.
+"""
+
+# Copyright (C) 2006, 2007 Collabora Ltd. <http://www.collabora.co.uk/>
 #
 # 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()
-- 
1.4.4.4

-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 266 bytes
Desc: Digital signature
Url : http://lists.freedesktop.org/archives/dbus/attachments/20070116/4381eb71/attachment.pgp


More information about the dbus mailing list