Thomas Schwinge wrote:
       FILE *f = fopen ("/sys/devices/system/node/online", "r");
       if (f == NULL)
         goto fail;
       char *lineptr = NULL;
     [...]
     fail:
       free (lineptr);

That happens when changing when happens during cleanup and
changing how many cleanup goto targets are.

Well spotted!

       char *lineptr = NULL;
       size_t nline;
       if (getline (&lineptr, &nline, f) <= 0)
     [...]

The 'getline' API states:

|  -- Function: ssize_t getline (char **LINEPTR, size_t *N, FILE *STREAM)
| [...]
|      If you set ‘*LINEPTR’ to a null pointer, and ‘*N’ to zero, before
|      the call, then ‘getline’ allocates the initial buffer [...]

..., so we should initialize 'nline' to zero.

This does not match the specification:

"The application shall ensure that *lineptr is a valid argument that
 could be passed to the free() function. If *n is non-zero, the
 application shall ensure that *lineptr either points to an object
 of size at least *n bytes, or is a null pointer.

 If *lineptr is a null pointer or if the object pointed to by *lineptr
 is of insufficient size, an object shall be allocated as if by malloc()"

Thus, if lineptr == NULL, the value of 'n' (alias 'nline') does not
matter.

See POSIX, i.e.IEEE Std 1003.1-2024
https://pubs.opengroup.org/onlinepubs/9799919799/functions/getdelim.html

* * *

        PR libgomp/125877
        libgomp/
        * config/linux/numa.c (gomp_get_numa_distance): Move 'lineptr'
        initialization earlier, fix 'getline' call, avoid double 'free'.
---
  libgomp/config/linux/numa.c | 5 ++---
  1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/libgomp/config/linux/numa.c b/libgomp/config/linux/numa.c
index 85214e56dc41..e092f398540f 100644
--- a/libgomp/config/linux/numa.c
+++ b/libgomp/config/linux/numa.c
@@ -87,14 +87,13 @@ retry:
    /* Obtain numa nodes.  */
num = 0;
+  char *lineptr = NULL;
    FILE *f = fopen ("/sys/devices/system/node/online", "r");
    if (f == NULL)
      goto fail;
-  char *lineptr = NULL;
-  size_t nline;
+  size_t nline = 0;

I think it looks more consistent if nline's declaration is placed
next to the lineptr's one, which means also moving it before FILE.

BTW: The n = 0 is not needed not only according to POSIX but also:

GLIBC has libio/iogetdelim.c → __getdelim):

  if (*lineptr == NULL || *n == 0)
    {
      *n = 120;
      *lineptr = (char *) malloc (*n);

and Newlib has (newlib/libc/stdio/getdelim.c → __getdelim):

  if (buf == NULL || *n < MIN_LINE_SIZE)
    {
      buf = (char *)realloc (*bufptr, DEFAULT_LINE_SIZE);

Thus, as mentioned, I don't see the need for the "= 0"
(not that it really harms).

    if (getline (&lineptr, &nline, f) <= 0)
      {
-      free (lineptr);
        fclose (f);
        goto fail;
      }

Also well spotted - as mentioned, I kept adding more goto
targets + doing cleanup + goto, but at the end I consolidated
it to a single one, but obviously failed to update all cases
for it :-/

Thanks for the fix, which LGTM.

Tobias

Reply via email to