Thanks to visit codestin.com
Credit goes to github.com

Skip to content

DivideByZeroException with concurrent initialisation of TermInfoDriver #18317

@ghost

Description

Steps to Reproduce

  1. Create an empty .net console app targeting net461
  2. Attempt to access any of the lockable properties from TermInfoDriver on multiple threads (example property I'm using is Background/ForegroundColor:
    public ConsoleColor BackgroundColor {
    get {
    if (!inited) {
    Init ();
    }
    return bgcolor;
    }
    set {
    if (!inited) {
    Init ();
    }
    ChangeColor (setbgcolor, value);
    bgcolor = value;
    }
    }
    public ConsoleColor ForegroundColor {
    get {
    if (!inited) {
    Init ();
    }
    return fgcolor;
    }
    set {
    if (!inited) {
    Init ();
    }
    ChangeColor (setfgcolor, value);
    fgcolor = value;
    }
    }
    )

Sample code to show exception

class Program
    {
		public static void Main(string[] args)
		{
			Parallel.Invoke(
				() => { var x = Console.ForegroundColor; },
				() => { Console.BackgroundColor = ConsoleColor.Black; }
			);
		}
    }
  1. Build and run the application

Current Behavior

Occasionally, the application will run without an issue. However, most of the time an exception is thrown due to the behaviour I've described in this other thread here.

Expected Behavior

No exception should be thrown.

On which platforms did you notice this

[x] macOS
[x] Linux
[x] Windows

Version Used:

6.4.0

Stacktrace

Unhandled Exception:
System.AggregateException: One or more errors occurred. ---> System.DivideByZeroException: Attempted to divide by zero.
  at System.TermInfoDriver.ChangeColor (System.String format, System.ConsoleColor color) [0x00016] in <filename unknown>:0 
  at System.TermInfoDriver.set_BackgroundColor (System.ConsoleColor value) [0x00011] in <filename unknown>:0 
  at System.ConsoleDriver.set_BackgroundColor (System.ConsoleColor value) [0x0001f] in <filename unknown>:0 
  at System.Console.set_BackgroundColor (System.ConsoleColor value) [0x00000] in <filename unknown>:0 
  at akka_test.Program+<>c.<Main>b__0_1 () [0x00001] in <filename unknown>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x00012] in <filename unknown>:0 
  at System.Threading.Tasks.Task.Execute () [0x00016] in <filename unknown>:0 
[MVID] 2320d006b1a64388aa1812d52f51bde3 4
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1,2,3,5,6
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.FastWaitAll (System.Threading.Tasks.Task[] tasks) [0x0006e] in <filename unknown>:0 
  at System.Threading.Tasks.Parallel.Invoke (System.Threading.Tasks.ParallelOptions parallelOptions, System.Action[] actions) [0x0032e] in <filename unknown>:0 
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1
---> (Inner Exception #0) System.DivideByZeroException: Attempted to divide by zero.
  at System.TermInfoDriver.ChangeColor (System.String format, System.ConsoleColor color) [0x00016] in <filename unknown>:0 
  at System.TermInfoDriver.set_BackgroundColor (System.ConsoleColor value) [0x00011] in <filename unknown>:0 
  at System.ConsoleDriver.set_BackgroundColor (System.ConsoleColor value) [0x0001f] in <filename unknown>:0 
  at System.Console.set_BackgroundColor (System.ConsoleColor value) [0x00000] in <filename unknown>:0 
  at akka_test.Program+<>c.<Main>b__0_1 () [0x00001] in <filename unknown>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x00012] in <filename unknown>:0 
  at System.Threading.Tasks.Task.Execute () [0x00016] in <filename unknown>:0 
[MVID] 2320d006b1a64388aa1812d52f51bde3 4
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1,2,3,5,6<---

[ERROR] FATAL UNHANDLED EXCEPTION: System.AggregateException: One or more errors occurred. ---> System.DivideByZeroException: Attempted to divide by zero.
  at System.TermInfoDriver.ChangeColor (System.String format, System.ConsoleColor color) [0x00016] in <filename unknown>:0 
  at System.TermInfoDriver.set_BackgroundColor (System.ConsoleColor value) [0x00011] in <filename unknown>:0 
  at System.ConsoleDriver.set_BackgroundColor (System.ConsoleColor value) [0x0001f] in <filename unknown>:0 
  at System.Console.set_BackgroundColor (System.ConsoleColor value) [0x00000] in <filename unknown>:0 
  at akka_test.Program+<>c.<Main>b__0_1 () [0x00001] in <filename unknown>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x00012] in <filename unknown>:0 
  at System.Threading.Tasks.Task.Execute () [0x00016] in <filename unknown>:0 
[MVID] 2320d006b1a64388aa1812d52f51bde3 4
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1,2,3,5,6
   --- End of inner exception stack trace ---
  at System.Threading.Tasks.Task.FastWaitAll (System.Threading.Tasks.Task[] tasks) [0x0006e] in <filename unknown>:0 
  at System.Threading.Tasks.Parallel.Invoke (System.Threading.Tasks.ParallelOptions parallelOptions, System.Action[] actions) [0x0032e] in <filename unknown>:0 
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1
---> (Inner Exception #0) System.DivideByZeroException: Attempted to divide by zero.
  at System.TermInfoDriver.ChangeColor (System.String format, System.ConsoleColor color) [0x00016] in <filename unknown>:0 
  at System.TermInfoDriver.set_BackgroundColor (System.ConsoleColor value) [0x00011] in <filename unknown>:0 
  at System.ConsoleDriver.set_BackgroundColor (System.ConsoleColor value) [0x0001f] in <filename unknown>:0 
  at System.Console.set_BackgroundColor (System.ConsoleColor value) [0x00000] in <filename unknown>:0 
  at akka_test.Program+<>c.<Main>b__0_1 () [0x00001] in <filename unknown>:0 
  at System.Threading.Tasks.Task.InnerInvoke () [0x00012] in <filename unknown>:0 
  at System.Threading.Tasks.Task.Execute () [0x00016] in <filename unknown>:0 
[MVID] 2320d006b1a64388aa1812d52f51bde3 4
[MVID] 7747cf446af449e194e4b4e70d85e773 0,1,2,3,5,6<---


Process finished with exit code 1.

Notes

The core problem is that the lock on an uninitialised TermInfoDriver happens immediately upon accessing a property (get or set) and is released immediately before the initialisation process is complete. So, subsequent calls which happen concurrently will complete before any expected fields are present.

I'm not sure about the best way to fix this but it would be good to have this lock released after the initialisation process happens, but we would need to potentially try/catch the whole init block to account for exceptions.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions