crashpad/handler/win/self_destroying_test_program.cc

102 lines
3.0 KiB
C++
Raw Normal View History

// Copyright 2015 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 <malloc.h>
#include <stdlib.h>
#include <windows.h>
#include <winternl.h>
#include "base/logging.h"
#include "client/crashpad_client.h"
#include "snapshot/win/process_reader_win.h"
namespace crashpad {
namespace {
Prepare for building with clang * Switch to Chromium's clang package on Windows. Fuchsia's clang package uses symlinks, which don't Just Work. See comment 3 on the linked bug for details. * Also tweak the installed path of the clang package to use win-amd64 instead of windows-amd64 to match gn's host_os variable, which is needed by the mini_chromium change in the roll mentioned below. * Add `__declspec(noinline)` to sources of some end-to-end test binaries where the test expects a certain stack layout that's perturbed by inlining * self_destroying_test_program.cc failed with Access Violation instead of with Breakpoint. I'm not 100% sure what's happening there as I couldn't reproduce it on my machine. The test uses VirtualFree(..., MEM_DECOMMIT) to make parts of the stack unreadable to make sure crashpad can handle that. My theory is that clang optimized out the call to `_alloca()`, which results in not enough of the stack being around for VirtualFree() to be able to decommit. https://geidav.wordpress.com/tag/reserved-memory/#:~:text=How%20does%20Windows%20manage%20stack%20memory%3F and https://godbolt.org/z/YdbYdKeMh suggest that this theory is not completely off -- but the `[[maybe_unused]] volatile void* do_not_optimize_away` bit feels homeopathic. And yet, with it this seems to pass CQ (see try results at patch sets 12 and 20) and without it it doesn't (see patch set 19). Maybe this was just luck and the test still feels flakily! (The linker's `/STACK` defaults to 1MB stack reserved and 4K committed -- 4K kind of seems like it should be enough for that VirtualFree call to succeed if that really is the problem.) So this part is a bit experimental. Anyways, nothing uses clang yet, so no behavior change at this point (other than `gclient sync` downloading less stuff and not failing by default on Windows). Includes a one-rev mini_chromium roll: https://chromium.googlesource.com/chromium/mini_chromium/+log/12ef786772d9..08d490553b0d $ git log 12ef78677..08d490553 --date=short --no-merges --format='%ad %ae %s' 2025-02-13 thakis Prepare mini_chromium for using clang on Windows Bug: 384682775 Change-Id: I33b54acf18cb6eadfd2167c76c0b4a5824efa64d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6242577 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org>
2025-02-24 14:21:04 -05:00
// Without this, clang optimizes away the _alloca below, which in turn
// makes the VirtualFree() crash with an access violation.
#if defined(__clang__)
#pragma clang optimize off
#endif
// We VirtualFree a region in ourselves (the stack) to confirm that the
// exception reporter captures as much as possible in the minidump and doesn't
// abort. __debugbreak() immediately after doing so because the process is
// clearly in a very broken state at this point.
Prepare for building with clang * Switch to Chromium's clang package on Windows. Fuchsia's clang package uses symlinks, which don't Just Work. See comment 3 on the linked bug for details. * Also tweak the installed path of the clang package to use win-amd64 instead of windows-amd64 to match gn's host_os variable, which is needed by the mini_chromium change in the roll mentioned below. * Add `__declspec(noinline)` to sources of some end-to-end test binaries where the test expects a certain stack layout that's perturbed by inlining * self_destroying_test_program.cc failed with Access Violation instead of with Breakpoint. I'm not 100% sure what's happening there as I couldn't reproduce it on my machine. The test uses VirtualFree(..., MEM_DECOMMIT) to make parts of the stack unreadable to make sure crashpad can handle that. My theory is that clang optimized out the call to `_alloca()`, which results in not enough of the stack being around for VirtualFree() to be able to decommit. https://geidav.wordpress.com/tag/reserved-memory/#:~:text=How%20does%20Windows%20manage%20stack%20memory%3F and https://godbolt.org/z/YdbYdKeMh suggest that this theory is not completely off -- but the `[[maybe_unused]] volatile void* do_not_optimize_away` bit feels homeopathic. And yet, with it this seems to pass CQ (see try results at patch sets 12 and 20) and without it it doesn't (see patch set 19). Maybe this was just luck and the test still feels flakily! (The linker's `/STACK` defaults to 1MB stack reserved and 4K committed -- 4K kind of seems like it should be enough for that VirtualFree call to succeed if that really is the problem.) So this part is a bit experimental. Anyways, nothing uses clang yet, so no behavior change at this point (other than `gclient sync` downloading less stuff and not failing by default on Windows). Includes a one-rev mini_chromium roll: https://chromium.googlesource.com/chromium/mini_chromium/+log/12ef786772d9..08d490553b0d $ git log 12ef78677..08d490553 --date=short --no-merges --format='%ad %ae %s' 2025-02-13 thakis Prepare mini_chromium for using clang on Windows Bug: 384682775 Change-Id: I33b54acf18cb6eadfd2167c76c0b4a5824efa64d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6242577 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org>
2025-02-24 14:21:04 -05:00
__declspec(noinline) bool FreeOwnStackAndBreak() {
ProcessReaderWin process_reader;
if (!process_reader.Initialize(GetCurrentProcess(),
ProcessSuspensionState::kRunning)) {
LOG(ERROR) << "ProcessReaderWin Initialize";
return false;
}
const std::vector<ProcessReaderWin::Thread> threads =
process_reader.Threads();
if (threads.empty()) {
LOG(ERROR) << "no threads";
return false;
}
// Push the stack up a bit so that hopefully the crash handler can succeed,
// but won't be able to read the base of the stack.
Prepare for building with clang * Switch to Chromium's clang package on Windows. Fuchsia's clang package uses symlinks, which don't Just Work. See comment 3 on the linked bug for details. * Also tweak the installed path of the clang package to use win-amd64 instead of windows-amd64 to match gn's host_os variable, which is needed by the mini_chromium change in the roll mentioned below. * Add `__declspec(noinline)` to sources of some end-to-end test binaries where the test expects a certain stack layout that's perturbed by inlining * self_destroying_test_program.cc failed with Access Violation instead of with Breakpoint. I'm not 100% sure what's happening there as I couldn't reproduce it on my machine. The test uses VirtualFree(..., MEM_DECOMMIT) to make parts of the stack unreadable to make sure crashpad can handle that. My theory is that clang optimized out the call to `_alloca()`, which results in not enough of the stack being around for VirtualFree() to be able to decommit. https://geidav.wordpress.com/tag/reserved-memory/#:~:text=How%20does%20Windows%20manage%20stack%20memory%3F and https://godbolt.org/z/YdbYdKeMh suggest that this theory is not completely off -- but the `[[maybe_unused]] volatile void* do_not_optimize_away` bit feels homeopathic. And yet, with it this seems to pass CQ (see try results at patch sets 12 and 20) and without it it doesn't (see patch set 19). Maybe this was just luck and the test still feels flakily! (The linker's `/STACK` defaults to 1MB stack reserved and 4K committed -- 4K kind of seems like it should be enough for that VirtualFree call to succeed if that really is the problem.) So this part is a bit experimental. Anyways, nothing uses clang yet, so no behavior change at this point (other than `gclient sync` downloading less stuff and not failing by default on Windows). Includes a one-rev mini_chromium roll: https://chromium.googlesource.com/chromium/mini_chromium/+log/12ef786772d9..08d490553b0d $ git log 12ef78677..08d490553 --date=short --no-merges --format='%ad %ae %s' 2025-02-13 thakis Prepare mini_chromium for using clang on Windows Bug: 384682775 Change-Id: I33b54acf18cb6eadfd2167c76c0b4a5824efa64d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6242577 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org>
2025-02-24 14:21:04 -05:00
[[maybe_unused]] volatile void* do_not_optimize_away = _alloca(16384);
// We can't succeed at MEM_RELEASEing this memory, but MEM_DECOMMIT is good
// enough to make it inaccessible.
if (!VirtualFree(reinterpret_cast<void*>(threads[0].stack_region_address),
100,
MEM_DECOMMIT)) {
PLOG(ERROR) << "VirtualFree";
return false;
}
// If the VirtualFree() succeeds, we may have already crashed. __debugbreak()
// just to be sure.
__debugbreak();
return true;
}
Prepare for building with clang * Switch to Chromium's clang package on Windows. Fuchsia's clang package uses symlinks, which don't Just Work. See comment 3 on the linked bug for details. * Also tweak the installed path of the clang package to use win-amd64 instead of windows-amd64 to match gn's host_os variable, which is needed by the mini_chromium change in the roll mentioned below. * Add `__declspec(noinline)` to sources of some end-to-end test binaries where the test expects a certain stack layout that's perturbed by inlining * self_destroying_test_program.cc failed with Access Violation instead of with Breakpoint. I'm not 100% sure what's happening there as I couldn't reproduce it on my machine. The test uses VirtualFree(..., MEM_DECOMMIT) to make parts of the stack unreadable to make sure crashpad can handle that. My theory is that clang optimized out the call to `_alloca()`, which results in not enough of the stack being around for VirtualFree() to be able to decommit. https://geidav.wordpress.com/tag/reserved-memory/#:~:text=How%20does%20Windows%20manage%20stack%20memory%3F and https://godbolt.org/z/YdbYdKeMh suggest that this theory is not completely off -- but the `[[maybe_unused]] volatile void* do_not_optimize_away` bit feels homeopathic. And yet, with it this seems to pass CQ (see try results at patch sets 12 and 20) and without it it doesn't (see patch set 19). Maybe this was just luck and the test still feels flakily! (The linker's `/STACK` defaults to 1MB stack reserved and 4K committed -- 4K kind of seems like it should be enough for that VirtualFree call to succeed if that really is the problem.) So this part is a bit experimental. Anyways, nothing uses clang yet, so no behavior change at this point (other than `gclient sync` downloading less stuff and not failing by default on Windows). Includes a one-rev mini_chromium roll: https://chromium.googlesource.com/chromium/mini_chromium/+log/12ef786772d9..08d490553b0d $ git log 12ef78677..08d490553 --date=short --no-merges --format='%ad %ae %s' 2025-02-13 thakis Prepare mini_chromium for using clang on Windows Bug: 384682775 Change-Id: I33b54acf18cb6eadfd2167c76c0b4a5824efa64d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6242577 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org>
2025-02-24 14:21:04 -05:00
__declspec(noinline) int SelfDestroyingMain(int argc, wchar_t* argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %ls <server_pipe_name>\n", argv[0]);
return EXIT_FAILURE;
}
CrashpadClient client;
if (!client.SetHandlerIPCPipe(argv[1])) {
LOG(ERROR) << "SetHandler";
return EXIT_FAILURE;
}
if (!FreeOwnStackAndBreak())
return EXIT_FAILURE;
// This will never be reached. On success, we'll have crashed above, or
// otherwise returned before here.
return EXIT_SUCCESS;
}
Prepare for building with clang * Switch to Chromium's clang package on Windows. Fuchsia's clang package uses symlinks, which don't Just Work. See comment 3 on the linked bug for details. * Also tweak the installed path of the clang package to use win-amd64 instead of windows-amd64 to match gn's host_os variable, which is needed by the mini_chromium change in the roll mentioned below. * Add `__declspec(noinline)` to sources of some end-to-end test binaries where the test expects a certain stack layout that's perturbed by inlining * self_destroying_test_program.cc failed with Access Violation instead of with Breakpoint. I'm not 100% sure what's happening there as I couldn't reproduce it on my machine. The test uses VirtualFree(..., MEM_DECOMMIT) to make parts of the stack unreadable to make sure crashpad can handle that. My theory is that clang optimized out the call to `_alloca()`, which results in not enough of the stack being around for VirtualFree() to be able to decommit. https://geidav.wordpress.com/tag/reserved-memory/#:~:text=How%20does%20Windows%20manage%20stack%20memory%3F and https://godbolt.org/z/YdbYdKeMh suggest that this theory is not completely off -- but the `[[maybe_unused]] volatile void* do_not_optimize_away` bit feels homeopathic. And yet, with it this seems to pass CQ (see try results at patch sets 12 and 20) and without it it doesn't (see patch set 19). Maybe this was just luck and the test still feels flakily! (The linker's `/STACK` defaults to 1MB stack reserved and 4K committed -- 4K kind of seems like it should be enough for that VirtualFree call to succeed if that really is the problem.) So this part is a bit experimental. Anyways, nothing uses clang yet, so no behavior change at this point (other than `gclient sync` downloading less stuff and not failing by default on Windows). Includes a one-rev mini_chromium roll: https://chromium.googlesource.com/chromium/mini_chromium/+log/12ef786772d9..08d490553b0d $ git log 12ef78677..08d490553 --date=short --no-merges --format='%ad %ae %s' 2025-02-13 thakis Prepare mini_chromium for using clang on Windows Bug: 384682775 Change-Id: I33b54acf18cb6eadfd2167c76c0b4a5824efa64d Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/6242577 Reviewed-by: Mark Mentovai <mark@chromium.org> Commit-Queue: Nico Weber <thakis@chromium.org>
2025-02-24 14:21:04 -05:00
#if defined(__clang__)
#pragma clang optimize on
#endif
} // namespace
} // namespace crashpad
int wmain(int argc, wchar_t* argv[]) {
return crashpad::SelfDestroyingMain(argc, argv);
}