Source code

Revision control

Copy as Markdown

Other Tools

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// The types here must match the ones in memory/build/PHC.h
use anyhow::{bail, Result};
use std::{
ffi::{c_char, c_void},
mem::{size_of, MaybeUninit},
slice,
};
pub(crate) const PHC_KIND_UNKNOWN: u32 = 0;
pub(crate) const PHC_KIND_NEVER_ALLOCATED_PAGE: u32 = 1;
pub(crate) const PHC_KIND_IN_USE_PAGE: u32 = 2;
pub(crate) const PHC_KIND_FREED_PAGE: u32 = 3;
pub(crate) const PHC_KIND_GUARD_PAGE: u32 = 4;
pub fn is_phc_kind(value: u32) -> bool {
matches!(
value,
PHC_KIND_UNKNOWN
| PHC_KIND_NEVER_ALLOCATED_PAGE
| PHC_KIND_IN_USE_PAGE
| PHC_KIND_FREED_PAGE
| PHC_KIND_GUARD_PAGE
)
}
const MAX_FRAMES: usize = 16;
#[repr(C)]
pub(crate) struct StackTrace {
pub(crate) length: usize,
pub(crate) pcs: [*const c_void; MAX_FRAMES],
pub(crate) has_stack: c_char,
}
#[repr(C)]
pub(crate) struct AddrInfo {
pub(crate) kind: u32,
pub(crate) base_addr: *const c_void,
pub(crate) usable_size: usize,
pub(crate) alloc_stack: StackTrace,
pub(crate) free_stack: StackTrace,
pub(crate) phc_was_locked: c_char,
}
impl AddrInfo {
pub(crate) fn from_bytes(buff: &[u8]) -> Result<AddrInfo> {
if buff.len() != size_of::<AddrInfo>() {
bail!(
"PHC AddrInfo structure size {} doesn't match expected size {}",
buff.len(),
size_of::<AddrInfo>()
);
}
let mut addr_info = MaybeUninit::<AddrInfo>::uninit();
// SAFETY: MaybeUninit<u8> is always valid, even for padding bytes
let uninit_addr_info = unsafe {
slice::from_raw_parts_mut(
addr_info.as_mut_ptr() as *mut MaybeUninit<u8>,
size_of::<AddrInfo>(),
)
};
for (index, &value) in buff.iter().enumerate() {
uninit_addr_info[index].write(value);
}
let addr_info = unsafe { addr_info.assume_init() };
if !addr_info.check_consistency() {
bail!("PHC AddrInfo structure is inconsistent");
}
Ok(addr_info)
}
pub(crate) fn kind_as_str(&self) -> &'static str {
match self.kind {
PHC_KIND_UNKNOWN => "Unknown(?!)",
PHC_KIND_NEVER_ALLOCATED_PAGE => "NeverAllocatedPage",
PHC_KIND_IN_USE_PAGE => "InUsePage(?!)",
PHC_KIND_FREED_PAGE => "FreedPage",
PHC_KIND_GUARD_PAGE => "GuardPage",
_ => "Invalid(?!)",
}
}
fn check_consistency(&self) -> bool {
if (!is_phc_kind(self.kind))
|| (self.alloc_stack.length > MAX_FRAMES)
|| (self.free_stack.length > MAX_FRAMES)
|| (self.alloc_stack.has_stack > 1)
|| (self.free_stack.has_stack > 1)
|| (self.phc_was_locked > 1)
{
return false;
}
true
}
}