[flang] [clang-tools-extra] [clang] [llvm] [flang ]GETLOG runtime and extension implementation: get login username (PR #70917)

Yi Wu via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 15 05:03:13 PST 2023


https://github.com/PAX-12-WU updated https://github.com/llvm/llvm-project/pull/70917

>From 0e98aa7ca15b05b91813eaeeb6ae1305e5f5384d Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Mon, 6 Nov 2023 19:49:13 +0000
Subject: [PATCH 1/6] GETLOG runtime and extension implementation: get login
 username

Get login username, ussage:
CHARACTER(32) :: login
CALL getlog(login)
WRITE(*,*) login
---
 flang/docs/Intrinsics.md                      |  2 +-
 .../Optimizer/Builder/Runtime/RTBuilder.h     |  8 ++++
 flang/include/flang/Runtime/command.h         |  6 +++
 flang/include/flang/Runtime/extensions.h      |  2 +
 flang/runtime/command.cpp                     | 40 +++++++++++++++++++
 flang/runtime/extensions.cpp                  |  6 +++
 flang/unittests/Runtime/CommandTest.cpp       | 15 ++++++-
 7 files changed, 77 insertions(+), 2 deletions(-)

diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index ab0a940e53e5538..cfe5dcd141e9821 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -751,7 +751,7 @@ This phase currently supports all the intrinsic procedures listed above but the
 | Object characteristic inquiry functions | ALLOCATED, ASSOCIATED, EXTENDS_TYPE_OF, IS_CONTIGUOUS, PRESENT, RANK, SAME_TYPE, STORAGE_SIZE |
 | Type inquiry intrinsic functions | BIT_SIZE, DIGITS, EPSILON, HUGE, KIND, MAXEXPONENT, MINEXPONENT, NEW_LINE, PRECISION, RADIX, RANGE, TINY|
 | Non-standard intrinsic functions | AND, OR, XOR, SHIFT, ZEXT, IZEXT, COSD, SIND, TAND, ACOSD, ASIND, ATAND, ATAN2D, COMPL, EQV, NEQV, INT8, JINT, JNINT, KNINT, QCMPLX, DREAL, DFLOAT, QEXT, QFLOAT, QREAL, DNUM, NUM, JNUM, KNUM, QNUM, RNUM, RAN, RANF, ILEN, SIZEOF, MCLOCK, SECNDS, COTAN, IBCHNG, ISHA, ISHC, ISHL, IXOR, IARG, IARGC, NARGS, NUMARG, BADDRESS, IADDR, CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, MALLOC |
-| Intrinsic subroutines |MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SYSTEM_CLOCK |
+| Intrinsic subroutines |MVBITS (elemental), CPU_TIME, DATE_AND_TIME, EVENT_QUERY, EXECUTE_COMMAND_LINE, GET_COMMAND, GET_COMMAND_ARGUMENT, GET_ENVIRONMENT_VARIABLE, GETLOG, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SYSTEM_CLOCK |
 | Atomic intrinsic subroutines | ATOMIC_ADD |
 | Collective intrinsic subroutines | CO_REDUCE |
 
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index b2774263e7a31a4..830df7ad006b54a 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -62,6 +62,14 @@ using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *);
 /// standard type `i32` when `sizeof(int)` is 4.
 template <typename T>
 static constexpr TypeBuilderFunc getModel();
+
+template <>
+constexpr TypeBuilderFunc getModel<unsigned int>() {
+  return [](mlir::MLIRContext *context) -> mlir::Type {
+    return mlir::IntegerType::get(context, 8 * sizeof(unsigned int));
+  };
+}
+
 template <>
 constexpr TypeBuilderFunc getModel<short int>() {
   return [](mlir::MLIRContext *context) -> mlir::Type {
diff --git a/flang/include/flang/Runtime/command.h b/flang/include/flang/Runtime/command.h
index ec6289390545479..1c212ef61697cd5 100644
--- a/flang/include/flang/Runtime/command.h
+++ b/flang/include/flang/Runtime/command.h
@@ -47,6 +47,12 @@ std::int32_t RTNAME(GetEnvVariable)(const Descriptor &name,
     bool trim_name = true, const Descriptor *errmsg = nullptr,
     const char *sourceFile = nullptr, int line = 0);
 }
+
+// Try to get the name of current user
+// Returns a STATUS as described in the standard.
+std::int32_t RTNAME(GetLog)(
+    const Descriptor *argument = nullptr, const Descriptor *errmsg = nullptr);
+
 } // namespace Fortran::runtime
 
 #endif // FORTRAN_RUNTIME_COMMAND_H_
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index ad592814e5acb79..d199d5e387b8648 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -28,5 +28,7 @@ std::int32_t FORTRAN_PROCEDURE_NAME(iargc)();
 void FORTRAN_PROCEDURE_NAME(getarg)(
     std::int32_t &n, std::int8_t *arg, std::int64_t length);
 
+void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *name, std::int64_t length);
+
 } // extern "C"
 #endif // FORTRAN_RUNTIME_EXTENSIONS_H_
diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index b81a0791c5e571b..6b2f313e227a196 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -15,6 +15,30 @@
 #include <cstdlib>
 #include <limits>
 
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <windows.h>
+
+#include <Lmcons.h> // UNLEN=256
+
+inline char *getlogin() {
+  char *username = NULL;
+  DWORD size = UNLEN + 1; // Constant for the maximum username length
+  username = (char *)malloc(size);
+
+  if (GetUserName(username, &size)) {
+    // Username retrieved successfully
+    return username;
+  } else {
+    free(username);
+    return NULL;
+  }
+}
+#else
+#include <unistd.h>
+#endif
+
 namespace Fortran::runtime {
 std::int32_t RTNAME(ArgumentCount)() {
   int argc{executionEnvironment.argc};
@@ -222,6 +246,22 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *value,
   return stat;
 }
 
+std::int32_t RTNAME(GetLog)(const Descriptor *value, const Descriptor *errmsg) {
+  FillWithSpaces(*value);
+
+  const char *arg = getlogin();
+  std::int64_t argLen{StringLength(arg)};
+  if (argLen <= 0) {
+    return ToErrmsg(errmsg, StatMissingArgument);
+  }
+
+  if (value) {
+    return CopyToDescriptor(*value, arg, argLen, errmsg);
+  }
+
+  return StatOk;
+}
+
 static std::size_t LengthWithoutTrailingSpaces(const Descriptor &d) {
   std::size_t s{d.ElementBytes() - 1};
   while (*d.OffsetElement(s) == ' ') {
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index b8e9b6eae132059..47b269d1e5b42af 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -37,5 +37,11 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
   (void)RTNAME(GetCommandArgument)(
       n, &value, nullptr, nullptr, __FILE__, __LINE__);
 }
+
+void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
+  Descriptor value{*Descriptor::Create(1, length, arg, 0)};
+  (void)RTNAME(GetLog)(&value, nullptr);
+}
+
 } // namespace Fortran::runtime
 } // extern "C"
diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index c3571c9684e4b07..e33dd7b0469ebf9 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -225,6 +225,12 @@ TEST_F(ZeroArguments, GetCommandArgument) {
   CheckMissingArgumentValue(1);
 }
 
+TEST_F(ZeroArguments, GetLog) {
+  CheckMissingArgumentValue(-1);
+  CheckArgumentValue(commandOnlyArgv[0], 0);
+  CheckMissingArgumentValue(1);
+}
+
 TEST_F(ZeroArguments, GetCommand) { CheckCommandValue(commandOnlyArgv, 1); }
 
 static const char *oneArgArgv[]{"aProgram", "anArgumentOfLength20"};
@@ -242,6 +248,13 @@ TEST_F(OneArgument, GetCommandArgument) {
   CheckMissingArgumentValue(2);
 }
 
+TEST_F(OneArgument, GetLog) {
+  CheckMissingArgumentValue(-1);
+  CheckArgumentValue(oneArgArgv[0], 0);
+  CheckArgumentValue(oneArgArgv[1], 1);
+  CheckMissingArgumentValue(2);
+}
+
 TEST_F(OneArgument, GetCommand) { CheckCommandValue(oneArgArgv, 2); }
 
 static const char *severalArgsArgv[]{
@@ -284,7 +297,7 @@ TEST_F(SeveralArguments, ArgValueTooShort) {
   ASSERT_NE(tooShort, nullptr);
   EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1);
   CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
-
+  
   OwningPtr<Descriptor> length{EmptyIntDescriptor()};
   ASSERT_NE(length, nullptr);
   OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};

>From ce001f38e45511d0c4381a65a95c0e76220e45c9 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Tue, 7 Nov 2023 15:09:23 +0000
Subject: [PATCH 2/6] add include string.h, wchar.h, link library, and format

---
 flang/runtime/command.cpp               | 25 ++++++++++++++++---------
 flang/unittests/Runtime/CommandTest.cpp |  2 +-
 2 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index 6b2f313e227a196..c5171a1ef36f282 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -14,26 +14,33 @@
 #include "flang/Runtime/descriptor.h"
 #include <cstdlib>
 #include <limits>
+#include <string.h>
 
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #define NOMINMAX
 #include <windows.h>
 
-#include <Lmcons.h> // UNLEN=256
+#include <lmcons.h> // UNLEN=256
+#include <wchar.h> // wchar_t cast to LPWSTR
+#pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
 
-inline char *getlogin() {
-  char *username = NULL;
-  DWORD size = UNLEN + 1; // Constant for the maximum username length
-  username = (char *)malloc(size);
+static inline char *getlogin() {
+  static char username[UNLEN + 1];
+  wchar_t w_username[UNLEN + 1];
+  DWORD namelen = sizeof(w_username) / sizeof(w_username[0]);
 
-  if (GetUserName(username, &size)) {
-    // Username retrieved successfully
-    return username;
+  if (GetUserName(w_username, &namelen)) {
+    // Convert the wchar_t string to a regular C string
+    if (wcstombs(username, w_username, UNLEN + 1) == -1) {
+      // Conversion failed
+      return NULL;
+    }
+    return (username[0] == 0 ? NULL : username);
   } else {
-    free(username);
     return NULL;
   }
+  return nullptr;
 }
 #else
 #include <unistd.h>
diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index e33dd7b0469ebf9..686dc273142badd 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -297,7 +297,7 @@ TEST_F(SeveralArguments, ArgValueTooShort) {
   ASSERT_NE(tooShort, nullptr);
   EXPECT_EQ(RTNAME(GetCommandArgument)(1, tooShort.get()), -1);
   CheckDescriptorEqStr(tooShort.get(), severalArgsArgv[1]);
-  
+
   OwningPtr<Descriptor> length{EmptyIntDescriptor()};
   ASSERT_NE(length, nullptr);
   OwningPtr<Descriptor> errMsg{CreateEmptyCharDescriptor()};

>From 0de53646977c88ebc7bdb799325e5d92269a2f62 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Fri, 10 Nov 2023 10:44:12 +0000
Subject: [PATCH 3/6] use getlogin_r instead of getlogin, check for
 POSIX-compliant

accourding to https://linux.die.net/man/3/getlogin_r,
`_REENTRANT || _POSIX_C_SOURCE >= 199506L` checks the existance of getlogin_r
---
 flang/runtime/command.cpp | 44 ++++++++++++++++++++++++++++-----------
 1 file changed, 32 insertions(+), 12 deletions(-)

diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index c5171a1ef36f282..aa7c777d767cbc3 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -24,26 +24,30 @@
 #include <lmcons.h> // UNLEN=256
 #include <wchar.h> // wchar_t cast to LPWSTR
 #pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
+#define LOGIN_NAME_MAX UNLEN
 
-static inline char *getlogin() {
-  static char username[UNLEN + 1];
+inline int getlogin_r(char *buf, size_t bufSize) {
   wchar_t w_username[UNLEN + 1];
   DWORD namelen = sizeof(w_username) / sizeof(w_username[0]);
 
   if (GetUserName(w_username, &namelen)) {
     // Convert the wchar_t string to a regular C string
-    if (wcstombs(username, w_username, UNLEN + 1) == -1) {
+    if (wcstombs(buf, w_username, UNLEN + 1) == -1) {
       // Conversion failed
-      return NULL;
+      return -1;
     }
-    return (username[0] == 0 ? NULL : username);
+    return (buf[0] == 0 ? -1 : 0);
   } else {
-    return NULL;
+    return -1;
   }
-  return nullptr;
+  return -1;
 }
-#else
+#elif _REENTRANT || _POSIX_C_SOURCE >= 199506L
+// System is posix-compliant and has getlogin_r
 #include <unistd.h>
+#else
+// System is not posix-compliant
+inline int getlogin_r(char *buf, size_t bufsize) { return -1; }
 #endif
 
 namespace Fortran::runtime {
@@ -253,17 +257,33 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *value,
   return stat;
 }
 
+// Trim space from right/end
+char *RTrim(char *str) {
+  int i = strlen(str);
+  while (' ' == str[--i]) {
+    str[i] = 0;
+  }
+  return str;
+}
+
 std::int32_t RTNAME(GetLog)(const Descriptor *value, const Descriptor *errmsg) {
   FillWithSpaces(*value);
 
-  const char *arg = getlogin();
-  std::int64_t argLen{StringLength(arg)};
-  if (argLen <= 0) {
+  std::array<char, LOGIN_NAME_MAX + 1> str;
+  int err = getlogin_r(str.data(), str.size());
+  if (err != 0) {
+    return ToErrmsg(errmsg, StatMissingArgument);
+  }
+
+  RTrim(str.data());
+  std::int64_t strLen{StringLength(str.data())};
+
+  if (strLen <= 0) {
     return ToErrmsg(errmsg, StatMissingArgument);
   }
 
   if (value) {
-    return CopyToDescriptor(*value, arg, argLen, errmsg);
+    return CopyToDescriptor(*value, str.data(), strLen, errmsg);
   }
 
   return StatOk;

>From 72727baf225979fcf3108be7a6d936aaed20b97c Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Fri, 10 Nov 2023 15:06:08 +0000
Subject: [PATCH 4/6] move implementation to extension.cpp, add assert for
 failure, and format

---
 .../Optimizer/Builder/Runtime/RTBuilder.h     |  8 ---
 flang/include/flang/Runtime/command.h         |  6 --
 flang/runtime/command.cpp                     | 67 -------------------
 flang/runtime/extensions.cpp                  | 47 ++++++++++++-
 4 files changed, 45 insertions(+), 83 deletions(-)

diff --git a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
index 830df7ad006b54a..b2774263e7a31a4 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/RTBuilder.h
@@ -62,14 +62,6 @@ using FuncTypeBuilderFunc = mlir::FunctionType (*)(mlir::MLIRContext *);
 /// standard type `i32` when `sizeof(int)` is 4.
 template <typename T>
 static constexpr TypeBuilderFunc getModel();
-
-template <>
-constexpr TypeBuilderFunc getModel<unsigned int>() {
-  return [](mlir::MLIRContext *context) -> mlir::Type {
-    return mlir::IntegerType::get(context, 8 * sizeof(unsigned int));
-  };
-}
-
 template <>
 constexpr TypeBuilderFunc getModel<short int>() {
   return [](mlir::MLIRContext *context) -> mlir::Type {
diff --git a/flang/include/flang/Runtime/command.h b/flang/include/flang/Runtime/command.h
index 1c212ef61697cd5..ec6289390545479 100644
--- a/flang/include/flang/Runtime/command.h
+++ b/flang/include/flang/Runtime/command.h
@@ -47,12 +47,6 @@ std::int32_t RTNAME(GetEnvVariable)(const Descriptor &name,
     bool trim_name = true, const Descriptor *errmsg = nullptr,
     const char *sourceFile = nullptr, int line = 0);
 }
-
-// Try to get the name of current user
-// Returns a STATUS as described in the standard.
-std::int32_t RTNAME(GetLog)(
-    const Descriptor *argument = nullptr, const Descriptor *errmsg = nullptr);
-
 } // namespace Fortran::runtime
 
 #endif // FORTRAN_RUNTIME_COMMAND_H_
diff --git a/flang/runtime/command.cpp b/flang/runtime/command.cpp
index aa7c777d767cbc3..b81a0791c5e571b 100644
--- a/flang/runtime/command.cpp
+++ b/flang/runtime/command.cpp
@@ -14,41 +14,6 @@
 #include "flang/Runtime/descriptor.h"
 #include <cstdlib>
 #include <limits>
-#include <string.h>
-
-#ifdef _WIN32
-#define WIN32_LEAN_AND_MEAN
-#define NOMINMAX
-#include <windows.h>
-
-#include <lmcons.h> // UNLEN=256
-#include <wchar.h> // wchar_t cast to LPWSTR
-#pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
-#define LOGIN_NAME_MAX UNLEN
-
-inline int getlogin_r(char *buf, size_t bufSize) {
-  wchar_t w_username[UNLEN + 1];
-  DWORD namelen = sizeof(w_username) / sizeof(w_username[0]);
-
-  if (GetUserName(w_username, &namelen)) {
-    // Convert the wchar_t string to a regular C string
-    if (wcstombs(buf, w_username, UNLEN + 1) == -1) {
-      // Conversion failed
-      return -1;
-    }
-    return (buf[0] == 0 ? -1 : 0);
-  } else {
-    return -1;
-  }
-  return -1;
-}
-#elif _REENTRANT || _POSIX_C_SOURCE >= 199506L
-// System is posix-compliant and has getlogin_r
-#include <unistd.h>
-#else
-// System is not posix-compliant
-inline int getlogin_r(char *buf, size_t bufsize) { return -1; }
-#endif
 
 namespace Fortran::runtime {
 std::int32_t RTNAME(ArgumentCount)() {
@@ -257,38 +222,6 @@ std::int32_t RTNAME(GetCommand)(const Descriptor *value,
   return stat;
 }
 
-// Trim space from right/end
-char *RTrim(char *str) {
-  int i = strlen(str);
-  while (' ' == str[--i]) {
-    str[i] = 0;
-  }
-  return str;
-}
-
-std::int32_t RTNAME(GetLog)(const Descriptor *value, const Descriptor *errmsg) {
-  FillWithSpaces(*value);
-
-  std::array<char, LOGIN_NAME_MAX + 1> str;
-  int err = getlogin_r(str.data(), str.size());
-  if (err != 0) {
-    return ToErrmsg(errmsg, StatMissingArgument);
-  }
-
-  RTrim(str.data());
-  std::int64_t strLen{StringLength(str.data())};
-
-  if (strLen <= 0) {
-    return ToErrmsg(errmsg, StatMissingArgument);
-  }
-
-  if (value) {
-    return CopyToDescriptor(*value, str.data(), strLen, errmsg);
-  }
-
-  return StatOk;
-}
-
 static std::size_t LengthWithoutTrailingSpaces(const Descriptor &d) {
   std::size_t s{d.ElementBytes() - 1};
   while (*d.OffsetElement(s) == ' ') {
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 47b269d1e5b42af..a699196699ab8fc 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -13,6 +13,41 @@
 #include "flang/Runtime/command.h"
 #include "flang/Runtime/descriptor.h"
 #include "flang/Runtime/io-api.h"
+#include <string.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#define NOMINMAX
+#include <windows.h>
+
+#include <lmcons.h> // UNLEN=256
+#include <wchar.h> // wchar_t cast to LPWSTR
+#pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
+#define LOGIN_NAME_MAX UNLEN
+
+inline int getlogin_r(char *buf, size_t bufSize) {
+  wchar_t w_username[UNLEN + 1];
+  DWORD namelen = sizeof(w_username) / sizeof(w_username[0]);
+
+  if (GetUserName(w_username, &namelen)) {
+    // Convert the wchar_t string to a regular C string
+    if (wcstombs(buf, w_username, UNLEN + 1) == -1) {
+      // Conversion failed
+      return -1;
+    }
+    return (buf[0] == 0 ? -1 : 0);
+  } else {
+    return -1;
+  }
+  return -1;
+}
+#elif _REENTRANT || _POSIX_C_SOURCE >= 199506L
+// System is posix-compliant and has getlogin_r
+#include <unistd.h>
+#else
+// System is not posix-compliant
+inline int getlogin_r(char *buf, size_t bufsize) { return -1; }
+#endif
 
 extern "C" {
 
@@ -39,8 +74,16 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
 }
 
 void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
-  Descriptor value{*Descriptor::Create(1, length, arg, 0)};
-  (void)RTNAME(GetLog)(&value, nullptr);
+  std::array<char, LOGIN_NAME_MAX + 1> str;
+  int error = getlogin_r(str.data(), str.size());
+  assert(error == 0 && "getlogin_r returned an error");
+
+  // Trim space from right/end
+  int i = str.size();
+  while (' ' == str[--i]) {
+    str[i] = 0;
+  }
+  strncpy(reinterpret_cast<char *>(arg), str.data(), length);
 }
 
 } // namespace Fortran::runtime

>From 17cf43659f6c9e07ae58f54499706a0055cc5c71 Mon Sep 17 00:00:00 2001
From: Yi Wu <yiwu02 at wdev-yiwu02.arm.com>
Date: Mon, 13 Nov 2023 16:03:19 +0000
Subject: [PATCH 5/6] Use a more secure version for transfoom wchar_t to char

---
 flang/runtime/extensions.cpp | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index a699196699ab8fc..aa14fb952ceb21c 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -21,17 +21,19 @@
 #include <windows.h>
 
 #include <lmcons.h> // UNLEN=256
+#include <stdlib.h> // wcstombs_s
 #include <wchar.h> // wchar_t cast to LPWSTR
 #pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
 #define LOGIN_NAME_MAX UNLEN
 
 inline int getlogin_r(char *buf, size_t bufSize) {
   wchar_t w_username[UNLEN + 1];
-  DWORD namelen = sizeof(w_username) / sizeof(w_username[0]);
+  DWORD nameLen = UNLEN + 1;
 
-  if (GetUserName(w_username, &namelen)) {
-    // Convert the wchar_t string to a regular C string
-    if (wcstombs(buf, w_username, UNLEN + 1) == -1) {
+  if (GetUserNameW(w_username, &nameLen)) {
+    // Convert the wchar_t string to a regular C string using wcstombs_s
+    if (wcstombs_s(nullptr, buf, sizeof(w_username), w_username, _TRUNCATE) !=
+        0) {
       // Conversion failed
       return -1;
     }
@@ -41,6 +43,7 @@ inline int getlogin_r(char *buf, size_t bufSize) {
   }
   return -1;
 }
+
 #elif _REENTRANT || _POSIX_C_SOURCE >= 199506L
 // System is posix-compliant and has getlogin_r
 #include <unistd.h>

>From 5f513f3bf0db25a788024d1c9ef429522b470549 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 15 Nov 2023 11:06:01 +0000
Subject: [PATCH 6/6] use cstring not string.h, add terminator, fill buffer
 with space

take copyBufferAndPad() out of anonymous namespace,
so it can be called in other places.
---
 flang/include/flang/Runtime/time-intrinsic.h | 11 +++++++++
 flang/runtime/extensions.cpp                 | 26 +++++++++++---------
 flang/runtime/time-intrinsic.cpp             | 25 ++++++++++---------
 3 files changed, 40 insertions(+), 22 deletions(-)

diff --git a/flang/include/flang/Runtime/time-intrinsic.h b/flang/include/flang/Runtime/time-intrinsic.h
index 650c02436ee49ea..a0c863712131b5c 100644
--- a/flang/include/flang/Runtime/time-intrinsic.h
+++ b/flang/include/flang/Runtime/time-intrinsic.h
@@ -9,6 +9,17 @@
 // Defines the API between compiled code and the implementations of time-related
 // intrinsic subroutines in the runtime library.
 
+// time-intrinsic.h
+#ifndef TIME_INTRINSIC_H
+#define TIME_INTRINSIC_H
+
+#include <cstddef>
+
+void copyBufferAndPad(
+    char *dest, std::size_t destChars, char *buffer, std::size_t len);
+
+#endif // TIME_INTRINSIC_H
+
 #ifndef FORTRAN_RUNTIME_TIME_INTRINSIC_H_
 #define FORTRAN_RUNTIME_TIME_INTRINSIC_H_
 
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index aa14fb952ceb21c..fe957d89853f704 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -10,18 +10,20 @@
 // extensions that will eventually be implemented in Fortran.
 
 #include "flang/Runtime/extensions.h"
+#include "terminator.h"
 #include "flang/Runtime/command.h"
 #include "flang/Runtime/descriptor.h"
 #include "flang/Runtime/io-api.h"
-#include <string.h>
+#include "flang/Runtime/time-intrinsic.h" // copyBufferAndPad
+#include <cstring>
 
 #ifdef _WIN32
 #define WIN32_LEAN_AND_MEAN
 #define NOMINMAX
 #include <windows.h>
 
+#include <cstdlib> // wcstombs_s
 #include <lmcons.h> // UNLEN=256
-#include <stdlib.h> // wcstombs_s
 #include <wchar.h> // wchar_t cast to LPWSTR
 #pragma comment(lib, "Advapi32.lib") // Link Advapi32.lib for GetUserName
 #define LOGIN_NAME_MAX UNLEN
@@ -30,7 +32,7 @@ inline int getlogin_r(char *buf, size_t bufSize) {
   wchar_t w_username[UNLEN + 1];
   DWORD nameLen = UNLEN + 1;
 
-  if (GetUserNameW(w_username, &nameLen)) {
+  if (GetUserName(w_username, &nameLen)) {
     // Convert the wchar_t string to a regular C string using wcstombs_s
     if (wcstombs_s(nullptr, buf, sizeof(w_username), w_username, _TRUNCATE) !=
         0) {
@@ -49,7 +51,11 @@ inline int getlogin_r(char *buf, size_t bufSize) {
 #include <unistd.h>
 #else
 // System is not posix-compliant
-inline int getlogin_r(char *buf, size_t bufsize) { return -1; }
+inline int getlogin_r(char *buf, size_t bufSize) {
+  std::memset(buf, ' ', bufSize - 1);
+  buf[bufSize - 1] = '\0';
+  return 0;
+}
 #endif
 
 extern "C" {
@@ -78,15 +84,13 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
 
 void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
   std::array<char, LOGIN_NAME_MAX + 1> str;
+
   int error = getlogin_r(str.data(), str.size());
-  assert(error == 0 && "getlogin_r returned an error");
+  Terminator terminator{__FILE__, __LINE__};
+  RUNTIME_CHECK(terminator, error == 0);
 
-  // Trim space from right/end
-  int i = str.size();
-  while (' ' == str[--i]) {
-    str[i] = 0;
-  }
-  strncpy(reinterpret_cast<char *>(arg), str.data(), length);
+  copyBufferAndPad(
+      reinterpret_cast<char *>(arg), length, str.data(), str.size());
 }
 
 } // namespace Fortran::runtime
diff --git a/flang/runtime/time-intrinsic.cpp b/flang/runtime/time-intrinsic.cpp
index 68d63253139f18a..8e8712f3b5e2974 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -39,6 +39,16 @@
 // overload will have a dummy parameter whose type indicates whether or not it
 // should be preferred. Any other parameters required for SFINAE should have
 // default values provided.
+
+void copyBufferAndPad(
+    char *dest, std::size_t destChars, char *buffer, std::size_t len) {
+  auto copyLen{std::min(len, destChars)};
+  std::memcpy(dest, buffer, copyLen);
+  for (auto i{copyLen}; i < destChars; ++i) {
+    dest[i] = ' ';
+  }
+}
+
 namespace {
 // Types for the dummy parameter indicating the priority of a given overload.
 // We will invoke our helper with an integer literal argument, so the overload
@@ -279,29 +289,22 @@ static void GetDateAndTime(Fortran::runtime::Terminator &terminator, char *date,
 
   static constexpr std::size_t buffSize{16};
   char buffer[buffSize];
-  auto copyBufferAndPad{
-      [&](char *dest, std::size_t destChars, std::size_t len) {
-        auto copyLen{std::min(len, destChars)};
-        std::memcpy(dest, buffer, copyLen);
-        for (auto i{copyLen}; i < destChars; ++i) {
-          dest[i] = ' ';
-        }
-      }};
+
   if (date) {
     auto len = std::strftime(buffer, buffSize, "%Y%m%d", &localTime);
-    copyBufferAndPad(date, dateChars, len);
+    copyBufferAndPad(date, dateChars, buffer, len);
   }
   if (time) {
     auto len{std::snprintf(buffer, buffSize, "%02d%02d%02d.%03jd",
         localTime.tm_hour, localTime.tm_min, localTime.tm_sec, ms)};
-    copyBufferAndPad(time, timeChars, len);
+    copyBufferAndPad(time, timeChars, buffer, len);
   }
   if (zone) {
     // Note: this may leave the buffer empty on many platforms. Classic flang
     // has a much more complex way of doing this (see __io_timezone in classic
     // flang).
     auto len{std::strftime(buffer, buffSize, "%z", &localTime)};
-    copyBufferAndPad(zone, zoneChars, len);
+    copyBufferAndPad(zone, zoneChars, buffer, len);
   }
   if (values) {
     auto typeCode{values->type().GetCategoryAndKind()};



More information about the cfe-commits mailing list