Thanks for reporting that. I installed the attached fix, which is more elaborate than what you suggested but simplifies the code and should help avoid similar problems in the future.
From 78d4ccd75531ac61552a6aa97c6df7238b16cbd3 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Mon, 11 Sep 2023 01:17:02 -0500
Subject: [PATCH] Fix pointer bug in drop_volume_label_suffix

Problem reported by Marc Espie in:
https://lists.gnu.org/r/bug-tar/2023-09/msg00003.html
* src/buffer.c (drop_volume_label_suffix):
Redo to not compute a pointer before the start of a buffer,
as this is not portable.
---
 THANKS       |  1 +
 src/buffer.c | 32 ++++++++++----------------------
 src/common.h |  3 ++-
 3 files changed, 13 insertions(+), 23 deletions(-)

diff --git a/THANKS b/THANKS
index b51f1694..fb8634e1 100644
--- a/THANKS
+++ b/THANKS
@@ -327,6 +327,7 @@ Mads Martin Joergensen	m...@suse.de
 Manfred Weichel		manfred.weic...@mch.sni.de
 Manuel Munier		manuel.mun...@loria.fr
 Marc Boucher		m...@cam.org
+Marc Espie		marc.espie.open...@gmail.com
 Marc Ewing		m...@redhat.com
 Marcin Matuszewski	mar...@frodo.nask.org.pl
 Marcus Daniels		mar...@sysc.pdx.edu
diff --git a/src/buffer.c b/src/buffer.c
index 8a575f9a..7f353fa4 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1565,33 +1565,21 @@ try_new_volume (void)
 }
 
 
-#define VOLUME_TEXT " Volume "
-#define VOLUME_TEXT_LEN (sizeof VOLUME_TEXT - 1)
-
 char *
 drop_volume_label_suffix (const char *label)
 {
-  const char *p;
-  size_t len = strlen (label);
-
-  if (len < 1)
-    return NULL;
+  static char const VOLUME_TEXT[] = " Volume ";
+  idx_t VOLUME_TEXT_LEN = sizeof VOLUME_TEXT - 1;
+  idx_t prefix_len = 0;
 
-  for (p = label + len - 1; p > label && isdigit ((unsigned char) *p); p--)
-    ;
-  if (p > label && p - (VOLUME_TEXT_LEN - 1) > label)
-    {
-      p -= VOLUME_TEXT_LEN - 1;
-      if (memcmp (p, VOLUME_TEXT, VOLUME_TEXT_LEN) == 0)
-	{
-	  char *s = xmalloc ((len = p - label) + 1);
-	  memcpy (s, label, len);
-	  s[len] = 0;
-	  return s;
-	}
-    }
+  for (idx_t i = 0; label[i]; i++)
+    if (!isdigit ((unsigned char) label[i]))
+      prefix_len = i + 1;
 
-  return NULL;
+  ptrdiff_t len = prefix_len - VOLUME_TEXT_LEN;
+  return (0 <= len && memcmp (label + len, VOLUME_TEXT, VOLUME_TEXT_LEN) == 0
+	  ? ximemdup0 (label, len)
+	  : NULL);
 }
 
 /* Check LABEL against the volume label, seen as a globbing
diff --git a/src/common.h b/src/common.h
index 89912567..55576ef3 100644
--- a/src/common.h
+++ b/src/common.h
@@ -460,7 +460,8 @@ extern uintmax_t continued_file_size;
 extern uintmax_t continued_file_offset;
 extern off_t records_written;
 
-char *drop_volume_label_suffix (const char *label);
+char *drop_volume_label_suffix (const char *label)
+  _GL_ATTRIBUTE_MALLOC _GL_ATTRIBUTE_DEALLOC_FREE;
 
 size_t available_space_after (union block *pointer);
 off_t current_block_ordinal (void);
-- 
2.41.0

Reply via email to