Почему происходит сбой csc.exe, когда я в последний раз оставляю выходную кодировку как UTF8?
Я испытываю или столкнулся с очень странной вещью.
Интересно, есть ли у других и почему это происходит.
Запустив однострочную программу с этой строкой System.Console.WriteLine(System.Console.OutputEncoding.EncodingName);
Я вижу, что кодировка Western European (DOS)
хорошо
Вот список некоторых кодовых страниц1200 Unicode
а также 65001 utf-8
а также Windows-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);
}
}
Работает, печатает
Western European (DOS)
Unicode (UTF-8)
Теперь, когда я снова запускаю csc, csc падает.
Я проверил свою оперативную память в течение 14 часов, 8 проходов, с memtest. Я запустил chkdsk мой жесткий диск, все хорошо. И это определенно не те, это проблема кодирования. Я знаю это, потому что, если я открою новое приглашение cmd, а затем запустите csc, он не вылетит.
Таким образом, выполнение этой острой программы изменяет оболочку таким образом, что в следующий раз при простом запуске csc произойдет аварийное завершение работы самого csc.
Если я скомпилирую приведенный ниже код, затем запустите его, затем запустите csc, затем запустите csc или csc what.cs, я получаю сбой csc.
Поэтому закройте командную строку, откройте новую.
На этот раз поэкспериментируйте с комментариями и раскомментируйте вторую строку программы
Я обнаружил, что если есть вторая строка (строка, которая изменяет кодовую страницу на 850 (DOS Western Europe)), то при следующем запуске 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;
// 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
}
}
Добавление строки / раскомментируйте последние строки, чтобы я
System.Console.OutputEncoding=System.Text.Encoding.GetEncoding(850);
остановил бы сбой, но это неадекватное решение, потому что, например. Если я хочу перенаправить вывод программы в файл, то мне нужен UTF8 от начала до конца, иначе он не работает
это работает с строкой кодовой страницы 850 без комментариев
c:\blah>uuu1>r.r<ENTER>
c:\blah>type r.r <ENTER>
c:\blah>ჵ
Если я раскомментирую последние строки, изменяя кодовую страницу на 850, тогда csc не будет аварийно завершать работу при следующем запуске, но перенаправление не будет работать, а rr не будет содержать этот символ.
Добавлено 2
Ответ Хана заставляет меня заметить еще один способ вызвать эту ошибку
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>
2 ответа
Итак, вы обнаружили ошибку в том, что компилятор 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
Фактический код для 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;
}
Авария происходит где-то около VSFAIL(), судя по машинному коду. Я вижу ответ E_FAIL. Однако он был изменен по сравнению с опубликованной версией, был изменен оператор if(), и похоже, что VSFAIL() был заменен на RETAILVERIFY(). Что-то сломалось, когда они внесли эти изменения, вероятно, в UnicodeToUTF8(), который теперь называется UTF16ToUTF8(). Еще раз подчеркнув, что версия, которую я разместил, на самом деле не дает сбоя, вы можете убедиться в этом сами, запустив C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe. Эта ошибка есть только в версии csc.exe версии 4.
Фактическую ошибку трудно найти из машинного кода, лучше всего позволить Microsoft беспокоиться об этом. Вы можете отправить сообщение об ошибке по адресу connect.microsoft.com. Я не вижу отчета, который напоминает это, довольно замечательный кстати. Обходной путь для этой ошибки - использовать CHCP, чтобы изменить кодовую страницу обратно.
Существуют разные статьи, которые намекают на то, что в консоли Windows есть много ошибок, связанных с Unicode. Статьи, такие как: https://alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode/
Вот один из обходных путей, который работает для меня. Вместо:
csc aaa1.cs
Попробуйте это (который перенаправит вывод CSC в файл):
csc /utf8output aaa1.cs > aaa1-compilation.log
Соответствующая документация: https://msdn.microsoft.com/en-us/library/d5bxd1x2.aspx
В некоторых международных конфигурациях выходные данные компилятора не могут правильно отображаться в консоли. В этих конфигурациях используйте /utf8output и перенаправьте вывод компилятора в файл.
добавлено барлопом
Глядя на чат, мы обнаружили, что делаем csc uuu1.cs<ENTER>
uuu1<ENTER>
затем, чтобы предотвратить сбой, каждый приходящий csc должен быть выполнен с /utf8output AND (по какой-то странной неизвестной причине), причудливо, с перенаправлением.. так, csc /utf8output uuu1.cs >asdfsdaf
Обходное решение Хана лучше, просто запустите chcp 850 (или любую кодовую страницу, которую вы используете) после uuu1<ENTER>
даже если chcp говорит, что это 850, вы все равно должны выполнить chcp 850. Тогда csc будет работать нормально.
Причина, по которой при возникновении проблемы вы должны запустить chcp 850, даже если chcp показывает 850, в том, что chcp покажет вам только входную кодировку, хотя chcp 850 изменит и входную кодировку, и выходную кодировку, и мы хотим, чтобы изменение выходной кодировки. Таким образом, chcp может показывать 850, даже если ваша выходная кодировка 65001, а проблема только в том случае, если выходная кодировка 65001