Skip to content

Commit

Permalink
fix: handle potentially unaligned frame pointer (#217)
Browse files Browse the repository at this point in the history
Signed-off-by: Gen Xu <xgbarry@gmail.com>
  • Loading branch information
gen-xu authored Jul 25, 2023
1 parent 13de063 commit 71957e2
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 2 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed
- Handle potentially unaligned frame pointer (#217)

## [0.12.0] - 2023-07-03

### Added
Expand Down
48 changes: 46 additions & 2 deletions src/backtrace/frame_pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@ impl super::Frame for Frame {
}
}

/// helper to read a pointer from a potentially unaligned address
///
/// # Safety
///
/// Same as [`std::ptr::read_unaligned`]
#[inline]
unsafe fn read_ptr<T>(ptr: *const T) -> T {
if ptr.align_offset(std::mem::align_of::<T>()) == 0 {
std::ptr::read(ptr)
} else {
std::ptr::read_unaligned(ptr)
}
}

pub struct Trace {}
impl super::Trace for Trace {
type Frame = Frame;
Expand Down Expand Up @@ -104,13 +118,13 @@ impl super::Trace for Trace {

// iterate to the next frame
let frame = Frame {
ip: unsafe { (*frame_pointer).ret },
ip: unsafe { read_ptr(frame_pointer).ret },
};

if !cb(&frame) {
break;
}
frame_pointer = unsafe { (*frame_pointer).frame_pointer };
frame_pointer = unsafe { read_ptr(frame_pointer).frame_pointer };
}
}
}
Expand All @@ -120,3 +134,33 @@ struct FramePointerLayout {
frame_pointer: *mut FramePointerLayout,
ret: usize,
}

#[cfg(test)]
mod tests {
use super::*;

#[repr(C, align(64))]
struct AlignToSixtyFour([u8; 64]);

impl Default for AlignToSixtyFour {
fn default() -> Self {
AlignToSixtyFour([0; 64])
}
}

#[test]
fn test_read_ptr_aligned() {
let x = AlignToSixtyFour::default();
let ptr = &x.0[0] as *const u8;
assert_eq!(unsafe { read_ptr(ptr) }, x.0[0]);
}

#[test]
fn test_read_ptr_unaligned() {
let mut x = AlignToSixtyFour::default();
let expected = usize::MAX / 2;
x.0[1..9].copy_from_slice(&expected.to_ne_bytes()[..]);
let ptr: *const usize = unsafe { std::mem::transmute(&x.0[1] as *const u8) };
assert_eq!(unsafe { read_ptr(ptr) }, expected);
}
}

0 comments on commit 71957e2

Please sign in to comment.