Repository navigation
Conversation
The data given to g_idle_add(), g_timeout_add() and their _seconds/_full variants is passed to the callback (and the destroy notify), which usually frees it. With <leak-ignore/> every such call was reported as Memory leak: data Configure them as <use> instead.
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
This PR causes a new false negative: leaks of a GMainContext passed to g_main_context_invoke / g_main_context_invoke_full are no longer reported. CheckLeakAutoVarImpl::functionCall applies a <use> function to every plain pointer variable in the call, because <use> has no argument number. So g_main_context_invoke(ctx, cb, NULL) now marks the context in ctx as taken over. That context comes from g_main_context_new(), which is in the g_main_context_unref group. GLib does not take ownership of the context; it only refs it internally. The base config reports Memory leak: ctx for this code; the PR does not. g_idle_add* and g_timeout_add* don't have this problem, because their only pointer parameters are the callback, the data and the destroy notify.
The memleak false positives that the PR is about are gone, and test/cfg/gtk.c passes. The new <arg> configuration for g_main_context_invoke* works: it reports a NULL callback as nullPointer and an uninitialized callback or priority as uninitvar.
Testing
Build: make -j8 cppcheck testrunner in pr/ succeeded.
cfg test: I ran test/cfg/gtk.c with the runtests.sh options (--check-library --platform=unix64 --enable=style,information --inconclusive --force --check-level=exhaustive --inline-suppr ... --library=gtk).
- With the PR's
gtk.cfg: clean, exit code 0. - With the base
gtk.cfg: 8memleakerrors in the new test functions. So the test does cover the change.
Regression found (I compared the PR's cfg with a copy of base's gtk.cfg, both run with the PR binary, since only the cfg changed):
static gboolean cb(gpointer data) { g_free(data); return FALSE; }
void ctx_leak(void)
{
GMainContext *ctx = g_main_context_new();
g_main_context_invoke(ctx, cb, NULL);
}
void ctx_ok(void)
{
GMainContext *ctx = g_main_context_new();
g_main_context_invoke(ctx, cb, NULL);
g_main_context_unref(ctx);
}$ cppcheck -q --library=/tmp/b/gtkbase.cfg t2.c
t2.c:16:1: error: Memory leak: ctx [memleak]
$ cppcheck -q --library=pr/cfg/gtk.cfg t2.c
(no output)
g_main_context_invoke_full(ctx, 0, cb, NULL, NULL) behaves the same way: base reports the leak, the PR does not.
Other checks:
g_main_context_invoke(NULL, NULL, NULL)now givesnullPointer, and an uninitialized callback or priority givesuninitvar.- A
malloc'd org_new'd pointer passed as the data is no longer reported, and no mismatch is reported either. - A conditional
if (x) g_idle_add(cb, p);is no longer reported. That matches howif (x) g_free(p);is already handled, so I don't count it as a problem of this PR.
Automated review of 51b97a0 by Claude. The pull request was built and tested locally.
| <use>g_register_data</use> | ||
| <use>g_idle_add</use> | ||
| <use>g_idle_add_full</use> | ||
| <use>g_main_context_invoke</use> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Thanks, you're right: applies to every pointer argument, so g_main_context_invoke(ctx, ...) hid a leak of ctx. I dropped g_main_context_invoke and g_main_context_invoke_full from this PR; they keep for now.
51b97a0 to
46f1427
Compare
dmcppcheck
left a comment
There was a problem hiding this comment.
AI review
The earlier problem is fixed: the PR no longer touches g_main_context_invoke*, so a leaked GMainContext is reported again. The memleak false positives that the PR is about are gone, and test/cfg/gtk.c passes.
New finding (minor false negative): removing <leak-ignore/> also removes the use-after-free check for these calls. With base, g_free(p); g_idle_add(cb, p); gives deallocuse. With the PR it gives nothing. In CheckLeakAutoVarImpl::functionCall, only leak-ignore functions go through checkTokenInsideExpression; a <use> function only changes the pointer's alloc status. Every <use> function behaves this way, so this is a trade-off of the approach rather than a bug in the cfg. It could still be pinned down with a test in test/cfg/gtk.c. I found no other problems.
Earlier comments
| # | Comment | By | Where | Status |
|---|---|---|---|---|
| 1 | on g_main_context_invoke* hides leaks of the GMainContext argument | AI review | cfg/gtk.cfg:722 |
❔ Code removed |
Testing
Build: make -j8 cppcheck in pr/ succeeded. Only the cfg changed, so I compared the PR's cfg/gtk.cfg with a copy of base's gtk.cfg, both run with the PR binary.
cfg test: I ran test/cfg/gtk.c with the runtests.sh options (--check-library --inline-suppr --error-exitcode=1 ... --library=gtk). It was clean, exit code 0.
Scratch test (scratch/t.c):
#include <glib.h>
#include <stdlib.h>
static gboolean cb(gpointer d){g_free(d);return FALSE;}
void a(void){ gchar *p=g_strdup("x"); g_idle_add(cb,p); g_free(p); }
void b(void){ gchar *p=g_strdup("x"); g_free(p); g_idle_add(cb,p); }
void c(void){ char *p=malloc(3); g_idle_add(cb,p); free(p); }
void d(void){ gchar *p=g_strdup("x"); gchar *q=g_strdup("y"); g_timeout_add(1,cb,p); }
void e(int x){ gchar *p=g_strdup("x"); if(x) return; g_idle_add(cb,p); }
void f(void){ g_idle_add(cb,g_strdup("x")); }
void g(void){ GMainContext *ctx=g_main_context_new(); g_main_context_invoke(ctx,cb,NULL);}
void h(void){ gchar *p=g_strdup("x"); g_idle_add_full(0,cb,p,g_free); g_free(p);}$ cppcheck -q --library=gtkbase.cfg --template='{line}:{id}:{message}' t.c
5:deallocuse:Dereferencing 'p' after it is deallocated / released
7:memleak:Memory leak: p
7:memleak:Memory leak: q
8:memleak:Memory leak: p
10:memleak:Memory leak: ctx
9:leakNoVarFunctionCall:Allocation with g_strdup, g_idle_add doesn't release it.
$ cppcheck -q --library=pr/cfg/gtk.cfg --template='{line}:{id}:{message}' t.c
7:memleak:Memory leak: q
8:memleak:Memory leak: p
10:memleak:Memory leak: ctx
- Lines 7, 8 and 9: the PR removes the intended false positives. The real leaks (
q, and the early-return path) are still reported. - Line 10: the
GMainContextleak from the earlier review is reported again. - Line 5: the
deallocusewarning (use after free) is lost, which is the new false negative. - Lines 4 and 11: the double free through the callback is not reported, with base or with the PR.
Automated review of 46f1427 by Claude. The pull request was built and tested locally.
| <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> |
There was a problem hiding this comment.
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.
I don't have a Trac account, so there is no ticket for this; the details are below. Feel free to create one and I'll add it to the title.
GLib passes the data to the callback, and to the destroy notify of the
_fullvariants, which commonly frees it, so there is no leak. gtk.cfg marked these functions<leak-ignore/>:g_idle_add,g_idle_add_fullg_timeout_add,g_timeout_add_seconds,g_timeout_add_full,g_timeout_add_seconds_fullThey are now
<use>in theg_freememory group, without<leak-ignore/>. Their only pointer arguments are the callback, the data and the destroy notify, so<use>can't hide another leak.This is the gtk.cfg change that #8953 (#15137) was made for: without that fix,
--check-librarystill reportedcheckLibraryUseIgnorefor these functions. Here<use>means what the reference describes: the function takes over the pointer.Tests:
test/cfg/gtk.ccovers all six functions; the memleak false positives show without the change.cfg/gtk.cfgvalidates againstcppcheck-cfg.rng.