microsoft / microsoft/WSL

init aborts (SIGABRT) when an interop client disconnects before its reply: wil::ResultException Broken pipe inside wil::scope_exit in the Interop thread

Open
#41,592 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

needs-author-feedback
Dominant language
C++
Stars
33.7k
Forks
1.8k
Avg merge
3d 17h
Merged PRs (30d)
116

Description

Environment

  • WSL 2.7.11.0, kernel 6.18.33.2-microsoft-standard-WSL2, WSLg 1.0.73.2
  • Windows 10.0.26200.9445
  • Ubuntu distro with [boot] systemd=true

What happens

The distro's init (init-systemd(Ubuntu), PID 2 inside the pid namespace) dies with SIGABRT. Afterwards every new wsl.exe -d Ubuntu session fails immediately with Wsl/Service/E_UNEXPECTED, interop calls from inside the distro hang, VS Code Remote loops on reconnect; systemd inside the distro keeps running. Only wsl --terminate Ubuntu recovers.

Three occurrences in 24 hours, identical crash dumps (%LOCALAPPDATA%\Temp\wsl-crashes\wsl-crash-*-2-_init-6.dmp, "pid: 2, executable: !init, signal: 6"). dmesg each time:

WSL (2 - Interop) ERROR: SendMessage:182: Failed to write message LxMessageResultBool. Channel: InteropServer
libc++abi:
terminating due to uncaught exception of type wil::ResultException: Broken pipe @C:/__w/1/s/src/shared/inc\SocketChannel.h:183 (SendMessage)
init: Interop: potentially unexpected fatal signal 6.
WSL (8531 - CaptureCrash): Capturing crash for pid: 2, executable: !init, signal: 6, port: 50005

One of the three additionally logged, right before the abort:

WSL (2 - Interop) ERROR: CreateLoginSession:2758: Timed out waiting for user session for uid=0

Where in the source (main as of 2026-09-11, eaa69e7)

src/linux/init/config.cpp, ConfigHandleInteropMessage, case LxInitMessageCreateLoginSession:

bool success = false;
auto sendResponse = wil::scope_exit([&]() { Transaction.SendResultMessage<bool>(success); });
...
success = CreateLoginSession(Config, ..., CreateSession->Uid);

CreateLoginSession can block for up to boot.initTimeout (10 s default) polling systemctl is-active user@<uid>.service, on the single "Interop" worker thread. If the client (the session leader /init that wsl.exe started) has gone away meanwhile because the Windows-side caller timed out or was killed, SendResultMessage throws wil::ResultException (EPIPE). It throws from inside the wil::scope_exit lambda, whose destructor is noexcept, so the surrounding try { ... } CATCH_LOG() never sees it and std::terminate takes the whole init down.

The Interop thread is also single and unbounded: for (;;) { Accept; ReceiveTransaction; ReceiveOrClosed; handle } with no receive timeout, so one stalled client (in our case a process throttled by a cgroup memory.high limit) queues every other session start behind it, which is what makes callers give up and close their end.

Reproduction

  1. wsl --terminate Ubuntu
  2. Make the first root session slow, for example a systemd that needs more than 10 s to reach user@0.service (we had Startup finished in 18.6s), or any load that delays it.
  3. From PowerShell: $j = Start-Job { wsl -d Ubuntu -u root -e true }; Wait-Job $j -Timeout 3; Stop-Job $j
  4. When CreateLoginSession times out (or merely finishes) and writes its bool result, init aborts and the distro is unusable until terminated.

Suggested fix

  • Send the result inside the try body instead of from a wil::scope_exit, or wrap the send in the lambda with a CATCH_LOG(); a client that hung up must not take init with it.
  • Ideally, bound ReceiveTransaction / ReceiveOrClosed on the Interop server socket with a timeout, so one stalled client cannot block every other session start.

Mitigation we use meanwhile (for others hitting this)

loginctl enable-linger root (and for the default user), so user@<uid>.service is active before the first session and CreateLoginSession returns at once; keep systemd's boot under boot.initTimeout; never wrap wsl.exe -d ... in a kill-on-timeout.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/linux/init/config.cpp at ConfigHandleInteropMessage and its LxInitMessageCreateLoginSession case; inspect how the scope_exit sends the result after CreateLoginSession blocks. Reproduce with the slow-session and killed wsl.exe steps, then verify a disconnected client no longer aborts init. Also inspect the Interop server loop around Accept, ReceiveTransaction, and ReceiveOrClosed for the stalled-client behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
networking, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.