Backed out 5 changesets (bug 1697895, bug 1682518, bug 1703761, bug 1711418) for causing Windows 2012 x64 asan buid bustages.

CLOSED TREE

Backed out changeset 4cc2cb3653f2 (bug 1711418)
Backed out changeset 02cf2dc4c3c8 (bug 1711418)
Backed out changeset ca35e73d9445 (bug 1703761)
Backed out changeset 43c12d3f5c4f (bug 1682518)
Backed out changeset d75aef90ac53 (bug 1697895)
This commit is contained in:
Brindusan Cristian 2021-06-10 16:30:44 +03:00
Родитель 406381b192
Коммит df90ffe9bc
9 изменённых файлов: 222 добавлений и 521 удалений

Просмотреть файл

@ -227,8 +227,7 @@ class WindowsProcessLauncher : public BaseProcessLauncher {
std::vector<std::string>&& aExtraOpts)
: BaseProcessLauncher(aHost, std::move(aExtraOpts)),
mProfileDir(aHost->mProfileDir),
mCachedNtdllThunk(aHost->sCachedNtDllThunk),
mWerDataPointer(&(aHost->mWerData)) {}
mCachedNtdllThunk(aHost->sCachedNtDllThunk) {}
protected:
bool SetChannel(IPC::Channel*) override { return true; }
@ -242,7 +241,6 @@ class WindowsProcessLauncher : public BaseProcessLauncher {
nsCOMPtr<nsIFile> mProfileDir;
const StaticAutoPtr<Buffer<IMAGE_THUNK_DATA>>& mCachedNtdllThunk;
CrashReporter::WindowsErrorReportingData const* mWerDataPointer;
};
typedef WindowsProcessLauncher ProcessLauncher;
#endif // XP_WIN
@ -404,9 +402,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
mProcessState(CREATING_CHANNEL),
#ifdef XP_WIN
mGroupId(u"-"),
mWerData{.mWerNotifyProc = CrashReporter::WerNotifyProc,
.mChildPid = 0,
.mMinidumpFile = {}},
#endif
#if defined(MOZ_SANDBOX) && defined(XP_WIN)
mEnableSandboxLogging(false),
@ -1521,10 +1516,6 @@ bool WindowsProcessLauncher::DoSetup() {
mLaunchOptions->handles_to_inherit.push_back(reinterpret_cast<HANDLE>(h));
std::string hStr = std::to_string(h);
mCmdLine->AppendLooseValue(UTF8ToWide(hStr));
char werDataAddress[17] = {};
SprintfLiteral(werDataAddress, "%p", mWerDataPointer);
mCmdLine->AppendLooseValue(UTF8ToWide(werDataAddress));
}
// Process type

Просмотреть файл

@ -24,7 +24,6 @@
#include "mozilla/UniquePtr.h"
#include "nsCOMPtr.h"
#include "nsExceptionHandler.h"
#include "nsXULAppAPI.h" // for GeckoProcessType
#include "nsString.h"
@ -225,7 +224,7 @@ class GeckoChildProcessHost : public ChildProcessHost,
#ifdef XP_WIN
void InitWindowsGroupID();
nsString mGroupId;
CrashReporter::WindowsErrorReportingData mWerData;
# ifdef MOZ_SANDBOX
RefPtr<AbstractSandboxBroker> mSandboxBroker;
std::vector<std::wstring> mAllowedFilesRead;

Просмотреть файл

@ -54,7 +54,6 @@ Structure:
AsyncShutdownTimeout: <json>, // Optional, present when a shutdown blocker failed to respond within a reasonable amount of time
AvailablePageFile: <size>, // Windows-only, available paging file in bytes
AvailablePhysicalMemory: <size>, // Windows-only, available physical memory in bytes
AvailableSwapMemory: <size>, // macOS- and Linux-only, available swap space
AvailableVirtualMemory: <size>, // Windows-only, available virtual memory in bytes
BlockedDllList: <list>, // Windows-only, see WindowsDllBlocklist.cpp for details
BlocklistInitFailed: "1", // Windows-only, present only if the DLL blocklist initialization failed
@ -63,15 +62,11 @@ Structure:
DOMFissionEnabled: "1", // Optional, if set indicates that a Fission window had been opened
EventLoopNestingLevel: <levels>, // Optional, present only if >0, indicates the nesting level of the event-loop
ExperimentalFeatures: <features>, // Optional, a comma-separated string that specifies the enabled experimental features from about:preferences#experimental
GPUProcessLaunchCount: <num>, // Number of times the GPU process was launched
ipc_channel_error: <error string>, // Optional, contains the string processing error reason for an ipc-based content crash
IsGarbageCollecting: "1", // Optional, if set indicates that the crash occurred while the garbage collector was running
LowCommitSpaceEvents: <num>, // Windows-only, present only if >0, number of low commit space events detected by the available memory tracker
MainThreadRunnableName: <name>, // Optional, Nightly-only, name of the currently executing nsIRunnable on the main thread
MozCrashReason: <reason>, // Optional, contains the string passed to MOZ_CRASH()
OOMAllocationSize: <size>, // Size of the allocation that caused an OOM
ProfilerChildShutdownPhase: <string>, // Profiler shutdown phase
PurgeablePhysicalMemory: <size>, // macOS-only, amount of memory that can be deallocated by the OS in case of memory pressure
QuotaManagerShutdownTimeout: <log-string>, // Optional, contains a list of shutdown steps and status of the quota manager clients
RemoteType: <type>, // Optional, type of content process, see below for a list of types
SecondsSinceLastCrash: <duration>, // Seconds elapsed since the last crash occurred
@ -84,7 +79,7 @@ Structure:
TotalVirtualMemory: <size>, // Windows-only, virtual memory in use expressed in bytes
UptimeTS: <duration>, // Seconds since Firefox was started, this can have a fractional component
User32BeforeBlocklist: "1", // Windows-only, present only if user32.dll was loaded before the DLL blocklist has been initialized
WindowsErrorReporting: "1", // Windows-only, present only if the crash was intercepted by the WER runtime exception module
MainThreadRunnableName: <name>, // Optional, Nightly-only, name of the currently executing nsIRunnable on the main thread
},
hasCrashEnvironment: bool
}
@ -228,17 +223,4 @@ Version History
- Firefox 62: Added LowCommitSpaceEvents (`bug 1464773 <https://bugzilla.mozilla.org/show_bug.cgi?id=1464773>`_).
- Firefox 63: Added RecordReplayError (`bug 1481009 <https://bugzilla.mozilla.org/show_bug.cgi?id=1481009>`_).
- Firefox 64: Added MemoryErrorCorrection (`bug 1498609 <https://bugzilla.mozilla.org/show_bug.cgi?id=1498609>`_).
- Firefox 68: Added IndexedDBShutdownTimeout and LocalStorageShutdownTimeout
(`bug 1539750 <https://bugzilla.mozilla.org/show_bug.cgi?id=1539750>`_).
- Firefox 74: Added AvailableSwapMemory and PurgeablePhysicalMemory
(`bug 1587721 <https://bugzilla.mozilla.org/show_bug.cgi?id=1587721>`_).
- Firefox 74: Added MainThreadRunnableName (`bug 1608158 <https://bugzilla.mozilla.org/show_bug.cgi?id=1608158>`_).
- Firefox 76: Added DOMFissionEnabled (`bug 1602918 <https://bugzilla.mozilla.org/show_bug.cgi?id=1602918>`_).
- Firefox 79: Added ExperimentalFeatures (`bug 1644544 <https://bugzilla.mozilla.org/show_bug.cgi?id=1644544>`_).
- Firefox 85: Added QuotaManagerShutdownTimeout, removed IndexedDBShutdownTimeout and LocalStorageShutdownTimeout
(`bug 1672369 <https://bugzilla.mozilla.org/show_bug.cgi?id=1672369>`_)
- Firefox 89: Added GPUProcessLaunchCount (`bug 1710448 <https://bugzilla.mozilla.org/show_bug.cgi?id=1710448>`_)
and ProfilerChildShutdownPhase (`bug 1704680 <https://bugzilla.mozilla.org/show_bug.cgi?id=1704680>`_).
- Firefox 90: Removed MemoryErrorCorrection (`bug 1710152 <https://bugzilla.mozilla.org/show_bug.cgi?id=1710152>`_)
and added WindowsErrorReporting (`bug 1703761 <https://bugzilla.mozilla.org/show_bug.cgi?id=1703761>`_).
- Firefox 90: Removed MemoryErrorCorrection (`bug 1710152 <https://bugzilla.mozilla.org/show_bug.cgi?id=1710152>`_).

Просмотреть файл

@ -974,13 +974,6 @@ VRProcessStatus:
Status of the VR process, can be set to "Running" or "Destroyed"
type: string
WindowsErrorReporting:
description: >
Set to 1 if this crash was intercepted via the Windows Error Reporting
runtime exception module.
type: boolean
ping: true
Winsock_LSP:
description: >
Information on winsock LSPs injected in our networking stack.
@ -991,3 +984,4 @@ XPCOMSpinEventLoopStack:
If we crash while some code is spinning manually the event
loop, we will see the stack of nested annotations here.
type: string

Просмотреть файл

@ -17,12 +17,12 @@ use std::mem::{size_of, zeroed};
use std::os::windows::ffi::{OsStrExt, OsStringExt};
use std::os::windows::io::AsRawHandle;
use std::path::{Path, PathBuf};
use std::ptr::{addr_of_mut, null, null_mut};
use std::ptr::{null, null_mut};
use std::slice::from_raw_parts;
use uuid::Uuid;
use winapi::shared::basetsd::{SIZE_T, ULONG_PTR};
use winapi::shared::minwindef::{
BOOL, BYTE, DWORD, FALSE, FILETIME, LPVOID, MAX_PATH, PBOOL, PDWORD, PULONG, TRUE, ULONG, WORD,
BOOL, BYTE, DWORD, FALSE, FILETIME, MAX_PATH, PBOOL, PDWORD, PULONG, TRUE, ULONG, WORD,
};
use winapi::shared::ntdef::{NTSTATUS, STRING, UNICODE_STRING};
use winapi::shared::ntstatus::STATUS_SUCCESS;
@ -30,69 +30,39 @@ use winapi::shared::winerror::{E_UNEXPECTED, S_OK};
use winapi::um::combaseapi::CoTaskMemFree;
use winapi::um::handleapi::CloseHandle;
use winapi::um::knownfolders::FOLDERID_RoamingAppData;
use winapi::um::memoryapi::{ReadProcessMemory, WriteProcessMemory};
use winapi::um::minwinbase::LPTHREAD_START_ROUTINE;
use winapi::um::memoryapi::ReadProcessMemory;
use winapi::um::processthreadsapi::{
CreateProcessW, CreateRemoteThread, GetProcessId, GetProcessTimes, GetThreadId, OpenProcess,
TerminateProcess, PROCESS_INFORMATION, STARTUPINFOW,
CreateProcessW, GetProcessId, GetProcessTimes, GetThreadId, TerminateProcess,
PROCESS_INFORMATION, STARTUPINFOW,
};
use winapi::um::psapi::K32GetModuleFileNameExW;
use winapi::um::shlobj::SHGetKnownFolderPath;
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::{
VerifyVersionInfoW, CREATE_NO_WINDOW, CREATE_UNICODE_ENVIRONMENT, NORMAL_PRIORITY_CLASS,
WAIT_OBJECT_0,
};
use winapi::um::winnt::{
VerSetConditionMask, CONTEXT, DWORDLONG, EXCEPTION_POINTERS, EXCEPTION_RECORD, HANDLE, HRESULT,
LIST_ENTRY, LPOSVERSIONINFOEXW, OSVERSIONINFOEXW, PCWSTR, PEXCEPTION_POINTERS,
PROCESS_ALL_ACCESS, PVOID, PWSTR, VER_GREATER_EQUAL, VER_MAJORVERSION, VER_MINORVERSION,
VER_SERVICEPACKMAJOR, VER_SERVICEPACKMINOR,
LIST_ENTRY, LPOSVERSIONINFOEXW, OSVERSIONINFOEXW, PCWSTR, PEXCEPTION_POINTERS, PVOID, PWSTR,
VER_GREATER_EQUAL, VER_MAJORVERSION, VER_MINORVERSION, VER_SERVICEPACKMAJOR,
VER_SERVICEPACKMINOR,
};
use winapi::STRUCT;
/* The following struct must be kept in sync with the identically named one in
* nsExceptionHandler.h. There is one copy of this structure for every child
* process and they are all stored within the main process'. WER will use it to
* communicate with the main process when a child process is encountered. */
#[repr(C)]
struct WindowsErrorReportingData {
wer_notify_proc: LPTHREAD_START_ROUTINE,
child_pid: DWORD,
minidump_name: [u8; 40],
oom_allocation_size: usize,
}
/* The following struct must be kept in sync with the identically named one in
* nsExceptionHandler.h. A copy of this is stored in every process and a pointer
* to it is passed to the runtime exception module. We will read it to gather
* information about the crashed process. */
#[repr(C)]
struct InProcessWindowsErrorReportingData {
process_type: u32,
oom_allocation_size_ptr: *mut usize,
}
// This value comes from GeckoProcessTypes.h
static MAIN_PROCESS_TYPE: u32 = 0;
#[no_mangle]
pub extern "C" fn OutOfProcessExceptionEventCallback(
context: PVOID,
_context: PVOID,
exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION,
b_ownership_claimed: PBOOL,
_wsz_event_name: PWSTR,
_pch_size: PDWORD,
_dw_signature_count: PDWORD,
) -> HRESULT {
let result = out_of_process_exception_event_callback(context, exception_information);
match result {
match out_of_process_exception_event_callback(exception_information) {
Ok(_) => {
unsafe {
// Inform WER that we claim ownership of this crash
*b_ownership_claimed = TRUE;
// Make sure that the process shuts down
// Make sure that Firefox shuts down
TerminateProcess((*exception_information).hProcess, 1);
}
S_OK
@ -131,138 +101,98 @@ pub extern "C" fn OutOfProcessExceptionEventDebuggerLaunchCallback(
}
fn out_of_process_exception_event_callback(
context: PVOID,
exception_information: PWER_RUNTIME_EXCEPTION_INFORMATION,
) -> Result<(), ()> {
let process = unsafe { (*exception_information).hProcess };
let application_info = ApplicationInformation::from_process(process)?;
let wer_data = read_from_process::<InProcessWindowsErrorReportingData>(
process,
context as *mut InProcessWindowsErrorReportingData,
)?;
let process = unsafe { (*exception_information).hProcess };
let startup_time = get_startup_time(process)?;
let oom_allocation_size = get_oom_allocation_size(process, &wer_data);
let crash_report = CrashReport::new(&application_info, startup_time, oom_allocation_size);
crash_report.write_minidump(exception_information)?;
if wer_data.process_type == MAIN_PROCESS_TYPE {
handle_main_process_crash(crash_report, process, &application_info)
} else {
handle_child_process_crash(crash_report, process)
}
}
fn handle_main_process_crash(
crash_report: CrashReport,
process: HANDLE,
application_information: &ApplicationInformation,
) -> Result<(), ()> {
crash_report.write_extra_file()?;
crash_report.write_event_file()?;
let mut environment = read_environment_block(process)?;
launch_crash_reporter_client(
&application_information.install_path,
&mut environment,
&crash_report,
let application_path = get_application_path(process)?;
let mut install_path = application_path.clone();
install_path.pop();
let application_data = ApplicationData::load_from_disk(install_path.as_ref())?;
let release_channel = get_release_channel(install_path.as_ref())?;
let crash_reports_dir = get_crash_reports_dir(&application_data)?;
let install_time = get_install_time(&crash_reports_dir, &application_data.build_id)?;
let startup_time = get_startup_time(process)?;
let crash_report = CrashReport::new(
&crash_reports_dir,
&release_channel,
&application_data,
&install_time,
startup_time,
);
crash_report.write_minidump(exception_information)?;
crash_report.write_extra_file()?;
crash_report.write_event_file()?;
launch_crash_reporter_client(&application_path, &mut environment, &crash_report);
Ok(())
}
fn handle_child_process_crash(crash_report: CrashReport, child_process: HANDLE) -> Result<(), ()> {
let command_line = read_command_line(child_process)?;
let (parent_pid, data_ptr) = parse_child_data(&command_line)?;
let parent_process = get_process_handle(parent_pid)?;
let mut wer_data: WindowsErrorReportingData = read_from_process(parent_process, data_ptr)?;
wer_data.child_pid = get_process_id(child_process)?;
wer_data.minidump_name = crash_report.get_minidump_name();
wer_data.oom_allocation_size = crash_report.oom_allocation_size;
let wer_notify_proc = wer_data.wer_notify_proc;
write_to_process(parent_process, wer_data, data_ptr)?;
notify_main_process(parent_process, wer_notify_proc, data_ptr)
}
fn read_from_process<T>(process: HANDLE, data_ptr: *mut T) -> Result<T, ()> {
let mut data: T = unsafe { zeroed() };
let res = unsafe {
ReadProcessMemory(
process,
data_ptr as *mut _,
addr_of_mut!(data) as *mut _,
size_of::<T>() as SIZE_T,
null_mut(),
)
};
bool_ok_or_err(res, data)
}
fn read_array_from_process<T: Clone + Default>(
process: HANDLE,
data_ptr: LPVOID,
count: usize,
) -> Result<Vec<T>, ()> {
let mut array = vec![Default::default(); count];
let size = size_of::<T>() as SIZE_T;
let size = size.checked_mul(count).ok_or(())?;
let res = unsafe {
ReadProcessMemory(
process,
data_ptr,
array.as_mut_ptr() as *mut _,
size,
null_mut(),
)
};
bool_ok_or_err(res, array)
}
fn write_to_process<T>(process: HANDLE, mut data: T, data_ptr: *mut T) -> Result<(), ()> {
let res = unsafe {
WriteProcessMemory(
process,
data_ptr as LPVOID,
addr_of_mut!(data) as *mut _,
size_of::<T>() as SIZE_T,
null_mut(),
)
};
bool_ok_or_err(res, ())
}
fn notify_main_process(
process: HANDLE,
wer_notify_proc: LPTHREAD_START_ROUTINE,
data_ptr: *mut WindowsErrorReportingData,
) -> Result<(), ()> {
let thread = unsafe {
CreateRemoteThread(
process,
null_mut(),
0,
wer_notify_proc,
data_ptr as LPVOID,
fn get_crash_reports_dir(application_data: &ApplicationData) -> Result<PathBuf, ()> {
let mut psz_path: PWSTR = null_mut();
unsafe {
let res = SHGetKnownFolderPath(
&FOLDERID_RoamingAppData as *const _,
0,
null_mut(),
)
};
&mut psz_path as *mut _,
);
if thread == null_mut() {
return Err(());
if res == S_OK {
let mut len = 0;
while psz_path.offset(len).read() != 0 {
len += 1;
}
let str = OsString::from_wide(from_raw_parts(psz_path, len as usize));
CoTaskMemFree(psz_path as _);
let mut path = PathBuf::from(str);
if let Some(vendor) = &application_data.vendor {
path.push(vendor);
}
path.push(&application_data.name);
path.push("Crash Reports");
Ok(path)
} else {
Err(())
}
}
}
// Don't wait forever as we want the process to get killed eventually
let res = unsafe { WaitForSingleObject(thread, 5000) };
if res != WAIT_OBJECT_0 {
return Err(());
fn get_application_path(process: HANDLE) -> Result<PathBuf, ()> {
let mut path: [u16; MAX_PATH + 1] = [0; MAX_PATH + 1];
unsafe {
let res = K32GetModuleFileNameExW(
process,
null_mut(),
(&mut path).as_mut_ptr(),
(MAX_PATH + 1) as u32,
);
if res == 0 {
return Err(());
}
let application_path = PathBuf::from(OsString::from_wide(&path[0..res as usize]));
Ok(application_path)
}
}
let res = unsafe { CloseHandle(thread) };
bool_ok_or_err(res, ())
fn get_release_channel(install_path: &Path) -> Result<String, ()> {
let channel_prefs =
File::open(install_path.join("defaults/pref/channel-prefs.js")).map_err(|_e| ())?;
let lines = BufReader::new(channel_prefs).lines();
let line = lines
.filter_map(Result::ok)
.find(|line| line.contains("app.update.channel"))
.ok_or(())?;
line.split("\"").nth(3).map(|s| s.to_string()).ok_or(())
}
fn get_install_time(crash_reports_path: &Path, build_id: &str) -> Result<String, ()> {
let file_name = "InstallTime".to_owned() + build_id;
let file_path = crash_reports_path.join(file_name);
read_to_string(file_path).map_err(|_e| ())
}
fn get_startup_time(process: HANDLE) -> Result<u64, ()> {
@ -289,46 +219,14 @@ fn get_startup_time(process: HANDLE) -> Result<u64, ()> {
Ok((start_time_in_ticks / windows_tick) - sec_to_unix_epoch)
}
fn get_oom_allocation_size(
process: HANDLE,
wer_data: &InProcessWindowsErrorReportingData,
) -> usize {
read_from_process(process, wer_data.oom_allocation_size_ptr).unwrap_or(0)
}
fn parse_child_data(command_line: &str) -> Result<(DWORD, *mut WindowsErrorReportingData), ()> {
let mut itr = command_line.rsplit(' ');
let address = itr.nth(1).ok_or(())?;
let address = usize::from_str_radix(address, 16).map_err(|_err| (()))?;
let address = address as *mut WindowsErrorReportingData;
let parent_pid = itr.nth(2).ok_or(())?;
let parent_pid = u32::from_str_radix(parent_pid, 10).map_err(|_err| (()))?;
Ok((parent_pid, address))
}
fn get_process_id(process: HANDLE) -> Result<DWORD, ()> {
match unsafe { GetProcessId(process) } {
0 => Err(()),
pid => Ok(pid),
}
}
fn get_process_handle(pid: DWORD) -> Result<HANDLE, ()> {
let handle = unsafe { OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid) };
if handle != null_mut() {
Ok(handle)
} else {
Err(())
}
}
fn launch_crash_reporter_client(
install_path: &Path,
application_path: &Path,
environment: &mut Vec<u16>,
crash_report: &CrashReport,
) {
// Prepare the command line
let mut install_path: PathBuf = application_path.into();
install_path.pop();
let client_path = install_path.join("crashreporter.exe");
let mut cmd_line = OsString::from("\"");
@ -413,189 +311,80 @@ impl ApplicationData {
#[derive(Serialize)]
#[allow(non_snake_case)]
struct Annotations {
BuildID: String,
struct Annotations<'a> {
BuildID: &'a str,
CrashTime: String,
InstallTime: String,
#[serde(skip_serializing_if = "Option::is_none")]
OOMAllocationSize: Option<String>,
ProductID: String,
ProductName: String,
ReleaseChannel: String,
ServerURL: String,
InstallTime: &'a str,
ProductID: &'a str,
ProductName: &'a str,
ReleaseChannel: &'a str,
ServerURL: &'a str,
StartupTime: String,
UptimeTS: String,
#[serde(skip_serializing_if = "Option::is_none")]
Vendor: Option<String>,
Version: String,
WindowsErrorReporting: String,
Vendor: Option<&'a str>,
Version: &'a str,
}
impl Annotations {
fn from_application_data(
application_data: &ApplicationData,
release_channel: String,
install_time: String,
impl Annotations<'_> {
fn from_application_data<'a>(
application_data: &'a ApplicationData,
release_channel: &'a str,
install_time: &'a str,
crash_time: u64,
startup_time: u64,
oom_allocation_size: usize,
) -> Annotations {
let oom_allocation_size = if oom_allocation_size != 0 {
Some(oom_allocation_size.to_string())
} else {
None
};
) -> Annotations<'a> {
Annotations {
BuildID: application_data.build_id.clone(),
BuildID: &application_data.build_id,
CrashTime: crash_time.to_string(),
InstallTime: install_time,
OOMAllocationSize: oom_allocation_size,
ProductID: application_data.product_id.clone(),
ProductName: application_data.name.clone(),
ProductID: &application_data.product_id,
ProductName: &application_data.name,
ReleaseChannel: release_channel,
ServerURL: application_data.server_url.clone(),
ServerURL: &application_data.server_url,
StartupTime: startup_time.to_string(),
UptimeTS: (crash_time - startup_time).to_string() + ".0",
Vendor: application_data.vendor.clone(),
Version: application_data.version.clone(),
WindowsErrorReporting: "1".to_string(),
Vendor: application_data.vendor.as_deref(),
Version: &application_data.version,
}
}
}
/// Encapsulates the information about the application that crashed. This includes the install path as well as version information
struct ApplicationInformation {
install_path: PathBuf,
application_data: ApplicationData,
release_channel: String,
crash_reports_dir: PathBuf,
install_time: String,
}
impl ApplicationInformation {
fn from_process(process: HANDLE) -> Result<ApplicationInformation, ()> {
let mut install_path = ApplicationInformation::get_application_path(process)?;
install_path.pop();
let application_data = ApplicationData::load_from_disk(install_path.as_ref())?;
let release_channel = ApplicationInformation::get_release_channel(install_path.as_ref())?;
let crash_reports_dir = ApplicationInformation::get_crash_reports_dir(&application_data)?;
let install_time = ApplicationInformation::get_install_time(
&crash_reports_dir,
&application_data.build_id,
)?;
Ok(ApplicationInformation {
install_path,
application_data,
release_channel,
crash_reports_dir,
install_time,
})
}
fn get_application_path(process: HANDLE) -> Result<PathBuf, ()> {
let mut path: [u16; MAX_PATH + 1] = [0; MAX_PATH + 1];
unsafe {
let res = K32GetModuleFileNameExW(
process,
null_mut(),
(&mut path).as_mut_ptr(),
(MAX_PATH + 1) as DWORD,
);
if res == 0 {
return Err(());
}
let application_path = PathBuf::from(OsString::from_wide(&path[0..res as usize]));
Ok(application_path)
}
}
fn get_release_channel(install_path: &Path) -> Result<String, ()> {
let channel_prefs =
File::open(install_path.join("defaults/pref/channel-prefs.js")).map_err(|_e| ())?;
let lines = BufReader::new(channel_prefs).lines();
let line = lines
.filter_map(Result::ok)
.find(|line| line.contains("app.update.channel"))
.ok_or(())?;
line.split("\"").nth(3).map(|s| s.to_string()).ok_or(())
}
fn get_crash_reports_dir(application_data: &ApplicationData) -> Result<PathBuf, ()> {
let mut psz_path: PWSTR = null_mut();
unsafe {
let res = SHGetKnownFolderPath(
&FOLDERID_RoamingAppData as *const _,
0,
null_mut(),
&mut psz_path as *mut _,
);
if res == S_OK {
let mut len = 0;
while psz_path.offset(len).read() != 0 {
len += 1;
}
let str = OsString::from_wide(from_raw_parts(psz_path, len as usize));
CoTaskMemFree(psz_path as _);
let mut path = PathBuf::from(str);
if let Some(vendor) = &application_data.vendor {
path.push(vendor);
}
path.push(&application_data.name);
path.push("Crash Reports");
Ok(path)
} else {
Err(())
}
}
}
fn get_install_time(crash_reports_path: &Path, build_id: &str) -> Result<String, ()> {
let file_name = "InstallTime".to_owned() + build_id;
let file_path = crash_reports_path.join(file_name);
read_to_string(file_path).map_err(|_e| ())
}
}
struct CrashReport {
struct CrashReport<'a> {
uuid: String,
crash_reports_path: PathBuf,
release_channel: String,
annotations: Annotations,
release_channel: &'a str,
annotations: Annotations<'a>,
crash_time: u64,
oom_allocation_size: usize,
}
impl CrashReport {
fn new(
application_information: &ApplicationInformation,
impl CrashReport<'_> {
fn new<'a>(
crash_reports_path: &Path,
release_channel: &'a str,
application_data: &'a ApplicationData,
install_time: &'a str,
startup_time: u64,
oom_allocation_size: usize,
) -> CrashReport {
) -> CrashReport<'a> {
let uuid = Uuid::new_v4()
.to_hyphenated()
.encode_lower(&mut Uuid::encode_buffer())
.to_owned();
let crash_reports_path = application_information.crash_reports_dir.clone();
let crash_reports_path = PathBuf::from(crash_reports_path);
let crash_time: u64 = unsafe { time(null_mut()) as u64 };
let annotations = Annotations::from_application_data(
&application_information.application_data,
application_information.release_channel.clone(),
application_information.install_time.clone(),
application_data,
release_channel,
install_time,
crash_time,
startup_time,
oom_allocation_size,
);
CrashReport {
uuid,
crash_reports_path,
release_channel: application_information.release_channel.clone(),
release_channel,
annotations,
crash_time,
oom_allocation_size,
}
}
@ -633,11 +422,6 @@ impl CrashReport {
self.get_pending_path().join(self.uuid.to_string() + ".dmp")
}
fn get_minidump_name(&self) -> [u8; 40] {
let bytes = (self.uuid.to_string() + ".dmp").into_bytes();
bytes[0..40].try_into().unwrap()
}
fn get_extra_file_path(&self) -> PathBuf {
self.get_pending_path()
.join(self.uuid.to_string() + ".extra")
@ -669,7 +453,7 @@ impl CrashReport {
let res = MiniDumpWriteDump(
(*exception_information).hProcess,
get_process_id((*exception_information).hProcess)?,
GetProcessId((*exception_information).hProcess),
minidump_file.as_raw_handle() as _,
minidump_type,
&mut exception,
@ -677,7 +461,10 @@ impl CrashReport {
/* callback */ null(),
);
bool_ok_or_err(res, ())
match res {
FALSE => Err(()),
_ => Ok(()),
}
}
}
@ -720,35 +507,7 @@ fn is_windows8_or_later() -> bool {
}
}
fn bool_ok_or_err<T>(res: BOOL, data: T) -> Result<T, ()> {
match res {
FALSE => Err(()),
_ => Ok(data),
}
}
fn read_environment_block(process: HANDLE) -> Result<Vec<u16>, ()> {
let upp = read_user_process_parameters(process)?;
// Read the environment
let buffer = upp.Environment;
let length = upp.EnvironmentSize;
let count = length as usize / 2;
read_array_from_process::<u16>(process, buffer, count)
}
fn read_command_line(process: HANDLE) -> Result<String, ()> {
let upp = read_user_process_parameters(process)?;
// Read the command-line
let buffer = upp.CommandLine.Buffer;
let length = upp.CommandLine.Length;
let count = (length as usize) / 2;
let command_line = read_array_from_process::<u16>(process, buffer as *mut _, count)?;
String::from_utf16(&command_line).map_err(|_err| ())
}
fn read_user_process_parameters(process: HANDLE) -> Result<RTL_USER_PROCESS_PARAMETERS, ()> {
let mut pbi: PROCESS_BASIC_INFORMATION = unsafe { zeroed() };
let mut length: ULONG = 0;
let result = unsafe {
@ -766,10 +525,59 @@ fn read_user_process_parameters(process: HANDLE) -> Result<RTL_USER_PROCESS_PARA
}
// Read the process environment block
let peb: PEB = read_from_process(process, pbi.PebBaseAddress)?;
let mut peb: PEB = unsafe { zeroed() };
let mut num_bytes: SIZE_T = 0;
let result = unsafe {
ReadProcessMemory(
process,
pbi.PebBaseAddress as *mut _,
&mut peb as *mut _ as _,
size_of::<PEB>(),
&mut num_bytes,
)
};
if result == 0 {
return Err(());
}
// Read the user process parameters
read_from_process::<RTL_USER_PROCESS_PARAMETERS>(process, peb.ProcessParameters)
let mut upp: RTL_USER_PROCESS_PARAMETERS = unsafe { zeroed() };
let result = unsafe {
ReadProcessMemory(
process,
peb.ProcessParameters as *mut _,
&mut upp as *mut _ as _,
size_of::<RTL_USER_PROCESS_PARAMETERS>(),
&mut num_bytes,
)
};
if result == 0 {
return Err(());
}
// Read the environment
let buffer = upp.Environment;
let length = upp.EnvironmentSize;
let mut environment: Vec<u16> = vec![Default::default(); ((length / 2) + 1) as _];
let result = unsafe {
ReadProcessMemory(
process,
buffer,
environment.as_mut_ptr() as _,
length as _,
&mut num_bytes,
)
};
if result == 0 {
Err(())
} else {
Ok(environment)
}
}
/******************************************************************************

Просмотреть файл

@ -209,8 +209,7 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) {
#endif // !defined(XP_WIN) && !defined(XP_MACOSX)
bool SetRemoteExceptionHandler(const char* aCrashPipe,
FileHandle aCrashTimeAnnotationFile,
ProcessId aParentPid) {
uintptr_t aCrashTimeAnnotationFile) {
return false;
}
@ -247,9 +246,9 @@ bool CreateAdditionalChildMinidump(ProcessHandle childPid,
bool UnsetRemoteExceptionHandler() { return false; }
#if defined(MOZ_WIDGET_ANDROID)
void SetNotificationPipeForChild(FileHandle childCrashFd) {}
void SetNotificationPipeForChild(int childCrashFd) {}
void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd) {}
void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd) {}
void AddLibraryMapping(const char* library_name, uintptr_t start_address,
size_t mapping_length, size_t file_offset) {}

Просмотреть файл

@ -1927,13 +1927,6 @@ static void TeardownAnnotationFacilities() {
#ifdef XP_WIN
struct InProcessWindowsErrorReportingData {
uint32_t mProcessType;
size_t* mOOMAllocationSizePtr;
};
static InProcessWindowsErrorReportingData gInProcessWerData = {};
bool GetRuntimeExceptionModulePath(wchar_t* aPath, const size_t aLength) {
const wchar_t* kModuleName = L"mozwer.dll";
DWORD res = GetModuleFileName(nullptr, aPath, aLength);
@ -1952,22 +1945,27 @@ bool GetRuntimeExceptionModulePath(wchar_t* aPath, const size_t aLength) {
#endif // XP_WIN
static void RegisterRuntimeExceptionModule(
GeckoProcessType aProcessType =
GeckoProcessType::GeckoProcessType_Default) {
void RegisterRuntimeExceptionModule(void) {
#ifdef XP_WIN
gInProcessWerData.mProcessType = aProcessType;
gInProcessWerData.mOOMAllocationSizePtr = &gOOMAllocationSize;
const size_t kPathLength = MAX_PATH + 1;
wchar_t path[kPathLength] = {};
if (GetRuntimeExceptionModulePath(path, kPathLength)) {
Unused << WerRegisterRuntimeExceptionModule(path, &gInProcessWerData);
Unused << WerRegisterRuntimeExceptionModule(path, nullptr);
}
DWORD dwFlags = 0;
if (WerGetFlags(GetCurrentProcess(), &dwFlags) == S_OK) {
Unused << WerSetFlags(dwFlags |
WER_FAULT_REPORTING_DISABLE_SNAPSHOT_HANG);
}
DWORD dwFlags = 0;
if (WerGetFlags(GetCurrentProcess(), &dwFlags) == S_OK) {
Unused << WerSetFlags(dwFlags | WER_FAULT_REPORTING_DISABLE_SNAPSHOT_HANG);
}
#endif // XP_WIN
}
void UnregisterRuntimeExceptionModule(void) {
#ifdef XP_WIN
const size_t kPathLength = MAX_PATH + 1;
wchar_t path[kPathLength] = {};
if (GetRuntimeExceptionModulePath(path, kPathLength)) {
Unused << WerUnregisterRuntimeExceptionModule(path, nullptr);
}
#endif // XP_WIN
}
@ -3527,13 +3525,13 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) {
#endif // defined(XP_LINUX)
bool SetRemoteExceptionHandler(const char* aCrashPipe,
FileHandle aCrashTimeAnnotationFile) {
uintptr_t aCrashTimeAnnotationFile) {
MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
RegisterRuntimeExceptionModule(XRE_GetProcessType());
InitializeAnnotationFacilities();
#if defined(XP_WIN)
gChildCrashAnnotationReportFd = aCrashTimeAnnotationFile;
gChildCrashAnnotationReportFd = (FileHandle)aCrashTimeAnnotationFile;
gExceptionHandler = new google_breakpad::ExceptionHandler(
L"", ChildFilter, ChildMinidumpCallback,
nullptr, // no callback context
@ -3631,55 +3629,6 @@ bool FinalizeOrphanedMinidump(uint32_t aChildPid, GeckoProcessType aType,
return WriteExtraFile(id, annotations);
}
#ifdef XP_WIN
// Function invoked by the WER runtime exception handler running in an
// external process. This function isn't used anywhere inside Gecko directly
// but rather invoked via CreateRemoteThread() in the main process.
DWORD WINAPI WerNotifyProc(LPVOID aParameter) {
const WindowsErrorReportingData* werData =
static_cast<const WindowsErrorReportingData*>(aParameter);
// Hold the mutex until the current dump request is complete, to
// prevent UnsetExceptionHandler() from pulling the rug out from
// under us.
MutexAutoLock safetyLock(*dumpSafetyLock);
if (!isSafeToDump || !ShouldReport()) {
return S_OK;
}
ProcessId pid = werData->mChildPid;
nsCOMPtr<nsIFile> minidump;
if (!GetPendingDir(getter_AddRefs(minidump))) {
return S_OK;
}
xpstring minidump_native_name(werData->mMinidumpFile,
werData->mMinidumpFile + 40);
nsString minidump_name(minidump_native_name.c_str());
minidump->Append(minidump_name);
{
MutexAutoLock lock(*dumpMapLock);
ChildProcessData* pd = pidToMinidump->PutEntry(pid);
MOZ_ASSERT(!pd->minidump);
pd->minidump = minidump;
pd->sequence = ++crashSequence;
pd->annotations = MakeUnique<AnnotationTable>();
(*pd->annotations)[Annotation::WindowsErrorReporting] = "1"_ns;
if (werData->mOOMAllocationSize > 0) {
char buffer[32] = {};
XP_STOA(werData->mOOMAllocationSize, buffer);
(*pd->annotations)[Annotation::OOMAllocationSize] = buffer;
}
PopulateContentProcessAnnotations(*(pd->annotations));
}
return S_OK;
}
#endif // XP_WIN
//-----------------------------------------------------------------------------
// CreateMinidumpsAndPair() and helpers
//

Просмотреть файл

@ -165,22 +165,6 @@ nsresult SetSubmitReports(bool aSubmitReport);
// Out-of-process crash reporter API.
#ifdef XP_WIN
// This data is stored in the parent process, there is one copy for each child
// process. The mChildPid and mMinidumpFile fields are filled by the WER runtime
// exception module when the associated child process crashes.
struct WindowsErrorReportingData {
// Points to the WerNotifyProc function.
LPTHREAD_START_ROUTINE mWerNotifyProc;
// PID of the child process that crashed.
DWORD mChildPid;
// Filename of the generated minidump; this is not a 0-terminated string
char mMinidumpFile[40];
// OOM allocation size for the crash (ignore if zero)
size_t mOOMAllocationSize;
};
#endif // XP_WIN
// Initializes out-of-process crash reporting. This method must be called
// before the platform-specific notification pipe APIs are called. If called
// from off the main thread, this method will synchronously proxy to the main
@ -316,7 +300,7 @@ void UnregisterInjectorCallback(DWORD processID);
// and the magic fd number it should be remapped to
// (|childCrashRemapFd|) before exec() in the child process.
// |SetRemoteExceptionHandler()| in the child process expects to find
// the server at |childCrashRemapFd|. Return true if successful.
// the server at |childCrashRemapFd|. Return true iff successful.
//
// If crash reporting is disabled, both outparams will be set to -1
// and |true| will be returned.
@ -324,22 +308,16 @@ bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
#endif // XP_WIN
// Windows Error Reporting helper
#if defined(XP_WIN)
DWORD WINAPI WerNotifyProc(LPVOID aParameter);
#endif
// Child-side API
bool SetRemoteExceptionHandler(
const char* aCrashPipe = nullptr,
FileHandle aCrashTimeAnnotationFile = kInvalidFileHandle);
bool SetRemoteExceptionHandler(const char* aCrashPipe = nullptr,
uintptr_t aCrashTimeAnnotationFile = 0);
bool UnsetRemoteExceptionHandler();
#if defined(MOZ_WIDGET_ANDROID)
// Android creates child process as services so we must explicitly set
// the handle for the pipe since it can't get remapped to a default value.
void SetNotificationPipeForChild(FileHandle childCrashFd);
void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd);
void SetNotificationPipeForChild(int childCrashFd);
void SetCrashAnnotationPipeForChild(int childCrashAnnotationFd);
#endif
// Annotates the crash report with the name of the calling thread.

Просмотреть файл

@ -506,27 +506,28 @@ nsresult XRE_InitChildProcess(int aArgc, char* aArgv[],
bool exceptionHandlerIsSet = false;
if (!CrashReporter::IsDummy()) {
CrashReporter::FileHandle crashTimeAnnotationFile =
CrashReporter::kInvalidFileHandle;
#if defined(XP_WIN)
if (aArgc < 1) {
return NS_ERROR_FAILURE;
}
// Pop the first argument, this is used by the WER runtime exception module
// which reads it from the command-line so we can just discard it here.
--aArgc;
const char* const crashTimeAnnotationArg = aArgv[--aArgc];
crashTimeAnnotationFile = reinterpret_cast<CrashReporter::FileHandle>(
std::stoul(std::string(crashTimeAnnotationArg)));
uintptr_t crashTimeAnnotationFile =
static_cast<uintptr_t>(std::stoul(std::string(crashTimeAnnotationArg)));
#endif
if (aArgc < 1) return NS_ERROR_FAILURE;
const char* const crashReporterArg = aArgv[--aArgc];
if (IsCrashReporterEnabled(crashReporterArg)) {
#if defined(XP_MACOSX)
exceptionHandlerIsSet =
CrashReporter::SetRemoteExceptionHandler(crashReporterArg);
#elif defined(XP_WIN)
exceptionHandlerIsSet = CrashReporter::SetRemoteExceptionHandler(
crashReporterArg, crashTimeAnnotationFile);
#else
exceptionHandlerIsSet = CrashReporter::SetRemoteExceptionHandler();
#endif
if (!exceptionHandlerIsSet) {
// Bug 684322 will add better visibility into this condition