bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Paul Eggert <eggert@cs.ucla.edu>
To: Peter Frazier <mrpeterfrazier@gmail.com>
Cc: bug-gnulib@gnu.org, Sam James <sam@gentoo.org>
Subject: Re: coreutils/gnulib - fts.c dangling pointers & gcc 13.1
Date: Sat, 4 Feb 2023 10:46:57 -0800	[thread overview]
Message-ID: <7cc5a194-7cd8-e88e-c8fe-b7fa4df4af01@cs.ucla.edu> (raw)
In-Reply-To: <7B6A1D32-7ECD-4DE0-9E0C-1955F9B756B5@gentoo.org>

[-- Attachment #1: Type: text/plain, Size: 304 bytes --]

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".

[-- Attachment #2: 0001-fts-pacify-GCC-13-Wuse-after-free.patch --]
[-- Type: text/x-patch, Size: 4715 bytes --]

From 6d488119c68989038faa05c9ee9d43c8c82487e4 Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@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  <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.
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


[-- Attachment #3: 0002-fts-pacify-GCC-12-Wstrict-aliasing.patch --]
[-- Type: text/x-patch, Size: 2001 bytes --]

From 32c16c45d7378b014d9aac6130104c4d02a9acdb Mon Sep 17 00:00:00 2001
From: Paul Eggert <eggert@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  <bruno@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


  reply	other threads:[~2023-02-04 18:47 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-03 20:24 coreutils/gnulib - fts.c dangling pointers & gcc 13.1 Peter Frazier
2023-02-03 22:11 ` Paul Eggert
2023-02-04 16:14   ` Sam James
2023-02-04 18:46     ` Paul Eggert [this message]
2023-02-04 19:53       ` Sam James
2023-02-04 20:20         ` Paul Eggert
2023-02-04 20:23           ` Sam James
2023-02-04 22:03             ` Paul Eggert
2023-02-04 22:10               ` Sam James

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=7cc5a194-7cd8-e88e-c8fe-b7fa4df4af01@cs.ucla.edu \
    --to=eggert@cs.ucla.edu \
    --cc=bug-gnulib@gnu.org \
    --cc=mrpeterfrazier@gmail.com \
    --cc=sam@gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).