Skip to content

Commit 1833c00

Browse files
committed
Make sure to handle null pointers correctly when calling slice::from_raw_parts
1 parent 5f795ef commit 1833c00

File tree

4 files changed

+107
-24
lines changed

4 files changed

+107
-24
lines changed

src/manual/core/mat.rs

Lines changed: 47 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -473,24 +473,30 @@ pub trait MatTraitConstManual: MatTraitConst {
473473
unsafe fn at_row_unchecked<T: DataType>(&self, row: i32) -> Result<&[T]> {
474474
// safe because Mat::size() can't be negative
475475
let width = self.size()?.width as usize;
476-
self.ptr(row).map(|x| slice::from_raw_parts(convert_ptr(x), width))
476+
self.ptr(row).map(|row| {
477+
if row.is_null() {
478+
&[]
479+
} else {
480+
slice::from_raw_parts(convert_ptr(row), width)
481+
}
482+
})
477483
}
478484

479485
#[inline]
480486
fn is_allocated(&self) -> bool {
481487
!self.data().is_null()
482488
}
483489

484-
/// Returns underlying data array as byte slice, Mat must be continuous.
490+
/// Returns underlying data array as byte slice, `Mat` must be continuous
485491
#[inline]
486492
fn data_bytes(&self) -> Result<&[u8]> {
487493
match_is_continuous(self).and_then(|_| {
488494
let data = self.data();
489-
if data.is_null() {
490-
Err(Error::new(core::StsNullPtr, "Function returned null pointer"))
495+
Ok(if data.is_null() {
496+
&[]
491497
} else {
492-
Ok(unsafe { slice::from_raw_parts(data, self.total() * self.elem_size()?) })
493-
}
498+
unsafe { slice::from_raw_parts(data, self.total() * self.elem_size()?) }
499+
})
494500
})
495501
}
496502

@@ -502,15 +508,15 @@ pub trait MatTraitConstManual: MatTraitConst {
502508
}
503509

504510
/// # Safety
505-
/// Caller must ensure that the `T` type argument corresponds to the data stored in the `Mat`
511+
/// Caller must ensure that the `T` type argument corresponds to the data stored in the `Mat` and `Mat` is continuous
506512
#[inline]
507513
unsafe fn data_typed_unchecked<T: DataType>(&self) -> Result<&[T]> {
508514
let data = self.data();
509-
if data.is_null() {
510-
Err(Error::new(core::StsNullPtr, "Function returned null pointer"))
515+
Ok(if data.is_null() {
516+
&[]
511517
} else {
512-
Ok(slice::from_raw_parts(data.cast::<T>(), self.total()))
513-
}
518+
slice::from_raw_parts(data.cast::<T>(), self.total())
519+
})
514520
}
515521

516522
fn to_vec_2d<T: DataType>(&self) -> Result<Vec<Vec<T>>> {
@@ -624,16 +630,26 @@ pub trait MatTraitManual: MatTraitConstManual + MatTrait {
624630
unsafe fn at_row_unchecked_mut<T: DataType>(&mut self, row: i32) -> Result<&mut [T]> {
625631
// safe because Mat::size() can't be negative
626632
let width = self.size()?.width as usize;
627-
self
628-
.ptr_mut(row)
629-
.map(|x| slice::from_raw_parts_mut(convert_ptr_mut(x), width))
633+
self.ptr_mut(row).map(|x| {
634+
if x.is_null() {
635+
&mut []
636+
} else {
637+
slice::from_raw_parts_mut(convert_ptr_mut(x), width)
638+
}
639+
})
630640
}
631641

632642
/// Returns underlying data array as mutable byte slice, Mat must be continuous.
633643
#[inline]
634644
fn data_bytes_mut(&mut self) -> Result<&mut [u8]> {
635-
match_is_continuous(self)
636-
.and_then(|_| Ok(unsafe { slice::from_raw_parts_mut(self.data_mut(), self.total() * self.elem_size()?) }))
645+
match_is_continuous(self).and_then(|_| {
646+
let data = self.data_mut();
647+
Ok(if data.is_null() {
648+
&mut []
649+
} else {
650+
unsafe { slice::from_raw_parts_mut(self.data_mut(), self.total() * self.elem_size()?) }
651+
})
652+
})
637653
}
638654

639655
#[inline]
@@ -643,11 +659,16 @@ pub trait MatTraitManual: MatTraitConstManual + MatTrait {
643659
}
644660

645661
/// # Safety
646-
/// Caller must ensure that the `T` type argument corresponds to the data stored in the `Mat`
662+
/// Caller must ensure that the `T` type argument corresponds to the data stored in the `Mat` and `Mat` is continuous
647663
#[inline]
648664
unsafe fn data_typed_unchecked_mut<T: DataType>(&mut self) -> Result<&mut [T]> {
649665
let total = self.total();
650-
Ok(slice::from_raw_parts_mut(self.data_mut().cast::<T>(), total))
666+
let data = self.data_mut();
667+
Ok(if data.is_null() {
668+
&mut []
669+
} else {
670+
slice::from_raw_parts_mut(data.cast::<T>(), total)
671+
})
651672
}
652673

653674
/// Returns a mutable iterator over `Mat` elements and their positions
@@ -707,9 +728,14 @@ impl Deref for MatSize {
707728

708729
#[inline]
709730
fn deref(&self) -> &Self::Target {
710-
// safe because `Mat::dims()` returns value >= 2
711-
let dims = self.dims() as usize;
712-
unsafe { slice::from_raw_parts(self.p(), dims) }
731+
let p = self.p();
732+
if p.is_null() {
733+
&[]
734+
} else {
735+
// safe because `Mat::dims()` returns value >= 2
736+
let dims = self.dims() as usize;
737+
unsafe { slice::from_raw_parts(p, dims) }
738+
}
713739
}
714740
}
715741

src/manual/core/vector.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,12 @@ where
199199
where
200200
Self: VectorExternCopyNonBool<T>,
201201
{
202-
unsafe { slice::from_raw_parts(self.extern_data(), self.len()) }
202+
let data = unsafe { self.extern_data() };
203+
if data.is_null() {
204+
&[]
205+
} else {
206+
unsafe { slice::from_raw_parts(data, self.len()) }
207+
}
203208
}
204209

205210
/// Return mutable slice to the elements of the array.
@@ -211,7 +216,12 @@ where
211216
where
212217
Self: VectorExternCopyNonBool<T>,
213218
{
214-
unsafe { slice::from_raw_parts_mut(self.extern_data_mut(), self.len()) }
219+
let data = unsafe { self.extern_data_mut() };
220+
if data.is_null() {
221+
&mut []
222+
} else {
223+
unsafe { slice::from_raw_parts_mut(data, self.len()) }
224+
}
215225
}
216226
}
217227

src/templ.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,12 @@ unsafe extern "C" fn ocvrs_create_string(s: *const c_char) -> *mut String {
119119
/// The return type of this function goes into `receive_byte_string`
120120
#[no_mangle]
121121
unsafe extern "C" fn ocvrs_create_byte_string(v: *const u8, len: size_t) -> *mut Vec<u8> {
122-
let v = slice::from_raw_parts(v, len).to_vec();
122+
let byte_slice = if v.is_null() {
123+
&[]
124+
} else {
125+
slice::from_raw_parts(v, len)
126+
};
127+
let v = byte_slice.to_vec();
123128
Box::into_raw(Box::new(v))
124129
}
125130

tests/slice_from_null.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use opencv::core::{Mat, MatSize, Vector};
2+
use opencv::prelude::*;
3+
use opencv::Result;
4+
use std::ptr;
5+
6+
/// test that null pointers are handled and not passed to slice::from_raw_parts
7+
#[test]
8+
fn from_nullptr_slice() -> Result<()> {
9+
{
10+
let mut vec = Vector::<i32>::new();
11+
let s = vec.as_slice();
12+
assert!(s.is_empty());
13+
14+
let s = vec.as_mut_slice();
15+
assert!(s.is_empty());
16+
}
17+
18+
{
19+
let mut m = Mat::default();
20+
assert_eq!(ptr::null(), m.data());
21+
22+
let r = unsafe { m.at_row_unchecked::<u8>(0)? };
23+
assert!(r.is_empty());
24+
25+
let r = unsafe { m.at_row_unchecked_mut::<u8>(0)? };
26+
assert!(r.is_empty());
27+
28+
let d = unsafe { m.data_typed_unchecked::<u8>()? };
29+
assert!(d.is_empty());
30+
31+
let d = unsafe { m.data_typed_unchecked_mut::<u8>()? };
32+
assert!(d.is_empty());
33+
}
34+
35+
{
36+
let s = unsafe { MatSize::new(ptr::null_mut()) };
37+
let s = &*s;
38+
assert!(s.is_empty());
39+
}
40+
41+
Ok(())
42+
}

0 commit comments

Comments
 (0)