@samitouri / QOSAMI-WSL / commits / de51e4ae

Fix potential hang when DockerIORelayHandle completes a write asynchronously (#40768)

* Save state * Add test coverage

Blue committed Jun 11, 2026 at 11:16 UTC de51e4ae5da41320b04c7392135d75e32e7b71c2
2 files changed +48
src/windows/common/HandleIO.cpp
+2
@@ -896,6 +896,8 @@ void DockerIORelayHandle::Collect()
896 if (ActiveHandle->GetState() == IOHandleStatus::Completed)
897 {
898 ActiveHandle = nullptr;
899 +
900 + ProcessNextHeader();
901 }
902 }
903
test/windows/WSLCTests.cpp
+46
@@ -8243,6 +8243,52 @@ class WSLCTests
8243
8244 runTest(input, largeStdout + "regularStdout", largeStderr);
8245 }
8246 +
8247 + // Validate that behavior is correct with various input sizes.
8248 + {
8249 + const std::string marker1 = "--start--";
8250 + const std::string marker2 = "--end--";
8251 +
8252 + auto runTest = [&](size_t payloadSize) {
8253 + std::vector<char> input;
8254 + insert(input, 1, marker1);
8255 + insert(input, 1, std::string(payloadSize, 'A'));
8256 + insert(input, 1, marker2);
8257 + const std::string expected = marker1 + std::string(payloadSize, 'A') + marker2;
8258 +
8259 + auto [inputRead, inputWrite] =
8260 + wsl::windows::common::wslutil::OpenAnonymousPipe(static_cast<DWORD>(input.size() + 1), true, false);
8261 + auto [stdoutRead, stdoutWrite] = wsl::windows::common::wslutil::OpenAnonymousPipe(4096, true, true);
8262 + auto [stderrRead, stderrWrite] = wsl::windows::common::wslutil::OpenAnonymousPipe(4096, true, true);
8263 +
8264 + DWORD written = 0;
8265 + THROW_IF_WIN32_BOOL_FALSE(WriteFile(inputWrite.get(), input.data(), static_cast<DWORD>(input.size()), &written, nullptr));
8266 + VERIFY_ARE_EQUAL(written, static_cast<DWORD>(input.size()));
8267 +
8268 + std::string output;
8269 + MultiHandleWait io;
8270 +
8271 + io.AddHandle(std::make_unique<DockerIORelayHandle>(
8272 + std::move(inputRead), std::move(stdoutWrite), std::move(stderrWrite), DockerIORelayHandle::Format::Raw));
8273 +
8274 + io.AddHandle(std::make_unique<ReadHandle>(std::move(stdoutRead), [&](const auto& buffer) {
8275 + output.append(buffer.data(), buffer.size());
8276 + if (output.find(marker2) != std::string::npos)
8277 + {
8278 + io.Cancel();
8279 + }
8280 + }));
8281 +
8282 + io.Run(std::chrono::seconds(60));
8283 +
8284 + VERIFY_ARE_EQUAL(expected, output);
8285 + };
8286 +
8287 + for (const size_t payloadSize : {1, 100, 4096, 8192, 32768, 64036, 65535, 65536, 65537, 65556, 65571, 65572, 65576, 130000})
8288 + {
8289 + runTest(payloadSize);
8290 + }
8291 + }
8292 }
8293
8294 WSLC_TEST_METHOD(ContainerRecoveryFromStorage)