Skip to content

Commit 3236fee

Browse files
authored
Merge pull request sfackler#2268 from alex/universal-raw-parts
Added a utility function to ensure we never have an issue with 0-length slices from pointers again
2 parents ad70a0b + e5bd08f commit 3236fee

File tree

8 files changed

+66
-44
lines changed

8 files changed

+66
-44
lines changed

clippy.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
disallowed-methods = [
2+
{ path = "std::slice::from_raw_parts", reason = "use util::from_raw_parts instead" },
3+
{ path = "std::slice::from_raw_parts_mut", reason = "use util::from_raw_parts_mut instead" },
4+
]

openssl/src/asn1.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ use std::convert::TryInto;
3232
use std::ffi::CString;
3333
use std::fmt;
3434
use std::ptr;
35-
use std::slice;
3635
use std::str;
3736

3837
use crate::bio::MemBio;
@@ -41,7 +40,7 @@ use crate::error::ErrorStack;
4140
use crate::nid::Nid;
4241
use crate::stack::Stackable;
4342
use crate::string::OpensslString;
44-
use crate::{cvt, cvt_p};
43+
use crate::{cvt, cvt_p, util};
4544
use openssl_macros::corresponds;
4645

4746
foreign_type_and_impl_send_sync! {
@@ -457,7 +456,7 @@ impl Asn1StringRef {
457456
/// [`as_utf8`]: struct.Asn1String.html#method.as_utf8
458457
#[corresponds(ASN1_STRING_get0_data)]
459458
pub fn as_slice(&self) -> &[u8] {
460-
unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
459+
unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) }
461460
}
462461

463462
/// Returns the number of bytes in the string.
@@ -597,7 +596,7 @@ impl Asn1BitStringRef {
597596
/// Returns the Asn1BitString as a slice.
598597
#[corresponds(ASN1_STRING_get0_data)]
599598
pub fn as_slice(&self) -> &[u8] {
600-
unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
599+
unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) }
601600
}
602601

603602
/// Returns the number of bytes in the string.
@@ -637,7 +636,7 @@ impl Asn1OctetStringRef {
637636
/// Returns the octet string as an array of bytes.
638637
#[corresponds(ASN1_STRING_get0_data)]
639638
pub fn as_slice(&self) -> &[u8] {
640-
unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) }
639+
unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) }
641640
}
642641

643642
/// Returns the number of bytes in the octet string.
@@ -701,7 +700,7 @@ impl Asn1Object {
701700
pub fn as_slice(&self) -> &[u8] {
702701
unsafe {
703702
let len = ffi::OBJ_length(self.as_ptr());
704-
slice::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len)
703+
util::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len)
705704
}
706705
}
707706
}

openssl/src/bio.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use cfg_if::cfg_if;
22
use libc::c_int;
33
use std::marker::PhantomData;
44
use std::ptr;
5-
use std::slice;
65

76
use crate::cvt_p;
87
use crate::error::ErrorStack;
8+
use crate::util;
99

1010
pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>);
1111

@@ -63,11 +63,7 @@ impl MemBio {
6363
unsafe {
6464
let mut ptr = ptr::null_mut();
6565
let len = ffi::BIO_get_mem_data(self.0, &mut ptr);
66-
if len == 0 {
67-
&[]
68-
} else {
69-
slice::from_raw_parts(ptr as *const _ as *const _, len as usize)
70-
}
66+
util::from_raw_parts(ptr as *const _ as *const _, len as usize)
7167
}
7268
}
7369

openssl/src/ssl/bio.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ use std::io;
99
use std::io::prelude::*;
1010
use std::panic::{catch_unwind, AssertUnwindSafe};
1111
use std::ptr;
12-
use std::slice;
1312

14-
use crate::cvt_p;
1513
use crate::error::ErrorStack;
14+
use crate::{cvt_p, util};
1615

1716
pub struct StreamState<S> {
1817
pub stream: S,
@@ -89,7 +88,7 @@ unsafe extern "C" fn bwrite<S: Write>(bio: *mut BIO, buf: *const c_char, len: c_
8988
BIO_clear_retry_flags(bio);
9089

9190
let state = state::<S>(bio);
92-
let buf = slice::from_raw_parts(buf as *const _, len as usize);
91+
let buf = util::from_raw_parts(buf as *const _, len as usize);
9392

9493
match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) {
9594
Ok(Ok(len)) => len as c_int,
@@ -111,7 +110,7 @@ unsafe extern "C" fn bread<S: Read>(bio: *mut BIO, buf: *mut c_char, len: c_int)
111110
BIO_clear_retry_flags(bio);
112111

113112
let state = state::<S>(bio);
114-
let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize);
113+
let buf = util::from_raw_parts_mut(buf as *mut _, len as usize);
115114

116115
match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) {
117116
Ok(Ok(len)) => len as c_int,

openssl/src/ssl/callbacks.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use libc::{c_int, c_uchar, c_uint, c_void};
1010
use std::ffi::CStr;
1111
use std::mem;
1212
use std::ptr;
13-
use std::slice;
1413
#[cfg(any(ossl111, boringssl))]
1514
use std::str;
1615
use std::sync::Arc;
@@ -28,6 +27,7 @@ use crate::ssl::{
2827
};
2928
#[cfg(ossl111)]
3029
use crate::ssl::{ClientHelloResponse, ExtensionContext};
30+
use crate::util;
3131
#[cfg(any(ossl111, boringssl))]
3232
use crate::util::ForeignTypeRefExt;
3333
#[cfg(ossl111)]
@@ -85,9 +85,9 @@ where
8585
None
8686
};
8787
// Give the callback mutable slices into which it can write the identity and psk.
88-
let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize);
88+
let identity_sl = util::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize);
8989
#[allow(clippy::unnecessary_cast)]
90-
let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
90+
let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
9191
match (*callback)(ssl, hint, identity_sl, psk_sl) {
9292
Ok(psk_len) => psk_len as u32,
9393
Err(e) => {
@@ -126,7 +126,7 @@ where
126126
};
127127
// Give the callback mutable slices into which it can write the psk.
128128
#[allow(clippy::unnecessary_cast)]
129-
let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
129+
let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize);
130130
match (*callback)(ssl, identity, psk_sl) {
131131
Ok(psk_len) => psk_len as u32,
132132
Err(e) => {
@@ -197,7 +197,7 @@ where
197197
.ex_data(SslContext::cached_ex_index::<F>())
198198
.expect("BUG: alpn callback missing") as *const F;
199199
#[allow(clippy::unnecessary_cast)]
200-
let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize);
200+
let protos = util::from_raw_parts(inbuf as *const u8, inlen as usize);
201201

202202
match (*callback)(ssl, protos) {
203203
Ok(proto) => {
@@ -416,7 +416,7 @@ where
416416
.ex_data(SslContext::cached_ex_index::<F>())
417417
.expect("BUG: get session callback missing") as *const F;
418418
#[allow(clippy::unnecessary_cast)]
419-
let data = slice::from_raw_parts(data as *const u8, len as usize);
419+
let data = util::from_raw_parts(data as *const u8, len as usize);
420420

421421
match (*callback)(ssl, data) {
422422
Some(session) => {
@@ -460,7 +460,7 @@ where
460460
.ex_data(SslContext::cached_ex_index::<F>())
461461
.expect("BUG: stateless cookie generate callback missing") as *const F;
462462
#[allow(clippy::unnecessary_cast)]
463-
let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize);
463+
let slice = util::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize);
464464
match (*callback)(ssl, slice) {
465465
Ok(len) => {
466466
*cookie_len = len as size_t;
@@ -488,7 +488,7 @@ where
488488
.ex_data(SslContext::cached_ex_index::<F>())
489489
.expect("BUG: stateless cookie verify callback missing") as *const F;
490490
#[allow(clippy::unnecessary_cast)]
491-
let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len);
491+
let slice = util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len);
492492
(*callback)(ssl, slice) as c_int
493493
}
494494

@@ -511,7 +511,7 @@ where
511511
// compatibility. See comments in dtls1.h.
512512
#[allow(clippy::unnecessary_cast)]
513513
let slice =
514-
slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1);
514+
util::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1);
515515
match (*callback)(ssl, slice) {
516516
Ok(len) => {
517517
*cookie_len = len as c_uint;
@@ -551,7 +551,7 @@ where
551551
.expect("BUG: cookie verify callback missing") as *const F;
552552
#[allow(clippy::unnecessary_cast)]
553553
let slice =
554-
slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
554+
util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
555555
(*callback)(ssl, slice) as c_int
556556
}
557557
}
@@ -663,7 +663,7 @@ where
663663
.expect("BUG: custom ext parse callback missing") as *const F;
664664
let ectx = ExtensionContext::from_bits_truncate(context);
665665
#[allow(clippy::unnecessary_cast)]
666-
let slice = slice::from_raw_parts(input as *const u8, inlen);
666+
let slice = util::from_raw_parts(input as *const u8, inlen);
667667
let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) {
668668
Some((chainidx, X509Ref::from_ptr(x)))
669669
} else {

openssl/src/ssl/mod.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ use crate::ssl::bio::BioMethod;
7777
use crate::ssl::callbacks::*;
7878
use crate::ssl::error::InnerError;
7979
use crate::stack::{Stack, StackRef, Stackable};
80+
use crate::util;
8081
use crate::util::{ForeignTypeExt, ForeignTypeRefExt};
8182
use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef};
8283
#[cfg(any(ossl102, boringssl, libressl261))]
@@ -101,7 +102,6 @@ use std::ops::{Deref, DerefMut};
101102
use std::panic::resume_unwind;
102103
use std::path::Path;
103104
use std::ptr;
104-
use std::slice;
105105
use std::str;
106106
use std::sync::{Arc, Mutex};
107107

@@ -708,7 +708,7 @@ pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]
708708
client.len() as c_uint,
709709
);
710710
if r == ffi::OPENSSL_NPN_NEGOTIATED {
711-
Some(slice::from_raw_parts(out as *const u8, outlen as usize))
711+
Some(util::from_raw_parts(out as *const u8, outlen as usize))
712712
} else {
713713
None
714714
}
@@ -2174,7 +2174,7 @@ impl SslSessionRef {
21742174
let mut len = 0;
21752175
let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
21762176
#[allow(clippy::unnecessary_cast)]
2177-
slice::from_raw_parts(p as *const u8, len as usize)
2177+
util::from_raw_parts(p as *const u8, len as usize)
21782178
}
21792179
}
21802180

@@ -2650,7 +2650,7 @@ impl SslRef {
26502650
if data.is_null() {
26512651
None
26522652
} else {
2653-
Some(slice::from_raw_parts(data, len as usize))
2653+
Some(util::from_raw_parts(data, len as usize))
26542654
}
26552655
}
26562656
}
@@ -2928,7 +2928,7 @@ impl SslRef {
29282928
if len < 0 {
29292929
None
29302930
} else {
2931-
Some(slice::from_raw_parts(p as *const u8, len as usize))
2931+
Some(util::from_raw_parts(p as *const u8, len as usize))
29322932
}
29332933
}
29342934
}
@@ -3099,7 +3099,7 @@ impl SslRef {
30993099
if len == 0 {
31003100
None
31013101
} else {
3102-
Some(slice::from_raw_parts(ptr, len))
3102+
Some(util::from_raw_parts(ptr, len))
31033103
}
31043104
}
31053105
}
@@ -3118,7 +3118,7 @@ impl SslRef {
31183118
if len == 0 {
31193119
None
31203120
} else {
3121-
Some(slice::from_raw_parts(ptr, len))
3121+
Some(util::from_raw_parts(ptr, len))
31223122
}
31233123
}
31243124
}
@@ -3137,7 +3137,7 @@ impl SslRef {
31373137
if len == 0 {
31383138
None
31393139
} else {
3140-
Some(slice::from_raw_parts(ptr, len))
3140+
Some(util::from_raw_parts(ptr, len))
31413141
}
31423142
}
31433143
}
@@ -3191,7 +3191,7 @@ impl SslRef {
31913191
if len == 0 {
31923192
None
31933193
} else {
3194-
Some(slice::from_raw_parts(ptr, len))
3194+
Some(util::from_raw_parts(ptr, len))
31953195
}
31963196
}
31973197
}
@@ -3764,7 +3764,7 @@ impl<S: Read + Write> SslStream<S> {
37643764
pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
37653765
// SAFETY: `ssl_read_uninit` does not de-initialize the buffer.
37663766
unsafe {
3767-
self.ssl_read_uninit(slice::from_raw_parts_mut(
3767+
self.ssl_read_uninit(util::from_raw_parts_mut(
37683768
buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
37693769
buf.len(),
37703770
))
@@ -3997,7 +3997,7 @@ impl<S: Read + Write> Read for SslStream<S> {
39973997
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
39983998
// SAFETY: `read_uninit` does not de-initialize the buffer
39993999
unsafe {
4000-
self.read_uninit(slice::from_raw_parts_mut(
4000+
self.read_uninit(util::from_raw_parts_mut(
40014001
buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
40024002
buf.len(),
40034003
))

openssl/src/util.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::error::ErrorStack;
2+
use crate::util;
23
use foreign_types::{ForeignType, ForeignTypeRef};
34
use libc::{c_char, c_int, c_void};
45
use std::any::Any;
@@ -49,7 +50,7 @@ where
4950
let callback = &mut *(cb_state as *mut CallbackState<F>);
5051

5152
let result = panic::catch_unwind(AssertUnwindSafe(|| {
52-
let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize);
53+
let pass_slice = util::from_raw_parts_mut(buf as *mut u8, size as usize);
5354
callback.cb.take().unwrap()(pass_slice)
5455
}));
5556

@@ -91,3 +92,27 @@ pub trait ForeignTypeRefExt: ForeignTypeRef {
9192
}
9293
}
9394
impl<FT: ForeignTypeRef> ForeignTypeRefExt for FT {}
95+
96+
/// The same as `slice::from_raw_parts`, except that `data` may be `NULL` if
97+
/// `len` is 0.
98+
pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
99+
if len == 0 {
100+
&[]
101+
} else {
102+
// Using this to implement the preferred API
103+
#[allow(clippy::disallowed_methods)]
104+
slice::from_raw_parts(data, len)
105+
}
106+
}
107+
108+
/// The same as `slice::from_raw_parts_mut`, except that `data` may be `NULL`
109+
/// if `len` is 0.
110+
pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
111+
if len == 0 {
112+
&mut []
113+
} else {
114+
// Using this to implement the preferred API
115+
#[allow(clippy::disallowed_methods)]
116+
slice::from_raw_parts_mut(data, len)
117+
}
118+
}

0 commit comments

Comments
 (0)