I manually inspected fts.c to look for violations of the C standard that
might draw GCC's attention, and installed the attached patches into
Gnulib. As you can see, they don't fix the technical violations of the C
standard. However, I hope they keep GCC happy. Please give them a try
with "GCC 13.1".From 6d488119c68989038faa05c9ee9d43c8c82487e4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 4 Feb 2023 10:07:11 -0800
Subject: [PATCH 1/2] 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.
---
ChangeLog | 18 ++++++++++++++++++
lib/fts.c | 15 ++++++++++-----
modules/fts | 1 +
3 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0f8b53ff13..ed999a6d50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2023-02-04 Paul Eggert <egg...@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 <br...@clisp.org>
assert-h, verify: Fix conflict with standard C++ header files on macOS.
diff --git a/lib/fts.c b/lib/fts.c
index 65a96e8add..3e5bb47aaf 100644
--- 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)
diff --git a/modules/fts b/modules/fts
index 18b10fac6e..fe56bae6e0 100644
--- a/modules/fts
+++ b/modules/fts
@@ -31,6 +31,7 @@ opendirat
readdir
stdbool
stddef
+stdint
configure.ac:
gl_FUNC_FTS
--
2.37.2
From 32c16c45d7378b014d9aac6130104c4d02a9acdb Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Sat, 4 Feb 2023 10:28:55 -0800
Subject: [PATCH 2/2] fts: pacify GCC 12 -Wstrict-aliasing
* lib/fts.c (ADJUST): Avoid -Wstrict-aliasing waring.
---
ChangeLog | 5 ++++-
lib/fts.c | 4 ++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ed999a6d50..ab24baf6f9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -13,7 +13,10 @@
(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.
+ actually accesses freed pointers, but does so in a way that
+ I hope GCC doesn’t notice. Although using ‘*(uintptr_t *) &P’
+ instead of ‘(uintptr_t) P’ would avoid accessing freed pointers,
+ it would provoke a -Wstrict-aliasing diagnostic.
* modules/fts (Depends-on): Add stdint.
2023-02-04 Bruno Haible <br...@clisp.org>
diff --git a/lib/fts.c b/lib/fts.c
index 3e5bb47aaf..78584b2902 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -1993,10 +1993,10 @@ fts_padjust (FTS *sp, FTSENT *head)
trick does not work on your platform, please report a bug. */
#define ADJUST(p) do { \
- uintptr_t old_accpath = *(uintptr_t *) &(p)->fts_accpath; \
+ uintptr_t old_accpath = (uintptr_t) (p)->fts_accpath; \
if (old_accpath != (uintptr_t) (p)->fts_name) { \
(p)->fts_accpath = \
- addr + (old_accpath - *(uintptr_t *) &(p)->fts_path); \
+ addr + (old_accpath - (uintptr_t) (p)->fts_path); \
} \
(p)->fts_path = addr; \
} while (0)
--
2.37.2