bfo22316 - add dbus_message_iter_abandon_container()
authorScott James Remnant <scott@ubuntu.com>
Thu, 9 Jul 2009 15:34:54 +0000 (16:34 +0100)
committerScott James Remnant <scott@ubuntu.com>
Thu, 9 Jul 2009 15:34:54 +0000 (16:34 +0100)
It's not currently possible to abandon creation of a container without
either hitting asserts or leaking memory.  This new function allows
that.

Signed-off-by: Scott James Remnant <scott@ubuntu.com>
dbus/dbus-message-util.c
dbus/dbus-message.c
dbus/dbus-message.h

index 3d5a00f..b995f5e 100644 (file)
@@ -1296,8 +1296,8 @@ _dbus_message_test (const char *test_data_dir)
 
   /* uh-oh, error, try and unwind */
 
-  _dbus_assert (dbus_message_iter_close_container (&array_iter, &struct_iter));
-  _dbus_assert (dbus_message_iter_close_container (&array_iter, &iter));
+  dbus_message_iter_abandon_container (&array_iter, &struct_iter);
+  dbus_message_iter_abandon_container (&array_iter, &iter);
 
   dbus_message_unref (message);
 
index edae425..30b5d6c 100644 (file)
@@ -2200,6 +2200,35 @@ _dbus_message_iter_close_signature (DBusMessageRealIter *real)
   return retval;
 }
 
+/**
+ * Frees the signature string and marks the iterator as not having a
+ * type_str anymore.  Since the new signature is not set, the message
+ * will generally be hosed after this is called.
+ *
+ * @param real an iterator without a type_str
+ */
+static void
+_dbus_message_iter_abandon_signature (DBusMessageRealIter *real)
+{
+  DBusString *str;
+
+  _dbus_assert (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+  _dbus_assert (real->u.writer.type_str != NULL);
+  _dbus_assert (real->sig_refcount > 0);
+
+  real->sig_refcount -= 1;
+
+  if (real->sig_refcount > 0)
+    return;
+  _dbus_assert (real->sig_refcount == 0);
+
+  str = real->u.writer.type_str;
+
+  _dbus_type_writer_remove_types (&real->u.writer);
+  _dbus_string_free (str);
+  dbus_free (str);
+}
+
 #ifndef DBUS_DISABLE_CHECKS
 static dbus_bool_t
 _dbus_message_iter_append_check (DBusMessageRealIter *iter)
@@ -2428,6 +2457,32 @@ dbus_message_iter_close_container (DBusMessageIter *iter,
 }
 
 /**
+ * Abandons creation of a contained-typed value and frees resources created
+ * by dbus_message_iter_open_container().  Once this returns, the message
+ * is hosed and you have to start over building the whole message.
+ *
+ * This should only be used to abandon creation of a message when you have
+ * open containers.
+ *
+ * @param iter the append iterator
+ * @param sub sub-iterator to close
+ */
+void
+dbus_message_iter_abandon_container (DBusMessageIter *iter,
+                                     DBusMessageIter *sub)
+{
+  DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
+  DBusMessageRealIter *real_sub = (DBusMessageRealIter *)sub;
+
+  _dbus_return_if_fail (_dbus_message_iter_append_check (real));
+  _dbus_return_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+  _dbus_return_if_fail (_dbus_message_iter_append_check (real_sub));
+  _dbus_return_if_fail (real_sub->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER);
+
+  _dbus_message_iter_abandon_signature (real);
+}
+
+/**
  * Sets a flag indicating that the message does not want a reply; if
  * this flag is set, the other end of the connection may (but is not
  * required to) optimize by not sending method return or error
index 2e29fef..49c7e72 100644 (file)
@@ -197,6 +197,8 @@ dbus_bool_t dbus_message_iter_open_container     (DBusMessageIter *iter,
                                                   DBusMessageIter *sub);
 dbus_bool_t dbus_message_iter_close_container    (DBusMessageIter *iter,
                                                   DBusMessageIter *sub);
+void        dbus_message_iter_abandon_container  (DBusMessageIter *iter,
+                                                  DBusMessageIter *sub);
 
 void dbus_message_lock    (DBusMessage  *message);