2010-05-06 20:13:59 +02:00
/* GLib testing framework examples and tests
*
2010-05-10 14:07:28 +02:00
* Copyright ( C ) 2008 - 2010 Red Hat , Inc .
2010-05-06 20:13:59 +02:00
*
2022-05-18 10:20:07 +02:00
* SPDX - License - Identifier : LGPL - 2.1 - or - later
*
2010-05-06 20:13:59 +02:00
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2017-05-27 17:19:21 +02:00
* version 2.1 of the License , or ( at your option ) any later version .
2010-05-06 20:13:59 +02:00
*
* This library 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
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General
2014-01-23 12:58:29 +01:00
* Public License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2010-05-06 20:13:59 +02:00
*
* Author : David Zeuthen < davidz @ redhat . com >
*/
2010-08-04 20:38:51 +02:00
# include <locale.h>
2010-05-06 20:13:59 +02:00
# include <gio/gio.h>
# include <string.h>
2018-09-09 14:46:33 +02:00
# ifndef _MSC_VER
2010-05-06 20:13:59 +02:00
# include <unistd.h>
2018-09-09 14:46:33 +02:00
# endif
2010-05-06 20:13:59 +02:00
# include <dbus/dbus.h>
/* ---------------------------------------------------------------------------------------------------- */
static void
hexdump ( const guchar * str , gsize len )
{
const guchar * data = ( const guchar * ) str ;
guint n , m ;
for ( n = 0 ; n < len ; n + = 16 )
{
g_printerr ( " %04x: " , n ) ;
for ( m = n ; m < n + 16 ; m + + )
{
if ( m > n & & ( m % 4 ) = = 0 )
g_printerr ( " " ) ;
if ( m < len )
g_printerr ( " %02x " , data [ m ] ) ;
else
g_printerr ( " " ) ;
}
g_printerr ( " " ) ;
for ( m = n ; m < len & & m < n + 16 ; m + + )
g_printerr ( " %c " , g_ascii_isprint ( data [ m ] ) ? data [ m ] : ' . ' ) ;
g_printerr ( " \n " ) ;
}
}
/* ---------------------------------------------------------------------------------------------------- */
static gboolean
append_gv_to_dbus_iter ( DBusMessageIter * iter ,
GVariant * value ,
GError * * error )
{
const GVariantType * type ;
type = g_variant_get_type ( value ) ;
if ( g_variant_type_equal ( type , G_VARIANT_TYPE_BOOLEAN ) )
{
dbus_bool_t v = g_variant_get_boolean ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_BOOLEAN , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_BYTE ) )
{
guint8 v = g_variant_get_byte ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_BYTE , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_INT16 ) )
{
gint16 v = g_variant_get_int16 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_INT16 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_UINT16 ) )
{
guint16 v = g_variant_get_uint16 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_UINT16 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_INT32 ) )
{
gint32 v = g_variant_get_int32 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_INT32 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_UINT32 ) )
{
guint32 v = g_variant_get_uint32 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_UINT32 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_INT64 ) )
{
gint64 v = g_variant_get_int64 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_INT64 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_UINT64 ) )
{
guint64 v = g_variant_get_uint64 ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_UINT64 , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_DOUBLE ) )
{
gdouble v = g_variant_get_double ( value ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_DOUBLE , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_STRING ) )
{
const gchar * v = g_variant_get_string ( value , NULL ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_STRING , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_OBJECT_PATH ) )
{
const gchar * v = g_variant_get_string ( value , NULL ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_OBJECT_PATH , & v ) ;
}
else if ( g_variant_type_equal ( type , G_VARIANT_TYPE_SIGNATURE ) )
{
const gchar * v = g_variant_get_string ( value , NULL ) ;
dbus_message_iter_append_basic ( iter , DBUS_TYPE_SIGNATURE , & v ) ;
}
else if ( g_variant_type_is_variant ( type ) )
{
DBusMessageIter sub ;
GVariant * child ;
child = g_variant_get_child_value ( value , 0 ) ;
dbus_message_iter_open_container ( iter , DBUS_TYPE_VARIANT ,
g_variant_get_type_string ( child ) ,
& sub ) ;
if ( ! append_gv_to_dbus_iter ( & sub , child , error ) )
{
g_variant_unref ( child ) ;
goto fail ;
}
dbus_message_iter_close_container ( iter , & sub ) ;
g_variant_unref ( child ) ;
}
else if ( g_variant_type_is_array ( type ) )
{
DBusMessageIter dbus_iter ;
const gchar * type_string ;
GVariantIter gv_iter ;
GVariant * item ;
type_string = g_variant_get_type_string ( value ) ;
type_string + + ; /* skip the 'a' */
dbus_message_iter_open_container ( iter , DBUS_TYPE_ARRAY ,
type_string , & dbus_iter ) ;
g_variant_iter_init ( & gv_iter , value ) ;
while ( ( item = g_variant_iter_next_value ( & gv_iter ) ) )
{
if ( ! append_gv_to_dbus_iter ( & dbus_iter , item , error ) )
{
goto fail ;
}
}
dbus_message_iter_close_container ( iter , & dbus_iter ) ;
}
else if ( g_variant_type_is_tuple ( type ) )
{
DBusMessageIter dbus_iter ;
GVariantIter gv_iter ;
GVariant * item ;
dbus_message_iter_open_container ( iter , DBUS_TYPE_STRUCT ,
NULL , & dbus_iter ) ;
g_variant_iter_init ( & gv_iter , value ) ;
while ( ( item = g_variant_iter_next_value ( & gv_iter ) ) )
{
if ( ! append_gv_to_dbus_iter ( & dbus_iter , item , error ) )
goto fail ;
}
dbus_message_iter_close_container ( iter , & dbus_iter ) ;
}
else if ( g_variant_type_is_dict_entry ( type ) )
{
DBusMessageIter dbus_iter ;
GVariant * key , * val ;
dbus_message_iter_open_container ( iter , DBUS_TYPE_DICT_ENTRY ,
NULL , & dbus_iter ) ;
key = g_variant_get_child_value ( value , 0 ) ;
if ( ! append_gv_to_dbus_iter ( & dbus_iter , key , error ) )
{
g_variant_unref ( key ) ;
goto fail ;
}
g_variant_unref ( key ) ;
val = g_variant_get_child_value ( value , 1 ) ;
if ( ! append_gv_to_dbus_iter ( & dbus_iter , val , error ) )
{
g_variant_unref ( val ) ;
goto fail ;
}
g_variant_unref ( val ) ;
dbus_message_iter_close_container ( iter , & dbus_iter ) ;
}
else
{
g_set_error ( error ,
G_IO_ERROR ,
G_IO_ERROR_INVALID_ARGUMENT ,
2013-05-20 22:54:48 +02:00
" Error serializing GVariant with type-string '%s' to a D-Bus message " ,
2010-05-06 20:13:59 +02:00
g_variant_get_type_string ( value ) ) ;
goto fail ;
}
return TRUE ;
fail :
return FALSE ;
}
static gboolean
append_gv_to_dbus_message ( DBusMessage * message ,
GVariant * value ,
GError * * error )
{
gboolean ret ;
guint n ;
ret = FALSE ;
if ( value ! = NULL )
{
DBusMessageIter iter ;
GVariantIter gv_iter ;
GVariant * item ;
dbus_message_iter_init_append ( message , & iter ) ;
g_variant_iter_init ( & gv_iter , value ) ;
n = 0 ;
while ( ( item = g_variant_iter_next_value ( & gv_iter ) ) )
{
if ( ! append_gv_to_dbus_iter ( & iter , item , error ) )
{
g_prefix_error ( error ,
" Error encoding in-arg %d: " ,
n ) ;
goto out ;
}
n + + ;
}
}
ret = TRUE ;
out :
return ret ;
}
static void
print_gv_dbus_message ( GVariant * value )
{
DBusMessage * message ;
char * blob ;
int blob_len ;
GError * error ;
message = dbus_message_new ( DBUS_MESSAGE_TYPE_METHOD_CALL ) ;
dbus_message_set_serial ( message , 0x41 ) ;
dbus_message_set_path ( message , " /foo/bar " ) ;
dbus_message_set_member ( message , " Member " ) ;
error = NULL ;
if ( ! append_gv_to_dbus_message ( message , value , & error ) )
{
g_printerr ( " Error printing GVariant as DBusMessage: %s " , error - > message ) ;
g_error_free ( error ) ;
goto out ;
}
dbus_message_marshal ( message , & blob , & blob_len ) ;
g_printerr ( " \n " ) ;
hexdump ( ( guchar * ) blob , blob_len ) ;
out :
dbus_message_unref ( message ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
dbus_1_message_append ( GString * s ,
guint indent ,
DBusMessageIter * iter )
{
gint arg_type ;
DBusMessageIter sub ;
g_string_append_printf ( s , " %*s " , indent , " " ) ;
arg_type = dbus_message_iter_get_arg_type ( iter ) ;
switch ( arg_type )
{
case DBUS_TYPE_BOOLEAN :
{
dbus_bool_t value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " bool: %s \n " , value ? " true " : " false " ) ;
break ;
}
case DBUS_TYPE_BYTE :
{
guchar value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " byte: 0x%02x \n " , ( guint ) value ) ;
break ;
}
case DBUS_TYPE_INT16 :
{
gint16 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " int16: % " G_GINT16_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_UINT16 :
{
guint16 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " uint16: % " G_GUINT16_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_INT32 :
{
gint32 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " int32: % " G_GINT32_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_UINT32 :
{
guint32 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " uint32: % " G_GUINT32_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_INT64 :
{
gint64 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " int64: % " G_GINT64_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_UINT64 :
{
guint64 value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " uint64: % " G_GUINT64_FORMAT " \n " , value ) ;
break ;
}
case DBUS_TYPE_DOUBLE :
{
gdouble value ;
dbus_message_iter_get_basic ( iter , & value ) ;
g_string_append_printf ( s , " double: %f \n " , value ) ;
break ;
}
case DBUS_TYPE_STRING :
{
const gchar * value ;
dbus_message_iter_get_basic ( iter , & value ) ;
2013-05-20 22:54:48 +02:00
g_string_append_printf ( s , " string: '%s' \n " , value ) ;
2010-05-06 20:13:59 +02:00
break ;
}
case DBUS_TYPE_OBJECT_PATH :
{
const gchar * value ;
dbus_message_iter_get_basic ( iter , & value ) ;
2013-05-20 22:54:48 +02:00
g_string_append_printf ( s , " object_path: '%s' \n " , value ) ;
2010-05-06 20:13:59 +02:00
break ;
}
case DBUS_TYPE_SIGNATURE :
{
const gchar * value ;
dbus_message_iter_get_basic ( iter , & value ) ;
2013-05-20 22:54:48 +02:00
g_string_append_printf ( s , " signature: '%s' \n " , value ) ;
2010-05-06 20:13:59 +02:00
break ;
}
2010-07-20 17:38:23 +02:00
# ifdef DBUS_TYPE_UNIX_FD
case DBUS_TYPE_UNIX_FD :
{
/* unfortunately there's currently no way to get just the
* protocol value , since dbus_message_iter_get_basic ( ) wants
* to be ' helpful ' and dup the fd for the user . . .
*/
g_string_append ( s , " unix-fd: (not extracted) \n " ) ;
break ;
}
# endif
2010-05-06 20:13:59 +02:00
case DBUS_TYPE_VARIANT :
g_string_append_printf ( s , " variant: \n " ) ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) )
{
dbus_1_message_append ( s , indent + 2 , & sub ) ;
dbus_message_iter_next ( & sub ) ;
}
break ;
case DBUS_TYPE_ARRAY :
g_string_append_printf ( s , " array: \n " ) ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) )
{
dbus_1_message_append ( s , indent + 2 , & sub ) ;
dbus_message_iter_next ( & sub ) ;
}
break ;
case DBUS_TYPE_STRUCT :
g_string_append_printf ( s , " struct: \n " ) ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) )
{
dbus_1_message_append ( s , indent + 2 , & sub ) ;
dbus_message_iter_next ( & sub ) ;
}
break ;
case DBUS_TYPE_DICT_ENTRY :
g_string_append_printf ( s , " dict_entry: \n " ) ;
dbus_message_iter_recurse ( iter , & sub ) ;
while ( dbus_message_iter_get_arg_type ( & sub ) )
{
dbus_1_message_append ( s , indent + 2 , & sub ) ;
dbus_message_iter_next ( & sub ) ;
}
break ;
default :
2013-05-20 22:54:48 +02:00
g_printerr ( " Error serializing D-Bus message to GVariant. Unsupported arg type '%c' (%d) " ,
2010-05-06 20:13:59 +02:00
arg_type ,
arg_type ) ;
g_assert_not_reached ( ) ;
break ;
}
}
static gchar *
dbus_1_message_print ( DBusMessage * message )
{
GString * s ;
guint n ;
DBusMessageIter iter ;
s = g_string_new ( NULL ) ;
n = 0 ;
dbus_message_iter_init ( message , & iter ) ;
while ( dbus_message_iter_get_arg_type ( & iter ) ! = DBUS_TYPE_INVALID )
{
g_string_append_printf ( s , " value %d: " , n ) ;
dbus_1_message_append ( s , 2 , & iter ) ;
dbus_message_iter_next ( & iter ) ;
n + + ;
}
return g_string_free ( s , FALSE ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
static gchar *
get_body_signature ( GVariant * value )
{
const gchar * s ;
gsize len ;
gchar * ret ;
2010-07-15 18:19:24 +02:00
if ( value = = NULL )
{
ret = g_strdup ( " " ) ;
goto out ;
}
2010-05-06 20:13:59 +02:00
s = g_variant_get_type_string ( value ) ;
len = strlen ( s ) ;
2010-07-15 18:19:24 +02:00
g_assert ( len > = 2 ) ;
2010-05-06 20:13:59 +02:00
ret = g_strndup ( s + 1 , len - 2 ) ;
2010-07-15 18:19:24 +02:00
out :
2010-05-06 20:13:59 +02:00
return ret ;
}
2015-04-22 00:55:49 +02:00
/* If @value is floating, this assumes ownership. */
2019-10-29 19:47:02 +01:00
static gchar *
get_and_check_serialization ( GVariant * value )
2010-05-06 20:13:59 +02:00
{
guchar * blob ;
gsize blob_size ;
DBusMessage * dbus_1_message ;
GDBusMessage * message ;
GDBusMessage * recovered_message ;
GError * error ;
DBusError dbus_error ;
2021-01-28 22:24:50 +01:00
gchar * last_serialization = NULL ;
2019-10-29 19:47:02 +01:00
gchar * s = NULL ;
2010-08-04 19:32:19 +02:00
guint n ;
2010-05-06 20:13:59 +02:00
message = g_dbus_message_new ( ) ;
g_dbus_message_set_body ( message , value ) ;
2010-05-06 23:31:51 +02:00
g_dbus_message_set_message_type ( message , G_DBUS_MESSAGE_TYPE_METHOD_CALL ) ;
2010-05-06 20:13:59 +02:00
g_dbus_message_set_serial ( message , 0x41 ) ;
s = get_body_signature ( value ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_PATH , g_variant_new_object_path ( " /foo/bar " ) ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_MEMBER , g_variant_new_string ( " Member " ) ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE , g_variant_new_signature ( s ) ) ;
g_free ( s ) ;
2010-08-04 19:32:19 +02:00
/* First check that the serialization to the D-Bus wire format is correct - do this for both byte orders */
for ( n = 0 ; n < 2 ; n + + )
2010-05-06 20:13:59 +02:00
{
2010-08-04 19:32:19 +02:00
GDBusMessageByteOrder byte_order ;
switch ( n )
{
case 0 :
byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN ;
break ;
case 1 :
byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN ;
break ;
case 2 :
g_assert_not_reached ( ) ;
break ;
}
g_dbus_message_set_byte_order ( message , byte_order ) ;
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
error = NULL ;
blob = g_dbus_message_to_blob ( message ,
& blob_size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& error ) ;
g_assert_no_error ( error ) ;
g_assert ( blob ! = NULL ) ;
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
switch ( byte_order )
{
case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN :
g_assert_cmpint ( blob [ 0 ] , = = , ' B ' ) ;
break ;
case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN :
g_assert_cmpint ( blob [ 0 ] , = = , ' l ' ) ;
break ;
}
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
dbus_error_init ( & dbus_error ) ;
dbus_1_message = dbus_message_demarshal ( ( char * ) blob , blob_size , & dbus_error ) ;
if ( dbus_error_is_set ( & dbus_error ) )
{
g_printerr ( " Error calling dbus_message_demarshal() on this blob: %s: %s \n " ,
dbus_error . name ,
dbus_error . message ) ;
hexdump ( blob , blob_size ) ;
dbus_error_free ( & dbus_error ) ;
s = g_variant_print ( value , TRUE ) ;
g_printerr ( " \n The blob was generated from the following GVariant value: \n %s \n \n " , s ) ;
g_free ( s ) ;
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
g_printerr ( " If the blob was encoded using DBusMessageIter, the payload would have been: \n " ) ;
print_gv_dbus_message ( value ) ;
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
g_assert_not_reached ( ) ;
}
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
s = dbus_1_message_print ( dbus_1_message ) ;
dbus_message_unref ( dbus_1_message ) ;
2010-05-06 20:13:59 +02:00
2010-08-04 19:32:19 +02:00
/* Then serialize back and check that the body is identical */
error = NULL ;
recovered_message = g_dbus_message_new_from_blob ( blob ,
blob_size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& error ) ;
g_assert_no_error ( error ) ;
2012-04-06 11:03:29 +02:00
g_assert ( recovered_message ! = NULL ) ;
2010-08-04 19:32:19 +02:00
if ( value = = NULL )
2010-07-15 18:19:24 +02:00
{
2010-08-04 19:32:19 +02:00
g_assert ( g_dbus_message_get_body ( recovered_message ) = = NULL ) ;
}
else
{
g_assert ( g_dbus_message_get_body ( recovered_message ) ! = NULL ) ;
2018-12-14 16:04:11 +01:00
g_assert_cmpvariant ( g_dbus_message_get_body ( recovered_message ) , value ) ;
2010-07-15 18:19:24 +02:00
}
2010-08-04 19:32:19 +02:00
g_object_unref ( recovered_message ) ;
2015-04-22 00:55:49 +02:00
g_free ( blob ) ;
2021-01-28 22:24:50 +01:00
if ( last_serialization ! = NULL )
{
g_assert_cmpstr ( last_serialization , = = , s ) ;
g_free ( last_serialization ) ;
}
last_serialization = g_steal_pointer ( & s ) ;
2010-05-06 20:13:59 +02:00
}
2010-08-04 19:32:19 +02:00
2010-05-06 20:13:59 +02:00
g_object_unref ( message ) ;
2019-10-29 19:47:02 +01:00
2021-01-28 22:24:50 +01:00
return g_steal_pointer ( & last_serialization ) ;
2019-10-29 19:47:02 +01:00
}
/* If @value is floating, this assumes ownership. */
static void
check_serialization ( GVariant * value ,
const gchar * expected_dbus_1_output )
{
gchar * s = get_and_check_serialization ( value ) ;
g_assert_cmpstr ( s , = = , expected_dbus_1_output ) ;
g_free ( s ) ;
2010-05-06 20:13:59 +02:00
}
static void
2019-10-30 16:48:57 +01:00
test_message_serialize_basic ( void )
2010-05-06 20:13:59 +02:00
{
2010-07-15 18:19:24 +02:00
check_serialization ( NULL , " " ) ;
2010-05-06 20:13:59 +02:00
check_serialization ( g_variant_new ( " (sogybnqiuxtd) " ,
" this is a string " ,
" /this/is/a/path " ,
" sad " ,
42 ,
TRUE ,
- 42 ,
60000 ,
- 44 ,
100000 ,
2016-12-02 11:06:23 +01:00
- ( G_GUINT64_CONSTANT ( 2 ) < < 34 ) ,
2010-05-06 20:13:59 +02:00
G_GUINT64_CONSTANT ( 0xffffffffffffffff ) ,
42.5 ) ,
2013-05-20 22:54:48 +02:00
" value 0: string: 'this is a string' \n "
" value 1: object_path: '/this/is/a/path' \n "
" value 2: signature: 'sad' \n "
2010-05-06 20:13:59 +02:00
" value 3: byte: 0x2a \n "
" value 4: bool: true \n "
" value 5: int16: -42 \n "
" value 6: uint16: 60000 \n "
" value 7: int32: -44 \n "
" value 8: uint32: 100000 \n "
" value 9: int64: -34359738368 \n "
" value 10: uint64: 18446744073709551615 \n "
" value 11: double: 42.500000 \n " ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
static void
2019-10-30 16:48:57 +01:00
test_message_serialize_complex ( void )
2010-05-06 20:13:59 +02:00
{
GError * error ;
GVariant * value ;
2019-10-29 19:47:02 +01:00
guint i ;
gchar * serialization = NULL ;
2010-05-06 20:13:59 +02:00
error = NULL ;
2010-05-14 18:49:51 +02:00
2010-05-06 20:13:59 +02:00
value = g_variant_parse ( G_VARIANT_TYPE ( " (aia{ss}) " ) ,
" ([1, 2, 3], {'one': 'white', 'two': 'black'}) " ,
NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( value ! = NULL ) ;
check_serialization ( value ,
" value 0: array: \n "
" int32: 1 \n "
" int32: 2 \n "
" int32: 3 \n "
" value 1: array: \n "
" dict_entry: \n "
2013-05-20 22:54:48 +02:00
" string: 'one' \n "
" string: 'white' \n "
2010-05-06 20:13:59 +02:00
" dict_entry: \n "
2013-05-20 22:54:48 +02:00
" string: 'two' \n "
" string: 'black' \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( value ) ;
2010-05-14 18:49:51 +02:00
value = g_variant_parse ( G_VARIANT_TYPE ( " (sa{sv}as) " ) ,
" ('01234567890123456', {}, ['Something']) " ,
NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( value ! = NULL ) ;
check_serialization ( value ,
2013-05-20 22:54:48 +02:00
" value 0: string: '01234567890123456' \n "
2010-05-14 18:49:51 +02:00
" value 1: array: \n "
" value 2: array: \n "
2013-05-20 22:54:48 +02:00
" string: 'Something' \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( value ) ;
2010-06-17 23:58:25 +02:00
/* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
check_serialization ( g_variant_new_parsed ( " (@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>}) " ) ,
" value 0: array: \n "
" value 1: array: \n "
" dict_entry: \n "
2013-05-20 22:54:48 +02:00
" string: 'cwd' \n "
2010-06-17 23:58:25 +02:00
" variant: \n "
2013-05-20 22:54:48 +02:00
" string: '/home/davidz/Hacking/glib/gio/tests' \n " ) ;
2010-07-20 17:38:23 +02:00
# ifdef DBUS_TYPE_UNIX_FD
value = g_variant_parse ( G_VARIANT_TYPE ( " (hah) " ) ,
" (42, [43, 44]) " ,
NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
g_assert ( value ! = NULL ) ;
/* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
* dbus_1_message_append ( ) above .
*/
check_serialization ( value ,
" value 0: unix-fd: (not extracted) \n "
" value 1: array: \n "
" unix-fd: (not extracted) \n "
" unix-fd: (not extracted) \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( value ) ;
2010-07-20 17:38:23 +02:00
# endif
2019-10-29 19:47:02 +01:00
/* Deep nesting of variants (just below the recursion limit). */
value = g_variant_new_string ( " buried " ) ;
for ( i = 0 ; i < 64 ; i + + )
value = g_variant_new_variant ( value ) ;
value = g_variant_new_tuple ( & value , 1 ) ;
serialization = get_and_check_serialization ( value ) ;
g_assert_nonnull ( serialization ) ;
g_assert_true ( g_str_has_prefix ( serialization ,
" value 0: variant: \n "
" variant: \n "
" variant: \n " ) ) ;
g_free ( serialization ) ;
/* Deep nesting of arrays and structs (just below the recursion limit).
* See https : //dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature */
value = g_variant_new_string ( " hello " ) ;
for ( i = 0 ; i < 32 ; i + + )
value = g_variant_new_tuple ( & value , 1 ) ;
for ( i = 0 ; i < 32 ; i + + )
value = g_variant_new_array ( NULL , & value , 1 ) ;
value = g_variant_new_tuple ( & value , 1 ) ;
serialization = get_and_check_serialization ( value ) ;
g_assert_nonnull ( serialization ) ;
g_assert_true ( g_str_has_prefix ( serialization ,
" value 0: array: \n "
" array: \n "
" array: \n " ) ) ;
g_free ( serialization ) ;
2010-05-06 20:13:59 +02:00
}
2010-08-04 17:26:48 +02:00
/* ---------------------------------------------------------------------------------------------------- */
2011-03-31 14:58:55 +02:00
static void
replace ( char * blob ,
gsize len ,
const char * before ,
const char * after )
{
gsize i ;
gsize slen = strlen ( before ) + 1 ;
g_assert_cmpuint ( strlen ( before ) , = = , strlen ( after ) ) ;
g_assert_cmpuint ( len , > = , slen ) ;
for ( i = 0 ; i < ( len - slen + 1 ) ; i + + )
{
if ( memcmp ( blob + i , before , slen ) = = 0 )
memcpy ( blob + i , after , slen ) ;
}
}
2010-08-04 17:26:48 +02:00
static void
2019-10-30 16:48:57 +01:00
test_message_serialize_invalid ( void )
2010-08-04 17:26:48 +02:00
{
guint n ;
2011-03-31 14:58:55 +02:00
/* Other things we could check (note that GDBus _does_ check for all
2010-08-04 17:26:48 +02:00
* these things - we just don ' t have test - suit coverage for it )
*
* - array exceeding 64 MiB ( 2 ^ 26 bytes ) - unfortunately libdbus - 1 checks
* this , e . g .
*
* process 19620 : arguments to dbus_message_iter_append_fixed_array ( ) were incorrect ,
* assertion " n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type) "
* failed in file dbus - message . c line 2344.
* This is normally a bug in some application using the D - Bus library .
* D - Bus not built with - rdynamic so unable to print a backtrace
* Aborted ( core dumped )
*
* - message exceeding 128 MiB ( 2 ^ 27 bytes )
*
* - endianness , message type , flags , protocol version
*/
for ( n = 0 ; n < 3 ; n + + )
{
GDBusMessage * message ;
GError * error ;
DBusMessage * dbus_message ;
char * blob ;
int blob_len ;
2011-03-31 14:58:55 +02:00
/* these are in pairs with matching length */
const gchar * valid_utf8_str = " this is valid... " ;
2010-08-04 17:26:48 +02:00
const gchar * invalid_utf8_str = " this is invalid \xff " ;
2011-03-31 14:58:55 +02:00
const gchar * valid_signature = " a{sv}a{sv}a{sv}aiai " ;
2010-08-04 17:26:48 +02:00
const gchar * invalid_signature = " not valid signature " ;
2011-03-31 14:58:55 +02:00
const gchar * valid_object_path = " /this/is/a/valid/dbus/object/path " ;
const gchar * invalid_object_path = " /this/is/not a valid object path! " ;
2010-08-04 17:26:48 +02:00
dbus_message = dbus_message_new ( DBUS_MESSAGE_TYPE_METHOD_CALL ) ;
dbus_message_set_serial ( dbus_message , 0x41 ) ;
dbus_message_set_path ( dbus_message , " /foo/bar " ) ;
dbus_message_set_member ( dbus_message , " Member " ) ;
switch ( n )
{
case 0 :
/* invalid UTF-8 */
dbus_message_append_args ( dbus_message ,
2011-03-31 14:58:55 +02:00
DBUS_TYPE_STRING , & valid_utf8_str ,
2010-08-04 17:26:48 +02:00
DBUS_TYPE_INVALID ) ;
break ;
case 1 :
/* invalid object path */
dbus_message_append_args ( dbus_message ,
2011-03-31 14:58:55 +02:00
DBUS_TYPE_OBJECT_PATH , & valid_object_path ,
2010-08-04 17:26:48 +02:00
DBUS_TYPE_INVALID ) ;
break ;
case 2 :
/* invalid signature */
dbus_message_append_args ( dbus_message ,
2011-03-31 14:58:55 +02:00
DBUS_TYPE_SIGNATURE , & valid_signature ,
2010-08-04 17:26:48 +02:00
DBUS_TYPE_INVALID ) ;
break ;
default :
g_assert_not_reached ( ) ;
break ;
}
dbus_message_marshal ( dbus_message , & blob , & blob_len ) ;
2011-03-31 14:58:55 +02:00
/* hack up the message to be invalid by replacing each valid string
* with its invalid counterpart */
replace ( blob , blob_len , valid_utf8_str , invalid_utf8_str ) ;
replace ( blob , blob_len , valid_object_path , invalid_object_path ) ;
replace ( blob , blob_len , valid_signature , invalid_signature ) ;
2010-08-04 17:26:48 +02:00
error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) blob ,
blob_len ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_error_free ( error ) ;
g_assert ( message = = NULL ) ;
dbus_free ( blob ) ;
2015-04-22 00:55:49 +02:00
dbus_message_unref ( dbus_message ) ;
2010-08-04 17:26:48 +02:00
}
}
2010-05-06 20:13:59 +02:00
/* ---------------------------------------------------------------------------------------------------- */
2010-08-04 20:38:51 +02:00
static void
2019-10-30 16:48:57 +01:00
test_message_serialize_header_checks ( void )
2010-08-04 20:38:51 +02:00
{
GDBusMessage * message ;
GDBusMessage * reply ;
2018-09-20 18:41:10 +02:00
GError * error = NULL ;
2010-08-04 20:38:51 +02:00
guchar * blob ;
gsize blob_size ;
/*
* check we can ' t serialize messages with INVALID type
*/
message = g_dbus_message_new ( ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: type is INVALID " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
g_object_unref ( message ) ;
2018-08-16 22:33:52 +02:00
/*
2023-12-07 00:40:49 +01:00
* check we can ' t serialize messages with an INVALID header
2018-08-16 22:33:52 +02:00
*/
message = g_dbus_message_new_signal ( " /the/path " , " The.Interface " , " TheMember " ) ;
2023-12-07 00:40:49 +01:00
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_INVALID , g_variant_new_boolean ( FALSE ) ) ;
2018-08-16 22:33:52 +02:00
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-07 00:40:49 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: INVALID header field supplied " ) ;
2018-08-16 22:33:52 +02:00
g_assert_null ( blob ) ;
g_clear_error ( & error ) ;
g_clear_object ( & message ) ;
2023-12-07 00:40:49 +01:00
/*
* check that we can ' t serialize messages with various fields set to incorrectly typed values
*/
const struct
{
GDBusMessageHeaderField field ;
const char * invalid_value ; /* as a GVariant in text form */
const char * expected_error_message ;
}
field_type_tests [ ] =
{
{
G_DBUS_MESSAGE_HEADER_FIELD_PATH ,
" '/correct/value/but/wrong/type' " ,
" Cannot serialize message: SIGNAL message: PATH header field is invalid; expected a value of type ‘ o’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE ,
" @u 5 " ,
" Cannot serialize message: SIGNAL message: INTERFACE header field is invalid; expected a value of type ‘ s’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE ,
" 'valid type, but not an interface name' " ,
" Cannot serialize message: SIGNAL message: INTERFACE header field does not contain a valid interface name "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_MEMBER ,
" @u 5 " ,
" Cannot serialize message: SIGNAL message: MEMBER header field is invalid; expected a value of type ‘ s’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_MEMBER ,
" 'valid type, but not a member name' " ,
" Cannot serialize message: SIGNAL message: MEMBER header field does not contain a valid member name "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME ,
" @u 5 " ,
" Cannot serialize message: SIGNAL message: ERROR_NAME header field is invalid; expected a value of type ‘ s’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME ,
" 'valid type, but not an error name' " ,
" Cannot serialize message: SIGNAL message: ERROR_NAME header field does not contain a valid error name "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL ,
" 'oops' " ,
" Cannot serialize message: SIGNAL message: REPLY_SERIAL header field is invalid; expected a value of type ‘ u’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION ,
" @u 5 " ,
" Cannot serialize message: SIGNAL message: DESTINATION header field is invalid; expected a value of type ‘ s’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_SENDER ,
" @u 5 " ,
" Cannot serialize message: SIGNAL message: SENDER header field is invalid; expected a value of type ‘ s’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE ,
" false " ,
" Cannot serialize message: SIGNAL message: SIGNATURE header field is invalid; expected a value of type ‘ g’ "
} ,
{
G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS ,
" 'five' " ,
" Cannot serialize message: SIGNAL message: NUM_UNIX_FDS header field is invalid; expected a value of type ‘ u’ "
} ,
} ;
for ( size_t i = 0 ; i < G_N_ELEMENTS ( field_type_tests ) ; i + + )
{
message = g_dbus_message_new_signal ( " /the/path " , " The.Interface " , " TheMember " ) ;
g_dbus_message_set_header ( message , field_type_tests [ i ] . field , g_variant_new_parsed ( field_type_tests [ i ] . invalid_value ) ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_cmpstr ( error - > message , = = , field_type_tests [ i ] . expected_error_message ) ;
g_assert_null ( blob ) ;
g_clear_error ( & error ) ;
g_clear_object ( & message ) ;
}
2010-08-04 20:38:51 +02:00
/*
* check we can ' t serialize signal messages with INTERFACE , PATH or MEMBER unset / set to reserved value
*/
message = g_dbus_message_new_signal ( " /the/path " , " The.Interface " , " TheMember " ) ;
/* ----- */
/* interface NULL => error */
g_dbus_message_set_interface ( message , NULL ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: INTERFACE header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* interface reserved value => error */
g_dbus_message_set_interface ( message , " org.freedesktop.DBus.Local " ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: INTERFACE header field is using the reserved value org.freedesktop.DBus.Local " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset interface */
g_dbus_message_set_interface ( message , " The.Interface " ) ;
/* ----- */
/* path NULL => error */
g_dbus_message_set_path ( message , NULL ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: PATH header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* path reserved value => error */
g_dbus_message_set_path ( message , " /org/freedesktop/DBus/Local " ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: PATH header field is using the reserved value /org/freedesktop/DBus/Local " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset path */
g_dbus_message_set_path ( message , " /the/path " ) ;
/* ----- */
/* member NULL => error */
g_dbus_message_set_member ( message , NULL ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: SIGNAL message: MEMBER header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset member */
g_dbus_message_set_member ( message , " TheMember " ) ;
/* ----- */
/* done */
g_object_unref ( message ) ;
/*
* check that we can ' t serialize method call messages with PATH or MEMBER unset
*/
message = g_dbus_message_new_method_call ( NULL , " /the/path " , NULL , " TheMember " ) ;
/* ----- */
/* path NULL => error */
g_dbus_message_set_path ( message , NULL ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: METHOD_CALL message: PATH header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset path */
g_dbus_message_set_path ( message , " /the/path " ) ;
/* ----- */
/* member NULL => error */
g_dbus_message_set_member ( message , NULL ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: METHOD_CALL message: MEMBER header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset member */
g_dbus_message_set_member ( message , " TheMember " ) ;
/* ----- */
/* done */
g_object_unref ( message ) ;
/*
* check that we can ' t serialize method reply messages with REPLY_SERIAL unset
*/
message = g_dbus_message_new_method_call ( NULL , " /the/path " , NULL , " TheMember " ) ;
g_dbus_message_set_serial ( message , 42 ) ;
/* method reply */
reply = g_dbus_message_new_method_reply ( message ) ;
g_assert_cmpint ( g_dbus_message_get_reply_serial ( reply ) , = = , 42 ) ;
g_dbus_message_set_header ( reply , G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL , NULL ) ;
blob = g_dbus_message_to_blob ( reply , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-08-16 17:14:49 +02:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
g_object_unref ( reply ) ;
/* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
reply = g_dbus_message_new_method_error ( message , " Some.Error.Name " , " the message " ) ;
g_assert_cmpint ( g_dbus_message_get_reply_serial ( reply ) , = = , 42 ) ;
/* nuke ERROR_NAME */
g_dbus_message_set_error_name ( reply , NULL ) ;
blob = g_dbus_message_to_blob ( reply , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: ERROR message: ERROR_NAME header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
/* reset ERROR_NAME */
g_dbus_message_set_error_name ( reply , " Some.Error.Name " ) ;
/* nuke REPLY_SERIAL */
g_dbus_message_set_header ( reply , G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL , NULL ) ;
blob = g_dbus_message_to_blob ( reply , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
2023-12-06 23:47:14 +01:00
g_assert_cmpstr ( error - > message , = = , " Cannot serialize message: ERROR message: REPLY_SERIAL header field is missing or invalid " ) ;
2018-09-20 18:41:10 +02:00
g_clear_error ( & error ) ;
2018-09-20 18:42:05 +02:00
g_assert_null ( blob ) ;
2010-08-04 20:38:51 +02:00
g_object_unref ( reply ) ;
g_object_unref ( message ) ;
}
2023-12-07 00:40:49 +01:00
static void
test_message_serialize_header_checks_valid ( void )
{
GDBusMessage * message = NULL , * reply = NULL ;
GError * local_error = NULL ;
guchar * blob ;
gsize blob_size ;
g_test_summary ( " Test that validation allows well-formed messages of all the different types " ) ;
/* Method call */
message = g_dbus_message_new_method_call ( " Some.Name " , " /the/path " , " org.some.Interface " , " TheMethod " ) ;
g_dbus_message_set_serial ( message , 666 ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
/* Method return */
reply = g_dbus_message_new_method_reply ( message ) ;
blob = g_dbus_message_to_blob ( reply , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
g_clear_object ( & reply ) ;
/* Error */
reply = g_dbus_message_new_method_error ( message , " Error.Name " , " Some error message " ) ;
blob = g_dbus_message_to_blob ( reply , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
g_clear_object ( & reply ) ;
g_clear_object ( & message ) ;
/* Signal */
message = g_dbus_message_new_signal ( " /the/path " , " org.some.Interface " , " SignalName " ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
g_clear_object ( & message ) ;
/* Also check that an unknown message type is allowed */
message = g_dbus_message_new ( ) ;
g_dbus_message_set_message_type ( message , 123 ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
g_clear_object ( & message ) ;
/* Even one with a well-defined field on it */
message = g_dbus_message_new ( ) ;
g_dbus_message_set_message_type ( message , 123 ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS , g_variant_new_uint32 ( 0 ) ) ;
blob = g_dbus_message_to_blob ( message , & blob_size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_no_error ( local_error ) ;
g_assert_nonnull ( blob ) ;
g_free ( blob ) ;
g_clear_object ( & message ) ;
}
2010-08-04 20:38:51 +02:00
/* ---------------------------------------------------------------------------------------------------- */
2012-04-06 11:03:29 +02:00
static void
2019-10-30 16:48:57 +01:00
test_message_parse_empty_arrays_of_arrays ( void )
2012-04-06 11:03:29 +02:00
{
GVariant * body ;
GError * error = NULL ;
2021-05-13 23:12:29 +02:00
g_test_bug ( " https://bugzilla.gnome.org/show_bug.cgi?id=673612 " ) ;
2012-04-06 11:03:29 +02:00
/* These three-element array of empty arrays were previously read back as a
* two - element array of empty arrays , due to sometimes erroneously skipping
* four bytes to align for the eight - byte - aligned grandchild types ( x and
* dict_entry ) .
*/
body = g_variant_parse ( G_VARIANT_TYPE ( " (aaax) " ) ,
" ([@aax [], [], []],) " , NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
check_serialization ( body ,
" value 0: array: \n "
" array: \n "
" array: \n "
" array: \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( body ) ;
2012-04-06 11:03:29 +02:00
body = g_variant_parse ( G_VARIANT_TYPE ( " (aaa{uu}) " ) ,
" ([@aa{uu} [], [], []],) " , NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
check_serialization ( body ,
" value 0: array: \n "
" array: \n "
" array: \n "
" array: \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( body ) ;
2012-04-06 11:03:29 +02:00
/* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
* message because it would try to read past the end of the string . Hence ,
* sending this to an application would make it fall off the bus . */
body = g_variant_parse ( G_VARIANT_TYPE ( " (a(aa{sv}as)) " ) ,
" ([ ([], []), "
" ([], []), "
" ([], [])],) " , NULL , NULL , & error ) ;
g_assert_no_error ( error ) ;
check_serialization ( body ,
" value 0: array: \n "
" struct: \n "
" array: \n "
" array: \n "
" struct: \n "
" array: \n "
" array: \n "
" struct: \n "
" array: \n "
" array: \n " ) ;
2015-04-22 00:55:49 +02:00
g_variant_unref ( body ) ;
2012-04-06 11:03:29 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
2014-07-22 21:13:50 +02:00
static void
2019-10-30 16:48:57 +01:00
test_message_serialize_double_array ( void )
2014-07-22 21:13:50 +02:00
{
GVariantBuilder builder ;
2015-04-21 21:46:47 +02:00
GVariant * body ;
2014-07-22 21:13:50 +02:00
2021-05-13 23:12:29 +02:00
g_test_bug ( " https://bugzilla.gnome.org/show_bug.cgi?id=732754 " ) ;
2014-07-22 21:13:50 +02:00
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " ad " ) ) ;
g_variant_builder_add ( & builder , " d " , ( gdouble ) 0.0 ) ;
g_variant_builder_add ( & builder , " d " , ( gdouble ) 8.0 ) ;
g_variant_builder_add ( & builder , " d " , ( gdouble ) 22.0 ) ;
g_variant_builder_add ( & builder , " d " , ( gdouble ) 0.0 ) ;
2015-04-21 21:46:47 +02:00
body = g_variant_new ( " (@ad) " , g_variant_builder_end ( & builder ) ) ;
check_serialization ( body ,
" value 0: array: \n "
" double: 0.000000 \n "
" double: 8.000000 \n "
" double: 22.000000 \n "
" double: 0.000000 \n " ) ;
2014-07-22 21:13:50 +02:00
}
/* ---------------------------------------------------------------------------------------------------- */
2018-08-16 22:33:52 +02:00
/* Test that an invalid header in a D-Bus message (specifically, with a type
* which doesn ’ t match what ’ s expected for the given header ) is gracefully
2020-11-18 13:49:54 +01:00
* handled with an error rather than a crash . */
2018-08-16 22:33:52 +02:00
static void
test_message_parse_non_signature_header ( void )
{
const guint8 data [ ] = {
2018-09-18 16:17:44 +02:00
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2018-08-16 22:33:52 +02:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0x00 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2018-08-16 22:33:52 +02:00
0x00 , 0x00 , 0x00 , 0xbc , /* message serial */
/* a{yv} of header fields:
* ( things start to be invalid below here ) */
2020-11-18 13:49:54 +01:00
0x10 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x08 , /* array key (SIGNATURE) */
2018-09-18 16:17:44 +02:00
/* Variant array value: */
2018-08-16 22:33:52 +02:00
0x04 , /* signature length */
' d ' , 0x00 , 0x00 , ' F ' , /* signature (invalid) */
0x00 , /* nul terminator */
2018-09-18 16:17:44 +02:00
/* (Variant array value payload missing) */
2020-11-18 13:49:54 +01:00
/* alignment padding before the next header array element, as structs must
* be 8 - aligned : */
0x00 ,
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
/* (message body is zero-length) */
2018-09-18 16:17:44 +02:00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
/* Test that an invalid header in a D-Bus message (specifically, containing a
* variant with an empty type signature ) is gracefully handled with an error
2020-11-18 13:49:54 +01:00
* rather than a crash . */
2018-09-18 16:17:44 +02:00
static void
test_message_parse_empty_signature_header ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2018-09-18 16:17:44 +02:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0x00 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2018-09-18 16:17:44 +02:00
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields:
2020-11-18 13:49:54 +01:00
* ( things start to be invalid below here ) */
0x10 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x20 , /* array key (this is not currently a valid header field) */
2018-09-18 16:17:44 +02:00
/* Variant array value: */
0x00 , /* signature length */
0x00 , /* nul terminator */
/* (Variant array value payload missing) */
2020-11-18 13:49:54 +01:00
/* alignment padding before the next header array element, as structs must
* be 8 - aligned : */
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
/* (message body is zero-length) */
2018-09-18 16:17:44 +02:00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
/* Test that an invalid header in a D-Bus message (specifically, containing a
* variant with a type signature containing multiple complete types ) is
2020-11-18 13:49:54 +01:00
* gracefully handled with an error rather than a crash . */
2018-09-18 16:17:44 +02:00
static void
test_message_parse_multiple_signature_header ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2018-09-18 16:17:44 +02:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0x00 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2018-09-18 16:17:44 +02:00
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields:
2020-11-18 13:49:54 +01:00
* ( things start to be invalid below here ) */
0x10 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x20 , /* array key (this is not currently a valid header field) */
2018-09-18 16:17:44 +02:00
/* Variant array value: */
0x02 , /* signature length */
' b ' , ' b ' , /* two complete types */
0x00 , /* nul terminator */
/* (Variant array value payload missing) */
2020-11-18 13:49:54 +01:00
/* alignment padding before the next header array element, as structs must
* be 8 - aligned : */
0x00 , 0x00 , 0x00 ,
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
/* (message body is zero-length) */
2018-08-16 22:33:52 +02:00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
2018-11-14 15:23:19 +01:00
/* Test that an invalid header in a D-Bus message (specifically, containing a
* variant with a valid type signature that is too long to be a valid
* # GVariantType due to exceeding the array nesting limits ) is gracefully
2020-11-18 13:49:54 +01:00
* handled with an error rather than a crash . */
2018-11-14 15:23:19 +01:00
static void
test_message_parse_over_long_signature_header ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2018-11-14 15:23:19 +01:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0x00 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2018-11-14 15:23:19 +01:00
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields:
2020-11-18 13:49:54 +01:00
* ( things start to be invalid below here ) */
0xa0 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x08 , /* array key (SIGNATURE) */
2018-11-14 15:23:19 +01:00
/* Variant array value: */
0x04 , /* signature length */
' g ' , 0x00 , 0x20 , 0x20 , /* one complete type plus some rubbish */
0x00 , /* nul terminator */
/* (Variant array value payload) */
/* Critically, this contains 128 nested ‘ a’ s, which exceeds
* % G_VARIANT_MAX_RECURSION_DEPTH . */
0xec ,
' a ' , ' b ' , ' g ' , ' d ' , ' u ' , ' d ' , ' d ' , ' d ' , ' d ' , ' d ' , ' d ' , ' d ' ,
' d ' , ' d ' , ' d ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' , ' a ' ,
2020-11-18 13:49:54 +01:00
' v ' ,
/* first header length is a multiple of 8 so no padding is needed */
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
/* (message body is zero-length) */
2018-11-14 15:23:19 +01:00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
2019-10-29 19:47:02 +01:00
/* Test that an invalid header in a D-Bus message (specifically, containing too
* many levels of nested variant ) is gracefully handled with an error rather
2020-11-18 13:49:54 +01:00
* than a crash . */
2019-10-29 19:47:02 +01:00
static void
test_message_parse_deep_header_nesting ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2019-10-29 19:47:02 +01:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0x00 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2019-10-29 19:47:02 +01:00
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields:
2020-11-18 13:49:54 +01:00
* ( things start to be invalid below here ) */
0xd0 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
2019-10-29 19:47:02 +01:00
0x20 , /* array key (this is not currently a valid header field) */
/* Variant array value: */
0x01 , /* signature length */
' v ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
/* Critically, this contains 64 nested variants (minus two for the
* ‘ arbitrary valid content ’ below , but ignoring two for the ` a { yv } `
* above ) , which in total exceeds % G_DBUS_MAX_TYPE_DEPTH . */
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
2020-11-18 13:49:54 +01:00
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
2019-10-29 19:47:02 +01:00
/* Some arbitrary valid content inside the innermost variant: */
0x01 , ' y ' , 0x00 , 0xcc ,
2020-11-18 13:49:54 +01:00
/* no padding needed as this header element length is a multiple of 8 */
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
/* (message body is zero-length) */
2019-10-29 19:47:02 +01:00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
/* Test that an invalid body in a D-Bus message (specifically, containing too
* many levels of nested variant ) is gracefully handled with an error rather
* than a crash . The set of bytes here are a modified version of the bytes from
* test_message_parse_deep_header_nesting ( ) . */
static void
test_message_parse_deep_body_nesting ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
2020-11-18 13:49:54 +01:00
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
2019-10-29 19:47:02 +01:00
0x01 , /* major protocol version */
2020-11-18 13:49:54 +01:00
0xc4 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
2019-10-29 19:47:02 +01:00
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields: */
2020-11-18 13:49:54 +01:00
0x10 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x08 , /* array key (SIGNATURE) */
2019-10-29 19:47:02 +01:00
/* Variant array value: */
0x01 , /* signature length */
' g ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x01 , ' v ' , 0x00 ,
2020-11-18 13:49:54 +01:00
/* alignment padding before the next header array element, as structs must
* be 8 - aligned : */
0x00 ,
0x05 , /* array key (REPLY_SERIAL, required for method return messages) */
/* Variant array value: */
0x01 , /* signature length */
' u ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x00 , 0x01 , 0x02 , 0x03 ,
2019-10-29 19:47:02 +01:00
/* Message body: over 64 levels of nested variant, which is not valid: */
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 , 0x01 , ' v ' , 0x00 ,
/* Some arbitrary valid content inside the innermost variant: */
0x01 , ' y ' , 0x00 , 0xcc ,
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
/* ---------------------------------------------------------------------------------------------------- */
2021-11-19 16:43:50 +01:00
static void
test_message_parse_truncated ( void )
{
GDBusMessage * message = NULL ;
GDBusMessage * message2 = NULL ;
GVariantBuilder builder ;
guchar * blob = NULL ;
gsize size = 0 ;
GError * error = NULL ;
g_test_summary ( " Test that truncated messages are properly rejected. " ) ;
g_test_bug ( " https://gitlab.gnome.org/GNOME/glib/-/issues/2528 " ) ;
message = g_dbus_message_new ( ) ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " (asbynqiuxtd) " ) ) ;
g_variant_builder_open ( & builder , G_VARIANT_TYPE ( " as " ) ) ;
g_variant_builder_add ( & builder , " s " , " fourtytwo " ) ;
g_variant_builder_close ( & builder ) ;
g_variant_builder_add ( & builder , " b " , TRUE ) ;
g_variant_builder_add ( & builder , " y " , 42 ) ;
g_variant_builder_add ( & builder , " n " , 42 ) ;
g_variant_builder_add ( & builder , " q " , 42 ) ;
g_variant_builder_add ( & builder , " i " , 42 ) ;
g_variant_builder_add ( & builder , " u " , 42 ) ;
g_variant_builder_add ( & builder , " x " , 42 ) ;
g_variant_builder_add ( & builder , " t " , 42 ) ;
g_variant_builder_add ( & builder , " d " , ( gdouble ) 42 ) ;
g_dbus_message_set_message_type ( message , G_DBUS_MESSAGE_TYPE_METHOD_CALL ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_PATH ,
g_variant_new_object_path ( " /foo/bar " ) ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_MEMBER ,
g_variant_new_string ( " Member " ) ) ;
g_dbus_message_set_body ( message , g_variant_builder_end ( & builder ) ) ;
blob = g_dbus_message_to_blob ( message , & size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_no_error ( error ) ;
g_clear_object ( & message ) ;
2021-11-23 13:57:29 +01:00
/* Try parsing all possible prefixes of the full @blob. */
for ( gsize i = 0 ; i < size ; i + + )
2021-11-19 16:43:50 +01:00
{
message2 = g_dbus_message_new_from_blob ( blob , i , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_error ( error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message2 ) ;
g_clear_error ( & error ) ;
}
message2 = g_dbus_message_new_from_blob ( blob , size , G_DBUS_CAPABILITY_FLAGS_NONE , & error ) ;
g_assert_no_error ( error ) ;
g_assert_true ( G_IS_DBUS_MESSAGE ( message2 ) ) ;
g_clear_object ( & message2 ) ;
g_free ( blob ) ;
}
2022-01-06 22:04:56 +01:00
static void
test_message_parse_empty_structure ( void )
{
const guint8 data [ ] =
{
' l ' , /* little-endian byte order */
0x02 , /* message type (method return) */
0x00 , /* message flags (none) */
0x01 , /* major protocol version */
0x08 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
0x00 , 0x00 , 0x00 , 0x00 , /* message serial */
/* a{yv} of header fields */
0x20 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x01 , /* array key (PATH) */
0x01 , /* signature length */
' o ' , /* type (OBJECT_PATH) */
0x00 , /* nul terminator */
0x05 , 0x00 , 0x00 , 0x00 , /* length 5 */
' / ' , ' p ' , ' a ' , ' t ' , ' h ' , 0x00 , 0x00 , 0x00 , /* string '/path' and padding */
0x03 , /* array key (MEMBER) */
0x01 , /* signature length */
' s ' , /* type (STRING) */
0x00 , /* nul terminator */
0x06 , 0x00 , 0x00 , 0x00 , /* length 6 */
' M ' , ' e ' , ' m ' , ' b ' , ' e ' , ' r ' , 0x00 , 0x00 , /* string 'Member' and padding */
0x08 , /* array key (SIGNATURE) */
0x01 , /* signature length */
' g ' , /* type (SIGNATURE) */
0x00 , /* nul terminator */
0x03 , /* length 3 */
' a ' , ' ( ' , ' ) ' , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , /* type 'a()' and padding */
0x08 , 0x00 , 0x00 , 0x00 , /* array length: 4 bytes */
0x00 , 0x00 , 0x00 , 0x00 , /* padding to 8 bytes */
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , /* array data */
0x00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
g_test_summary ( " Test that empty structures are rejected when parsing. " ) ;
g_test_bug ( " https://gitlab.gnome.org/GNOME/glib/-/issues/2557 " ) ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_cmpstr ( local_error - > message , = = , " Empty structures (tuples) are not allowed in D-Bus " ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
static void
test_message_serialize_empty_structure ( void )
{
GDBusMessage * message ;
GVariantBuilder builder ;
gsize size = 0 ;
GError * local_error = NULL ;
g_test_summary ( " Test that empty structures are rejected when serializing. " ) ;
g_test_bug ( " https://gitlab.gnome.org/GNOME/glib/-/issues/2557 " ) ;
message = g_dbus_message_new ( ) ;
g_variant_builder_init ( & builder , G_VARIANT_TYPE ( " (a()) " ) ) ;
g_variant_builder_open ( & builder , G_VARIANT_TYPE ( " a() " ) ) ;
g_variant_builder_add ( & builder , " () " ) ;
g_variant_builder_close ( & builder ) ;
g_dbus_message_set_message_type ( message , G_DBUS_MESSAGE_TYPE_METHOD_CALL ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_PATH ,
g_variant_new_object_path ( " /path " ) ) ;
g_dbus_message_set_header ( message , G_DBUS_MESSAGE_HEADER_FIELD_MEMBER ,
g_variant_new_string ( " Member " ) ) ;
g_dbus_message_set_body ( message , g_variant_builder_end ( & builder ) ) ;
g_dbus_message_to_blob ( message , & size , G_DBUS_CAPABILITY_FLAGS_NONE , & local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_cmpstr ( local_error - > message , = = , " Empty structures (tuples) are not allowed in D-Bus " ) ;
g_clear_error ( & local_error ) ;
g_clear_object ( & message ) ;
}
2023-08-16 17:14:49 +02:00
static void
test_message_parse_missing_header ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
0x01 , /* message type (method call) */
0x00 , /* message flags (none) */
0x01 , /* major protocol version */
0x12 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields: */
0x24 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x01 , /* array key (PATH, required for method call messages) */
/* Variant array value: */
0x01 , /* signature length */
' o ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x01 , 0x00 , 0x00 , 0x00 ,
' / ' , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x30 , /* array key (MEMBER, required for method call messages; CORRUPTED from 0x03) */
/* Variant array value: */
0x01 , /* signature length */
' s ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x03 , 0x00 , 0x00 , 0x00 ,
' H ' , ' e ' , ' y ' , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x08 , /* array key (SIGNATURE) */
/* Variant array value: */
0x01 , /* signature length */
' g ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x02 , ' s ' , ' s ' , 0x00 ,
/* Some arbitrary valid content inside the message body: */
0x03 , 0x00 , 0x00 , 0x00 ,
' h ' , ' e ' , ' y ' , 0x00 ,
0x05 , 0x00 , 0x00 , 0x00 ,
' t ' , ' h ' , ' e ' , ' r ' , ' e ' , 0x00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
g_test_summary ( " Test that missing (required) headers prompt an error. " ) ;
g_test_bug ( " https://gitlab.gnome.org/GNOME/glib/-/issues/3061 " ) ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
static void
test_message_parse_invalid_header_type ( void )
{
const guint8 data [ ] = {
' l ' , /* little-endian byte order */
0x01 , /* message type (method call) */
0x00 , /* message flags (none) */
0x01 , /* major protocol version */
0x12 , 0x00 , 0x00 , 0x00 , /* body length (in bytes) */
0x20 , 0x20 , 0x20 , 0x20 , /* message serial */
/* a{yv} of header fields: */
0x24 , 0x00 , 0x00 , 0x00 , /* array length (in bytes), must be a multiple of 8 */
0x01 , /* array key (PATH, required for method call messages) */
/* Variant array value: */
0x01 , /* signature length */
' o ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x01 , 0x00 , 0x00 , 0x00 ,
' / ' , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x03 , /* array key (MEMBER, required for method call messages) */
/* Variant array value: */
0x01 , /* signature length */
' t ' , /* one complete type; CORRUPTED, MEMBER should be 's' */
0x00 , /* nul terminator */
/* (Padding to 64-bit alignment of 't)' */
0x00 , 0x00 , 0x00 , 0x00 ,
/* (Variant array value payload) */
' H ' , ' e ' , ' y ' , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 ,
0x08 , /* array key (SIGNATURE) */
/* Variant array value: */
0x01 , /* signature length */
' g ' , /* one complete type */
0x00 , /* nul terminator */
/* (Variant array value payload) */
0x02 , ' s ' , ' s ' , 0x00 ,
/* Some arbitrary valid content inside the message body: */
0x03 , 0x00 , 0x00 , 0x00 ,
' h ' , ' e ' , ' y ' , 0x00 ,
0x05 , 0x00 , 0x00 , 0x00 ,
' t ' , ' h ' , ' e ' , ' r ' , ' e ' , 0x00
} ;
gsize size = sizeof ( data ) ;
GDBusMessage * message = NULL ;
GError * local_error = NULL ;
g_test_summary ( " Test that the type of well-known headers is checked. " ) ;
g_test_bug ( " https://gitlab.gnome.org/GNOME/glib/-/issues/3061 " ) ;
message = g_dbus_message_new_from_blob ( ( guchar * ) data , size ,
G_DBUS_CAPABILITY_FLAGS_NONE ,
& local_error ) ;
g_assert_error ( local_error , G_IO_ERROR , G_IO_ERROR_INVALID_ARGUMENT ) ;
g_assert_null ( message ) ;
g_clear_error ( & local_error ) ;
}
2021-11-19 16:43:50 +01:00
/* ---------------------------------------------------------------------------------------------------- */
2010-05-06 20:13:59 +02:00
int
main ( int argc ,
char * argv [ ] )
{
2018-05-25 19:26:43 +02:00
g_setenv ( " LC_ALL " , " C " , TRUE ) ;
2010-08-04 20:38:51 +02:00
setlocale ( LC_ALL , " C " ) ;
2022-11-23 12:15:20 +01:00
g_test_init ( & argc , & argv , G_TEST_OPTION_ISOLATE_DIRS , NULL ) ;
2010-05-06 20:13:59 +02:00
2019-10-30 16:48:57 +01:00
g_test_add_func ( " /gdbus/message-serialize/basic " ,
test_message_serialize_basic ) ;
g_test_add_func ( " /gdbus/message-serialize/complex " ,
test_message_serialize_complex ) ;
g_test_add_func ( " /gdbus/message-serialize/invalid " ,
test_message_serialize_invalid ) ;
g_test_add_func ( " /gdbus/message-serialize/header-checks " ,
test_message_serialize_header_checks ) ;
2023-12-07 00:40:49 +01:00
g_test_add_func ( " /gdbus/message-serialize/header-checks/valid " ,
test_message_serialize_header_checks_valid ) ;
2019-10-30 16:48:57 +01:00
g_test_add_func ( " /gdbus/message-serialize/double-array " ,
test_message_serialize_double_array ) ;
2022-01-06 22:04:56 +01:00
g_test_add_func ( " /gdbus/message-serialize/empty-structure " ,
test_message_serialize_empty_structure ) ;
2019-10-30 16:48:57 +01:00
g_test_add_func ( " /gdbus/message-parse/empty-arrays-of-arrays " ,
test_message_parse_empty_arrays_of_arrays ) ;
2018-08-16 22:33:52 +02:00
g_test_add_func ( " /gdbus/message-parse/non-signature-header " ,
test_message_parse_non_signature_header ) ;
2018-09-18 16:17:44 +02:00
g_test_add_func ( " /gdbus/message-parse/empty-signature-header " ,
test_message_parse_empty_signature_header ) ;
g_test_add_func ( " /gdbus/message-parse/multiple-signature-header " ,
test_message_parse_multiple_signature_header ) ;
2018-11-14 15:23:19 +01:00
g_test_add_func ( " /gdbus/message-parse/over-long-signature-header " ,
test_message_parse_over_long_signature_header ) ;
2019-10-29 19:47:02 +01:00
g_test_add_func ( " /gdbus/message-parse/deep-header-nesting " ,
test_message_parse_deep_header_nesting ) ;
g_test_add_func ( " /gdbus/message-parse/deep-body-nesting " ,
test_message_parse_deep_body_nesting ) ;
2021-11-19 16:43:50 +01:00
g_test_add_func ( " /gdbus/message-parse/truncated " ,
test_message_parse_truncated ) ;
2022-01-06 22:04:56 +01:00
g_test_add_func ( " /gdbus/message-parse/empty-structure " ,
test_message_parse_empty_structure ) ;
2023-08-16 17:14:49 +02:00
g_test_add_func ( " /gdbus/message-parse/missing-header " ,
test_message_parse_missing_header ) ;
g_test_add_func ( " /gdbus/message-parse/invalid-header-type " ,
test_message_parse_invalid_header_type ) ;
2014-07-22 21:13:50 +02:00
2010-05-06 20:13:59 +02:00
return g_test_run ( ) ;
}