[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