[glibc] intl: Fix undefined pointer behaviour

Adhemerval Zanella via Glibc-cvs <[email protected]> Wed, 20 May 2026 20:22:48 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=8aa4a704314e6039bf1efbc1d8d57bb095956862

commit 8aa4a704314e6039bf1efbc1d8d57bb095956862
Author: Avinal Kumar <[email protected]>
Date:   Mon May 18 15:44:52 2026 +0530

    intl: Fix undefined pointer behaviour
    
    In _nl_find_msg (dcigettext.c), outbuf was computed as
    freemem + sizeof(size_t) before checking whether freemem_size is
    large enough.  When freemem is NULL (initial state), this is
    undefined behaviour i.e arithmetic on a null pointer.  Move the
    outbuf assignment after the size check where freemem is guaranteed
    to be a valid allocation.
    
    In read_alias_file (localealias.c), after realloc the old
    string_space pointer is dangling.  The expression
    new_pool - string_space subtracts a valid pointer from a dangling
    one, which is undefined behaviour per ISO C 23.
    Rewrite as new_pool + (map[i].alias - string_space) so both
    operands of the subtraction point into the same (old) object
    before string_space is reassigned.
    
    Based on GNU gettext commits 695429040 and 2ebbdd0e2.
    Original author: Bruno Haible <[email protected]>
    
    Signed-off-by: Avinal Kumar <[email protected]>
    Reviewed-by: Adhemerval Zanella  <[email protected]>

Diff:
---
 intl/dcigettext.c  | 15 ++++++---------
 intl/localealias.c |  6 ++++--
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/intl/dcigettext.c b/intl/dcigettext.c
index d738e485f3..43b99c2dea 100644
--- a/intl/dcigettext.c
+++ b/intl/dcigettext.c
@@ -1136,7 +1136,6 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
 	    not_translated_yet:
 
 	      inbuf = (const unsigned char *) result;
-	      outbuf = freemem + sizeof (size_t);
 # ifndef _LIBC
 	      transmem_list = NULL;
 # endif
@@ -1145,13 +1144,16 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
 	      while (1)
 		{
 		  transmem_block_t *newmem;
-# ifdef _LIBC
-		  size_t non_reversible;
-		  int res;
 
 		  if (freemem_size < sizeof (size_t))
 		    goto resize_freemem;
 
+		  outbuf = freemem + sizeof (size_t);
+
+# ifdef _LIBC
+		  size_t non_reversible;
+		  int res;
+
 		  res = __gconv (convd->conv,
 				 &inbuf, inbuf + resultlen,
 				 &outbuf,
@@ -1177,9 +1179,6 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
 		  char *outptr = (char *) outbuf;
 		  size_t outleft;
 
-		  if (freemem_size < sizeof (size_t))
-		    goto resize_freemem;
-
 		  outleft = freemem_size - sizeof (size_t);
 		  if (iconv (convd->conv,
 			     (ICONV_CONST char **) &inptr, &inleft,
@@ -1248,8 +1247,6 @@ _nl_find_msg (struct loaded_l10nfile *domain_file,
 		  transmem_list = newmem;
 		  freemem = newmem;
 # endif
-
-		  outbuf = freemem + sizeof (size_t);
 		}
 
 	      /* We have now in our buffer a converted string.  Put this
diff --git a/intl/localealias.c b/intl/localealias.c
index fbb26d9efd..53da04ba2f 100644
--- a/intl/localealias.c
+++ b/intl/localealias.c
@@ -329,8 +329,10 @@ read_alias_file (const char *fname, int fname_len)
 
 			  for (i = 0; i < nmap; i++)
 			    {
-			      map[i].alias += new_pool - string_space;
-			      map[i].value += new_pool - string_space;
+			      map[i].alias =
+				new_pool + (map[i].alias - string_space);
+			      map[i].value =
+				new_pool + (map[i].value - string_space);
 			    }
 			}