<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">From b3f566ad048c193fece9902f3c04cc3bbe28e9fc Mon Sep 17 00:00:00 2001
From: Adam Sampson &lt;ats@offog.org&gt;
Date: Sat, 5 Jul 2025 16:53:38 +0100
Subject: [PATCH 4/4] Avoid undefined behaviour in rearrange_argv

If ptr_argv is pointing at the same location as argv[n] (e.g. if gcal is
invoked as "gcal -q FR"), then this code will realloc argv[n] but still
refer to the old value afterwards. If realloc returned the same pointer
then this will result in strcpy with overlapping arguments; if it
returned a different pointer then it's a use-after-free.

Use my_malloc to allocate the new argument explicitly, and only free the
old one after we're done copying it.
---
 src/gcal.c | 37 ++++++++++++++++++++-----------------
 1 file changed, 20 insertions(+), 17 deletions(-)

diff --git a/src/gcal.c b/src/gcal.c
index 6dd35ee..043c78c 100644
--- a/src/gcal.c
+++ b/src/gcal.c
@@ -3699,6 +3699,7 @@ rearrange_argv (opt_list, argc, argv)
   register int n = 1;
   auto char **ptr_argv = argv;
   auto char **ptr2_argv;
+  auto char *new_arg;
   auto Bool is_modified;
 
 
@@ -3771,17 +3772,18 @@ rearrange_argv (opt_list, argc, argv)
 				     short-style option character and its needed argument.
 				   */
 				  i--;
-				  argv[n] =
-				    (char *) my_realloc ((VOID_PTR) (argv[n]),
-							 strlen (*ptr_argv) +
-							 strlen (*ptr2_argv) +
-							 1,
-							 ERR_NO_MEMORY_AVAILABLE,
-							 __FILE__,
-							 ((long) __LINE__) -
-							 3L, "argv[n]", n);
-				  strcpy (argv[n], *ptr_argv);
-				  strcat (argv[n], *ptr2_argv);
+				  new_arg =
+				    (char *) my_malloc (strlen (*ptr_argv) +
+							strlen (*ptr2_argv) +
+							1,
+							ERR_NO_MEMORY_AVAILABLE,
+							__FILE__,
+							((long) __LINE__) -
+							3L, "argv[n]", n);
+				  strcpy (new_arg, *ptr_argv);
+				  strcat (new_arg, *ptr2_argv);
+				  free (argv[n]);
+				  argv[n] = new_arg;
 				  ptr_argv++;
 				  is_modified = TRUE;
 				}
@@ -3809,12 +3811,13 @@ rearrange_argv (opt_list, argc, argv)
 	     or     a command (an argument not leaded by a '-', '/', '@' or '%' character.
 	   */
 	  (*ptr_argv)--;
-	  argv[n] = (char *) my_realloc ((VOID_PTR) (argv[n]),
-					 strlen (*ptr_argv) + 1,
-					 ERR_NO_MEMORY_AVAILABLE,
-					 __FILE__, ((long) __LINE__) - 3L,
-					 "argv[n]", n);
-	  strcpy (argv[n], *ptr_argv);
+	  new_arg = (char *) my_malloc (strlen (*ptr_argv) + 1,
+					ERR_NO_MEMORY_AVAILABLE,
+					__FILE__, ((long) __LINE__) - 3L,
+					"argv[n]", n);
+	  strcpy (new_arg, *ptr_argv);
+	  free (argv[n]);
+	  argv[n] = new_arg;
 	}
       n++;
       i--;
-- 
2.50.0

</pre></body></html>