Commit fe403f1e authored by Gabriele Svelto's avatar Gabriele Svelto Committed by Pier Angelo Vendrame
Browse files

Bug 2050534 - Use only types that have the same C & Rust representation in the...

Bug 2050534 - Use only types that have the same C & Rust representation in the crash annotations  a=RyanVM,pascalc

Differential Revision: https://phabricator.services.mozilla.com/D311897
parent 304cb690
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -238,7 +238,7 @@ macro_rules! read_numeric_annotation {

fn write_phc_annotations(file: &mut File, buff: &[u8]) -> Result<()> {
    let addr_info = phc::AddrInfo::from_bytes(buff)?;
    if addr_info.kind == phc::Kind::Unknown {
    if addr_info.kind == phc::PHC_KIND_UNKNOWN {
        return Ok(());
    }

+23 −18
Original line number Diff line number Diff line
@@ -11,15 +11,21 @@ use std::{
    slice,
};

#[repr(C)]
#[derive(Clone, Copy, PartialEq)]
#[allow(dead_code)]
pub(crate) enum Kind {
    Unknown = 0,
    NeverAllocatedPage = 1,
    InUsePage = 2,
    FreedPage = 3,
    GuardPage = 4,
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;
@@ -33,7 +39,7 @@ pub(crate) struct StackTrace {

#[repr(C)]
pub(crate) struct AddrInfo {
    pub(crate) kind: Kind,
    pub(crate) kind: u32,
    pub(crate) base_addr: *const c_void,
    pub(crate) usable_size: usize,
    pub(crate) alloc_stack: StackTrace,
@@ -74,18 +80,17 @@ impl AddrInfo {

    pub(crate) fn kind_as_str(&self) -> &'static str {
        match self.kind {
            Kind::Unknown => "Unknown(?!)",
            Kind::NeverAllocatedPage => "NeverAllocatedPage",
            Kind::InUsePage => "InUsePage(?!)",
            Kind::FreedPage => "FreedPage",
            Kind::GuardPage => "GuardPage",
            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 {
        let kind_value = self.kind as u32;

        if (kind_value > Kind::GuardPage as u32)
        if (!is_phc_kind(self.kind))
            || (self.alloc_stack.length > MAX_FRAMES)
            || (self.free_stack.length > MAX_FRAMES)
            || (self.alloc_stack.has_stack > 1)
+62 −40
Original line number Diff line number Diff line
@@ -13,35 +13,43 @@ use std::{
#[cfg(any(target_os = "linux", target_os = "android"))]
use std::arch::global_asm;

#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum AnnotationContents {
    Empty,
    NSCStringPointer,
    CStringPointer,
    CString,
    ByteBuffer(u32),
    OwnedByteBuffer(u32),
pub const ANNOTATION_CONTENTS_EMPTY: u32 = 0;
pub const ANNOTATION_CONTENTS_NSCSTRINGPOINTER: u32 = 1;
pub const ANNOTATION_CONTENTS_CSTRINGPOINTER: u32 = 2;
pub const ANNOTATION_CONTENTS_CSTRING: u32 = 3;
pub const ANNOTATION_CONTENTS_BYTEBUFFER: u32 = 4;
pub const ANNOTATION_CONTENTS_OWNEDBYTEBUFFER: u32 = 5;

pub fn is_annotation_contents(value: u32) -> bool {
    matches!(
        value,
        ANNOTATION_CONTENTS_EMPTY
            | ANNOTATION_CONTENTS_NSCSTRINGPOINTER
            | ANNOTATION_CONTENTS_CSTRINGPOINTER
            | ANNOTATION_CONTENTS_CSTRING
            | ANNOTATION_CONTENTS_BYTEBUFFER
            | ANNOTATION_CONTENTS_OWNEDBYTEBUFFER
    )
}

#[repr(C)]
pub struct Annotation {
    pub id: u32,
    pub contents: AnnotationContents,
    pub contents: u32,
    pub len: usize,
    pub address: usize,
}

impl Drop for Annotation {
    fn drop(&mut self) {
        match self.contents {
            AnnotationContents::OwnedByteBuffer(len) => {
                if (self.address != 0) && (len > 0) {
                    let align = min(usize::next_power_of_two(len as usize), 32);
            ANNOTATION_CONTENTS_OWNEDBYTEBUFFER if (self.address != 0) && (self.len > 0) => {
                let align = min(usize::next_power_of_two(self.len), 32);
                unsafe {
                        let layout = Layout::from_size_align_unchecked(len as usize, align);
                    let layout = Layout::from_size_align_unchecked(self.len, align);
                    alloc::dealloc(self.address as *mut u8, layout);
                }
            }
            }
            _ => {
                // Nothing to do
            }
@@ -251,12 +259,13 @@ pub struct MozAnnotationNote {
    pub ehdr: isize,
}

fn store_annotation<T>(id: u32, contents: AnnotationContents, address: *const T) -> *const T {
fn store_annotation<T>(id: u32, contents: u32, len: usize, address: *const T) -> *const T {
    debug_assert!(is_annotation_contents(contents));

    let address = match contents {
        AnnotationContents::OwnedByteBuffer(len) => {
        ANNOTATION_CONTENTS_OWNEDBYTEBUFFER => {
            if !address.is_null() && (len > 0) {
                // Copy the contents of this annotation, we'll own the copy
                let len = len as usize;
                let align = min(usize::next_power_of_two(len), 32);
                unsafe {
                    let layout = Layout::from_size_align_unchecked(len, align);
@@ -275,10 +284,9 @@ fn store_annotation<T>(id: u32, contents: AnnotationContents, address: *const T)
    let annotations = &mut MOZANNOTATIONS.lock().unwrap().data;
    let old = if let Some(existing) = annotations.iter_mut().find(|e| e.id == id) {
        let old = match existing.contents {
            AnnotationContents::OwnedByteBuffer(len) => {
            ANNOTATION_CONTENTS_OWNEDBYTEBUFFER => {
                // If we owned the previous value of this annotation we must free it.
                if (existing.address != 0) && (len > 0) {
                    let len = len as usize;
                    let align = min(usize::next_power_of_two(len), 32);
                    unsafe {
                        let layout = Layout::from_size_align_unchecked(len, align);
@@ -291,12 +299,14 @@ fn store_annotation<T>(id: u32, contents: AnnotationContents, address: *const T)
        };

        existing.contents = contents;
        existing.len = len;
        existing.address = address as usize;
        old
    } else {
        annotations.push(Annotation {
            id,
            contents,
            len,
            address: address as usize,
        });
        null_mut::<T>()
@@ -319,7 +329,12 @@ pub extern "C" fn mozannotation_register_nscstring(
    id: u32,
    address: *const nsCString,
) -> *const nsCString {
    store_annotation(id, AnnotationContents::NSCStringPointer, address)
    store_annotation(
        id,
        ANNOTATION_CONTENTS_NSCSTRINGPOINTER,
        /* len */ 0,
        address,
    )
}

/// Create a copy of the provided string with a specified size that will be
@@ -332,11 +347,7 @@ pub extern "C" fn mozannotation_record_nscstring_from_raw_parts(
    address: *const u8,
    size: usize,
) {
    store_annotation(
        id,
        AnnotationContents::OwnedByteBuffer(size as u32),
        address,
    );
    store_annotation(id, ANNOTATION_CONTENTS_OWNEDBYTEBUFFER, size, address);
}

/// Register a pointer to a pointer to a nul-terminated string.
@@ -349,7 +360,12 @@ pub extern "C" fn mozannotation_register_cstring_ptr(
    id: u32,
    address: *const *const c_char,
) -> *const *const c_char {
    store_annotation(id, AnnotationContents::CStringPointer, address)
    store_annotation(
        id,
        ANNOTATION_CONTENTS_CSTRINGPOINTER,
        /* len */ 0,
        address,
    )
}

/// Register a pointer to a nul-terminated string.
@@ -359,7 +375,7 @@ pub extern "C" fn mozannotation_register_cstring_ptr(
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_register_cstring(id: u32, address: *const c_char) -> *const c_char {
    store_annotation(id, AnnotationContents::CString, address)
    store_annotation(id, ANNOTATION_CONTENTS_CSTRING, /* len */ 0, address)
}

/// Create a copy of the provided nul-terminated string which will be owned by
@@ -373,7 +389,7 @@ pub extern "C" fn mozannotation_register_cstring(id: u32, address: *const c_char
#[no_mangle]
pub unsafe extern "C" fn mozannotation_record_cstring(id: u32, address: *const c_char) {
    let len = unsafe { CStr::from_ptr(address).to_bytes().len() };
    store_annotation(id, AnnotationContents::OwnedByteBuffer(len as u32), address);
    store_annotation(id, ANNOTATION_CONTENTS_OWNEDBYTEBUFFER, len, address);
}

/// Register a pointer to a fixed size buffer.
@@ -385,9 +401,9 @@ pub unsafe extern "C" fn mozannotation_record_cstring(id: u32, address: *const c
pub extern "C" fn mozannotation_register_bytebuffer(
    id: u32,
    address: *const c_void,
    size: u32,
    size: usize,
) -> *const c_void {
    store_annotation(id, AnnotationContents::ByteBuffer(size), address)
    store_annotation(id, ANNOTATION_CONTENTS_BYTEBUFFER, size, address)
}

/// Create a copy of the provided buffer which will be owned by the crate, and
@@ -395,8 +411,8 @@ pub extern "C" fn mozannotation_register_bytebuffer(
///
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_record_bytebuffer(id: u32, address: *const c_void, size: u32) {
    store_annotation(id, AnnotationContents::OwnedByteBuffer(size), address);
pub extern "C" fn mozannotation_record_bytebuffer(id: u32, address: *const c_void, size: usize) {
    store_annotation(id, ANNOTATION_CONTENTS_OWNEDBYTEBUFFER, size, address);
}

/// Unregister a crash annotation. Returns the previously registered pointer or
@@ -406,7 +422,7 @@ pub extern "C" fn mozannotation_record_bytebuffer(id: u32, address: *const c_voi
/// This function will be exposed to C++
#[no_mangle]
pub extern "C" fn mozannotation_unregister(id: u32) -> *const c_void {
    store_annotation(id, AnnotationContents::Empty, null_mut())
    store_annotation(id, ANNOTATION_CONTENTS_EMPTY, /* len */ 0, null_mut())
}

/// Returns the raw address of an annotation if it has been registered or NULL
@@ -416,19 +432,25 @@ pub extern "C" fn mozannotation_unregister(id: u32) -> *const c_void {
///
/// # Safety
///
/// `contents` must point to an object of type [`AnnotationContents`]
/// `contents` must point to a u32-sized integer, and `len` to a usize-sized
/// integer.
#[no_mangle]
pub unsafe extern "C" fn mozannotation_get_contents(
    id: u32,
    contents: *mut AnnotationContents,
    contents: *mut u32,
    len: *mut usize,
) -> usize {
    let annotations = &MOZANNOTATIONS.lock().unwrap().data;
    if let Some(annotation) = annotations.iter().find(|e| e.id == id) {
        if annotation.contents == AnnotationContents::Empty {
        if annotation.contents == ANNOTATION_CONTENTS_EMPTY {
            return 0;
        }

        unsafe { *contents = annotation.contents };
        unsafe {
            *contents = annotation.contents;
            *len = annotation.len;
        }

        return annotation.address;
    }

+2 −0
Original line number Diff line number Diff line
@@ -14,4 +14,6 @@ pub enum AnnotationsRetrievalError {
    InvalidData,
    #[error("Could not execute operation on the target process")]
    ProcessReaderError(#[from] process_reader::error::ProcessReaderError),
    #[error("Could not read memory from the target process")]
    ReadError(#[from] process_reader::error::ReadError),
}
+22 −13
Original line number Diff line number Diff line
@@ -12,7 +12,11 @@ use process_reader::ProcessReader;

#[cfg(any(target_os = "windows", target_os = "macos"))]
use mozannotation_client::ANNOTATION_SECTION;
use mozannotation_client::{Annotation, AnnotationContents, AnnotationMutex};
use mozannotation_client::{
    Annotation, AnnotationMutex, ANNOTATION_CONTENTS_BYTEBUFFER, ANNOTATION_CONTENTS_CSTRING,
    ANNOTATION_CONTENTS_CSTRINGPOINTER, ANNOTATION_CONTENTS_EMPTY,
    ANNOTATION_CONTENTS_NSCSTRINGPOINTER, ANNOTATION_CONTENTS_OWNEDBYTEBUFFER,
};
#[cfg(any(target_os = "linux", target_os = "android"))]
use mozannotation_client::{MozAnnotationNote, ANNOTATION_NOTE_NAME, ANNOTATION_TYPE};
use std::cmp::min;
@@ -110,7 +114,7 @@ fn find_annotations(reader: &ProcessReader) -> Result<usize, AnnotationsRetrieva
fn read_annotation(
    reader: &ProcessReader,
    address: usize,
) -> Result<CAnnotation, process_reader::error::ReadError> {
) -> Result<CAnnotation, AnnotationsRetrievalError> {
    let raw_annotation = ManuallyDrop::new(reader.copy_object::<Annotation>(address)?);
    let mut annotation = CAnnotation {
        id: raw_annotation.id,
@@ -122,23 +126,28 @@ fn read_annotation(
    }

    match raw_annotation.contents {
        AnnotationContents::Empty => {}
        AnnotationContents::NSCStringPointer => {
        ANNOTATION_CONTENTS_EMPTY => {}
        ANNOTATION_CONTENTS_NSCSTRINGPOINTER => {
            let string = copy_nscstring(reader, raw_annotation.address)?;
            annotation.data = AnnotationData::String(string);
        }
        AnnotationContents::CStringPointer => {
        ANNOTATION_CONTENTS_CSTRINGPOINTER => {
            let string = copy_null_terminated_string_pointer(reader, raw_annotation.address)?;
            annotation.data = AnnotationData::String(string);
        }
        AnnotationContents::CString => {
            annotation.data =
                AnnotationData::String(reader.copy_null_terminated_string(raw_annotation.address)?);
        ANNOTATION_CONTENTS_CSTRING => {
            let string = reader.copy_null_terminated_string(raw_annotation.address)?;
            if !string.is_empty() {
                annotation.data = AnnotationData::String(string);
            }
        }
        AnnotationContents::ByteBuffer(size) | AnnotationContents::OwnedByteBuffer(size) => {
            let buffer = copy_bytebuffer(reader, raw_annotation.address, size)?;
        ANNOTATION_CONTENTS_BYTEBUFFER | ANNOTATION_CONTENTS_OWNEDBYTEBUFFER => {
            if raw_annotation.len > 0 {
                let buffer = copy_bytebuffer(reader, raw_annotation.address, raw_annotation.len)?;
                annotation.data = AnnotationData::ByteBuffer(buffer);
            }
        }
        _ => return Err(AnnotationsRetrievalError::InvalidData),
    };

    Ok(annotation)
@@ -183,7 +192,7 @@ fn copy_nscstring(
fn copy_bytebuffer(
    reader: &ProcessReader,
    address: usize,
    size: u32,
    size: usize,
) -> Result<Vec<u8>, process_reader::error::ReadError> {
    reader.copy_array::<u8>(address, size as _)
    reader.copy_array::<u8>(address, size)
}
Loading