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

            Bug ID: 101550
           Summary: -Wanalyzer-file-leak false positive with an array of
                    pointers, open and fdopen.
           Product: gcc
           Version: 11.1.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: analyzer
          Assignee: dmalcolm at gcc dot gnu.org
          Reporter: amatej at redhat dot com
  Target Milestone: ---

Hello, I have the following program:
----------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

typedef struct {
    FILE *foo_file;
} Foo;

FILE*
open_target_file()
{
    int fd = open("some.txt", O_CREAT|O_TRUNC|O_RDWR, 0666);
    if (fd == -1) {
        return NULL;
    }

    FILE *f = fdopen(fd, "w+b");
    if (f == NULL) {
        close(fd);
        return NULL;
    }

    return f;
}

void
prepare_next_transfer(Foo **targets)
{
    Foo *a1 = targets[0];

    a1->foo_file = open_target_file();

    if (a1->foo_file != NULL) {
        fclose(a1->foo_file);
    }
}

int
main() {
    Foo a1 = {NULL};
    Foo *data[] = {&a1, NULL};
    prepare_next_transfer(data);
}
----------------------------------------------------------

When I run:
$ gcc program.c -fanalyzer
I get:

In function ‘prepare_next_transfer’:
program.c:34:11: warning: leak of ‘f’ [CWE-401] [-Wanalyzer-malloc-leak]
   34 |     if (a1->foo_file != NULL) {
      |         ~~^~~~~~~~~~
  ‘prepare_next_transfer’: events 1-2
    |
    |   28 | prepare_next_transfer(Foo **data)
    |      | ^~~~~~~~~~~~~~~~~~~~~
    |      | |
    |      | (1) entry to ‘prepare_next_transfer’
    |......
    |   32 |     a1->foo_file = open_target_file();
    |      |                    ~~~~~~~~~~~~~~~~~~
    |      |                    |
    |      |                    (2) calling ‘open_target_file’ from
‘prepare_next_transfer’
    |
    +--> ‘open_target_file’: events 3-9
           |
           |   11 | open_target_file()
           |      | ^~~~~~~~~~~~~~~~
           |      | |
           |      | (3) entry to ‘open_target_file’
           |......
           |   14 |     if (fd == -1) {
           |      |        ~
           |      |        |
           |      |        (4) following ‘false’ branch (when ‘fd != -1’)...
           |......
           |   18 |     FILE *f = fdopen(fd, "w+b");
           |      |               ~~~~~~~~~~~~~~~~~
           |      |               |
           |      |               (5) ...to here
           |      |               (6) allocated here
           |   19 |     if (f == NULL) {
           |      |        ~
           |      |        |
           |      |        (7) assuming ‘f’ is non-NULL
           |      |        (8) following ‘false’ branch (when ‘f’ is
non-NULL)...
           |......
           |   24 |     return f;
           |      |            ~
           |      |            |
           |      |            (9) ...to here
           |
    <------+
    |
  ‘prepare_next_transfer’: events 10-11
    |
    |   32 |     a1->foo_file = open_target_file();
    |      |                    ^~~~~~~~~~~~~~~~~~
    |      |                    |
    |      |                    (10) returning to ‘prepare_next_transfer’ from
‘open_target_file’
    |   33 |
    |   34 |     if (a1->foo_file != NULL) {
    |      |         ~~~~~~~~~~~~
    |      |           |
    |      |           (11) ‘f’ leaks here; was allocated at (6)
    |

I think this is a false positive since ‘f’ is returned from ‘open_target_file’
assigned to ‘a1->foo_file‘ and fclosed, there should be no leak.

It goes away if fopen is used instead of open and fdopen or if the array of
pointers is not used.

I am using gcc-11.1.1-6.fc35.x86_64.

Thank you for your work.

Reply via email to