summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@collabora.com>2017-07-03 17:59:10 +0100
committerSimon McVittie <smcv@collabora.com>2017-11-24 12:17:17 +0000
commite49a21e357ef9de4c87cd6ab014d207a55bdb4e5 (patch)
tree4d320020d78af22da65a9d0211f6fca556fa0ecb
parent608a453b73a9f5b165d20f08cfb0f17a3147f514 (diff)
DBusString: Add _DBUS_STRING_INIT_INVALID and allow "freeing" it
This means we can finally use patterns like this: DBusString buffer = _DBUS_STRING_INIT_INVALID; dbus_bool_t ret = FALSE; ... some long setup ... if (!_dbus_string_init (&buffer)) goto out; ... some long operation ... ret = TRUE; out: ... free things ... _dbus_string_free (&buffer); ... free more things ... return ret; without having to have a separate boolean to track whether buffer has been initialized. One observable difference is that if s is a "const" (borrowed pointer) string, _dbus_string_free (&s) now sets it to be invalid. Previously, it would have kept its (borrowed pointer) contents, which seems like a violation of least-astonishment. Signed-off-by: Simon McVittie <smcv@collabora.com> Reviewed-by: Philip Withnall <withnall@endlessm.com> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89104
-rw-r--r--dbus/dbus-string-util.c10
-rw-r--r--dbus/dbus-string.c23
-rw-r--r--dbus/dbus-string.h16
3 files changed, 45 insertions, 4 deletions
diff --git a/dbus/dbus-string-util.c b/dbus/dbus-string-util.c
index 08e0e917a..a1390fea4 100644
--- a/dbus/dbus-string-util.c
+++ b/dbus/dbus-string-util.c
@@ -228,7 +228,7 @@ _DBUS_STRING_DEFINE_STATIC (test_static_string, "hello");
dbus_bool_t
_dbus_string_test (void)
{
- DBusString str;
+ DBusString str = _DBUS_STRING_INIT_INVALID;
DBusString other;
int i, a, end;
long v;
@@ -245,6 +245,11 @@ _dbus_string_test (void)
_dbus_assert (real_test_static_string->valid);
_dbus_assert (real_test_static_string->align_offset == 0);
+ /* Test that _DBUS_STRING_INIT_INVALID has the desired effect */
+ _dbus_string_free (&str);
+ _dbus_string_free (&str);
+ _dbus_string_free (&str);
+
/* Test shortening and setting length */
i = 0;
while (i < _DBUS_N_ELEMENTS (lens))
@@ -270,6 +275,9 @@ _dbus_string_test (void)
}
_dbus_string_free (&str);
+ /* Test that a cleared string is effectively _DBUS_STRING_INIT_INVALID */
+ _dbus_string_free (&str);
+ _dbus_string_free (&str);
++i;
}
diff --git a/dbus/dbus-string.c b/dbus/dbus-string.c
index 75134d6a8..5d3ddda00 100644
--- a/dbus/dbus-string.c
+++ b/dbus/dbus-string.c
@@ -251,7 +251,12 @@ _dbus_string_init_from_string(DBusString *str,
}
/**
- * Frees a string created by _dbus_string_init().
+ * Frees a string created by _dbus_string_init(), and fills it with the
+ * same contents as #_DBUS_STRING_INIT_INVALID.
+ *
+ * Unlike all other #DBusString API, it is also valid to call this function
+ * for a string that was filled with #_DBUS_STRING_INIT_INVALID.
+ * This is convenient for error rollback.
*
* @param str memory where the string is stored.
*/
@@ -259,20 +264,32 @@ void
_dbus_string_free (DBusString *str)
{
DBusRealString *real = (DBusRealString*) str;
+ /* DBusRealString and DBusString have the same members in the same order,
+ * just differently-named */
+ DBusRealString invalid = _DBUS_STRING_INIT_INVALID;
+
+ /* Allow for the _DBUS_STRING_INIT_INVALID case */
+ if (real->str == NULL && real->len == 0 && real->allocated == 0 &&
+ !real->constant && !real->locked && !real->valid &&
+ real->align_offset == 0)
+ return;
+
DBUS_GENERIC_STRING_PREAMBLE (real);
if (real->constant)
- return;
+ goto wipe;
/* so it's safe if @p str returned by a failed
* _dbus_string_init call
* Bug: https://bugs.freedesktop.org/show_bug.cgi?id=65959
*/
if (real->str == NULL)
- return;
+ goto wipe;
dbus_free (real->str - real->align_offset);
+wipe:
+ *real = invalid;
real->valid = FALSE;
}
diff --git a/dbus/dbus-string.h b/dbus/dbus-string.h
index e7060b9fb..5e2d945e3 100644
--- a/dbus/dbus-string.h
+++ b/dbus/dbus-string.h
@@ -54,6 +54,22 @@ struct DBusString
unsigned int dummy_bits : 3; /**< placeholder */
};
+/**
+ * Content for a DBusString that is considered invalid for all
+ * operations, except that it is valid to call _dbus_string_free()
+ * during error handling.
+ */
+#define _DBUS_STRING_INIT_INVALID \
+{ \
+ NULL, /* dummy1 */ \
+ 0, /* dummy2 */ \
+ 0, /* dummy3 */ \
+ 0, /* dummy_bit1 */ \
+ 0, /* dummy_bit2 */ \
+ 0, /* dummy_bit3 */ \
+ 0 /* dummy_bits */ \
+}
+
#ifdef DBUS_DISABLE_ASSERT
/* Some simple inlining hacks; the current linker is not smart enough
* to inline non-exported symbols across files in the library.