[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