当我上次将输出编码保留为UTF8时,为什么csc.exe会崩溃?

bar*_*lop 4 c# windows command-line csc

我正在遇到或遇到过一件非常奇怪的事情.

我想知道其他人是否有,以及为什么会这样.

使用此行运行单行程序后,System.Console.WriteLine(System.Console.OutputEncoding.EncodingName); 我看到编码是Western European (DOS)

精细

下面是一些代码页的列表 1200 Unicode ,并65001 utf-8Windows-1252 Western European (Windows)850 Western European DOShttps://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.110).aspx

假设我编写了一个C sharp程序来将编码更改为utf-8

class sdf
{
  static void Main(string[] args)
{
System.Console.WriteLine(System.Console.OutputEncoding.EncodingName);
  System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(65001);
System.Console.WriteLine(System.Console.OutputEncoding.EncodingName);
}
}
Run Code Online (Sandbox Code Playgroud)

它工作,它打印

Western European (DOS)
Unicode (UTF-8)
Run Code Online (Sandbox Code Playgroud)

现在当我再次运行csc时,csc崩溃了.

在此输入图像描述

我检查了我的内存14小时,8次通过,记忆了.我跑了chkdsk我的硬盘,一切都很好.这绝对不是那些,这是一个编码问题.我知道,因为如果我打开一个新的cmd提示符,然后运行csc,它不会崩溃.

所以运行那个急剧的程序,改变shell,这样下一次运行csc就会以很大的方式崩溃csc.

如果我编译下面的代码,然后运行它,然后运行csc,然后运行csc,或csc whatever.cs,我得到csc崩溃.

关闭cmd提示符,打开一个新提示符.

这一次,尝试评论并取消注释程序的第二行

我发现,如果第二行(将代码页更改为850(DOS西欧)的行,那么它将在下次运行csc时不会崩溃).

如果我注释掉第二行,那么程序退出时将代码页/编码更改为UTF-8然后下次csc运行时,csc崩溃.

//取消注释最后一行,然后//运行但下次使csc崩溃.

class asdf
{
  static void Main()
  {

     System.Console.OutputEncoding = System.Text.Encoding.UTF8; //output and to utf8
     System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850); 
  }
}
Run Code Online (Sandbox Code Playgroud)

我不是唯一一个碰到这样的人

虽然没有找到解释,但https://social.msdn.microsoft.com/Forums/vstudio/en-US/0e5f477e-0c32-4e88-acf7-d53d43d5b566/c-command-line-compiler-cscexe-immediately-crashes-当-在代码运行页-65001-UTF8?论坛= csharpgeneral

我可以通过确保最后一行将代码页设置为850来处理它.虽然我会解释这是一个不充分的解决方案..

另外我想知道CSC是否存在其他人也有的问题.或任何其他解决方案.

添加

uuu1.cs

// uuu1.cs
class asdf
{
static void Main()
{

System.Console.InputEncoding  = System.Text.Encoding.UTF8;
System.Console.OutputEncoding = System.Text.Encoding.UTF8;

// not unicode.  UTF8 means redirection will then work

System.Console.WriteLine("?");

// try redirecting too..

// and try  checking for csc crash or not
//System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850);
//System.Console.InputEncoding =System.Text.Encoding.GetEncoding(850);
//problem is that when that is commented, it breaks the redirection



}
}
Run Code Online (Sandbox Code Playgroud)

添加行/取消注释最后一行,所以我有

System.Console.OutputEncoding = System.Text.Encoding.GetEncoding(850);

会停止崩溃,但这是一个不充分的解决方案,因为例如..如果我想将程序的输出重定向到文件,那么我从头到尾一直需要UTF8,否则它不起作用

这适用于代码页850行未注释

c:\blah>uuu1>r.r<ENTER>  
c:\blah>type r.r <ENTER>  
c:\blah>?  
Run Code Online (Sandbox Code Playgroud)

如果我取消注释最后一行,从而将代码页更改为850,那么确保csc在下次运行时不会崩溃,但重定向不起作用且rr不包含该字符.

新增2

Han的回答让我注意到另一种触发此错误的方法

C:\Users\harvey\somecs3>csc<ENTER>
Microsoft (R) Visual C# Compiler version 4.0.30319.18408
for Microsoft (R) .NET Framework 4.5
Copyright (C) Microsoft Corporation. All rights reserved.

warning CS2008: No source files specified
error CS1562: Outputs without source must have the /out option specified

C:\Users\harvey\somecs3>chcp  65001<ENTER>
Active code page: 65001

C:\Users\harvey\somecs3>csc<ENTER>  <-- CRASH

C:\Users\harvey\somecs3>
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 6

好吧,你发现了C#编译器在切换到UTF-8时必须输出文本到控制台的方式的错误.它具有自我诊断功能,可确保从UTF-16编码的字符串到控制台输出代码页的转换正常工作,如果没有,则会重置大红色按钮.堆栈跟踪如下所示:

csc.exe!OnCriticalInternalError()  + 0x4 bytes  
csc.exe!ConsoleOutput::WideToConsole()  + 0xdc51 bytes  
csc.exe!ConsoleOutput::print_internal()  + 0x2c bytes   
csc.exe!ConsoleOutput::print()  + 0x80 bytes    
csc.exe!ConsoleOutput::PrintString()  + 0xb5 bytes  
csc.exe!ConsoleOutput::PrintBanner()  + 0x50 bytes  
csc.exe!_main()  + 0x2d0eb bytes    
Run Code Online (Sandbox Code Playgroud)

WideToConsole()的实际代码不可用,最接近的匹配是来自SSCLI20发行版的此版本:

/*
 * Like WideCharToMultiByte, but translates to the console code page. Returns length,
 * INCLUDING null terminator.
 */
int ConsoleOutput::WideCharToConsole(LPCWSTR wideStr, LPSTR lpBuffer, int nBufferMax)
{
    if (m_fUTF8Output) {
        if (nBufferMax == 0) {
            return UTF8LengthOfUnicode(wideStr, (int)wcslen(wideStr)) + 1; // +1 for nul terminator
        }
        else {
            int cchConverted = NULL_TERMINATED_MODE;
            return UnicodeToUTF8 (wideStr, &cchConverted, lpBuffer, nBufferMax);
        }

    }
    else {
        return WideCharToMultiByte(GetConsoleOutputCP(), 0, wideStr, -1, lpBuffer, nBufferMax, 0, 0);
    }
}

/*
 * Convert Unicode string to Console ANSI string allocated with VSAlloc
 */
HRESULT ConsoleOutput::WideToConsole(LPCWSTR wideStr, CAllocBuffer &buffer)
{
    int cch = WideCharToConsole(wideStr, NULL, 0);
    buffer.AllocCount(cch);
    if (0 == WideCharToConsole(wideStr, buffer.GetData(), cch)) {
        VSFAIL("How'd the string size change?");
        // We have to NULL terminate the output because WideCharToMultiByte didn't
        buffer.SetAt(0, '\0');
        return E_FAIL;
    }
    return S_OK;
}
Run Code Online (Sandbox Code Playgroud)

从机器代码判断,崩溃发生在VSFAIL()断言的某处.我可以看到返回E_FAIL语句.但是,从我发布的版本改变了,if()语句被修改了,看起来VSFAIL()被RETAILVERIFY()取代了.当他们做出这些更改时可能会出现问题,可能是在UnicodeToUTF8()中,现在名为UTF16ToUTF8().再次强调,我发布的版本实际上并没有崩溃,您可以通过运行C:\ Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe自行查看.只有vc版本的csc.exe有此错误.

实际的bug很难从机器代码中挖掘出来,最好让微软担心.您可以在connect.microsoft.com上提交错误.我没有看到类似它的报告,相当不错的顺便说一句.此错误的解决方法是使用CHCP更改代码页.