[flang] [llvm] [clang-tools-extra] [clang] [flang ]GETLOG runtime and extension implementation: get login username (PR #70917)
Yi Wu via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 6 04:43:46 PST 2023
https://github.com/yi-wu-arm 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 01/16] 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 ab0a940e53e55..cfe5dcd141e98 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 b2774263e7a31..830df7ad006b5 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 ec62893905454..1c212ef61697c 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 ad592814e5acb..d199d5e387b86 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 b81a0791c5e57..6b2f313e227a1 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 b8e9b6eae1320..47b269d1e5b42 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 c3571c9684e4b..e33dd7b0469eb 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 02/16] 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 6b2f313e227a1..c5171a1ef36f2 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 e33dd7b0469eb..686dc273142ba 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 03/16] 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 c5171a1ef36f2..aa7c777d767cb 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 04/16] 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 830df7ad006b5..b2774263e7a31 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 1c212ef61697c..ec62893905454 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 aa7c777d767cb..b81a0791c5e57 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 47b269d1e5b42..a699196699ab8 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 05/16] 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 a699196699ab8..aa14fb952ceb2 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 a1b1b66fab3add35f33e6f56618b3c28e5cfdbf8 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 06/16] 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 | 29 +++++++++++---------
flang/runtime/time-intrinsic.cpp | 26 ++++++++++--------
3 files changed, 42 insertions(+), 24 deletions(-)
diff --git a/flang/include/flang/Runtime/time-intrinsic.h b/flang/include/flang/Runtime/time-intrinsic.h
index 650c02436ee49..a0c863712131b 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 aa14fb952ceb2..ea53d97d98005 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,10 +32,9 @@ 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) {
+ if (wcstombs_s(nullptr, buf, bufSize, w_username, _TRUNCATE) != 0) {
// Conversion failed
return -1;
}
@@ -49,7 +50,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 +83,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 68d63253139f1..6a42734d78739 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -39,6 +39,17 @@
// 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.
+
+// outside anonymous namespace, function reused
+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 +290,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()};
>From fb910d1e9587a1558b62ccd54ab0be064e0429e9 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 22 Nov 2023 13:40:38 +0000
Subject: [PATCH 07/16] brace initialize array
---
flang/runtime/extensions.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index ea53d97d98005..23daa3eeb9d6c 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -29,7 +29,7 @@
#define LOGIN_NAME_MAX UNLEN
inline int getlogin_r(char *buf, size_t bufSize) {
- wchar_t w_username[UNLEN + 1];
+ wchar_t w_username[UNLEN + 1] = {};
DWORD nameLen = UNLEN + 1;
if (GetUserName(w_username, &nameLen)) {
@@ -82,7 +82,7 @@ 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;
+ std::array<char, LOGIN_NAME_MAX + 1> str = {};
int error = getlogin_r(str.data(), str.size());
Terminator terminator{__FILE__, __LINE__};
>From f066c81f943a266afbdcdd1bbd3123c27b690114 Mon Sep 17 00:00:00 2001
From: Yi Wu <43659785+yi-wu-arm at users.noreply.github.com>
Date: Wed, 22 Nov 2023 14:04:46 +0000
Subject: [PATCH 08/16] Update flang/runtime/extensions.cpp: brace
initialization
Co-authored-by: Kiran Chandramohan <kiranchandramohan at gmail.com>
---
flang/runtime/extensions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 23daa3eeb9d6c..e630abea799bd 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -30,7 +30,7 @@
inline int getlogin_r(char *buf, size_t bufSize) {
wchar_t w_username[UNLEN + 1] = {};
- DWORD nameLen = UNLEN + 1;
+ DWORD nameLen{UNLEN + 1};
if (GetUserName(w_username, &nameLen)) {
// Convert the wchar_t string to a regular C string using wcstombs_s
>From 8997af86097897765f8b1a5aba84ab357d07a5bc Mon Sep 17 00:00:00 2001
From: Yi Wu <43659785+yi-wu-arm at users.noreply.github.com>
Date: Wed, 22 Nov 2023 14:06:08 +0000
Subject: [PATCH 09/16] Update flang/runtime/extensions.cpp: brace
initialization
Co-authored-by: Kiran Chandramohan <kiranchandramohan at gmail.com>
---
flang/runtime/extensions.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index e630abea799bd..646ad120fcdfa 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -84,7 +84,7 @@ 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());
+ int error{getlogin_r(str.data(), str.size())};
Terminator terminator{__FILE__, __LINE__};
RUNTIME_CHECK(terminator, error == 0);
>From bad673a37d15418dd5119b639388e4600bbba197 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 22 Nov 2023 15:07:15 +0000
Subject: [PATCH 10/16] Revert "brace initialize array"
This reverts commit fb910d1e9587a1558b62ccd54ab0be064e0429e9.
---
flang/runtime/extensions.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 646ad120fcdfa..36f76a2f0e7b1 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -29,7 +29,7 @@
#define LOGIN_NAME_MAX UNLEN
inline int getlogin_r(char *buf, size_t bufSize) {
- wchar_t w_username[UNLEN + 1] = {};
+ wchar_t w_username[UNLEN + 1];
DWORD nameLen{UNLEN + 1};
if (GetUserName(w_username, &nameLen)) {
@@ -82,7 +82,7 @@ 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 = {};
+ std::array<char, LOGIN_NAME_MAX + 1> str;
int error{getlogin_r(str.data(), str.size())};
Terminator terminator{__FILE__, __LINE__};
>From b55bb5f23064eb342fb860e7e23ba49a84947b4c Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Mon, 27 Nov 2023 17:24:18 +0000
Subject: [PATCH 11/16] final nits
---
flang/include/flang/Runtime/time-intrinsic.h | 4 ++--
flang/runtime/extensions.cpp | 4 ++--
flang/runtime/time-intrinsic.cpp | 10 +++++-----
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/flang/include/flang/Runtime/time-intrinsic.h b/flang/include/flang/Runtime/time-intrinsic.h
index a0c863712131b..6f1e0f390abeb 100644
--- a/flang/include/flang/Runtime/time-intrinsic.h
+++ b/flang/include/flang/Runtime/time-intrinsic.h
@@ -15,8 +15,8 @@
#include <cstddef>
-void copyBufferAndPad(
- char *dest, std::size_t destChars, char *buffer, std::size_t len);
+void CopyBufferAndPad(
+ char *dest, std::size_t destChars, const char *buffer, std::size_t len);
#endif // TIME_INTRINSIC_H
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 36f76a2f0e7b1..1a3d2c8f74593 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -14,7 +14,7 @@
#include "flang/Runtime/command.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/io-api.h"
-#include "flang/Runtime/time-intrinsic.h" // copyBufferAndPad
+#include "flang/Runtime/time-intrinsic.h" // CopyBufferAndPad
#include <cstring>
#ifdef _WIN32
@@ -88,7 +88,7 @@ void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
Terminator terminator{__FILE__, __LINE__};
RUNTIME_CHECK(terminator, error == 0);
- copyBufferAndPad(
+ CopyBufferAndPad(
reinterpret_cast<char *>(arg), length, str.data(), str.size());
}
diff --git a/flang/runtime/time-intrinsic.cpp b/flang/runtime/time-intrinsic.cpp
index 6a42734d78739..6d234a58ff8a4 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -41,8 +41,8 @@
// default values provided.
// outside anonymous namespace, function reused
-void copyBufferAndPad(
- char *dest, std::size_t destChars, char *buffer, std::size_t len) {
+void CopyBufferAndPad(
+ char *dest, std::size_t destChars, const char *buffer, std::size_t len) {
auto copyLen{std::min(len, destChars)};
std::memcpy(dest, buffer, copyLen);
for (auto i{copyLen}; i < destChars; ++i) {
@@ -293,19 +293,19 @@ static void GetDateAndTime(Fortran::runtime::Terminator &terminator, char *date,
if (date) {
auto len = std::strftime(buffer, buffSize, "%Y%m%d", &localTime);
- copyBufferAndPad(date, dateChars, buffer, 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, buffer, 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, buffer, len);
+ CopyBufferAndPad(zone, zoneChars, buffer, len);
}
if (values) {
auto typeCode{values->type().GetCategoryAndKind()};
>From d1470b0fe34f025519552ddc682f742ae821a2f9 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Tue, 5 Dec 2023 13:14:58 +0000
Subject: [PATCH 12/16] Revert "use cstring not string.h, add terminator, fill
buffer with space"
This reverts commit a1b1b66fab3add35f33e6f56618b3c28e5cfdbf8.
---
flang/include/flang/Runtime/time-intrinsic.h | 11 ---------
flang/runtime/extensions.cpp | 9 +++----
flang/runtime/time-intrinsic.cpp | 26 +++++++++-----------
3 files changed, 15 insertions(+), 31 deletions(-)
diff --git a/flang/include/flang/Runtime/time-intrinsic.h b/flang/include/flang/Runtime/time-intrinsic.h
index 6f1e0f390abeb..650c02436ee49 100644
--- a/flang/include/flang/Runtime/time-intrinsic.h
+++ b/flang/include/flang/Runtime/time-intrinsic.h
@@ -9,17 +9,6 @@
// 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, const 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 1a3d2c8f74593..7e0f6494779f1 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -14,7 +14,6 @@
#include "flang/Runtime/command.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/io-api.h"
-#include "flang/Runtime/time-intrinsic.h" // CopyBufferAndPad
#include <cstring>
#ifdef _WIN32
@@ -82,14 +81,14 @@ 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 charLen{LOGIN_NAME_MAX + 1};
+ char str[charLen];
- int error{getlogin_r(str.data(), str.size())};
+ int error{getlogin_r(*str, charLen)};
Terminator terminator{__FILE__, __LINE__};
RUNTIME_CHECK(terminator, error == 0);
- CopyBufferAndPad(
- reinterpret_cast<char *>(arg), length, str.data(), str.size());
+ CopyBufferAndPad(reinterpret_cast<char *>(arg), length, *str, charLen);
}
} // namespace Fortran::runtime
diff --git a/flang/runtime/time-intrinsic.cpp b/flang/runtime/time-intrinsic.cpp
index 6d234a58ff8a4..68d63253139f1 100644
--- a/flang/runtime/time-intrinsic.cpp
+++ b/flang/runtime/time-intrinsic.cpp
@@ -39,17 +39,6 @@
// 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.
-
-// outside anonymous namespace, function reused
-void CopyBufferAndPad(
- char *dest, std::size_t destChars, const 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
@@ -290,22 +279,29 @@ 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, buffer, len);
+ copyBufferAndPad(date, dateChars, 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, buffer, len);
+ copyBufferAndPad(time, timeChars, 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, buffer, len);
+ copyBufferAndPad(zone, zoneChars, len);
}
if (values) {
auto typeCode{values->type().GetCategoryAndKind()};
>From 85d42d49042ee003ee0cb1a946be02c102d530a1 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Tue, 5 Dec 2023 16:39:57 +0000
Subject: [PATCH 13/16] move and use CopyAndPad from character.h
The compiler must have access to the implementations
of templated functions at the points where they're instantiated.
---
flang/include/flang/Runtime/character.h | 30 +++++++++++++++++++++++++
flang/runtime/character.cpp | 22 +-----------------
flang/runtime/extensions.cpp | 11 ++++-----
3 files changed, 37 insertions(+), 26 deletions(-)
diff --git a/flang/include/flang/Runtime/character.h b/flang/include/flang/Runtime/character.h
index 24f26920bdd2c..ec1fb02751164 100644
--- a/flang/include/flang/Runtime/character.h
+++ b/flang/include/flang/Runtime/character.h
@@ -6,6 +6,36 @@
//
//===----------------------------------------------------------------------===//
+// character.h
+#ifndef CHARACTER_H
+#define CHARACTER_H
+
+#include <cstddef>
+#include <algorithm>
+
+template <typename TO, typename FROM>
+void CopyAndPad(
+ TO *to, const FROM *from, std::size_t toChars, std::size_t fromChars) {
+ if constexpr (sizeof(TO) != sizeof(FROM)) {
+ std::size_t copyChars{std::min(toChars, fromChars)};
+ for (std::size_t j{0}; j < copyChars; ++j) {
+ to[j] = from[j];
+ }
+ for (std::size_t j{copyChars}; j < toChars; ++j) {
+ to[j] = static_cast<TO>(' ');
+ }
+ } else if (toChars <= fromChars) {
+ std::memcpy(to, from, toChars * sizeof(TO));
+ } else {
+ std::memcpy(to, from, fromChars * sizeof(TO));
+ for (std::size_t j{fromChars}; j < toChars; ++j) {
+ to[j] = static_cast<TO>(' ');
+ }
+ }
+}
+
+#endif // CHARACTER_H
+
// Defines API between compiled code and the CHARACTER
// support functions in the runtime library.
diff --git a/flang/runtime/character.cpp b/flang/runtime/character.cpp
index dd522f19a7ede..2a62a60874e74 100644
--- a/flang/runtime/character.cpp
+++ b/flang/runtime/character.cpp
@@ -11,6 +11,7 @@
#include "tools.h"
#include "flang/Common/bit-population-count.h"
#include "flang/Common/uint128.h"
+#include "flang/Runtime/character.h"
#include "flang/Runtime/cpp-type.h"
#include "flang/Runtime/descriptor.h"
#include <algorithm>
@@ -461,27 +462,6 @@ static void GeneralCharFuncKind(Descriptor &result, const Descriptor &string,
}
}
-template <typename TO, typename FROM>
-static void CopyAndPad(
- TO *to, const FROM *from, std::size_t toChars, std::size_t fromChars) {
- if constexpr (sizeof(TO) != sizeof(FROM)) {
- std::size_t copyChars{std::min(toChars, fromChars)};
- for (std::size_t j{0}; j < copyChars; ++j) {
- to[j] = from[j];
- }
- for (std::size_t j{copyChars}; j < toChars; ++j) {
- to[j] = static_cast<TO>(' ');
- }
- } else if (toChars <= fromChars) {
- std::memcpy(to, from, toChars * sizeof(TO));
- } else {
- std::memcpy(to, from, fromChars * sizeof(TO));
- for (std::size_t j{fromChars}; j < toChars; ++j) {
- to[j] = static_cast<TO>(' ');
- }
- }
-}
-
template <typename CHAR, bool ISMIN>
static void MaxMinHelper(Descriptor &accumulator, const Descriptor &x,
const Terminator &terminator) {
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 7e0f6494779f1..ee34eef99d4db 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -11,10 +11,10 @@
#include "flang/Runtime/extensions.h"
#include "terminator.h"
+#include "flang/Runtime/character.h"
#include "flang/Runtime/command.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/io-api.h"
-#include <cstring>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
@@ -81,14 +81,15 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
}
void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
- int charLen{LOGIN_NAME_MAX + 1};
- char str[charLen];
+ const int nameMaxLen = LOGIN_NAME_MAX + 1;
+ char str[nameMaxLen];
- int error{getlogin_r(*str, charLen)};
+ int error{getlogin_r(str, nameMaxLen)};
Terminator terminator{__FILE__, __LINE__};
RUNTIME_CHECK(terminator, error == 0);
- CopyBufferAndPad(reinterpret_cast<char *>(arg), length, *str, charLen);
+ // find first \0 in string then pad from there
+ CopyAndPad(reinterpret_cast<char *>(arg), str, length, std::strlen(str));
}
} // namespace Fortran::runtime
>From 99117e491ba0fd81dd7790bde6de91d0906b5a3b Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 6 Dec 2023 10:40:37 +0000
Subject: [PATCH 14/16] better tests and use min length for memcpy
---
flang/include/flang/Runtime/character.h | 5 ++-
flang/include/flang/Runtime/extensions.h | 1 +
flang/runtime/extensions.cpp | 2 +-
flang/unittests/Runtime/CMakeLists.txt | 1 +
flang/unittests/Runtime/CommandTest.cpp | 14 +------
flang/unittests/Runtime/ExtensionTest.cpp | 48 +++++++++++++++++++++++
6 files changed, 55 insertions(+), 16 deletions(-)
create mode 100644 flang/unittests/Runtime/ExtensionTest.cpp
diff --git a/flang/include/flang/Runtime/character.h b/flang/include/flang/Runtime/character.h
index ec1fb02751164..52cd48f9637e6 100644
--- a/flang/include/flang/Runtime/character.h
+++ b/flang/include/flang/Runtime/character.h
@@ -10,8 +10,9 @@
#ifndef CHARACTER_H
#define CHARACTER_H
-#include <cstddef>
#include <algorithm>
+#include <cstddef>
+#include <cstring>
template <typename TO, typename FROM>
void CopyAndPad(
@@ -27,7 +28,7 @@ void CopyAndPad(
} else if (toChars <= fromChars) {
std::memcpy(to, from, toChars * sizeof(TO));
} else {
- std::memcpy(to, from, fromChars * sizeof(TO));
+ std::memcpy(to, from, std::min(toChars, fromChars) * sizeof(TO));
for (std::size_t j{fromChars}; j < toChars; ++j) {
to[j] = static_cast<TO>(' ');
}
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index d199d5e387b86..4f78e92ae677b 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -28,6 +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);
+// GNU extension subroutine GETLOG(C).
void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *name, std::int64_t length);
} // extern "C"
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index ee34eef99d4db..21d2ece06865a 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -81,7 +81,7 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
}
void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
- const int nameMaxLen = LOGIN_NAME_MAX + 1;
+ const int nameMaxLen{LOGIN_NAME_MAX + 1};
char str[nameMaxLen];
int error{getlogin_r(str, nameMaxLen)};
diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt
index 23f02aa751246..a25472409ac94 100644
--- a/flang/unittests/Runtime/CMakeLists.txt
+++ b/flang/unittests/Runtime/CMakeLists.txt
@@ -7,6 +7,7 @@ add_flang_unittest(FlangRuntimeTests
Complex.cpp
CrashHandlerFixture.cpp
Derived.cpp
+ ExtensionTest.cpp
ExternalIOTest.cpp
Format.cpp
Inquiry.cpp
diff --git a/flang/unittests/Runtime/CommandTest.cpp b/flang/unittests/Runtime/CommandTest.cpp
index 61209541cdb1e..d003eacd177e8 100644
--- a/flang/unittests/Runtime/CommandTest.cpp
+++ b/flang/unittests/Runtime/CommandTest.cpp
@@ -10,6 +10,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/extensions.h"
#include "flang/Runtime/main.h"
#include <cstdlib>
@@ -225,12 +226,6 @@ 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"};
@@ -248,13 +243,6 @@ 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[]{
diff --git a/flang/unittests/Runtime/ExtensionTest.cpp b/flang/unittests/Runtime/ExtensionTest.cpp
new file mode 100644
index 0000000000000..d1147f18c2159
--- /dev/null
+++ b/flang/unittests/Runtime/ExtensionTest.cpp
@@ -0,0 +1,48 @@
+//===-- flang/unittests/Runtime/ExtensionTest.cpp
+//---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "CrashHandlerFixture.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+#include "flang/Runtime/descriptor.h"
+#include "flang/Runtime/extensions.h"
+#include "flang/Runtime/main.h"
+#include <cstdlib>
+
+#ifdef _WIN32
+#include <lmcons.h> // UNLEN=256
+#define LOGIN_NAME_MAX UNLEN
+#else
+#include <limits.h>
+#endif
+
+using namespace Fortran::runtime;
+
+struct ExtensionTests : CrashHandlerFixture {};
+
+TEST_F(ExtensionTests, GetlogGetName) {
+ const int charLen{3};
+ char input[charLen]{"\0\0"};
+
+ FORTRAN_PROCEDURE_NAME(getlog)
+ (reinterpret_cast<std::int8_t *>(input), charLen);
+
+ EXPECT_NE(input[0], '\0');
+}
+
+TEST_F(ExtensionTests, GetlogPadSpace) {
+ const int charLen{LOGIN_NAME_MAX +
+ 2}; // guarantee 1 char longer than max, last char should be pad space
+ char input[charLen];
+
+ FORTRAN_PROCEDURE_NAME(getlog)
+ (reinterpret_cast<std::int8_t *>(input), charLen);
+
+ EXPECT_EQ(input[charLen - 1], ' ');
+}
\ No newline at end of file
>From ea2ea3b3a473e0d0092ad8865c49f7e627a03c64 Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 6 Dec 2023 10:57:28 +0000
Subject: [PATCH 15/16] doc change: move getlog to Library subroutine row
---
flang/docs/Intrinsics.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index fd16ed3bcd6b6..4a6e68d708efb 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -657,6 +657,11 @@ CALL CO_REDUCE
CALL CO_SUM
```
+### Library subroutine
+```
+CALL GETLOG(USRNAME)
+```
+
## Non-standard intrinsics
### PGI
```
@@ -751,9 +756,10 @@ 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, GETPID, 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, GETLOG, 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, MOVE_ALLOC, RANDOM_INIT, RANDOM_NUMBER, RANDOM_SEED, SYSTEM_CLOCK |
| Atomic intrinsic subroutines | ATOMIC_ADD |
| Collective intrinsic subroutines | CO_REDUCE |
+| Library subroutines | GETLOG|
### Intrinsic Function Folding
>From 67d404585846786455310b55b44b2d1ac41caf7c Mon Sep 17 00:00:00 2001
From: Yi Wu <yi.wu2 at arm.com>
Date: Wed, 6 Dec 2023 12:42:37 +0000
Subject: [PATCH 16/16] small fixes to tests
---
flang/runtime/extensions.cpp | 5 ++++-
flang/unittests/Runtime/ExtensionTest.cpp | 9 +++++----
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/flang/runtime/extensions.cpp b/flang/runtime/extensions.cpp
index 21d2ece06865a..2457731ba7b92 100644
--- a/flang/runtime/extensions.cpp
+++ b/flang/runtime/extensions.cpp
@@ -80,13 +80,16 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
n, &value, nullptr, nullptr, __FILE__, __LINE__);
}
+// CALL GETLOG(USRNAME)
void FORTRAN_PROCEDURE_NAME(getlog)(std::int8_t *arg, std::int64_t length) {
const int nameMaxLen{LOGIN_NAME_MAX + 1};
char str[nameMaxLen];
int error{getlogin_r(str, nameMaxLen)};
Terminator terminator{__FILE__, __LINE__};
- RUNTIME_CHECK(terminator, error == 0);
+ if (error != 0) {
+ terminator.Crash("getlogin_r fail with a nonzero value: %d.\n", error);
+ }
// find first \0 in string then pad from there
CopyAndPad(reinterpret_cast<char *>(arg), str, length, std::strlen(str));
diff --git a/flang/unittests/Runtime/ExtensionTest.cpp b/flang/unittests/Runtime/ExtensionTest.cpp
index d1147f18c2159..a74da4e7005ba 100644
--- a/flang/unittests/Runtime/ExtensionTest.cpp
+++ b/flang/unittests/Runtime/ExtensionTest.cpp
@@ -16,10 +16,10 @@
#include <cstdlib>
#ifdef _WIN32
-#include <lmcons.h> // UNLEN=256
+#include <lmcons.h> // UNLEN
#define LOGIN_NAME_MAX UNLEN
#else
-#include <limits.h>
+#include <limits.h> // LOGIN_NAME_MAX
#endif
using namespace Fortran::runtime;
@@ -37,8 +37,9 @@ TEST_F(ExtensionTests, GetlogGetName) {
}
TEST_F(ExtensionTests, GetlogPadSpace) {
- const int charLen{LOGIN_NAME_MAX +
- 2}; // guarantee 1 char longer than max, last char should be pad space
+ // guarantee 1 char longer than max, last char should be pad with space
+ const int charLen{LOGIN_NAME_MAX + 2};
+
char input[charLen];
FORTRAN_PROCEDURE_NAME(getlog)
More information about the llvm-commits
mailing list