Commit 4c95a978 authored by Havoc Pennington's avatar Havoc Pennington

2003-03-14 Havoc Pennington <hp@redhat.com>

	* dbus/dbus-memory.c: add a "detect buffer overwrites on free"
	cheesy hack

	* dbus/dbus-transport-debug.c: rework this a good bit to be
	less complicated. hopefully still works.

	* dbus/dbus-server-debug.c (handle_new_client): remove timeout
	manually

	* glib/dbus-gmain.c (timeout_handler): don't remove timeout
	after running it

	* dbus/dbus-message.c (dbus_message_copy): rename from
	dbus_message_new_from_message, fix it up to copy
	all the message fields, add test case

	* bus/dispatch.c (bus_dispatch_test): add some more test code,
	not quite passing yet
parent f468907f
2003-03-14 Havoc Pennington <hp@redhat.com>
* dbus/dbus-memory.c: add a "detect buffer overwrites on free"
cheesy hack
* dbus/dbus-transport-debug.c: rework this a good bit to be
less complicated. hopefully still works.
* dbus/dbus-server-debug.c (handle_new_client): remove timeout
manually
* glib/dbus-gmain.c (timeout_handler): don't remove timeout
after running it
* dbus/dbus-message.c (dbus_message_copy): rename from
dbus_message_new_from_message, fix it up to copy
all the message fields, add test case
* bus/dispatch.c (bus_dispatch_test): add some more test code,
not quite passing yet
2003-03-14 Havoc Pennington <hp@pobox.com>
* bus/loop.c (bus_loop_iterate): add this so we can "run loop
......
......@@ -46,7 +46,7 @@ server_watch_callback (DBusWatch *watch,
{
BusContext *context = data;
dbus_server_handle_watch (context->server, watch, condition);
dbus_server_handle_watch (context->server, watch, condition);
}
static dbus_bool_t
......@@ -64,6 +64,7 @@ remove_server_watch (DBusWatch *watch,
bus_loop_remove_watch (watch, server_watch_callback, context);
}
static void
server_timeout_callback (DBusTimeout *timeout,
void *data)
......@@ -95,7 +96,7 @@ new_connection_callback (DBusServer *server,
if (!bus_connections_setup_connection (context->connections, new_connection))
_dbus_verbose ("No memory to setup new connection\n");
/* on OOM, we won't have ref'd the connection so it will die */
/* on OOM, we won't have ref'd the connection so it will die. */
}
BusContext*
......
......@@ -143,7 +143,8 @@ connection_watch_callback (DBusWatch *watch,
dbus_connection_handle_watch (connection, watch, condition);
while (dbus_connection_dispatch_message (connection));
while (dbus_connection_dispatch_message (connection))
;
dbus_connection_unref (connection);
}
......@@ -166,7 +167,15 @@ static void
connection_timeout_callback (DBusTimeout *timeout,
void *data)
{
DBusConnection *connection = data;
dbus_connection_ref (connection);
dbus_timeout_handle (timeout);
while (dbus_connection_dispatch_message (connection))
;
dbus_connection_unref (connection);
}
static dbus_bool_t
......
......@@ -28,6 +28,7 @@
#include "utils.h"
#include "bus.h"
#include "test.h"
#include "loop.h"
#include <dbus/dbus-internals.h>
#include <string.h>
......@@ -172,12 +173,15 @@ bus_dispatch (DBusConnection *connection,
_dbus_assert (message_name != NULL); /* DBusMessageLoader is supposed to check this */
_dbus_verbose ("DISPATCH: %s to %s\n",
message_name, service_name ? service_name : "peer");
/* If service_name is NULL, this is a message to the bus daemon, not intended
* to actually go "on the bus"; e.g. a peer-to-peer ping. Handle these
* immediately, especially disconnection messages.
*/
if (service_name == NULL)
{
{
if (strcmp (message_name, DBUS_MESSAGE_LOCAL_DISCONNECT) == 0)
bus_connection_disconnected (connection);
......@@ -374,12 +378,15 @@ bus_dispatch_remove_connection (DBusConnection *connection)
#ifdef DBUS_BUILD_TESTS
static void
run_test_bus (BusContext *context)
flush_bus (BusContext *context)
{
while (bus_loop_iterate (FALSE))
;
}
/* returns TRUE if the correct thing happens,
* but the correct thing may include OOM errors.
*/
static dbus_bool_t
check_hello_message (BusContext *context,
DBusConnection *connection)
......@@ -391,11 +398,28 @@ check_hello_message (BusContext *context,
DBUS_MESSAGE_HELLO);
if (message == NULL)
_dbus_assert_not_reached ("no memory");
return TRUE;
if (!dbus_connection_send (connection, message, &serial))
_dbus_assert_not_reached ("no memory");
return TRUE;
dbus_message_unref (message);
flush_bus (context);
message = dbus_connection_pop_message (connection);
if (message == NULL)
{
_dbus_warn ("Did not receive a reply to %s %d on %p\n",
DBUS_MESSAGE_HELLO, serial, connection);
return FALSE;
}
_dbus_verbose ("Received %s on %p\n",
dbus_message_get_name (message), connection);
dbus_message_unref (message);
return TRUE;
}
......@@ -410,8 +434,6 @@ bus_dispatch_test (const DBusString *test_data_dir)
DBusConnection *baz;
DBusResultCode result;
return TRUE; /* FIXME */
dbus_error_init (&error);
context = bus_context_new ("debug:name=test-server",
activation_dirs,
......@@ -431,7 +453,12 @@ bus_dispatch_test (const DBusString *test_data_dir)
if (baz == NULL)
_dbus_assert_not_reached ("could not alloc connection");
if (!check_hello_message (context, foo))
_dbus_assert_not_reached ("hello message failed");
if (!check_hello_message (context, bar))
_dbus_assert_not_reached ("hello message failed");
if (!check_hello_message (context, baz))
_dbus_assert_not_reached ("hello message failed");
return TRUE;
}
......
......@@ -262,8 +262,8 @@ bus_loop_remove_timeout (DBusTimeout *timeout,
timeout, function, data);
}
/* Returns TRUE if we dispatch any callbacks, which is just used in
* test code as a debug hack
/* Returns TRUE if we have any timeouts or ready file descriptors,
* which is just used in test code as a debug hack
*/
dbus_bool_t
......@@ -283,7 +283,12 @@ bus_loop_iterate (dbus_bool_t block)
fds = NULL;
watches_for_fds = NULL;
#if 0
_dbus_verbose (" iterate %d timeouts %d watches\n",
timeout_count, watch_count);
#endif
if (callbacks == NULL)
{
bus_loop_quit ();
......@@ -343,7 +348,9 @@ bus_loop_iterate (dbus_bool_t block)
{
unsigned long tv_sec;
unsigned long tv_usec;
retval = TRUE;
_dbus_get_current_time (&tv_sec, &tv_usec);
link = _dbus_list_get_first_link (&callbacks);
......@@ -445,16 +452,23 @@ bus_loop_iterate (dbus_bool_t block)
(tv_sec - tcb->last_tv_sec) * 1000 +
(tv_usec - tcb->last_tv_usec) / 1000;
#if 0
_dbus_verbose (" interval = %lu elapsed = %lu\n",
interval, elapsed);
#endif
if (interval <= elapsed)
{
/* Save last callback time and fire this timeout */
tcb->last_tv_sec = tv_sec;
tcb->last_tv_usec = tv_usec;
#if 0
_dbus_verbose (" invoking timeout\n");
#endif
(* tcb->function) (tcb->timeout,
cb->data);
retval = TRUE;
}
}
......@@ -504,6 +518,7 @@ bus_loop_iterate (dbus_bool_t block)
(* wcb->function) (wcb->watch,
condition,
((Callback*)wcb)->data);
retval = TRUE;
}
}
......
......@@ -53,10 +53,14 @@ main (int argc, char **argv)
if (!bus_dispatch_test (&test_data_dir))
die ("dispatch");
printf ("Success\n");
return 0;
#else /* DBUS_BUILD_TESTS */
printf ("Not compiled with test support\n");
return 0;
#endif
}
......@@ -330,13 +330,13 @@ echo "
"
if test x$enable_tests = xyes; then
echo "NOTE: building with unit tests increases the size of the installed library"
echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure"
fi
if test x$enable_gcov = xyes; then
echo "NOTE: building with coverage profiling is definitely for developers only"
fi
if test x$enable_verbose_mode = xyes; then
echo "NOTE: building with verbose mode increases library size, but is probably a good idea anyway."
echo "NOTE: building with verbose mode increases library size and may slightly increase security risk, but aids debugging."
fi
if test x$enable_asserts = xyes; then
echo "NOTE: building with assertions increases library size, but is probably a good idea anyway."
......
......@@ -207,8 +207,9 @@ _dbus_connection_queue_received_message (DBusConnection *connection,
_dbus_connection_wakeup_mainloop (connection);
_dbus_assert (dbus_message_get_name (message) != NULL);
_dbus_verbose ("Incoming message %p (%s) added to queue, %d incoming\n",
_dbus_verbose ("Message %p (%s) added to incoming queue %p, %d incoming\n",
message, dbus_message_get_name (message),
connection,
connection->n_incoming);
return TRUE;
......@@ -234,8 +235,8 @@ _dbus_connection_queue_synthesized_message_link (DBusConnection *connection,
_dbus_connection_wakeup_mainloop (connection);
_dbus_verbose ("Incoming synthesized message %p added to queue, %d incoming\n",
link->data, connection->n_incoming);
_dbus_verbose ("Synthesized message %p added to incoming queue %p, %d incoming\n",
link->data, connection, connection->n_incoming);
}
......@@ -283,8 +284,8 @@ _dbus_connection_message_sent (DBusConnection *connection,
connection->n_outgoing -= 1;
_dbus_verbose ("Message %p removed from outgoing queue, %d left to send\n",
message, connection->n_outgoing);
_dbus_verbose ("Message %p removed from outgoing queue %p, %d left to send\n",
message, connection, connection->n_outgoing);
if (connection->n_outgoing == 0)
_dbus_transport_messages_pending (connection->transport,
......@@ -334,7 +335,7 @@ _dbus_connection_remove_watch (DBusConnection *connection,
* available. Otherwise records the timeout to be added when said
* function is available. Also re-adds the timeout if the
* DBusAddTimeoutFunction changes. May fail due to lack of memory.
* The timeout will fire only one time.
* The timeout will fire repeatedly until removed.
*
* @param connection the connection.
* @param timeout the timeout to add.
......@@ -1035,9 +1036,10 @@ dbus_connection_send_preallocated (DBusConnection *connection,
dbus_message_ref (message);
connection->n_outgoing += 1;
_dbus_verbose ("Message %p (%s) added to outgoing queue, %d pending to send\n",
_dbus_verbose ("Message %p (%s) added to outgoing queue %p, %d pending to send\n",
message,
dbus_message_get_name (message),
connection,
connection->n_outgoing);
if (dbus_message_get_serial (message) == -1)
......@@ -1558,8 +1560,8 @@ _dbus_connection_pop_message_unlocked (DBusConnection *connection)
message = _dbus_list_pop_first (&connection->incoming_messages);
connection->n_incoming -= 1;
_dbus_verbose ("Incoming message %p removed from queue, %d incoming\n",
message, connection->n_incoming);
_dbus_verbose ("Message %p removed from incoming queue %p, %d incoming\n",
message, connection, connection->n_incoming);
return message;
}
......@@ -1859,11 +1861,10 @@ dbus_connection_set_watch_functions (DBusConnection *connection,
* g_timeout_add.
*
* The DBusTimeout can be queried for the timer interval using
* dbus_timeout_get_interval.
*
* Once a timeout occurs, dbus_timeout_handle should be called to invoke
* the timeout's callback, and the timeout should be automatically
* removed. i.e. timeouts are one-shot.
* dbus_timeout_get_interval(). dbus_timeout_handle() should
* be called repeatedly, each time the interval elapses, starting
* after it has elapsed once. The timeout stops firing when
* it is removed with the given remove_function.
*
* @param connection the connection.
* @param add_function function to add a timeout.
......
......@@ -76,6 +76,13 @@
static dbus_bool_t inited = FALSE;
static int fail_counts = -1;
static size_t fail_size = 0;
static dbus_bool_t guards = FALSE;
#define GUARD_VALUE 0xdeadbeef
#define GUARD_INFO_SIZE 8
#define GUARD_START_PAD 16
#define GUARD_END_PAD 16
#define GUARD_START_OFFSET (GUARD_START_PAD + GUARD_INFO_SIZE)
#define GUARD_EXTRA_SIZE (GUARD_START_OFFSET + GUARD_END_PAD)
#endif
#ifdef DBUS_BUILD_TESTS
......@@ -92,10 +99,133 @@ initialize_malloc_debug (void)
if (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN") != NULL)
fail_size = atoi (_dbus_getenv ("DBUS_MALLOC_FAIL_GREATER_THAN"));
if (_dbus_getenv ("DBUS_MALLOC_GUARDS") != NULL)
guards = TRUE;
inited = TRUE;
}
}
typedef enum
{
SOURCE_UNKNOWN,
SOURCE_MALLOC,
SOURCE_REALLOC,
SOURCE_MALLOC_ZERO,
SOURCE_REALLOC_NULL
} BlockSource;
static const char*
source_string (BlockSource source)
{
switch (source)
{
case SOURCE_UNKNOWN:
return "unknown";
case SOURCE_MALLOC:
return "malloc";
case SOURCE_REALLOC:
return "realloc";
case SOURCE_MALLOC_ZERO:
return "malloc0";
case SOURCE_REALLOC_NULL:
return "realloc(NULL)";
}
_dbus_assert_not_reached ("Invalid malloc block source ID");
return "invalid!";
}
static void
check_guards (void *free_block)
{
if (free_block != NULL)
{
unsigned char *block = ((unsigned char*)free_block) - GUARD_START_OFFSET;
size_t requested_bytes = *(dbus_uint32_t*)block;
BlockSource source = *(dbus_uint32_t*)(block + 4);
unsigned int i;
dbus_bool_t failed;
failed = FALSE;
#if 0
_dbus_verbose ("Checking %d bytes request from source %s\n",
requested_bytes, source_string (source));
#endif
i = GUARD_INFO_SIZE;
while (i < GUARD_START_OFFSET)
{
dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
if (value != GUARD_VALUE)
{
_dbus_warn ("Block of %u bytes from %s had start guard value 0x%x at %d expected 0x%x\n",
requested_bytes, source_string (source),
value, i, GUARD_VALUE);
failed = TRUE;
}
i += 4;
}
i = GUARD_START_OFFSET + requested_bytes;
while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
{
dbus_uint32_t value = *(dbus_uint32_t*) &block[i];
if (value != GUARD_VALUE)
{
_dbus_warn ("Block of %u bytes from %s had end guard value 0x%x at %d expected 0x%x\n",
requested_bytes, source_string (source),
value, i, GUARD_VALUE);
failed = TRUE;
}
i += 4;
}
if (failed)
_dbus_assert_not_reached ("guard value corruption");
}
}
static void*
set_guards (void *real_block,
size_t requested_bytes,
BlockSource source)
{
unsigned char *block = real_block;
unsigned int i;
if (block == NULL)
return NULL;
_dbus_assert (GUARD_START_OFFSET + GUARD_END_PAD == GUARD_EXTRA_SIZE);
*((dbus_uint32_t*)block) = requested_bytes;
*((dbus_uint32_t*)(block + 4)) = source;
i = GUARD_INFO_SIZE;
while (i < GUARD_START_OFFSET)
{
(*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
i += 4;
}
i = GUARD_START_OFFSET + requested_bytes;
while (i < (GUARD_START_OFFSET + requested_bytes + GUARD_END_PAD))
{
(*(dbus_uint32_t*) &block[i]) = GUARD_VALUE;
i += 4;
}
check_guards (block + GUARD_START_OFFSET);
return block + GUARD_START_OFFSET;
}
#endif
/**
......@@ -127,6 +257,13 @@ dbus_malloc (size_t bytes)
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
{
void *block;
block = malloc (bytes + GUARD_EXTRA_SIZE);
return set_guards (block, bytes, SOURCE_MALLOC);
}
#endif
else
return malloc (bytes);
......@@ -161,6 +298,13 @@ dbus_malloc0 (size_t bytes)
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
{
void *block;
block = calloc (bytes + GUARD_EXTRA_SIZE, 1);
return set_guards (block, bytes, SOURCE_MALLOC_ZERO);
}
#endif
else
return calloc (bytes, 1);
......@@ -200,6 +344,30 @@ dbus_realloc (void *memory,
#if DBUS_BUILD_TESTS
else if (fail_size != 0 && bytes > fail_size)
return NULL;
else if (guards)
{
if (memory)
{
void *block;
check_guards (memory);
block = realloc (((unsigned char*)memory) - GUARD_START_OFFSET,
bytes + GUARD_EXTRA_SIZE);
/* old guards shouldn't have moved */
check_guards (((unsigned char*)block) + GUARD_START_OFFSET);
return set_guards (block, bytes, SOURCE_REALLOC);
}
else
{
void *block;
block = malloc (bytes + GUARD_EXTRA_SIZE);
return set_guards (block, bytes, SOURCE_REALLOC_NULL);
}
}
#endif
else
{
......@@ -216,6 +384,16 @@ dbus_realloc (void *memory,
void
dbus_free (void *memory)
{
#ifdef DBUS_BUILD_TESTS
if (guards)
{
check_guards (memory);
if (memory)
free (((unsigned char*)memory) - GUARD_START_OFFSET);
return;
}
#endif
if (memory) /* we guarantee it's safe to free (NULL) */
free (memory);
}
......
......@@ -897,7 +897,7 @@ dbus_message_new_error_reply (DBusMessage *original_message,
* @returns the new message.
*/
DBusMessage *
dbus_message_new_from_message (const DBusMessage *message)
dbus_message_copy (const DBusMessage *message)
{
DBusMessage *retval;
int i;
......@@ -908,7 +908,11 @@ dbus_message_new_from_message (const DBusMessage *message)
retval->refcount = 1;
retval->byte_order = message->byte_order;
retval->client_serial = message->client_serial;
retval->reply_serial = message->reply_serial;
retval->header_padding = message->header_padding;
retval->locked = FALSE;
if (!_dbus_string_init (&retval->header, _DBUS_INT_MAX))
{
dbus_free (retval);
......@@ -3590,6 +3594,37 @@ dbus_internal_do_not_use_foreach_message_file (const char *test_d
return retval;
}
static void
verify_test_message (DBusMessage *message)
{
dbus_int32_t our_int;
char *our_str;
double our_double;
dbus_bool_t our_bool;
if (!dbus_message_get_args (message, NULL,
DBUS_TYPE_INT32, &our_int,
DBUS_TYPE_STRING, &our_str,
DBUS_TYPE_DOUBLE, &our_double,
DBUS_TYPE_BOOLEAN, &our_bool,
0))
_dbus_assert_not_reached ("Could not get arguments");
if (our_int != -0x12345678)
_dbus_assert_not_reached ("integers differ!");
if (our_double != 3.14159)
_dbus_assert_not_reached ("doubles differ!");
if (strcmp (our_str, "Test string") != 0)
_dbus_assert_not_reached ("strings differ!");
if (!our_bool)
_dbus_assert_not_reached ("booleans differ");
dbus_free (our_str);
}
/**
* @ingroup DBusMessageInternals
* Unit test for DBusMessage.
......@@ -3603,10 +3638,9 @@ _dbus_message_test (const char *test_data_dir)
DBusMessageLoader *loader;
int i;
const char *data;
dbus_int32_t our_int;
char *our_str;
double our_double;
dbus_bool_t our_bool;
DBusMessage *copy;
const char *name1;
const char *name2;
/* Test the vararg functions */
message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
......@@ -3622,28 +3656,29 @@ _dbus_message_test (const char *test_data_dir)
_dbus_verbose_bytes_of_string (&message->body, 0,
_dbus_string_get_length (&message->body));
if (!dbus_message_get_args (message, NULL,
DBUS_TYPE_INT32, &our_int,
DBUS_TYPE_STRING, &our_str,
DBUS_TYPE_DOUBLE, &our_double,
DBUS_TYPE_BOOLEAN, &our_bool,
0))
_dbus_assert_not_reached ("Could not get arguments");
verify_test_message (message);
if (our_int != -0x12345678)
_dbus_assert_not_reached ("integers differ!");
copy = dbus_message_copy (message);
_dbus_assert (message->client_serial == copy->client_serial);
_dbus_assert (message->reply_serial == copy->reply_serial);
_dbus_assert (message->header_padding == copy->header_padding);
_dbus_assert (_dbus_string_get_length (&message->header) ==
_dbus_string_get_length (&copy->header));
if (our_double != 3.14159)
_dbus_assert_not_reached ("doubles differ!");
_dbus_assert (_dbus_string_get_length (&message->body) ==
_dbus_string_get_length (&copy->body));
if (strcmp (our_str, "Test string") != 0)
_dbus_assert_not_reached ("strings differ!");
verify_test_message (copy);
if (!our_bool)
_dbus_assert_not_reached ("booleans differ");
name1 = dbus_message_get_name (message);
name2 = dbus_message_get_name (copy);
_dbus_assert (strcmp (name1, name2) == 0);
dbus_free (our_str);
dbus_message_unref (message);
dbus_message_unref (copy);
message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
_dbus_message_set_serial (message, 1);
......
......@@ -43,7 +43,7 @@ DBusMessage* dbus_message_new_reply (DBusMessage *original_message)
DBusMessage* dbus_message_new_error_reply (DBusMessage *original_message,
const char *error_name,
const char *error_message);
DBusMessage *dbus_message_new_from_message (const DBusMessage *message);
DBusMessage *dbus_message_copy (const DBusMessage *message);
void dbus_message_ref (DBusMessage *message);
void dbus_message_unref (DBusMessage *message);
......
......@@ -181,7 +181,7 @@ typedef struct
{
DBusServer *server;
DBusTransport *transport;
DBusTimeout *timeout;
} ServerAndTransport;
static void
......@@ -190,12 +190,13 @@ handle_new_client (void *data)
ServerAndTransport *st = data;
DBusTransport *transport;
DBusConnection *connection;
_dbus_verbose (" new debug client transport %p connecting to server\n",
st->transport);
transport = _dbus_transport_debug_server_new (st->transport);
if (transport == NULL)
{
return;
}
return;
connection = _dbus_connection_new_for_transport (transport);
_dbus_transport_unref (transport);
......@@ -214,9 +215,14 @@ handle_new_client (void *data)
st->server->new_connection_data);
dbus_server_unref (st->server);
}
_dbus_server_remove_timeout (st->server, st->timeout);
/* If no one grabbed a reference, the connection will die. */
dbus_connection_unref (connection);
/* killing timeout frees both "st" and "timeout" */
_dbus_timeout_unref (st->timeout);
}
/**
......@@ -231,7 +237,6 @@ dbus_bool_t
_dbus_server_debug_accept_transport (DBusServer *server,
DBusTransport *transport)
{
DBusTimeout *timeout = NULL;
ServerAndTransport *st = NULL;
st = dbus_new (ServerAndTransport, 1);
......@@ -241,22 +246,21 @@ _dbus_server_debug_accept_transport (DBusServer *server,
st->transport = transport;
st->server = server;
timeout = _dbus_timeout_new (DEFAULT_INTERVAL, handle_new_client, st, dbus_free);
st->timeout = _dbus_timeout_new (DEFAULT_INTERVAL, handle_new_client, st,
dbus_free);