Skip to content

[flang] GETLOG runtime and extension implementation: get login username #74628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 35 commits into from
Dec 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0e98aa7
GETLOG runtime and extension implementation: get login username
yiwu0b11 Nov 6, 2023
ce001f3
add include string.h, wchar.h, link library, and format
yiwu0b11 Nov 7, 2023
0de5364
use getlogin_r instead of getlogin, check for POSIX-compliant
yiwu0b11 Nov 10, 2023
72727ba
move implementation to extension.cpp, add assert for failure, and format
yiwu0b11 Nov 10, 2023
7c2f34f
Merge branch 'main' into getlog
yiwu0b11 Nov 13, 2023
17cf436
Use a more secure version for transfoom wchar_t to char
Nov 13, 2023
a1b1b66
use cstring not string.h, add terminator, fill buffer with space
yiwu0b11 Nov 15, 2023
fb910d1
brace initialize array
yiwu0b11 Nov 22, 2023
f066c81
Update flang/runtime/extensions.cpp: brace initialization
yiwu0b11 Nov 22, 2023
8997af8
Update flang/runtime/extensions.cpp: brace initialization
yiwu0b11 Nov 22, 2023
bad673a
Revert "brace initialize array"
yiwu0b11 Nov 22, 2023
b55bb5f
final nits
yiwu0b11 Nov 27, 2023
d1470b0
Revert "use cstring not string.h, add terminator, fill buffer with sp…
yiwu0b11 Dec 5, 2023
85d42d4
move and use CopyAndPad from character.h
yiwu0b11 Dec 5, 2023
99117e4
better tests and use min length for memcpy
yiwu0b11 Dec 6, 2023
ea2ea3b
doc change: move getlog to Library subroutine row
yiwu0b11 Dec 6, 2023
67d4045
small fixes to tests
yiwu0b11 Dec 6, 2023
3ac03a6
use env to set and test user name
yiwu0b11 Dec 6, 2023
266a269
get logname from environment variable LOGNAME not from getlog_r, and …
yiwu0b11 Dec 6, 2023
40ff373
windows use USERNAME environment variable
Dec 6, 2023
2cdaa2d
Revert "get logname from environment variable LOGNAME not from getlog…
yiwu0b11 Dec 6, 2023
ee6c27e
if getlogin returns an error, then get name from environment variable
yiwu0b11 Dec 6, 2023
2a24b43
brace-initialization, doc text moved, reorder if-else for clarity
yiwu0b11 Dec 6, 2023
499a162
use sizeof as length, remove charLen variable
yiwu0b11 Dec 6, 2023
025587a
get environment username on Windows to void link library, use std::by…
yiwu0b11 Dec 8, 2023
1800e8d
mini macro fix, clang-format
Dec 8, 2023
5c7ca33
some nits
yiwu0b11 Dec 8, 2023
53d6152
fix Windows environment variable tests
Dec 9, 2023
acaca0e
use strlen for size of char *str and move CopyAndPad to tools.h
yiwu0b11 Dec 13, 2023
456640a
clang-format
yiwu0b11 Dec 13, 2023
d89c02b
Revert "clang-format" and clang-format
yiwu0b11 Dec 13, 2023
9c73249
add RT_API_ATTRS to CopyAndPad, moved under Fortran::Runtime::
yiwu0b11 Dec 14, 2023
d0f0291
tets fix: include header file
yiwu0b11 Dec 15, 2023
60b20f1
Revert "tets fix: include header file" and tests fixes
yiwu0b11 Dec 15, 2023
4cb0574
Merge branch 'llvm:main' into getlog
yiwu0b11 Dec 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions flang/docs/Intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,11 @@ CACHESIZE, EOF, FP_CLASS, INT_PTR_KIND, ISNAN, LOC
MALLOC
```

### Library subroutine
```
CALL GETLOG(USRNAME)
```

## Intrinsic Procedure Name Resolution

When the name of a procedure in a program is the same as the one of an intrinsic
Expand Down Expand Up @@ -754,6 +759,7 @@ This phase currently supports all the intrinsic procedures listed above but the
| 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
Expand Down
4 changes: 4 additions & 0 deletions flang/include/flang/Runtime/extensions.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#define FORTRAN_PROCEDURE_NAME(name) name##_

#include <cstddef>
#include <cstdint>

extern "C" {
Expand All @@ -28,5 +29,8 @@ 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::byte *name, std::int64_t length);

} // extern "C"
#endif // FORTRAN_RUNTIME_EXTENSIONS_H_
22 changes: 1 addition & 21 deletions flang/runtime/character.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -464,27 +465,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) {
Expand Down
39 changes: 39 additions & 0 deletions flang/runtime/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@
// extensions that will eventually be implemented in Fortran.

#include "flang/Runtime/extensions.h"
#include "tools.h"
#include "flang/Runtime/command.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/io-api.h"

#if _REENTRANT || _POSIX_C_SOURCE >= 199506L
// System is posix-compliant and has getlogin_r
#include <unistd.h>
#endif

extern "C" {

namespace Fortran::runtime {

void GetUsernameEnvVar(
const char *envName, std::byte *arg, std::int64_t length) {
Descriptor name{*Descriptor::Create(
1, std::strlen(envName) + 1, const_cast<char *>(envName), 0)};
Descriptor value{*Descriptor::Create(1, length, arg, 0)};

RTNAME(GetEnvVariable)
(name, &value, nullptr, false, nullptr, __FILE__, __LINE__);
}
namespace io {
// SUBROUTINE FLUSH(N)
// FLUSH N
Expand All @@ -37,5 +53,28 @@ void FORTRAN_PROCEDURE_NAME(getarg)(
(void)RTNAME(GetCommandArgument)(
n, &value, nullptr, nullptr, __FILE__, __LINE__);
}

// CALL GETLOG(USRNAME)
void FORTRAN_PROCEDURE_NAME(getlog)(std::byte *arg, std::int64_t length) {
#if _REENTRANT || _POSIX_C_SOURCE >= 199506L
const int nameMaxLen{LOGIN_NAME_MAX + 1};
char str[nameMaxLen];

int error{getlogin_r(str, nameMaxLen)};
if (error == 0) {
// no error: find first \0 in string then pad from there
CopyAndPad(reinterpret_cast<char *>(arg), str, length, std::strlen(str));
} else {
// error occur: get username from environment variable
GetUsernameEnvVar("LOGNAME", arg, length);
}
#elif _WIN32
// Get username from environment to avoid link to Advapi32.lib
GetUsernameEnvVar("USERNAME", arg, length);
#else
GetUsernameEnvVar("LOGNAME", arg, length);
#endif
}

} // namespace Fortran::runtime
} // extern "C"
22 changes: 22 additions & 0 deletions flang/runtime/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,5 +411,27 @@ RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from,
bool toIsContiguous, bool fromIsContiguous);
RT_API_ATTRS void ShallowCopy(const Descriptor &to, const Descriptor &from);

// Defines a utility function for copying and padding characters
template <typename TO, typename FROM>
RT_API_ATTRS 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, std::min(toChars, fromChars) * sizeof(TO));
for (std::size_t j{fromChars}; j < toChars; ++j) {
to[j] = static_cast<TO>(' ');
}
}
}

} // namespace Fortran::runtime
#endif // FORTRAN_RUNTIME_TOOLS_H_
83 changes: 83 additions & 0 deletions flang/unittests/Runtime/CommandTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "flang/Runtime/descriptor.h"
#include "flang/Runtime/extensions.h"
#include "flang/Runtime/main.h"
#include <cstddef>
#include <cstdlib>

#if _REENTRANT || _POSIX_C_SOURCE >= 199506L
#include <limits.h> // LOGIN_NAME_MAX used in getlog test
#endif

using namespace Fortran::runtime;

template <std::size_t n = 64>
Expand Down Expand Up @@ -59,6 +65,13 @@ class CommandFixture : public ::testing::Test {
return res;
}

void CheckCharEqStr(const char *value, const std::string &expected) const {
ASSERT_NE(value, nullptr);
EXPECT_EQ(std::strncmp(value, expected.c_str(), expected.size()), 0)
<< "expected: " << expected << "\n"
<< "value: " << value;
}

void CheckDescriptorEqStr(
const Descriptor *value, const std::string &expected) const {
ASSERT_NE(value, nullptr);
Expand Down Expand Up @@ -397,6 +410,11 @@ class EnvironmentVariables : public CommandFixture {
protected:
EnvironmentVariables() : CommandFixture(0, nullptr) {
SetEnv("NAME", "VALUE");
#ifdef _WIN32
SetEnv("USERNAME", "loginName");
#else
SetEnv("LOGNAME", "loginName");
#endif
SetEnv("EMPTY", "");
}

Expand Down Expand Up @@ -494,3 +512,68 @@ TEST_F(EnvironmentVariables, ErrMsgTooShort) {
1);
CheckDescriptorEqStr(errMsg.get(), "Mis");
}

// username first char must not be null
TEST_F(EnvironmentVariables, GetlogGetName) {
const int charLen{3};
char input[charLen]{"\0\0"};

FORTRAN_PROCEDURE_NAME(getlog)
(reinterpret_cast<std::byte *>(input), charLen);

EXPECT_NE(input[0], '\0');
}

#if _REENTRANT || _POSIX_C_SOURCE >= 199506L
TEST_F(EnvironmentVariables, GetlogPadSpace) {
// guarantee 1 char longer than max, last char should be pad space
const int charLen{LOGIN_NAME_MAX + 2};
char input[charLen];

FORTRAN_PROCEDURE_NAME(getlog)
(reinterpret_cast<std::byte *>(input), charLen);

EXPECT_EQ(input[charLen - 1], ' ');
}
#endif

#ifdef _WIN32 // Test ability to get name from environment variable
TEST_F(EnvironmentVariables, GetlogEnvGetName) {
if (EnableFineGrainedTests()) {
ASSERT_NE(std::getenv("USERNAME"), nullptr)
<< "Environment variable USERNAME does not exist";

char input[]{"XXXXXXXXX"};
FORTRAN_PROCEDURE_NAME(getlog)
(reinterpret_cast<std::byte *>(input), sizeof(input));

CheckCharEqStr(input, "loginName");
}
}

TEST_F(EnvironmentVariables, GetlogEnvBufferShort) {
if (EnableFineGrainedTests()) {
ASSERT_NE(std::getenv("USERNAME"), nullptr)
<< "Environment variable USERNAME does not exist";

char input[]{"XXXXXX"};
FORTRAN_PROCEDURE_NAME(getlog)
(reinterpret_cast<std::byte *>(input), sizeof(input));

CheckCharEqStr(input, "loginN");
}
}

TEST_F(EnvironmentVariables, GetlogEnvPadSpace) {
if (EnableFineGrainedTests()) {
ASSERT_NE(std::getenv("USERNAME"), nullptr)
<< "Environment variable USERNAME does not exist";

char input[]{"XXXXXXXXXX"};
FORTRAN_PROCEDURE_NAME(getlog)
(reinterpret_cast<std::byte *>(input), sizeof(input));

CheckCharEqStr(input, "loginName ");
}
}
#endif