Bug 12552 - Console.ReadLine() does not read from console if stdout (but not stdin) is redirected
Summary: Console.ReadLine() does not read from console if stdout (but not stdin) is re...
Status: NEW
Alias: None
Product: Class Libraries
Classification: Mono
Component: mscorlib (show other bugs)
Version: 2.8.x
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2013-06-04 23:51 UTC by Greg Najda
Modified: 2016-04-09 09:53 UTC (History)
4 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments

Description Greg Najda 2013-06-04 23:51:17 UTC
Run the following program copied from my other bug report with stdout redirected but not stdin. On .NET it waits for a keypress, then exits.

C:\Users\Greg\Documents\Programming\consoletest\consoletest\bin\Debug>consoletest.exe > output.txt

output.txt contains:

Press a key
Key pressed: 78



On Mono in Linux, it exits immediately.

greg@Kubuntu:~/dev/consoletest/consoletest/bin/Debug$ mono consoletest.exe > output.txt
greg@Kubuntu:~/dev/consoletest/consoletest/bin/Debug$ cat output.txt
Press a key
Key pressed: 0
greg@Kubuntu:~/dev/consoletest/consoletest/bin/Debug$ mono --version
Mono JIT compiler version 2.10.8.1 (Debian 2.10.8.1-1ubuntu2.2)

This also prevents using programs that use ReadKey() with utilities like tee because piping to tee redirects stdout.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace consoletest
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Press a key");
            bool exceptionThrown = false;
            ConsoleKeyInfo key = new ConsoleKeyInfo();
            try
            {
                key = Console.ReadKey(intercept: true);
            }
            catch (InvalidOperationException)
            {
                // This is the documented behavior when reading from a non-console stdin
                Console.WriteLine("InvalidOperationException thrown.");
                exceptionThrown = true;
            }
            if (!exceptionThrown)
            {
                // Mono instead returns a ConsoleKeyInfo with a Key value of 0.
                Console.WriteLine("Key pressed: {0}", (int)key.Key);
            }
        }
    }
}
Comment 1 Greg Najda 2013-06-09 18:02:14 UTC
Console.ReadKey(bool intercept) calls ConsoleDriver.ReadKey(bool intercept) which calls IConsoleDriver.ReadKey(bool intercept). The static constructor of ConsoleDriver determines which implementation of IConsoleDriver is used for console operations.

static ConsoleDriver ()
{
	// Put the actual new statements into separate methods to avoid initalizing
	// three classes when only one is needed.
	if (!IsConsole) {
		driver = CreateNullConsoleDriver ();
	} else if (Environment.IsRunningOnWindows) {
		driver = CreateWindowsConsoleDriver ();
	} else {
		string term = Environment.GetEnvironmentVariable ("TERM");

		// Perhaps we should let the Terminfo driver return a
		// success/failure flag based on the terminal properties
		if (term == "dumb"){
			is_console = false;
			driver = CreateNullConsoleDriver ();
		} else
			driver = CreateTermInfoDriver (term);
	}
}


IsConsole effectively returns (Isatty (MonoIO.ConsoleOutput) && Isatty (MonoIO.ConsoleInput))

In other words, if stdout or stdin or both are not a console, then NullConsoleDriver is used. This prevents you from doing input console operations if stdout is redirected. A possible fix would be to have TermInfoDriver and WindowsConsoleDriver correctly handle the case where stdin or stdout is not a console and use TermInfoDriver/WindowsConsoleDriver even if one of stdin or stdout is not a console. Maybe even get rid of NullConsoleDriver entirely and only use TermInfoDriver/WindowsConsoleDriver and have them be aware of whether stdin and stdout are actually a console.
Comment 2 Miguel de Icaza [MSFT] 2015-06-12 12:32:03 UTC
This needs a new driver InputConsoleProvider that would allow input, but remove the Terminfo features
Comment 3 Vladimir Kargov 2016-04-09 09:53:30 UTC
Seems like this issue reveals itself in ASP.NET Core apps since stdout/stderr are always redirected:
https://github.com/dotnet/cli/blob/7e73e5c/src/dotnet/commands/dotnet-run/RunCommand.cs#L172

Example of usage that would cause the problem:
https://github.com/aspnet/benchmarks/blob/7b996e6/src/Benchmarks/Program.cs#L66

Note You need to log in before you can comment on or make changes to this bug.