Skip to content

Correctly set FileOffsets in WriteHandle#14562

Merged
OneBlue merged 2 commits intofeature/wsl-for-appsfrom
user/oneblue/write-offset
Mar 28, 2026
Merged

Correctly set FileOffsets in WriteHandle#14562
OneBlue merged 2 commits intofeature/wsl-for-appsfrom
user/oneblue/write-offset

Conversation

@OneBlue
Copy link
Copy Markdown
Collaborator

@OneBlue OneBlue commented Mar 28, 2026

Summary of the Pull Request

This change updates WriteHandle to correctly set offsets when writing to its handle.

If the handle was a file, then WriteHandle would always write to the same offset, effectively incorrectly truncating the file

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

Copilot AI review requested due to automatic review settings March 28, 2026 00:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes wsl::windows::common::relay::WriteHandle so that when the underlying handle is a seekable file, overlapped writes advance the file offset instead of repeatedly writing at the same position (which could overwrite/truncate previously written data).

Changes:

  • Add per-handle offset tracking to WriteHandle and apply it to OVERLAPPED.Offset/OffsetHigh for each write.
  • Advance the tracked offset on both synchronous and asynchronous write completion paths.
  • Add a new Windows test that validates WriteHandle behavior for pipes and disk files.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/windows/common/relay.hpp Adds stored offset state to WriteHandle.
src/windows/common/relay.cpp Initializes and updates WriteHandle’s file offset and sets OVERLAPPED offsets before each write.
test/windows/WSLCTests.cpp Adds WriteHandleContent test covering pipe and file output scenarios.

Comment thread test/windows/WSLCTests.cpp Outdated
wsl::windows::common::relay::MultiHandleWait io;

io.AddHandle(std::make_unique<wsl::windows::common::relay::ReadHandle>(
std::move(readPipe), [&](const gsl::span<char>& buffer) { readData.append(buffer.data(), buffer.size()); }));
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ReadHandle callback appends buffer.data() even when buffer can be an empty span (e.g., EOF/broken pipe paths may invoke the callback with an empty span whose .data() is null). Passing a null pointer to std::string::append(ptr, 0) is undefined behavior and can crash under some CRT/debug configurations. Guard on buffer.empty() (or append only when buffer.size() > 0).

Suggested change
std::move(readPipe), [&](const gsl::span<char>& buffer) { readData.append(buffer.data(), buffer.size()); }));
std::move(readPipe),
[&](const gsl::span<char>& buffer)
{
if (!buffer.empty())
{
readData.append(buffer.data(), buffer.size());
}
}));

Copilot uses AI. Check for mistakes.
Comment thread test/windows/WSLCTests.cpp Outdated
Comment on lines +4707 to +4711
auto outputFile = wil::create_new_file(L"write-handle-test", GENERIC_WRITE | GENERIC_READ, 0, nullptr);

auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
outputFile.reset();
std::filesystem::remove("write-handle-test");
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test creates a fixed relative filename ("write-handle-test") in the current working directory and uses CREATE_NEW semantics. If a previous run left the file behind (crash/abort) or tests run concurrently in the same working dir, this can become flaky. Prefer creating the file under std::filesystem::temp_directory_path() with a unique name (and/or do a best-effort pre-cleanup) and remove via the same full path.

Suggested change
auto outputFile = wil::create_new_file(L"write-handle-test", GENERIC_WRITE | GENERIC_READ, 0, nullptr);
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
outputFile.reset();
std::filesystem::remove("write-handle-test");
std::filesystem::path outputFilePath =
std::filesystem::temp_directory_path() /
(L"write-handle-test-" + std::to_wstring(GetCurrentProcessId()) + L".tmp");
auto outputFile = wil::create_new_file(outputFilePath.c_str(), GENERIC_WRITE | GENERIC_READ, 0, nullptr);
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
outputFile.reset();
std::error_code ec;
std::filesystem::remove(outputFilePath, ec);

Copilot uses AI. Check for mistakes.
@OneBlue OneBlue merged commit 933aedc into feature/wsl-for-apps Mar 28, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants