Skip to content
Merged
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
16 changes: 9 additions & 7 deletions cfg/gtk.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,12 @@
<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>

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

Taking these functions off <leak-ignore/> also turns off the use-after-free check for their arguments. CheckLeakAutoVarImpl::functionCall calls checkTokenInsideExpression only for leak-ignore functions; a <use> function only gets changeAllocStatus. As a result:

void b(void){ gchar *p=g_strdup("x"); g_free(p); g_idle_add(cb,p); }

Base reports deallocuse: Dereferencing 'p' after it is deallocated / released. With this PR nothing is reported. This is how <use> works in general, so it may be acceptable, but it is a new false negative for these six functions.

<use>g_idle_add_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,19 +4243,17 @@
</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">
<not-null/>
</arg>
<arg nr="2" direction="in">
<arg nr="2">
<not-uninit/>
</arg>
</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 +5656,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 @@ -5663,13 +5666,12 @@
<not-uninit/>
<not-null/>
</arg>
<arg nr="3" direction="in">
<arg nr="3">
<not-uninit/>
</arg>
</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 All @@ -5684,7 +5686,7 @@
<not-uninit/>
<not-null/>
</arg>
<arg nr="4" direction="in">
<arg nr="4">
<not-uninit/>
</arg>
<arg nr="5" direction="in">
Expand Down
47 changes: 47 additions & 0 deletions test/cfg/gtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -730,3 +730,50 @@ 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)
{
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_timeout_add_takes_data_test(void)
{
gchar *data = g_strdup("data");
g_timeout_add(10, source_func_frees_data, data);

gchar *data_seconds = g_strdup("data");
g_timeout_add_seconds(1, source_func_frees_data, data_seconds);

gchar *data_full = g_strdup("data");
g_timeout_add_full(0, 10, source_func_frees_data, data_full, destroy_notify_frees_data);

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);
}

// Handing over data that is already freed is a use after free.
// TODO: <use> functions don't get the deallocuse check yet.
void g_idle_add_freed_data_test(void)
{
gchar *data = g_strdup("data");
g_free(data);
// TODO cppcheck-suppress deallocuse
g_idle_add(source_func_frees_data, data);
}
Loading