]> Savannah Git Hosting - gnulib.git/commitdiff
fts: pacify GCC 13 -Wuse-after-free
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 4 Feb 2023 18:07:11 +0000 (10:07 -0800)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 4 Feb 2023 18:14:12 +0000 (10:14 -0800)
Problem reported by Peter Frazier in:
https://lists.gnu.org/r/bug-gnulib/2023-02/msg00000.html
* lib/fts.c: Include stdint.h.
(fts_build): Do not access freed pointer directly; instead,
save its bit-pattern into a uintptr_t, and use that to compare.
(ADJUST): Likewise, but more trickily since this hack
puns pointer types and relies on undefined behavior.
* modules/fts (Depends-on): Add stdint.

ChangeLog
lib/fts.c
modules/fts

index 0f8b53ff132f43a840df43ef94c78424cb6d0b64..ed999a6d50bb7dd643f68c257dbd39d97c7229e5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2023-02-04  Paul Eggert  <eggert@cs.ucla.edu>
+
+       fts: pacify GCC 13 -Wuse-after-free
+       Ordinarily I fix this sort of thing by using well-defined rather
+       than undefined behavior, but a straightforward patch along those
+       lines would change the fts_.h API since fts_accpath would change
+       from a pointer to an integer with a more-complex interpretation.
+       Instead, attempt to pacify GCC 13 with code that relies on
+       undefined but portable-in-practice behavior that GCC 13 does not
+       complain about.  GCC problem reported by Peter Frazier in:
+       https://lists.gnu.org/r/bug-gnulib/2023-02/msg00000.html
+       * lib/fts.c: Include stdint.h.
+       (fts_build): Do not access freed pointer directly; instead,
+       save its bit-pattern into a uintptr_t, and use that to compare.
+       (ADJUST): Likewise, but more trickily since this hack
+       puns pointer types and relies on undefined behavior.
+       * modules/fts (Depends-on): Add stdint.
+
 2023-02-04  Bruno Haible  <bruno@clisp.org>
 
        assert-h, verify: Fix conflict with standard C++ header files on macOS.
index 65a96e8addcb141709a2d431eeaaf5caeec82bb4..3e5bb47aaf0bfbb2141693d79e6077ace692aa65 100644 (file)
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -63,6 +63,7 @@ static char sccsid[] = "@(#)fts.c       8.6 (Berkeley) 8/14/94";
 #include <fcntl.h>
 #include <errno.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
@@ -1268,7 +1269,6 @@ fts_build (register FTS *sp, int type)
         register FTSENT *p, *head;
         register size_t nitems;
         FTSENT *tail;
-        void *oldaddr;
         int saved_errno;
         bool descend;
         bool doadjust;
@@ -1461,7 +1461,7 @@ fts_build (register FTS *sp, int type)
                         goto mem1;
                 if (d_namelen >= maxlen) {
                         /* include space for NUL */
-                        oldaddr = sp->fts_path;
+                        uintptr_t oldaddr = (uintptr_t) sp->fts_path;
                         if (! fts_palloc(sp, d_namelen + len + 1)) {
                                 /*
                                  * No more memory.  Save
@@ -1478,7 +1478,7 @@ mem1:                           saved_errno = errno;
                                 return (NULL);
                         }
                         /* Did realloc() change the pointer? */
-                        if (oldaddr != sp->fts_path) {
+                        if (oldaddr != (uintptr_t) sp->fts_path) {
                                 doadjust = true;
                                 if (ISSET(FTS_NOCHDIR))
                                         cp = sp->fts_path + len;
@@ -1988,10 +1988,15 @@ fts_padjust (FTS *sp, FTSENT *head)
         FTSENT *p;
         char *addr = sp->fts_path;
 
+        /* This code looks at bit-patterns of freed pointers to
+           relocate them, so it relies on undefined behavior.  If this
+           trick does not work on your platform, please report a bug.  */
+
 #define ADJUST(p) do {                                                  \
-        if ((p)->fts_accpath != (p)->fts_name) {                        \
+        uintptr_t old_accpath = *(uintptr_t *) &(p)->fts_accpath;       \
+        if (old_accpath != (uintptr_t) (p)->fts_name) {                 \
                 (p)->fts_accpath =                                      \
-                    (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
+                  addr + (old_accpath - *(uintptr_t *) &(p)->fts_path); \
         }                                                               \
         (p)->fts_path = addr;                                           \
 } while (0)
index 18b10fac6e923447e6557442d5226ec90d42e3a1..fe56bae6e04cc762c23179f3a08fda188e5bb5cf 100644 (file)
@@ -31,6 +31,7 @@ opendirat
 readdir
 stdbool
 stddef
+stdint
 
 configure.ac:
 gl_FUNC_FTS