https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103217
Dominique Martinet <npfhrotynz-ptnqh.myvf at noclue dot notk.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Resolution|FIXED |--- Status|RESOLVED |REOPENED --- Comment #4 from Dominique Martinet <npfhrotynz-ptnqh.myvf at noclue dot notk.org> --- Thanks for the fix! I've compiled gcc from master and can confirm this fixes the warning for the example I provided... But unfortunately it doesn't fix it for my real application, so my reproducer was simplified too much :/ (It fails on this file: https://github.com/cea-hpc/coordinatool/blob/06c5e319e3c934256d51c2af3ba5f7551bac4bff/copytool/coordinatool.c , but this project requires lustre development headers to compile so it's not a good reproducer) Here's a new attempt, this also gives a similar warning without a precise location on gcc master: ------- #include <getopt.h> #include <stdlib.h> #include <string.h> char *xstrdup(const char *src) { char *val = strdup(src); if (!val) abort(); return val; } struct test { char *one, *two; }; int main(int argc, char *argv[]) { struct test *options = calloc(1, sizeof(*options)); int rc; if (!options) abort(); while ((rc = getopt(argc, argv, "a:b:")) != -1) { switch (rc) { case 'a': free(options->one); options->one = xstrdup(optarg); break; case 'b': free(options->two); options->two = xstrdup(optarg); break; } } free(options->one); free(options->two); free(options); return 0; } ------- ---- In function ‘main’: cc1: warning: leak of ‘<unknown>’ [CWE-401] [-Wanalyzer-malloc-leak] ‘main’: events 1-2 | |/tmp/t4.c:16:5: | 16 | int main(int argc, char *argv[]) { | | ^~~~ | | | | | (1) entry to ‘main’ |...... | 19 | if (!options) | | ~ | | | | | (2) following ‘false’ branch (when ‘options’ is non-NULL)... | ‘main’: event 3 | |cc1: | (3): ...to here | ‘main’: events 4-6 | | 22 | while ((rc = getopt(argc, argv, "a:b:")) != -1) { | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ | | | | | (4) following ‘true’ branch (when ‘rc != -1’)... | 23 | switch (rc) { | | ~~~~~~ | | | | | (5) ...to here |...... | 30 | options->two = xstrdup(optarg); | | ~~~~~~~~~~~~~~~ | | | | | (6) calling ‘xstrdup’ from ‘main’ | +--> ‘xstrdup’: events 7-11 | | 5 | char *xstrdup(const char *src) { | | ^~~~~~~ | | | | | (7) entry to ‘xstrdup’ | 6 | char *val = strdup(src); | | ~~~~~~~~~~~ | | | | | (8) allocated here | 7 | if (!val) | | ~ | | | | | (9) assuming ‘val’ is non-NULL | | (10) following ‘false’ branch (when ‘val’ is non-NULL)... | 8 | abort(); | 9 | return val; | | ~~~ | | | | | (11) ...to here | <------+ | ‘main’: event 12 | | 30 | options->two = xstrdup(optarg); | | ^~~~~~~~~~~~~~~ | | | | | (12) returning to ‘main’ from ‘xstrdup’ | ‘main’: event 13 | |cc1: | (13): ‘<unknown>’ leaks here; was allocated at (8) | ---- I'm not sure it's accurate enough for my usecase though: in my project the "option" struct is declared on the stack and not dynamically allocated... and I cannot reproduce with "struct test option = { 0 };" so I'm not sure where this is different; I'll try a bit more and update this ticket if I find a better reproducer. (What do you prefer to move forward -- I've tried reopening the bug but you really fixed something so should I open a new bz instead and keep this resolved?)