为什么当我将输出编码设置为UTF8时,csc.exe会崩溃?

22 浏览
0 Comments

为什么当我将输出编码设置为UTF8时,csc.exe会崩溃?

我遇到了一个非常奇怪的问题。

我想知道其他人是否也遇到了这个问题,以及为什么会发生。

我运行了一行代码的程序,代码如下:System.Console.WriteLine(System.Console.OutputEncoding.EncodingName);,我发现编码是西欧(DOS)

好的

这是一些代码页的列表

1200 Unicode65001 utf-8Windows-1252 Western European (Windows)850 Western European DOS,链接在https://msdn.microsoft.com/en-us/library/system.text.encoding(v=vs.110).aspx

假设我编写一个C#程序来将编码更改为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);
}
}

它可以正常工作,输出为

西欧(DOS)
Unicode (UTF-8)

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

我用memtest检查了我的RAM 14个小时,8次通过,硬盘上的chkdsk也运行正常。这肯定不是这些问题,而是编码问题。

我知道这是编码问题,因为如果我打开一个新的cmd提示符,然后运行csc,它就不会崩溃。

因此,运行这个C#程序会改变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); 
  }
}

我不是唯一一个遇到这种问题的人,尽管在那里没有找到解释 https://social.msdn.microsoft.com/Forums/vstudio/en-US/0e5f477e-0c32-4e88-acf7-d53d43d5b566/c-command-line-compiler-cscexe-immediately-crashes-when-run-in-code-page-65001-utf8?forum=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;
// 不是unicode。UTF8表示重定向将正常工作
System.Console.WriteLine("ჵ");
// 尝试重定向..
// 并尝试检查是否会导致csc崩溃
//System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850);
//System.Console.InputEncoding =System.Text.Encoding.GetEncoding(850);
//问题是当它被注释掉时,它会破坏重定向
}
}

取消注释最后一行,即添加

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

将会阻止崩溃,但这是一个不完善的解决方案,因为例如...如果我想将程序的输出重定向到一个文件,那么我需要从开始到结束都使用UTF8,否则它不起作用。

这个解决方案在将代码页设置为850时可以工作

c:\blah>uuu1>r.r  
c:\blah>type r.r   
c:\blah>ჵ  

如果我取消注释最后一行,即将代码页更改为850,则csc不会在下一次运行时崩溃,但重定向不起作用,r.r中不包含该字符。

添加2

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

C:\Users\harvey\somecs3>csc
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
Active code page: 65001
C:\Users\harvey\somecs3>csc  <-- CRASH
C:\Users\harvey\somecs3>

0
0 Comments

csc.exe在将输出编码设置为UTF8时为什么会崩溃?出现这个问题的原因是C#编译器在将文本输出到控制台时处理方式存在错误。它具有自诊断功能,以确保从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

下面是WideToConsole()方法的代码:

/*

* 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;

}

崩溃发生在VSFAIL()断言附近,从机器代码可以判断。可以看到返回E_FAIL的语句。然而,与我发布的版本不同,if()语句被修改了,而且看起来VSFAIL()被RETAILVERIFY()替换了。在进行这些更改时出现了问题,可能是在现在被命名为UTF16ToUTF8()的UnicodeToUTF8()方法中出了问题。需要强调的是,我发布的版本实际上没有崩溃,你可以通过运行C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe来亲自验证。只有v4版本的csc.exe存在这个bug。

关于实际的bug,很难从机器代码中找出来,最好让微软来解决这个问题。你可以在connect.microsoft.com上报告这个bug,但我没有找到类似的报告。这个bug的解决方法是使用CHCP命令将代码页改回来。

我的版本是Microsoft (R) Visual C# Compiler version 4.0.30319.18408。

我看到的唯一的“提交bug”按钮在microsoft.net native页面上,connect.microsoft.com/VisualStudio/MSNetNative,但那只会跳转到一个错误页面,试图提交bug的时候出错了!i.imgur.com/Rxy8bW9.png,也许还有其他地方可以提交bug,如果你看到了提交bug的选项,请告诉我。

当我尝试时,看起来没问题。你必须登录才能进行提交。

与之相对比,如果我在目录中点击powershell,就会有一个提交bug的按钮。如果我点击visual studio,就会收到一条消息,上面写着“您已被邀请加入Visual Studio的私人NDA计划,您可以通过在页面顶部的下拉菜单“程序”中进行选择来查看特定内容。”在那个时候,我不知道下一步该点击什么,但点击“程序”似乎并没有帮助太多。

你可以提交这个bug报告,如果你看到了提交bug的选项,请告诉我。顺便说一句,如果已经运行了chcp 850,那么chcp命令就会显示代码页为850。所以为什么chcp 850会有所区别,我不知道,如果chcp命令已经显示为850,为什么还需要chcp 850。我现在已经提交了一个bug报告。但实际上,你必须先登出,然后转到connect.microsoft.com/VisualStudio,然后点击“提交bug”,然后提示登录,然后填写反馈表格。但在登录的情况下访问该URL会出现错误。webapps.stackexchange.com/questions/79495/…

你的代码只改变了输出代码页,即SetConsoleOutputCP,但是运行chcp.com只检查输入代码页,即GetConsoleCP。运行chcp.com 850会同时修改输入和输出代码页,即调用SetConsoleCP和SetConsoleOutputCP。另外,使用控制台中的代码页65001在不同版本的Windows中存在许多错误,从XP到Windows 10都有一些错误,其中一些错误是在conhost.exe(在Windows 8+中可能是condrv.sys)中,还有一些错误是在C运行时或其他库中。如果你需要在控制台中使用Unicode,应该使用[W]ide API。

非常有趣的观点,关于chcp只检查输入的观点。我在[W]ide API上找不到太多的信息。我如何在C#中使用"[W]ide API"来设置代码页为UTF8?

将输入和输出编码设置为System.Text.Encoding.Unicode。使用这个设置,Console.ReadLine调用Win32的ReadConsoleW,Console.WriteLine调用Win32的WriteConsoleW。注意,非Unicode编码调用ReadFile,它对于一行开头的Ctrl+Z有特殊处理,但ReadConsole没有。

谢谢。关于System.Text.Encoding.Unicode导致Console.ReadLine调用Win32 ReadConsoleW的信息在哪里可以找到?System.Console.InputEncoding=System.Text.Encoding.UTF8,我注意到chcp仍然显示为65001。并且仍然存在崩溃的csc bug。使用.Unicode时,chcp不会改变,csc不会崩溃。但是,如果我执行myprog>a.a,如果不使用UTF8,它不会重定向特殊字符。

当你重定向到管道或文件时,它会写入没有BOM(即"\uFEFF")的UTF-16,所以有些程序可能无法检测到文本的编码。如果System.Console.IsOutputRedirected,你可以在这种情况下写入BOM,或者切换到UTF-8,如果你更喜欢。

0
0 Comments

csc.exe在输出编码设置为UTF8时为什么会崩溃?出现这个问题的原因是Windows控制台存在许多与Unicode相关的错误。解决方法是使用utf8output参数并将输出重定向到文件。具体操作为,在运行csc命令时加上/utf8output参数并将输出重定向到文件。需要注意的是,只有同时使用了这两个操作,才能使CSC在UTF-8控制台下正常工作。这个问题的根本原因是输出编码为UTF-8时,再次运行csc命令会导致崩溃。因此,使用utf8output参数和输出重定向可以解决这个问题。具体操作的示例代码如下:

csc /utf8output aaa1.cs > aaa1-compilation.log

这样就可以将CSC的输出重定向到名为aaa1-compilation.log的文件中。通过这种方式可以避免CSC在UTF-8控制台下的崩溃问题,确保程序能够正常运行。

0