Merge branch 'wip/3v1n0/sanitizer-memory-fixes' into 'main'

Memory sanitizer fixes

See merge request GNOME/glib!4484
This commit is contained in:
Philip Withnall
2025-04-03 13:04:05 +00:00
12 changed files with 88 additions and 27 deletions

View File

@@ -539,7 +539,7 @@ test_connection_signal_handler (GDBusConnection *connection,
/* We defer quitting to a G_PRIORITY_DEFAULT_IDLE function so other queued signal
* callbacks have a chance to run first. They get dispatched with a higher priority
* of G_PIORITY_DEFAULT, so as long as the queue is non-empty g_main_loop_quit won't
* of G_PRIORITY_DEFAULT, so as long as the queue is non-empty g_main_loop_quit won't
* run
*/
g_idle_add_once ((GSourceOnceFunc) g_main_loop_quit, loop);

View File

@@ -1960,6 +1960,17 @@ test_threaded_unregistration_iteration (gboolean subtree)
g_clear_object (&call_result);
g_clear_object (&data.connection);
/* We defer quitting to a G_PRIORITY_DEFAULT_IDLE function so other queued
* signal callbacks have a chance to run first.
* In particular we want to ensure that all calls to on_object_unregistered()
* are delivered here before we end this function, so that there won't be any
* invalid stack access.
* They get dispatched with a higher priority (G_PRIORITY_DEFAULT), so as
* long as the queue is non-empty g_main_loop_quit won't run
*/
g_idle_add_once ((GSourceOnceFunc) g_main_loop_quit, loop);
g_main_loop_run (loop);
return unregistration_was_first;
}

View File

@@ -219,6 +219,7 @@ main (int argc, char **argv)
g_fprintf (stderr, "%s\n", message);
g_free (message);
gi_ir_parser_free (parser);
g_error_free (error);
return 1;
}
@@ -229,6 +230,7 @@ main (int argc, char **argv)
{
GITypelib *typelib = NULL;
int write_successful;
if (shlibs)
{
@@ -246,10 +248,14 @@ main (int argc, char **argv)
g_error (_("Invalid typelib for module %s: %s"),
module->name, error->message);
if (!write_out_typelib (NULL, typelib))
return 1;
write_successful = write_out_typelib (NULL, typelib);
g_clear_pointer (&typelib, gi_typelib_unref);
if (!write_successful)
{
gi_ir_parser_free (parser);
return 1;
}
}
g_debug ("[building] done");

View File

@@ -2312,7 +2312,7 @@ end_type_top (ParseContext *ctx)
if (!ctx->type_parameters)
goto out;
typenode = (GIIrNodeType*)ctx->type_parameters->data;
typenode = (GIIrNodeType *) g_steal_pointer (&ctx->type_parameters->data);
/* Default to pointer for unspecified containers */
if (typenode->tag == GI_TYPE_TAG_ARRAY ||
@@ -2336,32 +2336,32 @@ end_type_top (ParseContext *ctx)
case GI_IR_NODE_PARAM:
{
GIIrNodeParam *param = (GIIrNodeParam *)ctx->current_typed;
param->type = typenode;
param->type = g_steal_pointer (&typenode);
}
break;
case GI_IR_NODE_FIELD:
{
GIIrNodeField *field = (GIIrNodeField *)ctx->current_typed;
field->type = typenode;
field->type = g_steal_pointer (&typenode);
}
break;
case GI_IR_NODE_PROPERTY:
{
GIIrNodeProperty *property = (GIIrNodeProperty *) ctx->current_typed;
property->type = typenode;
property->type = g_steal_pointer (&typenode);
}
break;
case GI_IR_NODE_CONSTANT:
{
GIIrNodeConstant *constant = (GIIrNodeConstant *)ctx->current_typed;
constant->type = typenode;
constant->type = g_steal_pointer (&typenode);
}
break;
default:
g_printerr("current node is %d\n", CURRENT_NODE (ctx)->type);
g_assert_not_reached ();
}
g_list_free (ctx->type_parameters);
g_list_free_full (ctx->type_parameters, (GDestroyNotify) gi_ir_node_free);
out:
ctx->type_depth = 0;
@@ -2377,7 +2377,7 @@ end_type_recurse (ParseContext *ctx)
parent = (GIIrNodeType *) ((GList*)ctx->type_stack->data)->data;
if (ctx->type_parameters)
param = (GIIrNodeType *) ctx->type_parameters->data;
param = (GIIrNodeType *) g_steal_pointer (&ctx->type_parameters->data);
if (parent->tag == GI_TYPE_TAG_ARRAY ||
parent->tag == GI_TYPE_TAG_GLIST ||
@@ -2386,7 +2386,7 @@ end_type_recurse (ParseContext *ctx)
g_assert (param != NULL);
if (parent->parameter_type1 == NULL)
parent->parameter_type1 = param;
parent->parameter_type1 = g_steal_pointer (&param);
else
g_assert_not_reached ();
}
@@ -2395,13 +2395,14 @@ end_type_recurse (ParseContext *ctx)
g_assert (param != NULL);
if (parent->parameter_type1 == NULL)
parent->parameter_type1 = param;
parent->parameter_type1 = g_steal_pointer (&param);
else if (parent->parameter_type2 == NULL)
parent->parameter_type2 = param;
parent->parameter_type2 = g_steal_pointer (&param);
else
g_assert_not_reached ();
}
g_list_free (ctx->type_parameters);
g_clear_pointer ((GIIrNode **) &param, gi_ir_node_free);
g_list_free_full (ctx->type_parameters, (GDestroyNotify) gi_ir_node_free);
ctx->type_parameters = (GList *)ctx->type_stack->data;
ctx->type_stack = g_list_delete_link (ctx->type_stack, ctx->type_stack);
}

View File

@@ -123,12 +123,19 @@ g_bytes_new (gconstpointer data,
{
g_return_val_if_fail (data != NULL || size == 0, NULL);
if (data == NULL || size == 0)
{
g_assert (data != NULL || size == 0);
return g_bytes_new_with_free_func (NULL, size, NULL, NULL);
}
if (size <= G_BYTES_MAX_INLINE)
{
GBytesInline *bytes;
bytes = g_malloc (sizeof *bytes + size);
bytes->bytes.data = (data != NULL && size > 0) ? bytes->inline_data : NULL;
bytes->bytes.data = bytes->inline_data;
bytes->bytes.size = size;
bytes->bytes.free_func = NULL;
bytes->bytes.user_data = NULL;

View File

@@ -26,6 +26,7 @@
#include "garray.h"
#include "genviron.h"
#include "ghash.h"
#include "glib-private.h"
#include "gmessages.h"
#include "gstrfuncs.h"
#include "gthread.h"
@@ -807,6 +808,7 @@ g_get_language_names_with_category (const gchar *category_name)
cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, language_names_cache_free);
g_private_set (&cache_private, cache);
g_ignore_leak (cache);
}
languages = guess_category_value (category_name);
@@ -835,6 +837,7 @@ g_get_language_names_with_category (const gchar *category_name)
name_cache->languages = g_strdup (languages);
name_cache->language_names = (gchar **) g_ptr_array_free (array, FALSE);
g_hash_table_insert (cache, g_strdup (category_name), name_cache);
g_ignore_leak (name_cache);
}
return (const gchar * const *) name_cache->language_names;

View File

@@ -100,7 +100,7 @@ g_leak_sanitizer_is_supported (void)
#if defined (_GLIB_ADDRESS_SANITIZER)
return TRUE;
#elif defined (HAS_DYNAMIC_ASAN_LOADING)
return __lsan_enable != NULL && __lsan_ignore_object != NULL;
return G_UNLIKELY (__lsan_enable != NULL && __lsan_ignore_object != NULL);
#else
return FALSE;
#endif
@@ -122,7 +122,7 @@ g_ignore_leak (gconstpointer p)
if (p != NULL)
__lsan_ignore_object (p);
#elif defined (HAS_DYNAMIC_ASAN_LOADING)
if (p != NULL && __lsan_ignore_object != NULL)
if (G_LIKELY (p != NULL) && G_UNLIKELY (__lsan_ignore_object != NULL))
__lsan_ignore_object (p);
#endif
}
@@ -166,7 +166,7 @@ g_begin_ignore_leaks (void)
#if defined (_GLIB_ADDRESS_SANITIZER)
__lsan_disable ();
#elif defined (HAS_DYNAMIC_ASAN_LOADING)
if (__lsan_disable != NULL)
if (G_UNLIKELY (__lsan_disable != NULL))
__lsan_disable ();
#endif
}
@@ -183,7 +183,7 @@ g_end_ignore_leaks (void)
#if defined (_GLIB_ADDRESS_SANITIZER)
__lsan_enable ();
#elif defined (HAS_DYNAMIC_ASAN_LOADING)
if (__lsan_enable != NULL)
if (G_UNLIKELY (__lsan_enable != NULL))
__lsan_enable ();
#endif
}

View File

@@ -2778,6 +2778,8 @@ should_drop_message (GLogLevelFlags log_level,
if (log_domain == NULL)
{
log_domain_length = 0;
for (i = 0; i < n_fields; i++)
{
if (g_strcmp0 (fields[i].key, "GLIB_DOMAIN") == 0)

View File

@@ -40,6 +40,7 @@
#include "config.h"
#include "glib-private.h"
#include "gthread.h"
#include "gthreadprivate.h"
@@ -505,10 +506,11 @@ static GPrivate g_thread_specific_private = G_PRIVATE_INIT (g_thread_cleanup
*
* Sets the thread local variable @key to have a newly-allocated and zero-filled
* value of given @size, and returns a pointer to that memory. Allocations made
* using this API will be suppressed in valgrind: it is intended to be used for
* one-time allocations which are known to be leaked, such as those for
* per-thread initialisation data. Otherwise, this function behaves the same as
* g_private_set().
* using this API will be suppressed in valgrind (when the GLib default
* suppression file, `glib.supp`, is used) and leak sanitizer: it is intended to
* be used for one-time allocations which are known to be leaked, such as those
* for per-thread initialisation data. Otherwise, this function behaves the same
* as g_private_set().
*
* Returns: (transfer full): new thread-local heap allocation of size @size
* Since: 2.60
@@ -520,6 +522,7 @@ g_private_set_alloc0 (GPrivate *key,
{
gpointer allocated = g_malloc0 (size);
g_ignore_leak (allocated);
g_private_set (key, allocated);
return g_steal_pointer (&allocated);

View File

@@ -1415,6 +1415,8 @@ void
g_variant_store (GVariant *value,
gpointer data)
{
g_return_if_fail (data != NULL);
g_variant_lock (value);
if (value->state & STATE_SERIALISED)

View File

@@ -6187,12 +6187,16 @@ g_variant_byteswap (GVariant *value)
GVariantTypeInfo *type_info;
guint alignment;
GVariant *new;
gsize size = 0;
type_info = g_variant_get_type_info (value);
g_variant_type_info_query (type_info, &alignment, NULL);
if (alignment && g_variant_is_normal_form (value))
if (alignment)
size = g_variant_get_size (value);
if (size > 0 && g_variant_is_normal_form (value))
{
/* (potentially) contains multi-byte numeric data, but is also already in
* normal form so we can use a faster byteswapping codepath on the
@@ -6201,7 +6205,7 @@ g_variant_byteswap (GVariant *value)
GBytes *bytes;
serialised.type_info = g_variant_get_type_info (value);
serialised.size = g_variant_get_size (value);
serialised.size = size;
serialised.data = g_malloc (serialised.size);
serialised.depth = g_variant_get_depth (value);
serialised.ordered_offsets_up_to = G_MAXSIZE; /* operating on the normal form */

View File

@@ -2327,7 +2327,15 @@ test_byteswap (void)
* often makes something non-normal but still readable. */
three_size_copy = three.size + 1;
three_data_copy = g_malloc (three_size_copy);
memcpy (three_data_copy, three.data, three.size);
if (three.data)
{
g_assert_cmpuint (three.size, !=, 0);
memcpy (three_data_copy, three.data, three.size);
}
else
{
g_assert_cmpuint (three.size, ==, 0);
}
three_data_copy[three.size] = '\0';
three_variant = g_variant_new_from_data (G_VARIANT_TYPE (g_variant_type_info_get_type_string (three.type_info)),
@@ -2367,6 +2375,19 @@ test_byteswaps (void)
g_variant_type_info_assert_no_infos ();
}
static void
test_byteswap_zero_sized (void)
{
GVariant *variant;
GVariant *swapped;
variant = g_variant_new_from_data (G_VARIANT_TYPE_STRING, NULL, 0, TRUE, NULL, NULL);
swapped = g_variant_byteswap (variant);
g_variant_unref (variant);
g_variant_unref (swapped);
}
static void
test_serialiser_children (void)
{
@@ -5939,6 +5960,7 @@ main (int argc, char **argv)
g_test_add_func ("/gvariant/serialiser/variant", test_variants);
g_test_add_func ("/gvariant/serialiser/strings", test_strings);
g_test_add_func ("/gvariant/serialiser/byteswap", test_byteswaps);
g_test_add_func ("/gvariant/serialiser/byteswap/zero-sized", test_byteswap_zero_sized);
g_test_add_func ("/gvariant/serialiser/children", test_serialiser_children);
for (i = 1; i <= 20; i += 4)