+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.
#include <fcntl.h>
#include <errno.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
register FTSENT *p, *head;
register size_t nitems;
FTSENT *tail;
- void *oldaddr;
int saved_errno;
bool descend;
bool doadjust;
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
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;
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)