https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103217

--- Comment #5 from Dominique Martinet <npfhrotynz-ptnqh.myvf at noclue dot 
notk.org> ---
Ah, this apparently needed the unused fields in the struct, and the extra
config_init() call.

Here's something trimmed down from the actual program instead of building back
up:
-----
#define _POSIX_C_SOURCE 200809L

#include <getopt.h>
#include <stdlib.h>
#include <string.h>

struct state {
  const char *confpath;
  const char *host;
  const char *port;
  const char *state_dir_prefix;
};

static inline char *xstrdup(const char *s) { 
        char *val = strdup(s);
        if (!val)
                abort();
        return val;
}

int config_init(struct state *config);

int main(int argc, char *argv[]) { 
        int rc;
        struct state state = { 0 };

        config_init(&state);

        while ((rc = getopt(argc, argv, "H:p:")) != -1) { 
                switch (rc) { 
                case 'H':
                        free((void*)state.host);
                        state.host = xstrdup(optarg);
                        break;
                case 'p':
                        free((void*)state.port);
                        state.port = xstrdup(optarg);
                        break;
                } 
        } 

        free((void*)state.host);
        free((void*)state.port);
        return rc;
}
-----

-----
 /opt/gcc/bin/gcc -fanalyzer -c ../copytool/coordinatool.c
In function ‘main’:
cc1: warning: leak of ‘<unknown>’ [CWE-401] [-Wanalyzer-malloc-leak]
  ‘main’: events 1-4
    |
    |../copytool/coordinatool.c:25:5:
    |   25 | int main(int argc, char *argv[]) {
    |      |     ^~~~
    |      |     |
    |      |     (1) entry to ‘main’
    |......
    |   31 |         while ((rc = getopt(argc, argv, "H:p:")) != -1) {
    |      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                                  |
    |      |                                                  (2) following
‘true’ branch (when ‘rc != -1’)...
    |   32 |                 switch (rc) {
    |      |                 ~~~~~~
    |      |                 |
    |      |                 (3) ...to here
    |......
    |   39 |                         state.port = xstrdup(optarg);
    |      |                                      ~~~~~~~~~~~~~~~
    |      |                                      |
    |      |                                      (4) calling ‘xstrdup’ from
‘main’
    |
    +--> ‘xstrdup’: events 5-9
           |
           |   16 | static inline char *xstrdup(const char *s) {
           |      |                     ^~~~~~~
           |      |                     |
           |      |                     (5) entry to ‘xstrdup’
           |   17 |         char *val = strdup(s);
           |      |                     ~~~~~~~~~
           |      |                     |
           |      |                     (6) allocated here
           |   18 |         if (!val)
           |      |            ~         
           |      |            |
           |      |            (7) assuming ‘val’ is non-NULL
           |      |            (8) following ‘false’ branch (when ‘val’ is
non-NULL)...
           |   19 |                 abort();
           |   20 |         return val;
           |      |                ~~~   
           |      |                |
           |      |                (9) ...to here
           |
    <------+
    |
  ‘main’: event 10
    |
    |   39 |                         state.port = xstrdup(optarg);
    |      |                                      ^~~~~~~~~~~~~~~
    |      |                                      |
    |      |                                      (10) returning to ‘main’ from
‘xstrdup’
    |
  ‘main’: event 11
    |
    |cc1:
    | (11): ‘<unknown>’ leaks here; was allocated at (6)
    |
-----

Thanks!

Reply via email to