Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions libdd-common-ffi/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,11 +222,18 @@ impl<'a, T: 'a> Slice<'a, T> {
///
/// 1. Fails if `self.ptr` is null and `self.len` is not zero.
/// 2. Fails if `self.ptr` is not null and is unaligned.
/// 3. Fails if `self.len` is larger than [`isize::MAX`].
/// 3. Fails if the total size in bytes (`self.len * size_of::<T>()`) is larger than
/// [`isize::MAX`].
pub fn try_as_slice(&self) -> Result<&'a [T], SliceConversionError> {
let (ptr, len) = self.as_raw_parts();
if !ptr.is_null() {
if len > isize::MAX as usize {
// `from_raw_parts` bounds the total size in *bytes*, not the element
// count: for a wide `T` a count within `isize::MAX` can still
// overflow. `checked_mul` also covers the overflow and ZST cases.
let too_large = len
.checked_mul(core::mem::size_of::<T>())
.is_none_or(|bytes| bytes > isize::MAX as usize);
if too_large {
Err(SliceConversionError::LargeLength)
} else if !ptr.is_aligned() {
Err(SliceConversionError::MisalignedPointer)
Expand Down Expand Up @@ -480,6 +487,25 @@ mod tests {
));
}

#[test]
fn test_try_as_slice_large_byte_size() {
// `len` is within `isize::MAX` as an element count, but the byte size
// (`len * size_of::<u64>()`) exceeds it. The pointer is non-null and
// aligned, so the byte-size check is what must reject the slice.
let len = isize::MAX as usize / core::mem::size_of::<u64>() + 1;
let large_bytes: Slice<u64> = Slice {
ptr: ptr::NonNull::dangling().as_ptr(),
len,
_marker: PhantomData,
};

let result = large_bytes.try_as_slice();
assert!(matches!(
result.unwrap_err(),
SliceConversionError::LargeLength
));
}

#[test]
fn test_try_as_slice_misaligned_pointer() {
// Create a misaligned pointer for u64 by using a properly aligned
Expand Down
52 changes: 48 additions & 4 deletions libdd-common-ffi/src/slice_mut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,13 @@ impl<'a, T: 'a> MutSlice<'a, T> {
if let Some(ptr) = self.ptr {
// Crashing immediately is likely better than ignoring these.
assert!(ptr.is_aligned());
assert!(self.len <= isize::MAX as usize);
// Total byte size, not element count, must fit in isize::MAX
// (from_raw_parts_mut).
let too_large = self
.len
.checked_mul(core::mem::size_of::<T>())
.is_none_or(|bytes| bytes > isize::MAX as usize);
assert!(!too_large);
unsafe { slice::from_raw_parts_mut(ptr.as_ptr(), self.len) }
} else {
// Crashing immediately is likely better than ignoring this.
Expand All @@ -117,11 +123,18 @@ impl<'a, T: 'a> MutSlice<'a, T> {
/// instead.
/// - Returns [`SliceConversionError::MisalignedPointer`] if the pointer is non-null and is not
/// aligned correctly for the type.
/// - Returns [`SliceConversionError::LargeLength`] if the length of the slice exceeds
/// [`isize::MAX`].
/// - Returns [`SliceConversionError::LargeLength`] if the total size in bytes (`self.len *
/// size_of::<T>()`) exceeds [`isize::MAX`].
pub fn try_as_slice(&self) -> Result<&'a [T], SliceConversionError> {
if let Some(ptr) = self.ptr {
if self.len > isize::MAX as usize {
// `from_raw_parts` bounds the total size in *bytes*, not the element
// count: for a wide `T` a count within `isize::MAX` can still
// overflow. `checked_mul` also covers the overflow and ZST cases.
let too_large = self
.len
.checked_mul(core::mem::size_of::<T>())
.is_none_or(|bytes| bytes > isize::MAX as usize);
if too_large {
Err(SliceConversionError::LargeLength)
} else if !ptr.is_aligned() {
Err(SliceConversionError::MisalignedPointer)
Expand Down Expand Up @@ -263,6 +276,19 @@ mod tests {
_ = dangerous.as_mut_slice();
}

#[should_panic]
#[test]
fn test_long_byte_size_panic() {
// Element count within isize::MAX, byte size beyond it.
let len = isize::MAX as usize / core::mem::size_of::<u64>() + 1;
let mut dangerous: MutSlice<u64> = MutSlice {
ptr: Some(ptr::NonNull::dangling()),
len,
_marker: PhantomData,
};
_ = dangerous.as_mut_slice();
}

#[test]
fn test_try_as_slice_success() {
let mut data = vec![1u8, 2, 3, 4, 5];
Expand Down Expand Up @@ -314,6 +340,24 @@ mod tests {
));
}

#[test]
fn test_try_as_slice_large_byte_size() {
// `len` is within `isize::MAX` as an element count, but the byte size
// (`len * size_of::<u64>()`) exceeds it.
let len = isize::MAX as usize / core::mem::size_of::<u64>() + 1;
let large_bytes: MutSlice<u64> = MutSlice {
ptr: Some(ptr::NonNull::dangling()),
len,
_marker: PhantomData,
};

let result = large_bytes.try_as_slice();
assert!(matches!(
result.unwrap_err(),
SliceConversionError::LargeLength
));
}

#[test]
fn test_try_as_slice_misaligned_pointer() {
// Create a misaligned pointer for u64 by using a properly aligned
Expand Down
4 changes: 3 additions & 1 deletion libdd-data-pipeline-ffi/cbindgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ includes = ["common.h"]
after_includes = """
typedef struct ddog_TraceExporter ddog_TraceExporter;
typedef struct ddog_TracerSpan ddog_TracerSpan;
typedef struct ddog_TracerSpanEvent ddog_TracerSpanEvent;
typedef struct ddog_TracerTraceChunks ddog_TracerTraceChunks;
typedef struct ddog_TraceExporterCancelToken ddog_TraceExporterCancelToken;
"""

[export]
prefix = "ddog_"
renaming_overrides_prefixing = true
exclude = ["TraceExporter", "TracerSpan", "TracerTraceChunks", "TokioCancellationToken"]
exclude = ["TraceExporter", "TracerSpan", "TracerSpanEvent", "TracerTraceChunks", "TokioCancellationToken"]

[export.rename]
"ByteSlice" = "ddog_ByteSlice"
Expand All @@ -31,6 +32,7 @@ exclude = ["TraceExporter", "TracerSpan", "TracerTraceChunks", "TokioCancellatio
"ExporterErrorCode" = "ddog_TraceExporterErrorCode"
"ExporterError" = "ddog_TraceExporterError"
"TracerSpan" = "ddog_TracerSpan"
"TracerSpanEvent" = "ddog_TracerSpanEvent"
"TracerSpanFields" = "ddog_TracerSpanFields"
"TracerTraceChunks" = "ddog_TracerTraceChunks"
"TokioCancellationToken" = "ddog_TraceExporterCancelToken"
Expand Down
Loading
Loading