https://gcc.gnu.org/g:7099a54b01a0cd04247fe88e3545916ab5ee0d22

commit r17-5419-g7099a54b01a0cd04247fe88e3545916ab5ee0d22
Author: Harald Anlauf <[email protected]>
Date:   Tue Oct 20 20:29:19 2026 +0200

    fortran: Prevent gfc_copy_expr() truncating strings containing NUL 
[PR127892]
    
    gfc_copy_expr() would create a truncated copy of the internal
    representation of a string when it contained a NUL character.  This can
    occur while simplifying TRANSFER when the physical representation of its
    result is longer than that of SOURCE, and MOLD is of type CHARACTER.
    This lead to an invalid read reported by valgrind.
    
            PR fortran/127892
    
    gcc/fortran/ChangeLog:
    
            * expr.cc (gfc_copy_expr): Ensure that the result representation
            length is the same as that of the source.
            * gfortran.h (gfc_char_to_widechar): Adjust prototype.
            * scanner.cc (gfc_char_to_widechar): Add optional argument for
            the result representation length, instead of deriving it from the
            string argument.

Diff:
---
 gcc/fortran/expr.cc    | 3 ++-
 gcc/fortran/gfortran.h | 2 +-
 gcc/fortran/scanner.cc | 6 ++++--
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index 561318ed2e5f..9e06866ad630 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -349,7 +349,8 @@ gfc_copy_expr (gfc_expr *p)
          if (p->representation.string
              && p->ts.kind == gfc_default_character_kind)
            q->value.character.string
-             = gfc_char_to_widechar (q->representation.string);
+             = gfc_char_to_widechar (q->representation.string,
+                                     p->representation.length);
          else
            {
              s = gfc_get_wide_string (p->value.character.length + 1);
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 9d4455ec7e3d..7433de7c1c85 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3646,7 +3646,7 @@ size_t gfc_wide_strlen (const gfc_char_t *);
 int gfc_wide_strncasecmp (const gfc_char_t *, const char *, size_t);
 gfc_char_t *gfc_wide_memset (gfc_char_t *, gfc_char_t, size_t);
 char *gfc_widechar_to_char (const gfc_char_t *, int);
-gfc_char_t *gfc_char_to_widechar (const char *);
+gfc_char_t *gfc_char_to_widechar (const char *, gfc_charlen_t = -1);
 
 #define gfc_get_wide_string(n) XCNEWVEC (gfc_char_t, n)
 
diff --git a/gcc/fortran/scanner.cc b/gcc/fortran/scanner.cc
index ccd44a145d55..9b77e5590654 100644
--- a/gcc/fortran/scanner.cc
+++ b/gcc/fortran/scanner.cc
@@ -203,7 +203,7 @@ gfc_widechar_to_char (const gfc_char_t *s, int length)
 }
 
 gfc_char_t *
-gfc_char_to_widechar (const char *s)
+gfc_char_to_widechar (const char *s, gfc_charlen_t length)
 {
   size_t len, i;
   gfc_char_t *res;
@@ -211,7 +211,9 @@ gfc_char_to_widechar (const char *s)
   if (s == NULL)
     return NULL;
 
-  len = strlen (s);
+  /* Passing a negative length is used to indicate that length should be
+     calculated using strlen().  */
+  len = (length >= 0 ? (size_t) length : strlen (s));
   res = gfc_get_wide_string (len + 1);
 
   for (i = 0; i < len; i++)

Reply via email to