[llvm] [Flang][runtime] Fix RENAME intrinsic, remove trailing blanks (PR #159123)

Michael Klemm via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 17 01:19:03 PDT 2025


https://github.com/mjklemm updated https://github.com/llvm/llvm-project/pull/159123

>From 664be1d1b7d632f34a4265bfc747801b63e4c5f2 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Tue, 16 Sep 2025 18:33:16 +0200
Subject: [PATCH 1/4] [Flang][runtime] Fix RENAME intrinsic, remove trailing
 blanks

The RENAME intrinsic did not correctly remove trailing spaces from
filenames.  This PR introduces code to remove trailing blanks as
documented by GFortran.
---
 flang-rt/lib/runtime/misc-intrinsic.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/flang-rt/lib/runtime/misc-intrinsic.cpp b/flang-rt/lib/runtime/misc-intrinsic.cpp
index 4d1165f25687c..a3aa0953f776e 100644
--- a/flang-rt/lib/runtime/misc-intrinsic.cpp
+++ b/flang-rt/lib/runtime/misc-intrinsic.cpp
@@ -65,8 +65,20 @@ void RTDEF(Rename)(const Descriptor &path1, const Descriptor &path2,
   char *pathDst{EnsureNullTerminated(
       path2.OffsetElement(), path2.ElementBytes(), terminator)};
 
+  // Trim trailing blanks
+  auto srcTrimPos{TrimTrailingSpaces(pathSrc, path1.ElementBytes())};
+  auto dstTrimPos{TrimTrailingSpaces(pathDst, path2.ElementBytes())};
+  char *srcPathTrim{
+      static_cast<char *>(alloca((srcTrimPos + 1) * sizeof(char)))};
+  char *dstPathTrim{
+      static_cast<char *>(alloca((dstTrimPos + 1) * sizeof(char)))};
+  std::strncpy(srcPathTrim, pathSrc, srcTrimPos);
+  std::strncpy(dstPathTrim, pathDst, dstTrimPos);
+  srcPathTrim[srcTrimPos] = '\0';
+  dstPathTrim[dstTrimPos] = '\0';
+
   // We simply call rename(2) from POSIX
-  int result{rename(pathSrc, pathDst)};
+  int result{rename(srcPathTrim, dstPathTrim)};
   if (status) {
     // When an error has happened,
     int errorCode{0}; // Assume success

>From b20d0ab493ceb73f574b9c4f87493c875c499aab Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Tue, 16 Sep 2025 18:58:44 +0200
Subject: [PATCH 2/4] Update flang-rt/lib/runtime/misc-intrinsic.cpp

Co-authored-by: Copilot <175728472+Copilot at users.noreply.github.com>
---
 flang-rt/lib/runtime/misc-intrinsic.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang-rt/lib/runtime/misc-intrinsic.cpp b/flang-rt/lib/runtime/misc-intrinsic.cpp
index a3aa0953f776e..b8652b54aa61d 100644
--- a/flang-rt/lib/runtime/misc-intrinsic.cpp
+++ b/flang-rt/lib/runtime/misc-intrinsic.cpp
@@ -72,8 +72,8 @@ void RTDEF(Rename)(const Descriptor &path1, const Descriptor &path2,
       static_cast<char *>(alloca((srcTrimPos + 1) * sizeof(char)))};
   char *dstPathTrim{
       static_cast<char *>(alloca((dstTrimPos + 1) * sizeof(char)))};
-  std::strncpy(srcPathTrim, pathSrc, srcTrimPos);
-  std::strncpy(dstPathTrim, pathDst, dstTrimPos);
+  std::memcpy(srcPathTrim, pathSrc, srcTrimPos);
+  std::memcpy(dstPathTrim, pathDst, dstTrimPos);
   srcPathTrim[srcTrimPos] = '\0';
   dstPathTrim[dstTrimPos] = '\0';
 

>From 6827079255dbd0183c413e9516d40d0e349024b3 Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Wed, 17 Sep 2025 10:11:21 +0200
Subject: [PATCH 3/4] Introduce function IsNullTerminated

---
 flang-rt/include/flang-rt/runtime/tools.h | 3 +++
 flang-rt/lib/runtime/tools.cpp            | 6 +++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/flang-rt/include/flang-rt/runtime/tools.h b/flang-rt/include/flang-rt/runtime/tools.h
index 1939c4d907be4..648d32e78ac00 100644
--- a/flang-rt/include/flang-rt/runtime/tools.h
+++ b/flang-rt/include/flang-rt/runtime/tools.h
@@ -525,6 +525,9 @@ RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from,
     bool toIsContiguous, bool fromIsContiguous);
 RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from);
 
+// Determines if a character string is null-terminated.
+RT_API_ATTRS bool IsNullTerminated(char *str, std::size_t length);
+
 // Ensures that a character string is null-terminated, allocating a /p length +1
 // size memory for null-terminator if necessary. Returns the original or a newly
 // allocated null-terminated string (responsibility for deallocation is on the
diff --git a/flang-rt/lib/runtime/tools.cpp b/flang-rt/lib/runtime/tools.cpp
index 03ee982d913bb..b687a8088fdfa 100644
--- a/flang-rt/lib/runtime/tools.cpp
+++ b/flang-rt/lib/runtime/tools.cpp
@@ -273,9 +273,13 @@ RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from) {
   ShallowCopy(to, from, to.IsContiguous(), from.IsContiguous());
 }
 
+RT_API_ATTRS bool IsNullTerminated(char *str, std::size_t length) {
+  return !(runtime::memchr(str, '\0', length) == nullptr);
+}
+
 RT_API_ATTRS char *EnsureNullTerminated(
     char *str, std::size_t length, Terminator &terminator) {
-  if (runtime::memchr(str, '\0', length) == nullptr) {
+  if (!IsNullTerminated(str, length)) {
     char *newCmd{(char *)AllocateMemoryOrCrash(terminator, length + 1)};
     runtime::memcpy(newCmd, str, length);
     newCmd[length] = '\0';

>From 8b60514096adedf9fb937d9503b913714a5ad35d Mon Sep 17 00:00:00 2001
From: Michael Klemm <michael.klemm at amd.com>
Date: Wed, 17 Sep 2025 10:18:51 +0200
Subject: [PATCH 4/4] Add proper handling of null-terminated character strings

---
 flang-rt/lib/runtime/misc-intrinsic.cpp | 35 ++++++++++++++++---------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/flang-rt/lib/runtime/misc-intrinsic.cpp b/flang-rt/lib/runtime/misc-intrinsic.cpp
index b8652b54aa61d..48fd54670854d 100644
--- a/flang-rt/lib/runtime/misc-intrinsic.cpp
+++ b/flang-rt/lib/runtime/misc-intrinsic.cpp
@@ -15,6 +15,8 @@
 #include <cstdio>
 #include <cstring>
 
+#include "../../include/flang-rt/runtime/descriptor.h"
+
 namespace Fortran::runtime {
 
 static RT_API_ATTRS void TransferImpl(Descriptor &result,
@@ -60,25 +62,34 @@ void RTDEF(Rename)(const Descriptor &path1, const Descriptor &path2,
     const Descriptor *status, const char *sourceFile, int line) {
   Terminator terminator{sourceFile, line};
 #if !defined(RT_DEVICE_COMPILATION)
+  // Get the raw strings (null-terminated)
   char *pathSrc{EnsureNullTerminated(
       path1.OffsetElement(), path1.ElementBytes(), terminator)};
   char *pathDst{EnsureNullTerminated(
       path2.OffsetElement(), path2.ElementBytes(), terminator)};
+  char *srcFilePath = pathSrc;
+  char *dstFilePath = pathDst;
 
-  // Trim trailing blanks
-  auto srcTrimPos{TrimTrailingSpaces(pathSrc, path1.ElementBytes())};
-  auto dstTrimPos{TrimTrailingSpaces(pathDst, path2.ElementBytes())};
-  char *srcPathTrim{
-      static_cast<char *>(alloca((srcTrimPos + 1) * sizeof(char)))};
-  char *dstPathTrim{
-      static_cast<char *>(alloca((dstTrimPos + 1) * sizeof(char)))};
-  std::memcpy(srcPathTrim, pathSrc, srcTrimPos);
-  std::memcpy(dstPathTrim, pathDst, dstTrimPos);
-  srcPathTrim[srcTrimPos] = '\0';
-  dstPathTrim[dstTrimPos] = '\0';
+  // Trim trailing blanks (if string have not been null-terminated)
+  if (!IsNullTerminated(path1.OffsetElement(), path1.ElementBytes())) {
+    auto srcTrimPos{TrimTrailingSpaces(pathSrc, path1.ElementBytes())};
+    char *srcPathTrim{
+        static_cast<char *>(alloca((srcTrimPos + 1) * sizeof(char)))};
+    std::memcpy(srcPathTrim, pathSrc, srcTrimPos);
+    srcPathTrim[srcTrimPos] = '\0';
+    srcFilePath = srcPathTrim;
+  }
+  if (!IsNullTerminated(path2.OffsetElement(), path2.ElementBytes())) {
+    auto dstTrimPos{TrimTrailingSpaces(pathDst, path2.ElementBytes())};
+    char *dstPathTrim{
+        static_cast<char *>(alloca((dstTrimPos + 1) * sizeof(char)))};
+    std::memcpy(dstPathTrim, pathDst, dstTrimPos);
+    dstPathTrim[dstTrimPos] = '\0';
+    dstFilePath = dstPathTrim;
+  }
 
   // We simply call rename(2) from POSIX
-  int result{rename(srcPathTrim, dstPathTrim)};
+  int result{rename(srcFilePath, dstFilePath)};
   if (status) {
     // When an error has happened,
     int errorCode{0}; // Assume success



More information about the llvm-commits mailing list