Skip to content

Commit 99c6de5

Browse files
Weichenleeeee123lhecker
authored andcommitted
Fix WSLENV environment variable duplication in ConptyConnection (#19167)
This PR fixes issue #7130 where WT_SESSION and WT_PROFILE_ID environment variables were being duplicated in the WSLENV environment variable when multiple terminal sessions were created. The previous implementation always appended WT_SESSION:WT_PROFILE_ID: to WSLENV without checking if these variables already existed, causing duplication. Closes #7130 Co-authored-by: Leonard Hecker <[email protected]> (cherry picked from commit 7d6e0c8) Service-Card-Id: PVTI_lADOAF3p4s4AxadtzgdDF2w Service-Version: 1.23
1 parent 7c593c5 commit 99c6de5

File tree

2 files changed

+64
-10
lines changed

2 files changed

+64
-10
lines changed

src/cascadia/TerminalConnection/ConptyConnection.cpp

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,41 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
6666

6767
// WSLENV is a colon-delimited list of environment variables (+flags) that should appear inside WSL
6868
// https://devblogs.microsoft.com/commandline/share-environment-vars-between-wsl-and-windows/
69-
std::wstring wslEnv{ L"WT_SESSION:WT_PROFILE_ID:" };
69+
70+
// WSLENV.1: Get a handle to the WSLENV environment variable.
71+
auto& wslEnv = environment.as_map()[L"WSLENV"];
72+
std::wstring additionalWslEnv;
73+
74+
// WSLENV.2: Figure out what variables are already in WSLENV.
75+
std::unordered_set<std::wstring_view> wslEnvVars;
76+
for (const auto& part : til::split_iterator{ std::wstring_view{ wslEnv }, L':' })
77+
{
78+
// Each part may contain a variable name and flags (e.g., /p, /l, etc.)
79+
// We only care about the variable name for WSLENV.
80+
const auto key = til::safe_slice_len(part, 0, part.rfind(L'/'));
81+
wslEnvVars.emplace(key);
82+
}
83+
84+
// WSLENV.3: Add our terminal-specific environment variables to WSLENV.
85+
static constexpr std::wstring_view builtinWslEnvVars[] = {
86+
L"WT_SESSION",
87+
L"WT_PROFILE_ID",
88+
};
89+
// Misdiagnosis in MSVC 14.44.35207. No pointer arithmetic in sight.
90+
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
91+
for (const auto& key : builtinWslEnvVars)
92+
{
93+
if (wslEnvVars.emplace(key).second)
94+
{
95+
additionalWslEnv.append(key);
96+
additionalWslEnv.push_back(L':');
97+
}
98+
}
99+
70100
if (_environment)
71101
{
72102
// Order the environment variable names so that resolution order is consistent
103+
// NOTE(lhecker): I'm like 99% sure that this is unnecessary.
73104
std::set<std::wstring, til::env_key_sorter> keys{};
74105
for (const auto item : _environment)
75106
{
@@ -85,18 +116,39 @@ namespace winrt::Microsoft::Terminal::TerminalConnection::implementation
85116
const auto value = winrt::unbox_value<hstring>(_environment.Lookup(key));
86117

87118
environment.set_user_environment_var(key.c_str(), value.c_str());
88-
// For each environment variable added to the environment, also add it to WSLENV
89-
wslEnv += key + L":";
119+
120+
// WSLENV.4: Add custom user environment variables to WSLENV.
121+
if (wslEnvVars.emplace(key).second)
122+
{
123+
additionalWslEnv.append(key);
124+
additionalWslEnv.push_back(L':');
125+
}
90126
}
91127
CATCH_LOG();
92128
}
93129
}
94130

95-
// We want to prepend new environment variables to WSLENV - that way if a variable already
96-
// exists in WSLENV but with a flag, the flag will be respected.
97-
// (This behaviour was empirically observed)
98-
wslEnv += environment.as_map()[L"WSLENV"];
99-
environment.as_map().insert_or_assign(L"WSLENV", wslEnv);
131+
if (!additionalWslEnv.empty())
132+
{
133+
// WSLENV.5: In the next step we'll prepend `additionalWslEnv` to `wslEnv`,
134+
// so make sure that we have a single colon in between them.
135+
const auto hasColon = additionalWslEnv.ends_with(L':');
136+
const auto needsColon = !wslEnv.starts_with(L':');
137+
if (hasColon != needsColon)
138+
{
139+
if (hasColon)
140+
{
141+
additionalWslEnv.pop_back();
142+
}
143+
else
144+
{
145+
additionalWslEnv.push_back(L':');
146+
}
147+
}
148+
149+
// WSLENV.6: Prepend our additional environment variables to WSLENV.
150+
wslEnv.insert(0, additionalWslEnv);
151+
}
100152
}
101153

102154
auto newEnvVars = environment.to_string();

src/inc/til.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,22 @@
5555
namespace til // Terminal Implementation Library. Also: "Today I Learned"
5656
{
5757
template<typename T>
58-
as_view_t<T> safe_slice_abs(const T& view, size_t beg, size_t end)
58+
as_view_t<T> safe_slice_abs(const T& view, size_t beg, size_t end) noexcept
5959
{
6060
const auto len = view.size();
6161
end = std::min(end, len);
6262
beg = std::min(beg, end);
63+
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
6364
return { view.data() + beg, end - beg };
6465
}
6566

6667
template<typename T>
67-
as_view_t<T> safe_slice_len(const T& view, size_t start, size_t count)
68+
as_view_t<T> safe_slice_len(const T& view, size_t start, size_t count) noexcept
6869
{
6970
const auto len = view.size();
7071
start = std::min(start, len);
7172
count = std::min(count, len - start);
73+
#pragma warning(suppress : 26481) // Don't use pointer arithmetic. Use span instead (bounds.1).
7274
return { view.data() + start, count };
7375
}
7476

0 commit comments

Comments
 (0)