Skip to content

Commit 9c673c0

Browse files
authored
Merge pull request #191 from boostorg/get-env-thread
Make `getenv` thread-safe
2 parents 1423d15 + b9ff85d commit 9c673c0

File tree

4 files changed

+52
-5
lines changed

4 files changed

+52
-5
lines changed

.github/workflows/ci_tests.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ jobs:
108108
# Run test with both bash and powershell and watch for "Using std::cin" on bash but not on powershell
109109
- name: Test
110110
working-directory: build
111-
run: ctest --output-on-failure -C ${{matrix.buildType}} --verbose
111+
run: |
112+
# The bash shell adds an incompatible PATH for MinGW: https://github.com/actions/runner-images/issues/11102
113+
[[ "${{runner.os}}" != 'Windows' ]] || export PATH="/c/mingw64/bin:$PATH"
114+
ctest --output-on-failure -C ${{matrix.buildType}} --verbose
112115
- name: Test on PowerShell
113116
working-directory: build
114117
shell: powershell

doc/changelog.dox

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//
2-
// Copyright (c) 2019-2023 Alexander Grund
2+
// Copyright (c) 2019-2024 Alexander Grund
33
//
44
// Distributed under the Boost Software License, Version 1.0.
55
// https://www.boost.org/LICENSE_1_0.txt
@@ -8,6 +8,10 @@
88

99
\section changelog Changelog
1010

11+
\subsection changelog_11_3_1 Nowide 11.3.1 (Boost 1.88)
12+
- Fix redefinition of `_CRT_SECURE_NO_WARNINGS`
13+
- Make `getenv` thread-safe
14+
1115
\subsection changelog_11_3_0 Nowide 11.3.0 (Boost 1.82)
1216
- Add `convert_string` overload accepting a string
1317
- Add `quoted` to output (quoted) paths (std::filesystem or boost::filesystem)

include/boost/nowide/cstdlib.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ namespace nowide {
2121
///
2222
/// \brief UTF-8 aware getenv. Returns 0 if the variable is not set.
2323
///
24-
/// This function is not thread safe or reenterable as defined by the standard library
24+
/// The string pointed to shall not be modified by the program.
25+
/// This function is thread-safe as long as no other thread modifies the host environment.
26+
/// However subsequent calls to this function might overwrite the string pointed to.
27+
///
28+
/// Warning: The returned pointer might only be valid for as long as the calling thread is alive.
29+
/// So avoid passing it across thread boundaries.
2530
///
2631
BOOST_NOWIDE_DECL char* getenv(const char* key);
2732

src/cstdlib.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,46 @@ namespace nowide {
4848
#include <vector>
4949
#include <windows.h>
5050

51+
namespace {
52+
// thread_local was broken on MinGW for all 32bit compiler releases prior to 11.x, see
53+
// https://sourceforge.net/p/mingw-w64/bugs/527/
54+
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83562
55+
// Using a non-trivial destructor causes program termination on thread exit.
56+
#if defined(__MINGW32__) && !defined(__MINGW64__) && !defined(__clang__) && (__GNUC__ < 11)
57+
class stackstring_for_thread
58+
{
59+
union
60+
{
61+
boost::nowide::stackstring s_;
62+
};
63+
64+
public:
65+
stackstring_for_thread() : s_(){};
66+
// Empty destructor so the union member (using a non-trivial destructor) does not get destroyed.
67+
// This will leak memory if any is allocated by the stackstring for each terminated thread
68+
// but as most values fit into the stack buffer this is rare and still better than a crash.
69+
~stackstring_for_thread(){};
70+
void convert(const wchar_t* begin, const wchar_t* end)
71+
{
72+
s_.convert(begin, end);
73+
}
74+
75+
char* get()
76+
{
77+
return s_.get();
78+
}
79+
};
80+
#else
81+
using stackstring_for_thread = boost::nowide::stackstring;
82+
#endif
83+
84+
} // namespace
85+
5186
namespace boost {
5287
namespace nowide {
5388
char* getenv(const char* key)
5489
{
55-
static stackstring value;
90+
thread_local stackstring_for_thread value;
5691

5792
const wshort_stackstring name(key);
5893

@@ -72,7 +107,7 @@ namespace nowide {
72107
return 0;
73108
ptr = &tmp[0];
74109
}
75-
value.convert(ptr);
110+
value.convert(ptr, ptr + n);
76111
return value.get();
77112
}
78113

0 commit comments

Comments
 (0)