Skip to content

Commit 4cc42c9

Browse files
committed
prepare for merge
1 parent 3867ac9 commit 4cc42c9

File tree

8 files changed

+160
-136
lines changed

8 files changed

+160
-136
lines changed

datadog-profiling-ffi/src/profile_handle.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
use allocator_api2::alloc::AllocError;
1212
use allocator_api2::boxed::Box;
1313
use datadog_profiling::profiles::ProfileError;
14+
use ddcommon::error::FfiSafeErrorMessage;
1415
use std::ffi::CStr;
1516
use std::fmt;
1617
use std::ptr::NonNull;
@@ -57,15 +58,15 @@ pub struct EmptyHandleError;
5758
/// # Safety
5859
///
5960
/// Uses c-str literal to ensure valid UTF-8 and null termination.
60-
unsafe impl ddcommon::ffi::ThinError for EmptyHandleError {
61+
unsafe impl ddcommon::error::FfiSafeErrorMessage for EmptyHandleError {
6162
fn as_ffi_str(&self) -> &'static CStr {
6263
c"handle used with an interior null pointer"
6364
}
6465
}
6566

6667
impl fmt::Display for EmptyHandleError {
6768
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68-
ddcommon::ffi::error_as_rust_str(self).fmt(f)
69+
self.as_rust_str().fmt(f)
6970
}
7071
}
7172

@@ -104,7 +105,7 @@ impl core::error::Error for AllocHandleError {}
104105

105106
impl From<EmptyHandleError> for ProfileError {
106107
fn from(err: EmptyHandleError) -> ProfileError {
107-
ProfileError::other(ddcommon::ffi::error_as_rust_str(&err))
108+
ProfileError::other(err.as_rust_str())
108109
}
109110
}
110111

datadog-profiling-ffi/src/status.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ impl ProfileStatus {
194194
err: c"another error occured, but cannot be displayed because it has interior null bytes".as_ptr(),
195195
};
196196

197-
pub fn from_thin_error<E: ddcommon::ffi::ThinError>(err: E) -> Self {
197+
pub fn from_thin_error<E: ddcommon::error::FfiSafeErrorMessage>(
198+
err: E,
199+
) -> Self {
198200
ProfileStatus::from(err.as_ffi_str())
199201
}
200202

datadog-profiling/src/profiles/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ impl ProfileError {
5151
Self::Other(error.into())
5252
}
5353

54-
pub fn from_thin_error<E: ddcommon::ffi::ThinError>(error: E) -> Self {
55-
Self::other(Cow::Borrowed(ddcommon::ffi::error_as_rust_str(&error)))
54+
pub fn from_thin_error<E: ddcommon::error::FfiSafeErrorMessage>(error: E) -> Self {
55+
Self::other(Cow::Borrowed(error.as_rust_str()))
5656
}
5757

5858
/// Create a formatted error string. If memory allocation fails, a less

ddcommon-ffi/src/slice.rs

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// SPDX-License-Identifier: Apache-2.0
33

44
use core::slice;
5+
use ddcommon::error::FfiSafeErrorMessage;
56
use serde::ser::Error;
67
use serde::Serializer;
78
use std::borrow::Cow;
@@ -11,6 +12,14 @@ use std::marker::PhantomData;
1112
use std::os::raw::c_char;
1213
use std::str::Utf8Error;
1314

15+
#[repr(C)]
16+
#[derive(Clone, Copy, Debug)]
17+
pub enum SliceConversionError {
18+
LargeLength,
19+
NullPointer,
20+
MisalignedPointer,
21+
}
22+
1423
#[repr(C)]
1524
#[derive(Copy, Clone)]
1625
pub struct Slice<'a, T: 'a> {
@@ -25,6 +34,25 @@ pub struct Slice<'a, T: 'a> {
2534
_marker: PhantomData<&'a [T]>,
2635
}
2736

37+
/// # Safety
38+
/// All strings are valid UTF-8 (enforced by using c-str literals in Rust).
39+
unsafe impl FfiSafeErrorMessage for SliceConversionError {
40+
fn as_ffi_str(&self) -> &'static std::ffi::CStr {
41+
match self {
42+
SliceConversionError::LargeLength => c"length was too large",
43+
SliceConversionError::NullPointer => c"null pointer with non-zero length",
44+
SliceConversionError::MisalignedPointer => c"pointer was not aligned for the type",
45+
}
46+
}
47+
}
48+
impl Display for SliceConversionError {
49+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50+
Display::fmt(self.as_rust_str(), f)
51+
}
52+
}
53+
54+
impl core::error::Error for SliceConversionError {}
55+
2856
impl<'a, T: 'a> core::ops::Deref for Slice<'a, T> {
2957
type Target = [T];
3058

@@ -55,51 +83,25 @@ pub type ByteSlice<'a> = Slice<'a, u8>;
5583

5684
/// This exists as an intrinsic, but it is private.
5785
pub fn is_aligned_and_not_null<T>(ptr: *const T) -> bool {
58-
!ptr.is_null() && is_aligned(ptr)
59-
}
60-
61-
#[inline]
62-
fn is_aligned<T>(ptr: *const T) -> bool {
63-
debug_assert!(!ptr.is_null());
64-
ptr as usize % std::mem::align_of::<T>() == 0
65-
}
66-
67-
#[repr(C)]
68-
#[derive(Clone, Copy, Debug)]
69-
pub enum SliceConversionError {
70-
LargeLength,
71-
NullPointer,
72-
MisalignedPointer,
86+
!ptr.is_null() && ptr.is_aligned()
7387
}
7488

75-
/// # Safety
76-
/// All strings are valid UTF-8 (enforced by using c-str literals in Rust)
77-
unsafe impl ddcommon::ffi::ThinError for SliceConversionError {
78-
fn as_ffi_str(&self) -> &'static std::ffi::CStr {
79-
match self {
80-
SliceConversionError::LargeLength => c"length was too large",
81-
SliceConversionError::NullPointer => c"null pointer with non-zero length",
82-
SliceConversionError::MisalignedPointer => c"pointer was not aligned for the type",
83-
}
84-
}
85-
}
86-
87-
impl Display for SliceConversionError {
88-
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
89-
Display::fmt(ddcommon::ffi::error_as_rust_str(self), f)
90-
}
91-
}
92-
93-
impl core::error::Error for SliceConversionError {}
94-
9589
pub trait AsBytes<'a> {
96-
fn as_bytes(&self) -> &'a [u8] {
97-
{
98-
#[allow(clippy::expect_used)]
99-
self.try_as_bytes().expect("failed to interpret as bytes")
100-
}
101-
}
90+
fn as_bytes(&self) -> &'a [u8];
10291

92+
/// Tries to interpret the structure as a slice of bytes.
93+
///
94+
/// # Errors
95+
///
96+
/// - Returns [`SliceConversionError::NullPointer`] if the slice has a null pointer and a
97+
/// length other than zero. If pointer is null and length is zero, then return `Ok(&[])`
98+
/// instead.
99+
/// - Returns [`SliceConversionError::MisalignedPointer`] if the pointer is non-null and is not
100+
/// aligned correctly for the type (not generally possible with types which are inherently
101+
/// byte oriented, but is if the slice is of some other type which is being safely
102+
/// reinterpreted as bytes).
103+
/// - Returns [`SliceConversionError::LargeLength`] if the length of the slice exceeds
104+
/// [`isize::MAX`].
103105
fn try_as_bytes(&self) -> Result<&'a [u8], SliceConversionError>;
104106

105107
#[inline]
@@ -130,20 +132,30 @@ pub trait AsBytes<'a> {
130132
}
131133

132134
impl<'a> AsBytes<'a> for Slice<'a, u8> {
135+
fn as_bytes(&self) -> &'a [u8] {
136+
self.as_slice()
137+
}
138+
133139
fn try_as_bytes(&self) -> Result<&'a [u8], SliceConversionError> {
134140
self.try_as_slice()
135141
}
136142
}
137143

138144
impl<'a> AsBytes<'a> for Slice<'a, i8> {
145+
fn as_bytes(&self) -> &'a [u8] {
146+
#[allow(clippy::expect_used)]
147+
self.try_as_bytes()
148+
.expect("AsBytes::as_bytes failed to convert to a Rust slice")
149+
}
150+
139151
fn try_as_bytes(&self) -> Result<&'a [u8], SliceConversionError> {
140-
self.try_as_slice().map(|i8_slice| {
152+
self.try_as_slice().map(|slice| {
141153
// SAFETY: we've gone through a successful try_as_slice, so the
142154
// enforceable characteristics such as fitting in isize::MAX are
143155
// all good. The rest is safe only if the consumer respects the
144156
// inherent safety requirements--doesn't give invalid length,
145157
// pointer to invalid memory, etc.
146-
unsafe { slice::from_raw_parts(i8_slice.as_ptr().cast(), self.len) }
158+
unsafe { slice::from_raw_parts(slice.as_ptr().cast(), self.len) }
147159
})
148160
}
149161
}
@@ -160,7 +172,7 @@ impl<'a> AsBytes<'a> for &'a [c_char] {
160172
}
161173
}
162174

163-
impl<'a, T> Slice<'a, T> {
175+
impl<'a, T: 'a> Slice<'a, T> {
164176
/// Creates a valid empty slice (len=0, ptr is non-null).
165177
#[must_use]
166178
pub const fn empty() -> Self {
@@ -198,10 +210,10 @@ impl<'a, T> Slice<'a, T> {
198210
}
199211
}
200212

201-
#[inline]
202213
pub fn as_slice(&self) -> &'a [T] {
203214
#[allow(clippy::expect_used)]
204-
self.try_as_slice().expect("ffi Slice wasn't a valid slice")
215+
self.try_as_slice()
216+
.expect("ffi Slice failed to convert to a Rust slice")
205217
}
206218

207219
/// Tries to convert the FFI slice into a standard slice.
@@ -212,15 +224,16 @@ impl<'a, T> Slice<'a, T> {
212224
/// 2. Fails if `self.ptr` is not null and is unaligned.
213225
/// 3. Fails if `self.len` is larger than [`isize::MAX`].
214226
pub fn try_as_slice(&self) -> Result<&'a [T], SliceConversionError> {
215-
if !self.ptr.is_null() {
216-
if self.len() > isize::MAX as usize {
227+
let (ptr, len) = self.as_raw_parts();
228+
if !ptr.is_null() {
229+
if len > isize::MAX as usize {
217230
Err(SliceConversionError::LargeLength)
218-
} else if self.ptr.is_aligned() {
231+
} else if !ptr.is_aligned() {
219232
Err(SliceConversionError::MisalignedPointer)
220233
} else {
221-
Ok(unsafe { slice::from_raw_parts(self.ptr, self.len) })
234+
Ok(unsafe { slice::from_raw_parts(ptr, len) })
222235
}
223-
} else if self.len != 0 {
236+
} else if len != 0 {
224237
Err(SliceConversionError::NullPointer)
225238
} else {
226239
Ok(&[])

0 commit comments

Comments
 (0)