dotnet/runtime

Deadlock in the Console.OutputEncoding setter

Open

#83.723 aperta il 21 mar 2023

Vedi su GitHub
 (4 commenti) (0 reazioni) (0 assegnatari)C# (5445 fork)batch import
area-System.Consolehelp wantedos-linuxos-mac-os-x

Metriche repository

Star
 (17.886 star)
Metriche merge PR
 (Merge medio 12g 11h) (661 PR mergiate in 30 g)

Descrizione

Description

The Console.OutputEncoding setter takes a lock on s_syncObject then calls Flush() on the s_out and s_error streams. Those streams are SyncTextWriter objects which have the MethodImpl(MethodImplOptions.Synchronized)attribute set on their methods. If another thread flushes the console output (e.g. ConsoleLoggerProcessor.ProcessLogQueue) the locks will be taken in the reverse order: SyncTextWriter.Flush, that ends up in Console.Out.EnsureInitialized() which takes the s_syncObject lock.

Reproduction Steps

I managed to sometimes repro the issue on Linux (WSL) with .net 6.0.14. Here are the deadlocked threads:

Thread 0x121

[Deadlocked, double-click or press enter to view all thread stacks] [Waiting on lock owned by Thread 0x12F] System.Private.CoreLib.dll!System.IO.TextWriter.SyncTextWriter.Flush() Line 759 C# System.Console.dll!System.Console.OutputEncoding.set(System.Text.Encoding value) Line 147 C#

Thread 0x12F

[Deadlocked, double-click or press enter to view all thread stacks] [Waiting on lock owned by Thread 0x121] System.Private.CoreLib.dll!System.Threading.Monitor.Enter(object obj, ref bool lockTaken) Line 49 C# System.Console.dll!System.Console.get_Out.__EnsureInitialized|26_0() Line 205 C# System.Console.dll!System.Console.Out.get() Line 199 C# System.Console.dll!System.ConsolePal.UpdatedCachedCursorPosition(byte* bufPtr, int count, int cursorVersion) Line 1320 C# System.Console.dll!System.ConsolePal.Write(Microsoft.Win32.SafeHandles.SafeFileHandle fd, System.ReadOnlySpan buffer, bool mayChangeCursorPosition) Line 1308 C# System.Console.dll!System.ConsolePal.UnixConsoleStream.Write(System.ReadOnlySpan buffer) Line 1468 C# System.Private.CoreLib.dll!System.IO.StreamWriter.Flush(bool flushStream, bool flushEncoder) Line 330 C# System.Private.CoreLib.dll!System.IO.StreamWriter.Write(string value) Line 495 C# System.Private.CoreLib.dll!System.IO.TextWriter.SyncTextWriter.Write(string value) Line 798 C# Microsoft.Extensions.Logging.Console.dll!Microsoft.Extensions.Logging.Console.ConsoleLoggerProcessor.WriteMessage(Microsoft.Extensions.Logging.Console.LogMessageEntry entry) Line 58 C# Microsoft.Extensions.Logging.Console.dll!Microsoft.Extensions.Logging.Console.ConsoleLoggerProcessor.ProcessLogQueue() Line 64 C# System.Private.CoreLib.dll!System.Threading.Thread.StartCallback() Line 106 C# [Native to Managed Transition]

Expected behavior

The process shouldn't deadlock when setting the output encoding.

Actual behavior

The process deadlocks.

Regression?

No response

Known Workarounds

No response

Configuration

x64 .NET 6.0.14, Ubuntu WSL

Other information

No response

Guida contributor