-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
Description
dotnet --info crashes in hostfxr when printing environment variables if a variable contains a %-string, when stdout is redirected to a file on Windows.
Reproduction Steps
-
Set a
DOTNET_*environment variable to a value which contains a %-specifier.For instance, set
DOTNET_DbgMiniDumpName=dump_%e_%p.dmp. (Interestingly, the CoreCLR crash handler is actually invoked and generates a crash dump for this.) -
Run
dotnet --info > file.txt
Expected behavior
No crash, and environment variables are printed.
Actual behavior
Host crashes.
Example failing case: https://github.com/MonoMod/MonoMod/actions/runs/17620993089/job/50066937459?pr=258
Example passing case (running .NET 9.0.9): https://github.com/MonoMod/MonoMod/actions/runs/17620993089/job/50066937838?pr=258
Regression?
This worked in 9.0.9 and before; it seems to be new in 10.0.0-rc.1 hostfxr.
Known Workarounds
No response
Configuration
.NET 10.0.0-rc.1.25451.107
Windows-specific, does not appear to be architecture-specific
Other information
The issue appears to be here:
runtime/src/native/corehost/hostmisc/pal.windows.cpp
Lines 32 to 37 in cbfd526
| if (isConsoleOutput == FALSE) | |
| { | |
| // We use file_vprintf to handle UTF-8 formatting. The WriteFile api will output the bytes directly with Unicode bytes, | |
| // while pal::file_vprintf will convert the characters to UTF-8. | |
| pal::file_vprintf(fallbackFileHandle, message, va_list()); | |
| } |
message here is already formatted to contain the correct string, but it's being re-formatted by the underlying vfwprintf call, but this time with an empty va_list.
I believe the following patch would fix the error:
namespace
{
+ void file_printf(FILE* fallbackFileHandle, const pal::char_t* format, ...)
+ {
+ va_list args;
+ va_start(args, format);
+ pal::file_vprintf(fallbackFileHandle, format, args);
+ va_end(args);
+ }
+
void print_line_to_handle(const pal::char_t* message, HANDLE handle, FILE* fallbackFileHandle) {
// String functions like vfwprintf convert wide to multi-byte characters as if wcrtomb were called - that is, using the current C locale (LC_TYPE).
// In order to properly print UTF-8 and GB18030 characters to the console without requiring the user to use chcp to a compatible locale, we use WriteConsoleW.
// However, WriteConsoleW will fail if the output is redirected to a file - in that case we will write to the fallbackFileHandle
DWORD output;
// GetConsoleMode returns FALSE when the output is redirected to a file, and we need to output to the fallback file handle.
BOOL isConsoleOutput = ::GetConsoleMode(handle, &output);
if (isConsoleOutput == FALSE)
{
// We use file_vprintf to handle UTF-8 formatting. The WriteFile api will output the bytes directly with Unicode bytes,
// while pal::file_vprintf will convert the characters to UTF-8.
- pal::file_vprintf(fallbackFileHandle, message, va_list());
+ file_printf(fallbackFileHandle, "%s", message);
}
else {
::WriteConsoleW(handle, message, (int)pal::strlen(message), NULL, NULL);
::WriteConsoleW(handle, _X("\n"), 1, NULL, NULL);
}
}
}