Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

ShellStream.Dispose deadlocks when the server closes the channel at the same time

Aperta
#1,851 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
69/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
csharp

Direzione di ricerca

Start by reading src/Renci.SshNet/ShellStream.cs around Dispose(bool) and Channel_Closed, then trace the Close paths in src/Renci.SshNet/Channels/Channel.cs. Check how locks and event handlers interact in the reported race, and add a regression test that reproduces concurrent disposal and remote channel closure. Done means the test completes reliably without deadlocking.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Version

SSH.NET 2026.0.0 (tag 2026.0.0, 7b2fd3d). The same code is on develop today. .NET 10, Linux x64 and arm64.

Summary

Disposing a ShellStream while the server closes its channel can deadlock forever. The two threads take the same two locks in opposite order, and neither wait has a timeout:

Thread Holds Waits for
Caller: ShellStream.Dispose() ShellStream._sync Channel._messagingLock
Session listener: SSH_MSG_CHANNEL_CLOSE received Channel._messagingLock ShellStream._sync
The two paths

Caller thread, disposing the stream:

  1. ShellStream.Dispose(bool) takes lock (_sync) (src/Renci.SshNet/ShellStream.cs:970).
  2. Still inside that lock it calls _channel.Dispose() (ShellStream.cs:986).
  3. Channel.Dispose(bool) calls Close() (src/Renci.SshNet/Channels/Channel.cs:844), which takes lock (_messagingLock) (Channel.cs:534).

Listener thread, handling the server's SSH_MSG_CHANNEL_CLOSE:

  1. OnChannelClose calls OnClose() (Channel.cs:698), which calls Close() (Channel.cs:426) and takes lock (_messagingLock) (Channel.cs:534).
  2. Still inside that lock it raises Closed (Channel.cs:578).
  3. ShellStream.Channel_Closed handles it by calling Dispose() (ShellStream.cs:1006), which waits for lock (_sync) (ShellStream.cs:970).

If the caller enters step 1 of its path before the listener reaches step 3 of its own, each thread holds the lock the other one needs. A stack dump of a hung process shows exactly these two frames.

Repro

The race is timing-dependent. A simplified loop against a real OpenSSH server (a sketch of our test, not run as written here):

for (var i = 0; i < 100; i++)
{
    using var client = new SshClient(host, port, user, password);
    client.Connect();
    var stream = client.CreateShellStream("xterm", 80, 24, 0, 0, 4096);
    stream.WriteLine("exit");   // the server closes the channel shortly after
    stream.Dispose();           // races with the listener's Channel_Closed -> Dispose
}

In our test suite this hung 4 of 15 runs: a test class whose Dispose() disposed the ShellStream while the remote shell exited. The process never recovered; CI killed it after an hour.

Workaround we use

Call SshClient.Disconnect() before disposing the ShellStream. That stops the listener thread, so no Closed event can arrive while Dispose holds _sync. With it, 12 of 12 runs passed.

Possible fixes
  • In ShellStream.Dispose, detach the handlers and dispose _channel outside lock (_sync): take the lock only to set _disposed, then release it before calling _channel.Dispose().
  • Or, in Channel.Close, raise Closed after leaving lock (_messagingLock), so that no user code runs while that lock is held.
Lingua principale
C#
Stelle
4.4k
Fork
988
Merge medio
4g 22h
PR unite (30g)
5

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di sshnet/SSH.NET

Tutte le issue di sshnet/SSH.NET

Issue simili

Altre issue su C#

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.