Skip to content

Fix FailFast message formatting race #56388

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 27, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions src/coreclr/classlibnative/bcltype/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ INT32 QCALLTYPE SystemNative::GetProcessorCount()
// managed string object buffer. This buffer is not always used, see comments in
// the method below.
WCHAR g_szFailFastBuffer[256];
WCHAR *g_pFailFastBuffer = g_szFailFastBuffer;

#define FAIL_FAST_STATIC_BUFFER_LENGTH (sizeof(g_szFailFastBuffer) / sizeof(WCHAR))

// This is the common code for FailFast processing that is wrapped by the two
Expand Down Expand Up @@ -243,7 +245,7 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce
// Another option would seem to be to implement a new frame type that
// protects object references as pinned, but that seems like overkill for
// just this problem.
WCHAR *pszMessage = NULL;
WCHAR *pszMessageBuffer = NULL;
DWORD cchMessage = (gc.refMesgString == NULL) ? 0 : gc.refMesgString->GetStringLength();

WCHAR * errorSourceString = NULL;
Expand All @@ -262,32 +264,44 @@ void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExce

if (cchMessage < FAIL_FAST_STATIC_BUFFER_LENGTH)
{
pszMessage = g_szFailFastBuffer;
// The static buffer can be used only once to avoid race condition with other threads
pszMessageBuffer = InterlockedExchangeT(&g_pFailFastBuffer, NULL);
}
else

if (pszMessageBuffer == NULL)
{
// We can fail here, but we can handle the fault.
CONTRACT_VIOLATION(FaultViolation);
pszMessage = new (nothrow) WCHAR[cchMessage + 1];
if (pszMessage == NULL)
pszMessageBuffer = new (nothrow) WCHAR[cchMessage + 1];
if (pszMessageBuffer == NULL)
{
// Truncate the message to what will fit in the static buffer.
cchMessage = FAIL_FAST_STATIC_BUFFER_LENGTH - 1;
pszMessage = g_szFailFastBuffer;
pszMessageBuffer = InterlockedExchangeT(&g_pFailFastBuffer, NULL);
}
}

if (cchMessage > 0)
memcpyNoGCRefs(pszMessage, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
pszMessage[cchMessage] = W('\0');
const WCHAR *pszMessage;
if (pszMessageBuffer != NULL)
{
if (cchMessage > 0)
memcpyNoGCRefs(pszMessageBuffer, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
pszMessageBuffer[cchMessage] = W('\0');
pszMessage = pszMessageBuffer;
}
else
{
pszMessage = W("There is not enough memory to print the supplied FailFast message.");
cchMessage = (DWORD)wcslen(pszMessage);
}

if (cchMessage == 0) {
WszOutputDebugString(W("CLR: Managed code called FailFast without specifying a reason.\r\n"));
}
else {
WszOutputDebugString(W("CLR: Managed code called FailFast, saying \""));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not your change, but to be consistent with the other CLR termination messages, this would be ...called FailFast. "));. They all suffix the message after a period.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to keep it on one line (ie, space instead of \r\n). That is the existing pattern and it works well with logs and concurrent console output where the two lines can otherwise get separated.

WszOutputDebugString(W("CLR: Managed code called FailFast.\r\n"));
WszOutputDebugString(pszMessage);
WszOutputDebugString(W("\"\r\n"));
WszOutputDebugString(W("\r\n"));
}

LPCWSTR argExceptionString = NULL;
Expand Down