// Copyright 2016 The Crashpad Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include #include #include #include namespace { // This custom logging function is to avoid taking a dependency on base in this // standalone DLL. Don’t call this directly, use the LOG_FATAL() and // PLOG_FATAL() macros below. __declspec(noreturn) void LogFatal(const char* file, int line, bool get_last_error, const char* format, ...) { DWORD last_error = ERROR_SUCCESS; if (get_last_error) { last_error = GetLastError(); } char fname[_MAX_FNAME]; char ext[_MAX_EXT]; if (_splitpath_s(file, nullptr, 0, nullptr, 0, fname, sizeof(fname), ext, sizeof(ext)) == 0) { fprintf(stderr, "%s%s", fname, ext); } else { fputs(file, stderr); } fprintf(stderr, ":%d: ", line); va_list va; va_start(va, format); vfprintf(stderr, format, va); va_end(va); if (get_last_error) { fprintf(stderr, ": error %lu", last_error); } fputs("\n", stderr); fflush(stderr); TerminateProcess(GetCurrentProcess(), 1); __fastfail(FAST_FAIL_FATAL_APP_EXIT); } #define LOG_FATAL(...) \ do { \ LogFatal(__FILE__, __LINE__, false, __VA_ARGS__); \ } while (false) #define PLOG_FATAL(...) \ do { \ LogFatal(__FILE__, __LINE__, true, __VA_ARGS__); \ } while (false) } // namespace // This program intentionally blocks in DllMain which is executed with the // loader lock locked. This allows us to test that // CrashpadClient::DumpAndCrashTargetProcess() can still dump the target in this // case. BOOL WINAPI DllMain(HINSTANCE, DWORD reason, LPVOID) { switch (reason) { case DLL_PROCESS_DETACH: case DLL_THREAD_DETACH: { // Recover the event handle stashed by the main executable. static constexpr size_t kEventStringSize = 19; wchar_t event_string[kEventStringSize]; SetLastError(ERROR_SUCCESS); DWORD size = GetEnvironmentVariable( L"CRASHPAD_TEST_DLL_EVENT", event_string, kEventStringSize); if (size == 0 && GetLastError() != ERROR_SUCCESS) { PLOG_FATAL("GetEnvironmentVariable"); } if (size == 0 || size >= kEventStringSize) { LOG_FATAL("GetEnvironmentVariable: size %u", size); } HANDLE event; int converted = swscanf(event_string, L"%p", &event); if (converted != 1) { LOG_FATAL("swscanf: converted %d", converted); } // Let the main thread know that the loader lock is and will remain held. if (!SetEvent(event)) { PLOG_FATAL("SetEvent"); } Sleep(INFINITE); break; } } return TRUE; }