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/11] 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....@arm.com> Date: Tue, 7 Nov 2023 15:09:23 +0000 Subject: [PATCH 02/11] 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....@arm.com> Date: Fri, 10 Nov 2023 10:44:12 +0000 Subject: [PATCH 03/11] 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....@arm.com> Date: Fri, 10 Nov 2023 15:06:08 +0000 Subject: [PATCH 04/11] 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 <yiw...@wdev-yiwu02.arm.com> Date: Mon, 13 Nov 2023 16:03:19 +0000 Subject: [PATCH 05/11] 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 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/11] 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 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..ea53d97d9800538 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 68d63253139f18a..6a42734d7873938 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/11] 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 ea53d97d9800538..23daa3eeb9d6c5b 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/11] 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 23daa3eeb9d6c5b..e630abea799bdfe 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/11] 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 e630abea799bdfe..646ad120fcdfa10 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/11] 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 646ad120fcdfa10..36f76a2f0e7b1ed 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/11] 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 a0c863712131b5c..6f1e0f390abeb10 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 36f76a2f0e7b1ed..1a3d2c8f7459321 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 6a42734d7873938..6d234a58ff8a43f 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()}; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits