2012-12-23 45 views
3

我有一个超级简单的程序。我的意图是将标准输入复制到标准输出。这里的源代码:将stdin复制到标准输出导致奇怪的结果

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

namespace LALA 
{ 
    class LALA 
    { 
     static void Main() 
     { 
      int bufferSize = 40; 
      Console.OpenStandardInput().CopyTo(Console.OpenStandardOutput(), bufferSize); 
     } 
    } 
} 

如果我设置bufferSize至40,那么对于任意输入我只看到“C O 4 N”,“C上S”,或“C onsole”等 如果我设置bufferSize到41,那么一切都很好。

我的问题是我做错了什么,以及意外值超过41工作?

为了澄清,这是输出当我输入ASD:

c:\some_path>ConsoleApplication2.exe 
asd 
C o n 
+0

你的意见是什么? – keyboardP

+0

你不清楚你在观察什么。你给出的代码对我来说工作得很好。你提供什么作为输入? –

+0

对我来说看起来不错。 –

回答

1

惊喜!这似乎是内部缓冲区溢出,我会分享我发现的内容,尽管这对我来说还不是一个真正的证据。

为Stream类的CopyTo方法的代码是:(采取反射器)

public void CopyTo(Stream destination, int bufferSize) 
{ 
    //bunch of non relevant validations... 

    this.InternalCopyTo(destination, bufferSize); 
} 

现在对于InternalCopyTo的代码是:

private void InternalCopyTo(Stream destination, int bufferSize) 
{ 
    byte[] array = new byte[bufferSize]; 
    int count; 
    while ((count = this.Read(array, 0, array.Length)) != 0) 
    { 
     destination.Write(array, 0, count); 
    } 
} 

控制台流实例是__ConsoleStream型的(密封在System.IO中的内部类)及其Read方法代码:

public override int Read([In] [Out] byte[] buffer, int offset, int count) 
{ 
    //bunch of non relevant validations... 

    int errorCode = 0; 
    int num = __ConsoleStream.ReadFileNative(this._handle, buffer, offset, count, 0, out errorCode); 
    if (num == -1) 
    { 
     __Error.WinIOError(errorCode, string.Empty); 
    } 
    return num; 
} 
__ConsoleStream的10

最后ReadFileNative代码:

private unsafe static int ReadFileNative(SafeFileHandle hFile, byte[] bytes, int offset, int count, int mustBeZero, out int errorCode) 
{ 
    if (bytes.Length - offset < count) 
    { 
     throw new IndexOutOfRangeException(Environment.GetResourceString("IndexOutOfRange_IORaceCondition")); 
    } 
    if (bytes.Length == 0) 
    { 
     errorCode = 0; 
     return 0; 
    } 
    __ConsoleStream.WaitForAvailableConsoleInput(hFile); 
    int result; 
    int num; 
    fixed (byte* ptr = bytes) 
    { 
     num = __ConsoleStream.ReadFile(hFile, ptr + (IntPtr)offset/1, count, out result, Win32Native.NULL); 
    } 
    if (num != 0) 
    { 
     errorCode = 0; 
     return result; 
    } 
    errorCode = Marshal.GetLastWin32Error(); 
    if (errorCode == 109) 
    { 
     return 0; 
    } 
    return -1; 
} 

ReadFile方法是低级别的呼叫:

[DllImport("kernel32.dll", SetLastError = true)] 
private unsafe static extern int ReadFile(SafeFileHandle handle, byte* bytes, int numBytesToRead, out int numBytesRead, IntPtr mustBeZero); 

我在这一点上的假设是,在幕后,40个字节被“保留”的地方到内部数据,所以如果缓冲区不超过这个数量,你会看到在这种情况下控制台应用程序中的保留数据是进程名称。

我会继续调查这一点,当我有更多的时间和尝试重现,这种情况是非常特殊的,因为两个流指向相同的“文件”,所以你可以在阅读时写入它。