Change `upb` crate source to not use std or alloc

PiperOrigin-RevId: 671865731
This commit is contained in:
Protobuf Team Bot 2024-09-06 13:04:52 -07:00 коммит произвёл Copybara-Service
Родитель e3f37a2eb0
Коммит b35d4bad3c
13 изменённых файлов: 94 добавлений и 101 удалений

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

@ -13,7 +13,6 @@ use crate::{
Proxied, ProxiedInMapValue, ProxiedInRepeated, Repeated, RepeatedMut, RepeatedView, View,
};
use core::fmt::Debug;
use std::alloc::Layout;
use std::mem::{size_of, ManuallyDrop, MaybeUninit};
use std::ptr::{self, NonNull};
use std::slice;
@ -133,21 +132,6 @@ impl<'msg> MutatorMessageRef<'msg> {
}
}
fn copy_bytes_in_arena<'msg>(arena: &'msg Arena, val: &'msg [u8]) -> &'msg [u8] {
// SAFETY: the alignment of `[u8]` is less than `UPB_MALLOC_ALIGN`.
let new_alloc = unsafe { arena.alloc(Layout::for_value(val)) };
debug_assert_eq!(new_alloc.len(), val.len());
let start: *mut u8 = new_alloc.as_mut_ptr().cast();
// SAFETY:
// - `new_alloc` is writeable for `val.len()` bytes.
// - After the copy, `new_alloc` is initialized for `val.len()` bytes.
unsafe {
val.as_ptr().copy_to_nonoverlapping(start, val.len());
&*(new_alloc as *mut _ as *mut [u8])
}
}
/// Kernel-specific owned `string` and `bytes` field type.
#[doc(hidden)]
pub struct InnerProtoString(OwnedArenaBox<[u8]>);
@ -167,7 +151,7 @@ impl InnerProtoString {
impl From<&[u8]> for InnerProtoString {
fn from(val: &[u8]) -> InnerProtoString {
let arena = Arena::new();
let in_arena_copy = arena.copy_slice_in(val);
let in_arena_copy = arena.copy_slice_in(val).unwrap();
// SAFETY:
// - `in_arena_copy` is valid slice that will live for `arena`'s lifetime and
// this is the only reference in the program to it.
@ -354,7 +338,7 @@ macro_rules! impl_repeated_bytes {
len
);
for (src_ptr, dest_ptr) in src_ptrs.iter().zip(dest_ptrs) {
*dest_ptr = copy_bytes_in_arena(&arena, src_ptr.as_ref()).into();
*dest_ptr = arena.copy_slice_in(src_ptr.as_ref()).unwrap().into();
}
}
}

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

@ -6,12 +6,11 @@
// https://developers.google.com/open-source/licenses/bsd
use super::opaque_pointee::opaque_pointee;
use std::alloc::{self, Layout};
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::mem::{align_of, MaybeUninit};
use std::ptr::{self, NonNull};
use std::slice;
use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::mem::{align_of, align_of_val, size_of_val, MaybeUninit};
use core::ptr::{self, NonNull};
use core::slice;
opaque_pointee!(upb_Arena);
pub type RawArena = NonNull<upb_Arena>;
@ -79,75 +78,85 @@ impl Arena {
self.raw
}
/// Allocates some memory on the arena.
/// Allocates some memory on the arena. Returns None if the allocation
/// failed.
///
/// # Safety
///
/// - `layout`'s alignment must be less than `UPB_MALLOC_ALIGN`.
/// - `align` must be less than `UPB_MALLOC_ALIGN`.
#[allow(clippy::mut_from_ref)]
#[inline]
pub unsafe fn alloc(&self, layout: Layout) -> &mut [MaybeUninit<u8>] {
debug_assert!(layout.align() <= UPB_MALLOC_ALIGN);
pub unsafe fn alloc(&self, size: usize, align: usize) -> Option<&mut [MaybeUninit<u8>]> {
debug_assert!(align <= UPB_MALLOC_ALIGN);
// SAFETY: `self.raw` is a valid UPB arena
let ptr = unsafe { upb_Arena_Malloc(self.raw, layout.size()) };
if ptr.is_null() {
alloc::handle_alloc_error(layout);
}
let ptr = unsafe { upb_Arena_Malloc(self.raw, size) };
// SAFETY:
// - `upb_Arena_Malloc` promises that if the return pointer is non-null, it is
// dereferencable for `size` bytes and has an alignment of `UPB_MALLOC_ALIGN`
// until the arena is destroyed.
// - `[MaybeUninit<u8>]` has no alignment requirement, and `ptr` is aligned to a
// `UPB_MALLOC_ALIGN` boundary.
unsafe { slice::from_raw_parts_mut(ptr.cast(), layout.size()) }
if ptr.is_null() {
None
} else {
// SAFETY:
// - `upb_Arena_Malloc` promises that if the return pointer is non-null, it is
// dereferencable for `size` bytes and has an alignment of `UPB_MALLOC_ALIGN`
// until the arena is destroyed.
// - `[MaybeUninit<u8>]` has no alignment requirement, and `ptr` is aligned to a
// `UPB_MALLOC_ALIGN` boundary.
Some(unsafe { slice::from_raw_parts_mut(ptr.cast(), size) })
}
}
/// Same as alloc() but panics if `layout.align() > UPB_MALLOC_ALIGN`.
/// Same as alloc() but panics if `align > UPB_MALLOC_ALIGN`.
#[allow(clippy::mut_from_ref)]
#[inline]
pub fn checked_alloc(&self, layout: Layout) -> &mut [MaybeUninit<u8>] {
assert!(layout.align() <= UPB_MALLOC_ALIGN);
// SAFETY: layout.align() <= UPB_MALLOC_ALIGN asserted.
unsafe { self.alloc(layout) }
pub fn checked_alloc(&self, size: usize, align: usize) -> Option<&mut [MaybeUninit<u8>]> {
assert!(align <= UPB_MALLOC_ALIGN);
// SAFETY: align <= UPB_MALLOC_ALIGN asserted.
unsafe { self.alloc(size, align) }
}
/// Copies the T into this arena and returns a pointer to the T data inside
/// the arena.
pub fn copy_in<'a, T: Copy>(&'a self, data: &T) -> &'a T {
let layout = Layout::for_value(data);
let alloc = self.checked_alloc(layout);
/// the arena. Returns None if the allocation failed.
pub fn copy_in<'a, T: Copy>(&'a self, data: &T) -> Option<&'a T> {
let size = size_of_val(data);
let align = align_of_val(data);
// SAFETY:
// - alloc is valid for `layout.len()` bytes and is the uninit bytes are written
// to not read from until written.
// - T is copy so copying the bytes of the value is sound.
unsafe {
let alloc = alloc.as_mut_ptr().cast::<MaybeUninit<T>>();
// let data = (data as *const T).cast::<MaybeUninit<T>>();
(*alloc).write(*data)
}
self.checked_alloc(size, align).map(|alloc| {
// SAFETY:
// - alloc is valid for `size` bytes and is the uninit bytes are written to not
// read from until written.
// - T is copy so copying the bytes of the value is sound.
unsafe {
let alloc = alloc.as_mut_ptr().cast::<MaybeUninit<T>>();
&*(*alloc).write(*data)
}
})
}
pub fn copy_str_in<'a>(&'a self, s: &str) -> &'a str {
let copied_bytes = self.copy_slice_in(s.as_bytes());
// SAFETY: `copied_bytes` has same contents as `s` and so must meet &str
// criteria.
unsafe { std::str::from_utf8_unchecked(copied_bytes) }
/// Copies the str into this arena and returns a pointer to the T data
/// inside the arena. Returns None if the allocation failed.
pub fn copy_str_in<'a>(&'a self, s: &str) -> Option<&'a str> {
self.copy_slice_in(s.as_bytes()).map(|copied_bytes| {
// SAFETY: `copied_bytes` has same contents as `s` and so must meet &str
// criteria.
unsafe { core::str::from_utf8_unchecked(copied_bytes) }
})
}
pub fn copy_slice_in<'a, T: Copy>(&'a self, data: &[T]) -> &'a [T] {
let layout = Layout::for_value(data);
let alloc: *mut T = self.checked_alloc(layout).as_mut_ptr().cast();
// SAFETY:
// - uninit_alloc is valid for `layout.len()` bytes and is the uninit bytes are
// written to not read from until written.
// - T is copy so copying the bytes of the values is sound.
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), alloc, data.len());
slice::from_raw_parts_mut(alloc, data.len())
}
/// Copies the slice into this arena and returns a pointer to the T data
/// inside the arena. Returns None if the allocation failed.
pub fn copy_slice_in<'a, T: Copy>(&'a self, data: &[T]) -> Option<&'a [T]> {
let size = size_of_val(data);
let align = align_of_val(data);
self.checked_alloc(size, align).map(|alloc| {
let alloc: *mut T = alloc.as_mut_ptr().cast();
// SAFETY:
// - uninit_alloc is valid for `layout.len()` bytes and is the uninit bytes are
// written to not read from until written.
// - T is copy so copying the bytes of the values is sound.
unsafe {
ptr::copy_nonoverlapping(data.as_ptr(), alloc, data.len());
slice::from_raw_parts(alloc, data.len())
}
})
}
/// Fuse two arenas so they share the same lifetime.

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

@ -7,7 +7,7 @@
use super::opaque_pointee::opaque_pointee;
use super::{upb_MessageValue, upb_MutableMessageValue, CType, RawArena};
use std::ptr::NonNull;
use core::ptr::NonNull;
opaque_pointee!(upb_Array);
pub type RawArray = NonNull<upb_Array>;
@ -20,8 +20,8 @@ extern "C" {
pub fn upb_Array_Append(arr: RawArray, val: upb_MessageValue, arena: RawArena) -> bool;
pub fn upb_Array_Resize(arr: RawArray, size: usize, arena: RawArena) -> bool;
pub fn upb_Array_Reserve(arr: RawArray, size: usize, arena: RawArena) -> bool;
pub fn upb_Array_MutableDataPtr(arr: RawArray) -> *mut std::ffi::c_void;
pub fn upb_Array_DataPtr(arr: RawArray) -> *const std::ffi::c_void;
pub fn upb_Array_MutableDataPtr(arr: RawArray) -> *mut core::ffi::c_void;
pub fn upb_Array_DataPtr(arr: RawArray) -> *const core::ffi::c_void;
pub fn upb_Array_GetMutable(arr: RawArray, i: usize) -> upb_MutableMessageValue;
}

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

@ -6,7 +6,7 @@
// https://developers.google.com/open-source/licenses/bsd
use super::opaque_pointee::opaque_pointee;
use std::ptr::NonNull;
use core::ptr::NonNull;
opaque_pointee!(upb_ExtensionRegistry);
pub type RawExtensionRegistry = NonNull<upb_ExtensionRegistry>;

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

@ -7,7 +7,7 @@
use super::opaque_pointee::opaque_pointee;
use super::{upb_MessageValue, CType, RawArena};
use std::ptr::NonNull;
use core::ptr::NonNull;
opaque_pointee!(upb_Map);
pub type RawMap = NonNull<upb_Map>;

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

@ -10,7 +10,7 @@ use super::{
upb_ExtensionRegistry, upb_MiniTable, upb_MiniTableField, RawArena, RawArray, RawMap,
StringView,
};
use std::ptr::NonNull;
use core::ptr::NonNull;
opaque_pointee!(upb_Message);
pub type RawMessage = NonNull<upb_Message>;
@ -215,7 +215,7 @@ extern "C" {
pub fn upb_Message_SetBaseField(
m: RawMessage,
f: *const upb_MiniTableField,
val: *const std::ffi::c_void,
val: *const core::ffi::c_void,
);
/// # Safety

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

@ -12,8 +12,8 @@ use super::{RawArray, RawMap, RawMessage, StringView};
#[derive(Clone, Copy)]
pub union upb_MessageValue {
pub bool_val: bool,
pub float_val: std::ffi::c_float,
pub double_val: std::ffi::c_double,
pub float_val: core::ffi::c_float,
pub double_val: core::ffi::c_double,
pub uint32_val: u32,
pub int32_val: i32,
pub uint64_val: u64,
@ -24,14 +24,14 @@ pub union upb_MessageValue {
pub msg_val: Option<RawMessage>,
pub str_val: StringView,
tagged_msg_val: *const std::ffi::c_void,
tagged_msg_val: *const core::ffi::c_void,
}
impl upb_MessageValue {
pub fn zeroed() -> Self {
// SAFETY: zero bytes is a valid representation for at least one value in the
// union (actually valid for all of them).
unsafe { std::mem::zeroed() }
unsafe { core::mem::zeroed() }
}
}

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

@ -6,7 +6,7 @@
// https://developers.google.com/open-source/licenses/bsd
use super::opaque_pointee::opaque_pointee;
use std::ptr::NonNull;
use core::ptr::NonNull;
opaque_pointee!(upb_MiniTable);
pub type RawMiniTable = NonNull<upb_MiniTable>;

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

@ -15,7 +15,7 @@ macro_rules! opaque_pointee {
#[repr(C)]
pub struct $name {
_data: [u8; 0],
_marker: std::marker::PhantomData<(*mut u8, std::marker::PhantomPinned)>,
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
};
}

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

@ -6,9 +6,9 @@
// https://developers.google.com/open-source/licenses/bsd
use super::Arena;
use std::fmt::{self, Debug};
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use core::fmt::{self, Debug};
use core::ops::{Deref, DerefMut};
use core::ptr::NonNull;
/// An 'owned' T, similar to a Box<T> where the T is data
/// held in a upb Arena. By holding the data pointer and a corresponding arena
@ -18,7 +18,7 @@ use std::ptr::NonNull;
/// inside `arena`. This avoids typical concerns of self-referential data
/// structures because `arena` modifications (other than drop) will never
/// invalidate `data`, and `data` and `arena` are both behind indirections which
/// avoids any concern with std::mem::swap.
/// avoids any concern with core::mem::swap.
pub struct OwnedArenaBox<T: ?Sized + 'static> {
data: NonNull<T>,
arena: Arena,
@ -87,7 +87,7 @@ impl<T: Debug + 'static> Debug for OwnedArenaBox<T> {
#[cfg(test)]
mod tests {
use super::*;
use std::str;
use core::str;
#[test]
fn test_byte_slice_pointer_roundtrip() {
@ -101,7 +101,7 @@ mod tests {
fn test_alloc_str_roundtrip() {
let arena = Arena::new();
let s: &str = "Hello";
let arena_alloc_str: NonNull<str> = arena.copy_str_in(s).into();
let arena_alloc_str: NonNull<str> = arena.copy_str_in(s).unwrap().into();
let owned_data = unsafe { OwnedArenaBox::new(arena_alloc_str, arena) };
assert_eq!(&*owned_data, s);
}
@ -109,7 +109,7 @@ mod tests {
#[test]
fn test_sized_type_roundtrip() {
let arena = Arena::new();
let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).into();
let arena_alloc_u32: NonNull<u32> = arena.copy_in(&7u32).unwrap().into();
let mut owned_data = unsafe { OwnedArenaBox::new(arena_alloc_u32, arena) };
assert_eq!(*owned_data, 7);
*owned_data = 8;

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

@ -7,11 +7,11 @@
/// ABI compatible struct with upb_StringView.
///
/// Note that this has semantics similar to `std::string_view` in C++ and
/// Note that this has semantics similar to `core::string_view` in C++ and
/// `&[u8]` in Rust, but is not ABI-compatible with either.
///
/// If `len` is 0, then `ptr` is allowed to be either null or dangling. C++
/// considers a dangling 0-len `std::string_view` to be invalid, and Rust
/// considers a dangling 0-len `core::string_view` to be invalid, and Rust
/// considers a `&[u8]` with a null data pointer to be invalid.
#[repr(C)]
#[derive(Copy, Clone)]
@ -38,7 +38,7 @@ impl StringView {
// SAFETY:
// - `ptr` is non-null
// - `ptr` is valid for `len` bytes as promised by the caller.
unsafe { std::slice::from_raw_parts(self.ptr, self.len) }
unsafe { core::slice::from_raw_parts(self.ptr, self.len) }
}
}
}

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

@ -50,7 +50,7 @@ pub unsafe fn debug_string(msg: RawMessage, mt: *const upb_MiniTable) -> String
// `mt`
// - `buf` is nullptr and `buf_len` is 0
let len =
unsafe { upb_DebugString(msg, mt, Options::NoSortMaps as i32, std::ptr::null_mut(), 0) };
unsafe { upb_DebugString(msg, mt, Options::NoSortMaps as i32, core::ptr::null_mut(), 0) };
assert!(len < isize::MAX as usize);
// +1 for the trailing NULL
let mut buf = vec![0u8; len + 1];

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

@ -50,7 +50,7 @@ pub unsafe fn encode(
mini_table: *const upb_MiniTable,
) -> Result<Vec<u8>, EncodeStatus> {
let arena = Arena::new();
let mut buf: *mut u8 = std::ptr::null_mut();
let mut buf: *mut u8 = core::ptr::null_mut();
let mut len = 0usize;
// SAFETY:
@ -61,7 +61,7 @@ pub unsafe fn encode(
if status == EncodeStatus::Ok {
assert!(!buf.is_null()); // EncodeStatus Ok should never return NULL data, even for len=0.
// SAFETY: upb guarantees that `buf` is valid to read for `len`.
Ok(unsafe { &*std::ptr::slice_from_raw_parts(buf, len) }.to_vec())
Ok(unsafe { &*core::ptr::slice_from_raw_parts(buf, len) }.to_vec())
} else {
Err(status)
}
@ -88,7 +88,7 @@ pub unsafe fn decode(
// - `buf` is legally readable for at least `buf_size` bytes.
// - `extreg` is null.
let status =
unsafe { upb_Decode(buf, len, msg, mini_table, std::ptr::null(), options, arena.raw()) };
unsafe { upb_Decode(buf, len, msg, mini_table, core::ptr::null(), options, arena.raw()) };
match status {
DecodeStatus::Ok => Ok(()),
_ => Err(status),