diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2023-02-04 10:07:11 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2023-02-04 10:14:12 -0800 |
commit | 6d488119c68989038faa05c9ee9d43c8c82487e4 (patch) | |
tree | 60493da32f5ac7007870c7b7a88b3d011479cfa8 /lib/fts.c | |
parent | 4e9fcc7b84fcac07a3e5a3cd5f66d1ff320dc8e8 (diff) | |
download | gnulib-6d488119c68989038faa05c9ee9d43c8c82487e4.tar.gz |
fts: pacify GCC 13 -Wuse-after-free
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.
Diffstat (limited to 'lib/fts.c')
-rw-r--r-- | lib/fts.c | 15 |
1 files changed, 10 insertions, 5 deletions
@@ -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) |