summaryrefslogtreecommitdiff
path: root/dbus/dbus-message.c
diff options
context:
space:
mode:
Diffstat (limited to 'dbus/dbus-message.c')
-rw-r--r--dbus/dbus-message.c205
1 files changed, 139 insertions, 66 deletions
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index f48977ca..2c30482c 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -56,7 +56,7 @@ static void dbus_message_finalize (DBusMessage *message);
* @{
*/
-#ifdef DBUS_BUILD_TESTS
+#ifdef DBUS_ENABLE_EMBEDDED_TESTS
static dbus_bool_t
_dbus_enable_message_cache (void)
{
@@ -462,7 +462,7 @@ set_or_delete_string_field (DBusMessage *message,
/** Avoid caching too many messages */
#define MAX_MESSAGE_CACHE_SIZE 5
-_DBUS_DEFINE_GLOBAL_LOCK (message_cache);
+/* Protected by _DBUS_LOCK (message_cache) */
static DBusMessage *message_cache[MAX_MESSAGE_CACHE_SIZE];
static int message_cache_count = 0;
static dbus_bool_t message_cache_shutdown_registered = FALSE;
@@ -472,7 +472,9 @@ dbus_message_cache_shutdown (void *data)
{
int i;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "before registering a shutdown function");
i = 0;
while (i < MAX_MESSAGE_CACHE_SIZE)
@@ -504,7 +506,12 @@ dbus_message_get_cached (void)
message = NULL;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* we'd have initialized global locks before caching anything,
+ * so there can't be anything in the cache */
+ return NULL;
+ }
_dbus_assert (message_cache_count >= 0);
@@ -616,7 +623,13 @@ dbus_message_cache_or_finalize (DBusMessage *message)
was_cached = FALSE;
- _DBUS_LOCK (message_cache);
+ if (!_DBUS_LOCK (message_cache))
+ {
+ /* The only way to get a non-null message goes through
+ * dbus_message_get_cached() which takes the lock. */
+ _dbus_assert_not_reached ("we would have initialized global locks "
+ "the first time we constructed a message");
+ }
if (!message_cache_shutdown_registered)
{
@@ -672,7 +685,7 @@ dbus_message_cache_or_finalize (DBusMessage *message)
dbus_message_finalize (message);
}
-#ifndef DBUS_DISABLE_CHECKS
+#if defined(DBUS_ENABLE_CHECKS) || defined(DBUS_ENABLE_ASSERT)
static dbus_bool_t
_dbus_message_iter_check (DBusMessageRealIter *iter)
{
@@ -720,15 +733,13 @@ _dbus_message_iter_check (DBusMessageRealIter *iter)
return TRUE;
}
-#endif /* DBUS_DISABLE_CHECKS */
+#endif /* DBUS_ENABLE_CHECKS || DBUS_ENABLE_ASSERT */
/**
* Implementation of the varargs arg-getting functions.
* dbus_message_get_args() is the place to go for complete
* documentation.
*
- * @todo This may leak memory and file descriptors if parsing fails. See #21259
- *
* @see dbus_message_get_args
* @param iter the message iter
* @param error error to be filled in
@@ -743,8 +754,9 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
va_list var_args)
{
DBusMessageRealIter *real = (DBusMessageRealIter *)iter;
- int spec_type, msg_type, i;
+ int spec_type, msg_type, i, j;
dbus_bool_t retval;
+ va_list copy_args;
_dbus_assert (_dbus_message_iter_check (real));
@@ -753,12 +765,17 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
spec_type = first_arg_type;
i = 0;
+ /* copy var_args first, then we can do another iteration over it to
+ * free memory and close unix fds if parse failed at some point.
+ */
+ DBUS_VA_COPY (copy_args, var_args);
+
while (spec_type != DBUS_TYPE_INVALID)
{
msg_type = dbus_message_iter_get_arg_type (iter);
if (msg_type != spec_type)
- {
+ {
dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
"Argument %d is specified to be of type \"%s\", but "
"is actually of type \"%s\"\n", i,
@@ -766,7 +783,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
_dbus_type_to_string (msg_type));
goto out;
- }
+ }
if (spec_type == DBUS_TYPE_UNIX_FD)
{
@@ -879,30 +896,30 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
/* Now go through and dup each string */
_dbus_type_reader_recurse (&real->u.reader, &array);
- i = 0;
- while (i < n_elements)
+ j = 0;
+ while (j < n_elements)
{
const char *s;
_dbus_type_reader_read_basic (&array,
(void *) &s);
- str_array[i] = _dbus_strdup (s);
- if (str_array[i] == NULL)
+ str_array[j] = _dbus_strdup (s);
+ if (str_array[j] == NULL)
{
dbus_free_string_array (str_array);
_DBUS_SET_OOM (error);
goto out;
}
- ++i;
+ ++j;
if (!_dbus_type_reader_next (&array))
- _dbus_assert (i == n_elements);
+ _dbus_assert (j == n_elements);
}
_dbus_assert (_dbus_type_reader_get_current_type (&array) == DBUS_TYPE_INVALID);
- _dbus_assert (i == n_elements);
- _dbus_assert (str_array[i] == NULL);
+ _dbus_assert (j == n_elements);
+ _dbus_assert (str_array[j] == NULL);
*str_array_p = str_array;
*n_elements_p = n_elements;
@@ -925,6 +942,9 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
}
#endif
+ /* how many arguments already handled */
+ i++;
+
spec_type = va_arg (var_args, int);
if (!_dbus_type_reader_next (&real->u.reader) && spec_type != DBUS_TYPE_INVALID)
{
@@ -932,14 +952,71 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
"Message has only %d arguments, but more were expected", i);
goto out;
}
-
- i++;
}
retval = TRUE;
out:
+ /* there may memory or unix fd leak in the above iteration if parse failed.
+ * so we have another iteration over copy_args to free memory and close
+ * unix fds.
+ */
+ if (!retval)
+ {
+ spec_type = first_arg_type;
+ j = 0;
+ while (j < i)
+ {
+ if (spec_type == DBUS_TYPE_UNIX_FD)
+ {
+#ifdef HAVE_UNIX_FD_PASSING
+ int *pfd;
+
+ pfd = va_arg (copy_args, int *);
+ _dbus_assert(pfd);
+ if (*pfd >= 0)
+ {
+ _dbus_close (*pfd, NULL);
+ *pfd = -1;
+ }
+#endif
+ }
+ else if (dbus_type_is_basic (spec_type))
+ {
+ /* move the index forward */
+ va_arg (copy_args, DBusBasicValue *);
+ }
+ else if (spec_type == DBUS_TYPE_ARRAY)
+ {
+ int spec_element_type;
+
+ spec_element_type = va_arg (copy_args, int);
+ if (dbus_type_is_fixed (spec_element_type))
+ {
+ /* move the index forward */
+ va_arg (copy_args, const DBusBasicValue **);
+ va_arg (copy_args, int *);
+ }
+ else if (_DBUS_TYPE_IS_STRINGLIKE (spec_element_type))
+ {
+ char ***str_array_p;
+
+ str_array_p = va_arg (copy_args, char ***);
+ /* move the index forward */
+ va_arg (copy_args, int *);
+ _dbus_assert (str_array_p != NULL);
+ dbus_free_string_array (*str_array_p);
+ *str_array_p = NULL;
+ }
+ }
+
+ spec_type = va_arg (copy_args, int);
+ j++;
+ }
+ }
+
+ va_end (copy_args);
return retval;
}
@@ -1202,7 +1279,7 @@ dbus_message_new (int message_type)
*
* @param destination name that the message should be sent to or #NULL
* @param path object path the message should be sent to
- * @param interface interface to invoke method on, or #NULL
+ * @param iface interface to invoke method on, or #NULL
* @param method method to invoke
*
* @returns a new DBusMessage, free with dbus_message_unref()
@@ -1210,7 +1287,7 @@ dbus_message_new (int message_type)
DBusMessage*
dbus_message_new_method_call (const char *destination,
const char *path,
- const char *interface,
+ const char *iface,
const char *method)
{
DBusMessage *message;
@@ -1220,8 +1297,8 @@ dbus_message_new_method_call (const char *destination,
_dbus_return_val_if_fail (destination == NULL ||
_dbus_check_is_valid_bus_name (destination), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
- _dbus_return_val_if_fail (interface == NULL ||
- _dbus_check_is_valid_interface (interface), NULL);
+ _dbus_return_val_if_fail (iface == NULL ||
+ _dbus_check_is_valid_interface (iface), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_member (method), NULL);
message = dbus_message_new_empty_header ();
@@ -1231,7 +1308,7 @@ dbus_message_new_method_call (const char *destination,
if (!_dbus_header_create (&message->header,
DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_METHOD_CALL,
- destination, path, interface, method, NULL))
+ destination, path, iface, method, NULL))
{
dbus_message_unref (message);
return NULL;
@@ -1294,22 +1371,22 @@ dbus_message_new_method_return (DBusMessage *method_call)
* specification defines the syntax of these fields).
*
* @param path the path to the object emitting the signal
- * @param interface the interface the signal is emitted from
+ * @param iface the interface the signal is emitted from
* @param name name of the signal
* @returns a new DBusMessage, free with dbus_message_unref()
*/
DBusMessage*
dbus_message_new_signal (const char *path,
- const char *interface,
+ const char *iface,
const char *name)
{
DBusMessage *message;
_dbus_return_val_if_fail (path != NULL, NULL);
- _dbus_return_val_if_fail (interface != NULL, NULL);
+ _dbus_return_val_if_fail (iface != NULL, NULL);
_dbus_return_val_if_fail (name != NULL, NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_path (path), NULL);
- _dbus_return_val_if_fail (_dbus_check_is_valid_interface (interface), NULL);
+ _dbus_return_val_if_fail (_dbus_check_is_valid_interface (iface), NULL);
_dbus_return_val_if_fail (_dbus_check_is_valid_member (name), NULL);
message = dbus_message_new_empty_header ();
@@ -1319,7 +1396,7 @@ dbus_message_new_signal (const char *path,
if (!_dbus_header_create (&message->header,
DBUS_COMPILER_BYTE_ORDER,
DBUS_MESSAGE_TYPE_SIGNAL,
- NULL, path, interface, name, NULL))
+ NULL, path, iface, name, NULL))
{
dbus_message_unref (message);
return NULL;
@@ -3069,23 +3146,23 @@ dbus_message_get_path_decomposed (DBusMessage *message,
* in the D-Bus specification.
*
* @param message the message
- * @param interface the interface or #NULL to unset
+ * @param iface the interface or #NULL to unset
* @returns #FALSE if not enough memory
*/
dbus_bool_t
dbus_message_set_interface (DBusMessage *message,
- const char *interface)
+ const char *iface)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
_dbus_return_val_if_fail (!message->locked, FALSE);
- _dbus_return_val_if_fail (interface == NULL ||
- _dbus_check_is_valid_interface (interface),
+ _dbus_return_val_if_fail (iface == NULL ||
+ _dbus_check_is_valid_interface (iface),
FALSE);
return set_or_delete_string_field (message,
DBUS_HEADER_FIELD_INTERFACE,
DBUS_TYPE_STRING,
- interface);
+ iface);
}
/**
@@ -3120,28 +3197,28 @@ dbus_message_get_interface (DBusMessage *message)
* Checks if the message has an interface
*
* @param message the message
- * @param interface the interface name
+ * @param iface the interface name
* @returns #TRUE if the interface field in the header matches
*/
dbus_bool_t
dbus_message_has_interface (DBusMessage *message,
- const char *interface)
+ const char *iface)
{
const char *msg_interface;
msg_interface = dbus_message_get_interface (message);
if (msg_interface == NULL)
{
- if (interface == NULL)
+ if (iface == NULL)
return TRUE;
else
return FALSE;
}
- if (interface == NULL)
+ if (iface == NULL)
return FALSE;
- if (strcmp (msg_interface, interface) == 0)
+ if (strcmp (msg_interface, iface) == 0)
return TRUE;
return FALSE;
@@ -3474,13 +3551,13 @@ dbus_message_get_signature (DBusMessage *message)
static dbus_bool_t
_dbus_message_has_type_interface_member (DBusMessage *message,
int type,
- const char *interface,
+ const char *iface,
const char *member)
{
const char *n;
_dbus_assert (message != NULL);
- _dbus_assert (interface != NULL);
+ _dbus_assert (iface != NULL);
_dbus_assert (member != NULL);
if (dbus_message_get_type (message) != type)
@@ -3496,7 +3573,7 @@ _dbus_message_has_type_interface_member (DBusMessage *message,
{
n = dbus_message_get_interface (message);
- if (n == NULL || strcmp (n, interface) == 0)
+ if (n == NULL || strcmp (n, iface) == 0)
return TRUE;
}
@@ -3512,18 +3589,18 @@ _dbus_message_has_type_interface_member (DBusMessage *message,
* protocol allows method callers to leave out the interface name.
*
* @param message the message
- * @param interface the name to check (must not be #NULL)
+ * @param iface the name to check (must not be #NULL)
* @param method the name to check (must not be #NULL)
*
* @returns #TRUE if the message is the specified method call
*/
dbus_bool_t
dbus_message_is_method_call (DBusMessage *message,
- const char *interface,
+ const char *iface,
const char *method)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (interface != NULL, FALSE);
+ _dbus_return_val_if_fail (iface != NULL, FALSE);
_dbus_return_val_if_fail (method != NULL, FALSE);
/* don't check that interface/method are valid since it would be
* expensive, and not catch many common errors
@@ -3531,7 +3608,7 @@ dbus_message_is_method_call (DBusMessage *message,
return _dbus_message_has_type_interface_member (message,
DBUS_MESSAGE_TYPE_METHOD_CALL,
- interface, method);
+ iface, method);
}
/**
@@ -3540,18 +3617,18 @@ dbus_message_is_method_call (DBusMessage *message,
* has a different interface or member field, returns #FALSE.
*
* @param message the message
- * @param interface the name to check (must not be #NULL)
+ * @param iface the name to check (must not be #NULL)
* @param signal_name the name to check (must not be #NULL)
*
* @returns #TRUE if the message is the specified signal
*/
dbus_bool_t
dbus_message_is_signal (DBusMessage *message,
- const char *interface,
+ const char *iface,
const char *signal_name)
{
_dbus_return_val_if_fail (message != NULL, FALSE);
- _dbus_return_val_if_fail (interface != NULL, FALSE);
+ _dbus_return_val_if_fail (iface != NULL, FALSE);
_dbus_return_val_if_fail (signal_name != NULL, FALSE);
/* don't check that interface/name are valid since it would be
* expensive, and not catch many common errors
@@ -3559,7 +3636,7 @@ dbus_message_is_signal (DBusMessage *message,
return _dbus_message_has_type_interface_member (message,
DBUS_MESSAGE_TYPE_SIGNAL,
- interface, signal_name);
+ iface, signal_name);
}
/**
@@ -3799,7 +3876,7 @@ _dbus_message_loader_new (void)
SCM_RIGHTS works we need to preallocate an fd array of the maximum
number of unix fds we want to receive in advance. A
try-and-reallocate loop is not possible. */
- loader->max_message_unix_fds = 1024;
+ loader->max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS;
if (!_dbus_string_init (&loader->data))
{
@@ -3896,12 +3973,10 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader,
*
* @param loader the loader.
* @param buffer the buffer.
- * @param bytes_read number of bytes that were read into the buffer.
*/
void
_dbus_message_loader_return_buffer (DBusMessageLoader *loader,
- DBusString *buffer,
- int bytes_read)
+ DBusString *buffer)
{
_dbus_assert (loader->buffer_outstanding);
_dbus_assert (buffer == &loader->data);
@@ -3965,7 +4040,7 @@ _dbus_message_loader_get_unix_fds(DBusMessageLoader *loader,
*
* @param loader the message loader.
* @param fds the array fds were read into
- * @param max_n_fds how many fds were read
+ * @param n_fds how many fds were read
*/
void
@@ -4393,7 +4468,7 @@ _dbus_message_loader_get_max_message_size (DBusMessageLoader *loader)
* Sets the maximum unix fds per message we allow.
*
* @param loader the loader
- * @param size the max number of unix fds in a message
+ * @param n the max number of unix fds in a message
*/
void
_dbus_message_loader_set_max_message_unix_fds (DBusMessageLoader *loader,
@@ -4420,8 +4495,8 @@ _dbus_message_loader_get_max_message_unix_fds (DBusMessageLoader *loader)
return loader->max_message_unix_fds;
}
-static DBusDataSlotAllocator slot_allocator;
-_DBUS_DEFINE_GLOBAL_LOCK (message_slots);
+static DBusDataSlotAllocator slot_allocator =
+ _DBUS_DATA_SLOT_ALLOCATOR_INIT (_DBUS_LOCK_NAME (message_slots));
/**
* Allocates an integer ID to be used for storing application-specific
@@ -4441,7 +4516,6 @@ dbus_bool_t
dbus_message_allocate_data_slot (dbus_int32_t *slot_p)
{
return _dbus_data_slot_allocator_alloc (&slot_allocator,
- &_DBUS_LOCK_NAME (message_slots),
slot_p);
}
@@ -4737,7 +4811,7 @@ dbus_message_demarshal (const char *str,
_dbus_message_loader_get_buffer (loader, &buffer);
_dbus_string_append_len (buffer, str, len);
- _dbus_message_loader_return_buffer (loader, buffer, len);
+ _dbus_message_loader_return_buffer (loader, buffer);
if (!_dbus_message_loader_queue_messages (loader))
goto fail_oom;
@@ -4772,9 +4846,8 @@ dbus_message_demarshal (const char *str,
* Generally, this function is only useful for encapsulating D-Bus messages in
* a different protocol.
*
- * @param str data to be marshalled
- * @param len the length of str
- * @param error the location to save errors to
+ * @param buf data to be marshalled
+ * @param len the length of @p buf
* @returns -1 if there was no valid data to be demarshalled, 0 if there wasn't enough data to determine how much should be demarshalled. Otherwise returns the number of bytes to be demarshalled
*
*/