Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions cfg/gtk.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,14 @@
<alloc init="true" no-fail="true">g_variant_type_dup_string</alloc>
<alloc init="true" no-fail="true">g_value_dup_string</alloc>
<use>g_register_data</use>
<use>g_idle_add</use>
<use>g_idle_add_full</use>
<use>g_main_context_invoke</use>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI review

<use> has no argument number. CheckLeakAutoVarImpl::functionCall treats every plain pointer variable in a non-leak-ignore call as taken over, and that includes the GMainContext *context argument. As a result, this leak is no longer found (base reports Memory leak: ctx, the PR reports nothing):

void f(void) {
    GMainContext *ctx = g_main_context_new();
    g_main_context_invoke(ctx, cb, NULL);
}

The same happens with g_main_context_invoke_full. GLib does not take ownership of the context. Consider adding a test/cfg/gtk.c case with // cppcheck-suppress memleak for this, and fixing it in the library or check, for example with a per-argument <use>/ownership setting. Otherwise, consider leaving the g_main_context_invoke* functions out of this change.

<use>g_main_context_invoke_full</use>
<use>g_timeout_add</use>
<use>g_timeout_add_full</use>
<use>g_timeout_add_seconds</use>
<use>g_timeout_add_seconds_full</use>
<dealloc>g_free</dealloc>
</memory>
<memory>
Expand Down Expand Up @@ -4237,7 +4245,6 @@
</function>
<!--guint g_idle_add (GSourceFunc function, gpointer data); -->
<function name="g_idle_add">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="guint"/>
<arg nr="1" direction="in">
Expand All @@ -4249,7 +4256,6 @@
</function>
<!--guint g_idle_add_full (gint priority, GSourceFunc function, gpointer data, GDestroyNotify notify); -->
<function name="g_idle_add_full">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="guint"/>
<arg nr="1">
Expand Down Expand Up @@ -5652,7 +5658,6 @@
<!-- guint g_timeout_add ( guint interval, GSourceFunc function, gpointer data) -->
<!-- guint g_timeout_add_seconds ( guint interval, GSourceFunc function, gpointer data) -->
<function name="g_timeout_add,g_timeout_add_seconds">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="guint"/>
<arg nr="1" direction="in">
Expand All @@ -5669,7 +5674,6 @@
</function>
<!-- guint g_timeout_add_full (gint priority, guint interval, GSourceFunc function, gpointer data, GDestroyNotify notify) -->
<function name="g_timeout_add_full,g_timeout_add_seconds_full">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="guint"/>
<arg nr="1" direction="in">
Expand Down Expand Up @@ -6996,13 +7000,31 @@
<leak-ignore/>
<noreturn>false</noreturn>
</function>
<!-- void g_main_context_invoke (GMainContext *context, GSourceFunc function, gpointer data); -->
<function name="g_main_context_invoke">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="void"/>
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-uninit/>
<not-null/>
</arg>
<arg nr="3" direction="in"/>
</function>
<!-- void g_main_context_invoke_full (GMainContext *context, gint priority, GSourceFunc function, gpointer data, GDestroyNotify notify); -->
<function name="g_main_context_invoke_full">
<leak-ignore/>
<noreturn>false</noreturn>
<returnValue type="void"/>
<arg nr="1" direction="in"/>
<arg nr="2" direction="in">
<not-uninit/>
</arg>
<arg nr="3" direction="in">
<not-uninit/>
<not-null/>
</arg>
<arg nr="4" direction="in"/>
<arg nr="5" direction="in"/>
</function>
<function name="g_main_context_is_owner">
<leak-ignore/>
Expand Down
53 changes: 53 additions & 0 deletions test/cfg/gtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,3 +730,56 @@ int g_define_enum_and_flags_type_test(void) {
return e + f;
}
#endif

static gboolean source_func_frees_data(gpointer data)
{
g_free(data);
return FALSE;
}

static void destroy_notify_frees_data(gpointer data)
{
g_free(data);
}

// The data passed to a GSource is owned by the callback or the destroy notify
// from then on, so it does not leak.
void g_idle_add_takes_data_test(void)
{
// cppcheck-suppress constVariablePointer
gchar *data = g_strdup("data");
g_idle_add(source_func_frees_data, data);

gchar *data_full = g_strdup("data");
g_idle_add_full(200, source_func_frees_data, data_full, NULL);
}

void g_main_context_invoke_takes_data_test(void)
{
// cppcheck-suppress constVariablePointer
gchar *data = g_strdup("data");
g_main_context_invoke(NULL, source_func_frees_data, data);

// cppcheck-suppress constVariablePointer
gchar *data_full = g_strdup("data");
g_main_context_invoke_full(NULL, 0, source_func_frees_data, data_full, destroy_notify_frees_data);
}

void g_timeout_add_takes_data_test(void)
{
// cppcheck-suppress constVariablePointer
gchar *data = g_strdup("data");
g_timeout_add(10, source_func_frees_data, data);

// cppcheck-suppress constVariablePointer
gchar *data_seconds = g_strdup("data");
g_timeout_add_seconds(1, source_func_frees_data, data_seconds);

// cppcheck-suppress constVariablePointer
gchar *data_full = g_strdup("data");
g_timeout_add_full(0, 10, source_func_frees_data, data_full, destroy_notify_frees_data);

// cppcheck-suppress constVariablePointer
gchar *data_seconds_full = g_strdup("data");
g_timeout_add_seconds_full(0, 1, source_func_frees_data, data_seconds_full, destroy_notify_frees_data);
}
Loading