Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unaligned pointer passed to slice::from_raw_parts_mut #4850

Open
shinmao opened this issue Apr 21, 2024 · 1 comment
Open

Unaligned pointer passed to slice::from_raw_parts_mut #4850

shinmao opened this issue Apr 21, 2024 · 1 comment

Comments

@shinmao
Copy link

shinmao commented Apr 21, 2024

Unsoundness

Hi, we considered that flip_bitmap_x and flip_bitmap_y break the alignment requirements of unsafe function slice::from_raw_parts_mut with unaligned raw pointer.

fn flip_bitmap_x(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for row in pixels.chunks_mut(width) {
row.reverse();

fn flip_bitmap_y(bitmap: &mut [u8], width: usize, height: usize) {
assert!(bitmap.len() == width * height * 4);
let pixels = unsafe { slice::from_raw_parts_mut(bitmap.as_mut_ptr() as *mut u32, width * height) };
for y in 0 .. height / 2 {
let low_row = y * width;
let high_row = (height - 1 - y) * width;
for x in 0 .. width {
pixels.swap(low_row + x, high_row + x);

Since both of the functions are private, we also checked whether the callers of functions passed the type aligned to 4 bytes actually in the library. We found that in the function rasterize_glyph

if font.flags.contains(FontInstanceFlags::FLIP_X) {
flip_bitmap_x(&mut final_buffer, actual_width, actual_height);
left = -(left + actual_width as i32);
}
if font.flags.contains(FontInstanceFlags::FLIP_Y) {
flip_bitmap_y(&mut final_buffer, actual_width, actual_height);
top = -(top - actual_height as i32);

final_buffer is created from u8 slice in line 948, which is aligned to 1 byte. Therefore, we are sure that final_buffer is cast to 4 bytes and creates an unaligned pointer.

When the slice is created from unaligned raw pointer, the undefined behavior could lead to inconsistent results in different systems and architectures, which will change the pixels values here. Considering use ptr::copy_non_overlapping to create a new type aligned to 4 bytes before passing into from_raw_parts would be more safe.

@mrobinson
Copy link
Member

Hi! Thanks for reporting this issue. Do you mind reporting it at https://bugzilla.mozilla.org. This repository is just a downstream mirror of the WebRender with some patches applied for Servo. Almost all work on WebRender is happening upstream in the Gecko repository. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants