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....@arm.com> Date: Mon, 6 Nov 2023 19:49:13 +0000 Subject: [PATCH 01/17] 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....@arm.com> Date: Tue, 7 Nov 2023 15:09:23 +0000 Subject: [PATCH 02/17] 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....@arm.com> Date: Fri, 10 Nov 2023 10:44:12 +0000 Subject: [PATCH 03/17] 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....@arm.com> Date: Fri, 10 Nov 2023 15:06:08 +0000 Subject: [PATCH 04/17] 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 <yiw...@wdev-yiwu02.arm.com> Date: Mon, 13 Nov 2023 16:03:19 +0000 Subject: [PATCH 05/17] 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....@arm.com> Date: Wed, 15 Nov 2023 11:06:01 +0000 Subject: [PATCH 06/17] 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....@arm.com> Date: Wed, 22 Nov 2023 13:40:38 +0000 Subject: [PATCH 07/17] 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-...@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:04:46 +0000 Subject: [PATCH 08/17] Update flang/runtime/extensions.cpp: brace initialization Co-authored-by: Kiran Chandramohan <kiranchandramo...@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-...@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:06:08 +0000 Subject: [PATCH 09/17] Update flang/runtime/extensions.cpp: brace initialization Co-authored-by: Kiran Chandramohan <kiranchandramo...@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....@arm.com> Date: Wed, 22 Nov 2023 15:07:15 +0000 Subject: [PATCH 10/17] 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....@arm.com> Date: Mon, 27 Nov 2023 17:24:18 +0000 Subject: [PATCH 11/17] 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....@arm.com> Date: Tue, 5 Dec 2023 13:14:58 +0000 Subject: [PATCH 12/17] 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....@arm.com> Date: Tue, 5 Dec 2023 16:39:57 +0000 Subject: [PATCH 13/17] 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....@arm.com> Date: Wed, 6 Dec 2023 10:40:37 +0000 Subject: [PATCH 14/17] 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....@arm.com> Date: Wed, 6 Dec 2023 10:57:28 +0000 Subject: [PATCH 15/17] 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....@arm.com> Date: Wed, 6 Dec 2023 12:42:37 +0000 Subject: [PATCH 16/17] 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) >From 3ac03a67ea06185f8cdbe1f0cbb8c88405f3492b Mon Sep 17 00:00:00 2001 From: Yi Wu <yi....@arm.com> Date: Wed, 6 Dec 2023 13:11:23 +0000 Subject: [PATCH 17/17] use env to set and test user name --- flang/unittests/Runtime/CMakeLists.txt | 1 - flang/unittests/Runtime/CommandTest.cpp | 31 ++++++++++++++ flang/unittests/Runtime/ExtensionTest.cpp | 49 ----------------------- 3 files changed, 31 insertions(+), 50 deletions(-) delete mode 100644 flang/unittests/Runtime/ExtensionTest.cpp diff --git a/flang/unittests/Runtime/CMakeLists.txt b/flang/unittests/Runtime/CMakeLists.txt index a25472409ac94..23f02aa751246 100644 --- a/flang/unittests/Runtime/CMakeLists.txt +++ b/flang/unittests/Runtime/CMakeLists.txt @@ -7,7 +7,6 @@ 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 d003eacd177e8..6287e6a40c681 100644 --- a/flang/unittests/Runtime/CommandTest.cpp +++ b/flang/unittests/Runtime/CommandTest.cpp @@ -398,6 +398,7 @@ class EnvironmentVariables : public CommandFixture { protected: EnvironmentVariables() : CommandFixture(0, nullptr) { SetEnv("NAME", "VALUE"); + SetEnv("LOGNAME", "loginName"); SetEnv("EMPTY", ""); } @@ -495,3 +496,33 @@ TEST_F(EnvironmentVariables, ErrMsgTooShort) { 1); CheckDescriptorEqStr(errMsg.get(), "Mis"); } + +TEST_F(EnvironmentVariables, GetlogGetName) { + const int charLen{11}; + char input[charLen]{"XXXXXXXXX"}; + + FORTRAN_PROCEDURE_NAME(getlog) + (reinterpret_cast<std::int8_t *>(input), charLen); + + EXPECT_NE(input, "loginName"); +} + +TEST_F(EnvironmentVariables, GetlogBufferShort) { + const int charLen{7}; + char input[charLen]{"XXXXXX"}; + + FORTRAN_PROCEDURE_NAME(getlog) + (reinterpret_cast<std::int8_t *>(input), charLen); + + EXPECT_NE(input, "loginN"); +} + +TEST_F(EnvironmentVariables, GetlogPadSpace) { + const int charLen{12}; + char input[charLen]{"XXXXXXXXXX"}; + + FORTRAN_PROCEDURE_NAME(getlog) + (reinterpret_cast<std::int8_t *>(input), charLen); + + EXPECT_NE(input, "loginName "); +} diff --git a/flang/unittests/Runtime/ExtensionTest.cpp b/flang/unittests/Runtime/ExtensionTest.cpp deleted file mode 100644 index a74da4e7005ba..0000000000000 --- a/flang/unittests/Runtime/ExtensionTest.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===-- 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 -#define LOGIN_NAME_MAX UNLEN -#else -#include <limits.h> // LOGIN_NAME_MAX -#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) { - // 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) - (reinterpret_cast<std::int8_t *>(input), charLen); - - EXPECT_EQ(input[charLen - 1], ' '); -} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits