/* -*- mode: C; c-file-style: "gnu" -*- */ /* dbus-message-factory.c Generator of valid and invalid message data for test suite * * Copyright (C) 2005 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #ifdef DBUS_BUILD_TESTS #include "dbus-message-factory.h" #include "dbus-message-private.h" #include "dbus-test.h" #include typedef enum { CHANGE_TYPE_ADJUST, CHANGE_TYPE_ABSOLUTE } ChangeType; #define BYTE_ORDER_OFFSET 0 #define TYPE_OFFSET 1 #define BODY_LENGTH_OFFSET 4 #define FIELDS_ARRAY_LENGTH_OFFSET 12 static void iter_recurse (DBusMessageDataIter *iter) { iter->depth += 1; _dbus_assert (iter->depth < _DBUS_MESSAGE_DATA_MAX_NESTING); _dbus_assert (iter->sequence_nos[iter->depth] >= 0); } static int iter_get_sequence (DBusMessageDataIter *iter) { _dbus_assert (iter->sequence_nos[iter->depth] >= 0); return iter->sequence_nos[iter->depth]; } static void iter_set_sequence (DBusMessageDataIter *iter, int sequence) { _dbus_assert (sequence >= 0); iter->sequence_nos[iter->depth] = sequence; } static void iter_unrecurse (DBusMessageDataIter *iter) { iter->depth -= 1; _dbus_assert (iter->depth >= 0); } static void iter_next (DBusMessageDataIter *iter) { iter->sequence_nos[iter->depth] += 1; } static dbus_bool_t iter_first_in_series (DBusMessageDataIter *iter) { int i; i = iter->depth; while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) { if (iter->sequence_nos[i] != 0) return FALSE; ++i; } return TRUE; } typedef dbus_bool_t (* DBusInnerGeneratorFunc) (DBusMessageDataIter *iter, DBusMessage **message_p); typedef dbus_bool_t (* DBusMessageGeneratorFunc) (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity); static void set_reply_serial (DBusMessage *message) { if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_reply_serial (message, 100)) _dbus_assert_not_reached ("oom"); } static dbus_bool_t generate_trivial_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; switch (iter_get_sequence (iter)) { case 0: message = dbus_message_new_method_call ("org.freedesktop.TextEditor", "/foo/bar", "org.freedesktop.DocumentFactory", "Create"); break; case 1: message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); set_reply_serial (message); break; case 2: message = dbus_message_new_signal ("/foo/bar", "org.freedesktop.DocumentFactory", "Created"); break; case 3: message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (!dbus_message_set_error_name (message, "org.freedesktop.TestErrorName")) _dbus_assert_not_reached ("oom"); { DBusMessageIter iter; const char *v_STRING = "This is an error"; dbus_message_iter_init_append (message, &iter); if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &v_STRING)) _dbus_assert_not_reached ("oom"); } set_reply_serial (message); break; default: return FALSE; } if (message == NULL) _dbus_assert_not_reached ("oom"); *message_p = message; return TRUE; } static dbus_bool_t generate_many_bodies_inner (DBusMessageDataIter *iter, DBusMessage **message_p) { DBusMessage *message; DBusString signature; DBusString body; /* Keeping this small makes things go faster */ message = dbus_message_new_method_call ("o.z.F", "/", "o.z.B", "Nah"); if (message == NULL) _dbus_assert_not_reached ("oom"); set_reply_serial (message); if (!_dbus_string_init (&signature) || !_dbus_string_init (&body)) _dbus_assert_not_reached ("oom"); if (dbus_internal_do_not_use_generate_bodies (iter_get_sequence (iter), message->byte_order, &signature, &body)) { const char *v_SIGNATURE; v_SIGNATURE = _dbus_string_get_const_data (&signature); if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_SIGNATURE)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_move (&body, 0, &message->body, 0)) _dbus_assert_not_reached ("oom"); _dbus_marshal_set_uint32 (&message->header.data, BODY_LENGTH_OFFSET, _dbus_string_get_length (&message->body), message->byte_order); *message_p = message; } else { dbus_message_unref (message); *message_p = NULL; } _dbus_string_free (&signature); _dbus_string_free (&body); return *message_p != NULL; } static void generate_from_message (DBusString *data, DBusValidity *expected_validity, DBusMessage *message) { _dbus_message_set_serial (message, 1); _dbus_message_lock (message); *expected_validity = DBUS_VALID; /* move for efficiency, since we'll nuke the message anyway */ if (!_dbus_string_move (&message->header.data, 0, data, 0)) _dbus_assert_not_reached ("oom"); if (!_dbus_string_copy (&message->body, 0, data, _dbus_string_get_length (data))) _dbus_assert_not_reached ("oom"); } static dbus_bool_t generate_outer (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity, DBusInnerGeneratorFunc func) { DBusMessage *message; message = NULL; if (!(*func)(iter, &message)) return FALSE; iter_next (iter); _dbus_assert (message != NULL); generate_from_message (data, expected_validity, message); dbus_message_unref (message); return TRUE; } static dbus_bool_t generate_trivial (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { return generate_outer (iter, data, expected_validity, generate_trivial_inner); } static dbus_bool_t generate_many_bodies (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { return generate_outer (iter, data, expected_validity, generate_many_bodies_inner); } static DBusMessage* simple_method_call (void) { DBusMessage *message; /* Keeping this small makes stuff go faster */ message = dbus_message_new_method_call ("o.b.Q", "/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; } static DBusMessage* simple_signal (void) { DBusMessage *message; message = dbus_message_new_signal ("/f/b", "o.b.Z", "Fro"); if (message == NULL) _dbus_assert_not_reached ("oom"); return message; } static DBusMessage* simple_method_return (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); if (message == NULL) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; } static DBusMessage* simple_error (void) { DBusMessage *message; message = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); if (message == NULL) _dbus_assert_not_reached ("oom"); if (!dbus_message_set_error_name (message, "foo.bar")) _dbus_assert_not_reached ("oom"); set_reply_serial (message); return message; } static dbus_bool_t generate_special (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int item_seq; DBusMessage *message; int pos; dbus_int32_t v_INT32; _dbus_assert (_dbus_string_get_length (data) == 0); message = NULL; pos = -1; v_INT32 = 42; item_seq = iter_get_sequence (iter); if (item_seq == 0) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); /* set an invalid typecode */ _dbus_string_set_byte (data, pos + 1, '$'); *expected_validity = DBUS_INVALID_UNKNOWN_TYPECODE; } else if (item_seq == 1) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH+2]; const char *v_STRING; int i; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) { long_sig[i] = DBUS_TYPE_ARRAY; ++i; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION; } else if (item_seq == 2) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2+4]; const char *v_STRING; int i; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH + 1)) { long_sig[i] = DBUS_STRUCT_BEGIN_CHAR; ++i; } long_sig[i] = DBUS_TYPE_INT32; ++i; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*2 + 3)) { long_sig[i] = DBUS_STRUCT_END_CHAR; ++i; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION; } else if (item_seq == 3) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); *expected_validity = DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED; } else if (item_seq == 4) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_END_CHAR); *expected_validity = DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED; } else if (item_seq == 5) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_STRUCT_BEGIN_CHAR); _dbus_string_set_byte (data, pos + 2, DBUS_STRUCT_END_CHAR); *expected_validity = DBUS_INVALID_STRUCT_HAS_NO_FIELDS; } else if (item_seq == 6) { message = simple_method_call (); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, TYPE_OFFSET, DBUS_MESSAGE_TYPE_INVALID); *expected_validity = DBUS_INVALID_BAD_MESSAGE_TYPE; } else if (item_seq == 7) { /* Messages of unknown type are considered valid */ message = simple_method_call (); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, TYPE_OFFSET, 100); *expected_validity = DBUS_VALID; } else if (item_seq == 8) { message = simple_method_call (); generate_from_message (data, expected_validity, message); _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, message->byte_order); _dbus_marshal_set_uint32 (data, FIELDS_ARRAY_LENGTH_OFFSET, DBUS_MAXIMUM_MESSAGE_LENGTH / 2 + 4, message->byte_order); *expected_validity = DBUS_INVALID_MESSAGE_TOO_LONG; } else if (item_seq == 9) { const char *v_STRING = "not a valid bus name"; message = simple_method_call (); if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING, &v_STRING)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_BAD_SENDER; } else if (item_seq == 10) { message = simple_method_call (); if (!dbus_message_set_interface (message, DBUS_INTERFACE_LOCAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_USES_LOCAL_INTERFACE; } else if (item_seq == 11) { message = simple_method_call (); if (!dbus_message_set_path (message, DBUS_PATH_LOCAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_USES_LOCAL_PATH; } else if (item_seq == 12) { /* Method calls don't have to have interface */ message = simple_method_call (); if (!dbus_message_set_interface (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_VALID; } else if (item_seq == 13) { /* Signals require an interface */ message = simple_signal (); if (!dbus_message_set_interface (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_INTERFACE; } else if (item_seq == 14) { message = simple_method_return (); if (!_dbus_header_delete_field (&message->header, DBUS_HEADER_FIELD_REPLY_SERIAL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_REPLY_SERIAL; } else if (item_seq == 15) { message = simple_error (); if (!dbus_message_set_error_name (message, NULL)) _dbus_assert_not_reached ("oom"); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_MISSING_ERROR_NAME; } else if (item_seq == 16) { char long_sig[DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*4+8]; const char *v_STRING; int i; int n_begins; message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); i = 0; while (i <= (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH*3 + 3)) { long_sig[i] = DBUS_TYPE_ARRAY; ++i; long_sig[i] = DBUS_DICT_ENTRY_BEGIN_CHAR; ++i; long_sig[i] = DBUS_TYPE_INT32; ++i; } n_begins = i / 3; long_sig[i] = DBUS_TYPE_INT32; ++i; while (n_begins > 0) { long_sig[i] = DBUS_DICT_ENTRY_END_CHAR; ++i; n_begins -= 1; } long_sig[i] = DBUS_TYPE_INVALID; v_STRING = long_sig; if (!_dbus_header_set_field_basic (&message->header, DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE, &v_STRING)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); *expected_validity = DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION; } else if (item_seq == 17) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED; } else if (item_seq == 18) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_DICT_ENTRY_END_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED; } else if (item_seq == 19) { message = simple_method_call (); if (!dbus_message_append_args (message, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INT32, &v_INT32, DBUS_TYPE_INVALID)) _dbus_assert_not_reached ("oom"); _dbus_header_get_field_raw (&message->header, DBUS_HEADER_FIELD_SIGNATURE, NULL, &pos); generate_from_message (data, expected_validity, message); _dbus_string_set_byte (data, pos + 1, DBUS_TYPE_ARRAY); _dbus_string_set_byte (data, pos + 2, DBUS_DICT_ENTRY_BEGIN_CHAR); _dbus_string_set_byte (data, pos + 3, DBUS_DICT_ENTRY_END_CHAR); *expected_validity = DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS; } else { return FALSE; } if (message) dbus_message_unref (message); iter_next (iter); return TRUE; } static dbus_bool_t generate_wrong_length (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 }; int adjust; int len_seq; restart: len_seq = iter_get_sequence (iter); if (len_seq == _DBUS_N_ELEMENTS (lengths)) return FALSE; _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths)); iter_recurse (iter); if (!generate_many_bodies (iter, data, expected_validity)) { iter_set_sequence (iter, 0); /* reset to first body */ iter_unrecurse (iter); iter_next (iter); /* next length adjustment */ goto restart; } iter_unrecurse (iter); adjust = lengths[len_seq]; if (adjust < 0) { if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE) _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE); else _dbus_string_shorten (data, - adjust); *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON; } else { if (!_dbus_string_lengthen (data, adjust)) _dbus_assert_not_reached ("oom"); *expected_validity = DBUS_INVALID_TOO_MUCH_DATA; } /* Fixup lengths */ { int old_body_len; int new_body_len; int byte_order; _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); old_body_len = _dbus_marshal_read_uint32 (data, BODY_LENGTH_OFFSET, byte_order, NULL); _dbus_assert (old_body_len < _dbus_string_get_length (data)); new_body_len = old_body_len + adjust; if (new_body_len < 0) { new_body_len = 0; /* we just munged the header, and aren't sure how */ *expected_validity = DBUS_VALIDITY_UNKNOWN; } _dbus_verbose ("changing body len from %u to %u by adjust %d\n", old_body_len, new_body_len, adjust); _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET, new_body_len, byte_order); } return TRUE; } static dbus_bool_t generate_byte_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int byte_seq; int v_BYTE; /* This is a little convoluted to make the bodies the * outer loop and each byte of each body the inner * loop */ restart: if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; iter_recurse (iter); byte_seq = iter_get_sequence (iter); iter_next (iter); iter_unrecurse (iter); if (byte_seq == _dbus_string_get_length (data)) { _dbus_string_set_length (data, 0); /* reset byte count */ iter_recurse (iter); iter_set_sequence (iter, 0); iter_unrecurse (iter); goto restart; } else { /* Undo the "next" in generate_many_bodies */ iter_set_sequence (iter, iter_get_sequence (iter) - 1); } _dbus_assert (byte_seq < _dbus_string_get_length (data)); v_BYTE = _dbus_string_get_byte (data, byte_seq); v_BYTE += byte_seq; /* arbitrary but deterministic change to the byte */ _dbus_string_set_byte (data, byte_seq, v_BYTE); *expected_validity = DBUS_VALIDITY_UNKNOWN; return TRUE; } static dbus_bool_t find_next_typecode (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int body_seq; int byte_seq; int base_depth; base_depth = iter->depth; restart: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); body_seq = iter_get_sequence (iter); if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; /* Undo the "next" in generate_many_bodies */ iter_set_sequence (iter, body_seq); iter_recurse (iter); while (TRUE) { _dbus_assert (iter->depth == (base_depth + 1)); byte_seq = iter_get_sequence (iter); _dbus_assert (byte_seq <= _dbus_string_get_length (data)); if (byte_seq == _dbus_string_get_length (data)) { /* reset byte count */ iter_set_sequence (iter, 0); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); iter_next (iter); /* go to the next body */ goto restart; } _dbus_assert (byte_seq < _dbus_string_get_length (data)); if (_dbus_type_is_valid (_dbus_string_get_byte (data, byte_seq))) break; else iter_next (iter); } _dbus_assert (byte_seq == iter_get_sequence (iter)); _dbus_assert (byte_seq < _dbus_string_get_length (data)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); return TRUE; } static const int typecodes[] = { DBUS_TYPE_INVALID, DBUS_TYPE_BYTE, DBUS_TYPE_BOOLEAN, DBUS_TYPE_INT16, DBUS_TYPE_UINT16, DBUS_TYPE_INT32, DBUS_TYPE_UINT32, DBUS_TYPE_INT64, DBUS_TYPE_UINT64, DBUS_TYPE_DOUBLE, DBUS_TYPE_STRING, DBUS_TYPE_OBJECT_PATH, DBUS_TYPE_SIGNATURE, DBUS_TYPE_ARRAY, DBUS_TYPE_VARIANT, DBUS_STRUCT_BEGIN_CHAR, DBUS_STRUCT_END_CHAR, DBUS_DICT_ENTRY_BEGIN_CHAR, DBUS_DICT_ENTRY_END_CHAR, 255 /* random invalid typecode */ }; static dbus_bool_t generate_typecode_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int byte_seq; int typecode_seq; int base_depth; base_depth = iter->depth; restart: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); if (!find_next_typecode (iter, data, expected_validity)) return FALSE; iter_recurse (iter); byte_seq = iter_get_sequence (iter); _dbus_assert (byte_seq < _dbus_string_get_length (data)); iter_recurse (iter); typecode_seq = iter_get_sequence (iter); iter_next (iter); _dbus_assert (typecode_seq <= _DBUS_N_ELEMENTS (typecodes)); if (typecode_seq == _DBUS_N_ELEMENTS (typecodes)) { _dbus_assert (iter->depth == (base_depth + 2)); iter_set_sequence (iter, 0); /* reset typecode sequence */ iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_next (iter); /* go to the next byte_seq */ iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); goto restart; } _dbus_assert (iter->depth == (base_depth + 2)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); #if 0 printf ("Changing byte %d in message %d to %c\n", byte_seq, iter_get_sequence (iter), typecodes[typecode_seq]); #endif _dbus_string_set_byte (data, byte_seq, typecodes[typecode_seq]); *expected_validity = DBUS_VALIDITY_UNKNOWN; return TRUE; } typedef struct { ChangeType type; dbus_uint32_t value; /* cast to signed for adjusts */ } UIntChange; static const UIntChange uint32_changes[] = { { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -1 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -2 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) -3 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 1 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 2 }, { CHANGE_TYPE_ADJUST, (dbus_uint32_t) 3 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX }, { CHANGE_TYPE_ABSOLUTE, 0 }, { CHANGE_TYPE_ABSOLUTE, 1 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 1 }, { CHANGE_TYPE_ABSOLUTE, _DBUS_UINT32_MAX - 5 } }; static dbus_bool_t generate_uint32_changed (DBusMessageDataIter *iter, DBusString *data, DBusValidity *expected_validity) { int body_seq; int byte_seq; int change_seq; dbus_uint32_t v_UINT32; int byte_order; const UIntChange *change; int base_depth; /* Outer loop is each body, next loop is each change, * inner loop is each change location */ base_depth = iter->depth; next_body: _dbus_assert (iter->depth == (base_depth + 0)); _dbus_string_set_length (data, 0); body_seq = iter_get_sequence (iter); if (!generate_many_bodies (iter, data, expected_validity)) return FALSE; _dbus_assert (iter->depth == (base_depth + 0)); iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */ iter_recurse (iter); next_change: _dbus_assert (iter->depth == (base_depth + 1)); change_seq = iter_get_sequence (iter); if (change_seq == _DBUS_N_ELEMENTS (uint32_changes)) { /* Reset change count */ iter_set_sequence (iter, 0); iter_unrecurse (iter); iter_next (iter); goto next_body; } _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); byte_seq = iter_get_sequence (iter); /* skip 4 bytes at a time */ iter_next (iter); iter_next (iter); iter_next (iter); iter_next (iter); iter_unrecurse (iter); _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq); if (byte_seq >= (_dbus_string_get_length (data) - 4)) { /* reset byte count */ _dbus_assert (iter->depth == (base_depth + 1)); iter_recurse (iter); _dbus_assert (iter->depth == (base_depth + 2)); iter_set_sequence (iter, 0); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 1)); iter_next (iter); goto next_change; } _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4)); byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET); v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL); change = &uint32_changes[change_seq]; if (change->type == CHANGE_TYPE_ADJUST) { v_UINT32 += (int) change->value; } else { v_UINT32 = change->value; } #if 0 printf ("body %d change %d pos %d ", body_seq, change_seq, byte_seq); if (change->type == CHANGE_TYPE_ADJUST) printf ("adjust by %d", (int) change->value); else printf ("set to %u", change->value); printf (" \t%u -> %u\n", _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL), v_UINT32); #endif _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order); *expected_validity = DBUS_VALIDITY_UNKNOWN; _dbus_assert (iter->depth == (base_depth + 1)); iter_unrecurse (iter); _dbus_assert (iter->depth == (base_depth + 0)); return TRUE; } typedef struct { const char *name; DBusMessageGeneratorFunc func; } DBusMessageGenerator; static const DBusMessageGenerator generators[] = { { "trivial example of each message type", generate_trivial }, { "assorted arguments", generate_many_bodies }, { "assorted special cases", generate_special }, { "each uint32 modified", generate_uint32_changed }, { "wrong body lengths", generate_wrong_length }, { "each byte modified", generate_byte_changed }, #if 0 /* This is really expensive and doesn't add too much coverage */ { "change each typecode", generate_typecode_changed } #endif }; void _dbus_message_data_free (DBusMessageData *data) { _dbus_string_free (&data->data); } void _dbus_message_data_iter_init (DBusMessageDataIter *iter) { int i; iter->depth = 0; i = 0; while (i < _DBUS_MESSAGE_DATA_MAX_NESTING) { iter->sequence_nos[i] = 0; ++i; } iter->count = 0; } dbus_bool_t _dbus_message_data_iter_get_and_next (DBusMessageDataIter *iter, DBusMessageData *data) { DBusMessageGeneratorFunc func; int generator; restart: generator = iter_get_sequence (iter); if (generator == _DBUS_N_ELEMENTS (generators)) return FALSE; iter_recurse (iter); if (iter_first_in_series (iter)) { printf (" testing message loading: %s ", generators[generator].name); fflush (stdout); } func = generators[generator].func; if (!_dbus_string_init (&data->data)) _dbus_assert_not_reached ("oom"); if ((*func)(iter, &data->data, &data->expected_validity)) ; else { iter_set_sequence (iter, 0); iter_unrecurse (iter); iter_next (iter); /* next generator */ _dbus_string_free (&data->data); printf ("%d test loads cumulative\n", iter->count); goto restart; } iter_unrecurse (iter); iter->count += 1; return TRUE; } #endif /* DBUS_BUILD_TESTS */