Skip to content

Commit 9b07e8e

Browse files
committed
secp-sys: Use NonNull in API instead of *mut T
Currently we expect non-null pointers when we take `*mut T` parameters, however we do not check that the pointers are non-null because we never set VERIFY in our C build. We can use the `NonNull` type to enforce no-null-ness as long as we use `NonNull::new`. In a couple of instances we manually check that a buffer is not empty and therefore that the pointer to it is non-null so we can safely use `NonNull::new_unchecked`. Replace mutable pointer parameters `*mut T` (e.g. `*mut c_void`) and return types with `NonNull<T>`. Fix #546
1 parent 5256139 commit 9b07e8e

File tree

3 files changed

+49
-60
lines changed

3 files changed

+49
-60
lines changed

secp256k1-sys/src/lib.rs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub mod types;
3939
pub mod recovery;
4040

4141
use core::{slice, ptr};
42+
use core::ptr::NonNull;
4243
use types::*;
4344

4445
/// Flag for context to enable no precomputation
@@ -512,7 +513,7 @@ extern "C" {
512513

513514
// Contexts
514515
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_context_preallocated_destroy")]
515-
pub fn secp256k1_context_preallocated_destroy(cx: *mut Context);
516+
pub fn secp256k1_context_preallocated_destroy(cx: NonNull<Context>);
516517

517518
// Signatures
518519
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_ecdsa_signature_parse_der")]
@@ -585,16 +586,16 @@ extern "C" {
585586
pub fn secp256k1_context_preallocated_size(flags: c_uint) -> size_t;
586587

587588
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_context_preallocated_create")]
588-
pub fn secp256k1_context_preallocated_create(prealloc: *mut c_void, flags: c_uint) -> *mut Context;
589+
pub fn secp256k1_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context>;
589590

590591
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_context_preallocated_clone_size")]
591592
pub fn secp256k1_context_preallocated_clone_size(cx: *const Context) -> size_t;
592593

593594
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_context_preallocated_clone")]
594-
pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context;
595+
pub fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context>;
595596

596597
#[cfg_attr(not(rust_secp_no_symbol_renaming), link_name = "rustsecp256k1_v0_6_1_context_randomize")]
597-
pub fn secp256k1_context_randomize(cx: *mut Context,
598+
pub fn secp256k1_context_randomize(cx: NonNull<Context>,
598599
seed32: *const c_uchar)
599600
-> c_int;
600601
// Pubkeys
@@ -789,7 +790,7 @@ extern "C" {
789790
/// The newly created secp256k1 raw context.
790791
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
791792
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
792-
pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context {
793+
pub unsafe fn secp256k1_context_create(flags: c_uint) -> NonNull<Context> {
793794
rustsecp256k1_v0_6_1_context_create(flags)
794795
}
795796

@@ -800,7 +801,7 @@ pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context {
800801
#[allow(clippy::missing_safety_doc)] // Documented above.
801802
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
802803
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
803-
pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_create(flags: c_uint) -> *mut Context {
804+
pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_create(flags: c_uint) -> NonNull<Context> {
804805
use core::mem;
805806
use crate::alloc::alloc;
806807
assert!(ALIGN_TO >= mem::align_of::<usize>());
@@ -817,7 +818,8 @@ pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_create(flags: c_uint) -> *
817818
(ptr as *mut usize).write(bytes);
818819
// We must offset a whole ALIGN_TO in order to preserve the same alignment
819820
// this means we "lose" ALIGN_TO-size_of(usize) for padding.
820-
let ptr = ptr.add(ALIGN_TO) as *mut c_void;
821+
let ptr = ptr.add(ALIGN_TO);
822+
let ptr = NonNull::new_unchecked(ptr as *mut c_void); // Checked above.
821823
secp256k1_context_preallocated_create(ptr, flags)
822824
}
823825

@@ -832,17 +834,18 @@ pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_create(flags: c_uint) -> *
832834
/// `ctx` must be a valid pointer to a block of memory created using [`secp256k1_context_create`].
833835
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
834836
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
835-
pub unsafe fn secp256k1_context_destroy(ctx: *mut Context) {
837+
pub unsafe fn secp256k1_context_destroy(ctx: NonNull<Context>) {
836838
rustsecp256k1_v0_6_1_context_destroy(ctx)
837839
}
838840

839841
#[no_mangle]
840842
#[allow(clippy::missing_safety_doc)] // Documented above.
841843
#[cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))]
842844
#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", not(rust_secp_no_symbol_renaming)))))]
843-
pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_destroy(ctx: *mut Context) {
845+
pub unsafe extern "C" fn rustsecp256k1_v0_6_1_context_destroy(mut ctx: NonNull<Context>) {
844846
use crate::alloc::alloc;
845847
secp256k1_context_preallocated_destroy(ctx);
848+
let ctx: *mut Context = ctx.as_mut();
846849
let ptr = (ctx as *mut u8).sub(ALIGN_TO);
847850
let bytes = (ptr as *mut usize).read();
848851
let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap();
@@ -966,8 +969,8 @@ mod fuzz_dummy {
966969

967970
extern "C" {
968971
fn rustsecp256k1_v0_6_1_context_preallocated_size(flags: c_uint) -> size_t;
969-
fn rustsecp256k1_v0_6_1_context_preallocated_create(prealloc: *mut c_void, flags: c_uint) -> *mut Context;
970-
fn rustsecp256k1_v0_6_1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context;
972+
fn rustsecp256k1_v0_6_1_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context>;
973+
fn rustsecp256k1_v0_6_1_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context>;
971974
}
972975

973976
#[cfg(feature = "lowmemory")]
@@ -985,7 +988,7 @@ mod fuzz_dummy {
985988
const HAVE_CONTEXT_WORKING: usize = 1;
986989
const HAVE_CONTEXT_DONE: usize = 2;
987990
static mut PREALLOCATED_CONTEXT: [u8; CTX_SIZE] = [0; CTX_SIZE];
988-
pub unsafe fn secp256k1_context_preallocated_create(prealloc: *mut c_void, flags: c_uint) -> *mut Context {
991+
pub unsafe fn secp256k1_context_preallocated_create(prealloc: NonNull<c_void>, flags: c_uint) -> NonNull<Context> {
989992
// While applications should generally avoid creating too many contexts, sometimes fuzzers
990993
// perform tasks repeatedly which real applications may only do rarely. Thus, we want to
991994
// avoid being overly slow here. We do so by having a static context and copying it into
@@ -998,9 +1001,9 @@ mod fuzz_dummy {
9981001
if have_ctx == HAVE_CONTEXT_NONE {
9991002
assert!(rustsecp256k1_v0_6_1_context_preallocated_size(SECP256K1_START_SIGN | SECP256K1_START_VERIFY) + std::mem::size_of::<c_uint>() <= CTX_SIZE);
10001003
assert_eq!(rustsecp256k1_v0_6_1_context_preallocated_create(
1001-
PREALLOCATED_CONTEXT[..].as_ptr() as *mut c_void,
1004+
NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut c_void),
10021005
SECP256K1_START_SIGN | SECP256K1_START_VERIFY),
1003-
PREALLOCATED_CONTEXT[..].as_ptr() as *mut Context);
1006+
NonNull::new_unchecked(PREALLOCATED_CONTEXT[..].as_mut_ptr() as *mut Context));
10041007
assert_eq!(HAVE_PREALLOCATED_CONTEXT.swap(HAVE_CONTEXT_DONE, Ordering::AcqRel),
10051008
HAVE_CONTEXT_WORKING);
10061009
} else if have_ctx == HAVE_CONTEXT_DONE {
@@ -1015,25 +1018,25 @@ mod fuzz_dummy {
10151018
std::thread::yield_now();
10161019
}
10171020
}
1018-
ptr::copy_nonoverlapping(PREALLOCATED_CONTEXT[..].as_ptr(), prealloc as *mut u8, CTX_SIZE);
1019-
let ptr = (prealloc as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
1021+
ptr::copy_nonoverlapping(PREALLOCATED_CONTEXT[..].as_ptr(), prealloc.as_ptr() as *mut u8, CTX_SIZE);
1022+
let ptr = (prealloc.as_ptr()).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
10201023
(ptr as *mut c_uint).write(flags);
1021-
prealloc as *mut Context
1024+
NonNull::new_unchecked(prealloc.as_ptr() as *mut Context)
10221025
}
10231026
pub unsafe fn secp256k1_context_preallocated_clone_size(_cx: *const Context) -> size_t { CTX_SIZE }
1024-
pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: *mut c_void) -> *mut Context {
1027+
pub unsafe fn secp256k1_context_preallocated_clone(cx: *const Context, prealloc: NonNull<c_void>) -> NonNull<Context> {
10251028
let orig_ptr = (cx as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
1026-
let new_ptr = (prealloc as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
1029+
let new_ptr = (prealloc.as_ptr() as *mut u8).add(CTX_SIZE).sub(std::mem::size_of::<c_uint>());
10271030
let flags = (orig_ptr as *mut c_uint).read();
10281031
(new_ptr as *mut c_uint).write(flags);
10291032
rustsecp256k1_v0_6_1_context_preallocated_clone(cx, prealloc)
10301033
}
10311034

1032-
pub unsafe fn secp256k1_context_randomize(cx: *mut Context,
1035+
pub unsafe fn secp256k1_context_randomize(cx: NonNull<Context>,
10331036
_seed32: *const c_uchar)
10341037
-> c_int {
10351038
// This function is really slow, and unsuitable for fuzzing
1036-
check_context_flags(cx, 0);
1039+
check_context_flags(cx.as_ptr(), 0);
10371040
1
10381041
}
10391042

src/context.rs

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -204,18 +204,12 @@ mod alloc_only {
204204
let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
205205
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
206206
let ptr = unsafe { alloc::alloc(layout) };
207-
if ptr.is_null() {
208-
alloc::handle_alloc_error(layout);
209-
}
207+
let ptr = NonNull::new(ptr as *mut c_void)
208+
.unwrap_or_else(|| alloc::handle_alloc_error(layout));
210209

211210
#[allow(unused_mut)] // ctx is not mutated under some feature combinations.
212211
let mut ctx = Secp256k1 {
213-
ctx: unsafe {
214-
NonNull::new_unchecked(ffi::secp256k1_context_preallocated_create(
215-
ptr as *mut c_void,
216-
C::FLAGS,
217-
))
218-
},
212+
ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr, C::FLAGS) },
219213
phantom: PhantomData,
220214
};
221215

@@ -269,16 +263,11 @@ mod alloc_only {
269263
let size = unsafe { ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr()) };
270264
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
271265
let ptr = unsafe { alloc::alloc(layout) };
272-
if ptr.is_null() {
273-
alloc::handle_alloc_error(layout);
274-
}
266+
let ptr = NonNull::new(ptr as *mut c_void)
267+
.unwrap_or_else(|| alloc::handle_alloc_error(layout));
268+
275269
Secp256k1 {
276-
ctx: unsafe {
277-
NonNull::new_unchecked(ffi::secp256k1_context_preallocated_clone(
278-
self.ctx.as_ptr(),
279-
ptr as *mut c_void,
280-
))
281-
},
270+
ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx.as_ptr(), ptr) },
282271
phantom: PhantomData,
283272
}
284273
}
@@ -327,13 +316,11 @@ impl<'buf, C: Context + 'buf> Secp256k1<C> {
327316
if buf.len() < Self::preallocate_size_gen() {
328317
return Err(Error::NotEnoughMemory);
329318
}
319+
// Safe because buf is not null since it is not empty.
320+
let buf = unsafe { NonNull::new_unchecked(buf.as_mut_c_ptr() as *mut c_void) };
321+
330322
Ok(Secp256k1 {
331-
ctx: unsafe {
332-
NonNull::new_unchecked(ffi::secp256k1_context_preallocated_create(
333-
buf.as_mut_c_ptr() as *mut c_void,
334-
C::FLAGS,
335-
))
336-
},
323+
ctx: unsafe { ffi::secp256k1_context_preallocated_create(buf, AllPreallocated::FLAGS) },
337324
phantom: PhantomData,
338325
})
339326
}
@@ -361,9 +348,9 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> {
361348
/// * Violating these may lead to Undefined Behavior.
362349
///
363350
pub unsafe fn from_raw_all(
364-
raw_ctx: *mut ffi::Context,
351+
raw_ctx: NonNull<ffi::Context>,
365352
) -> ManuallyDrop<Secp256k1<AllPreallocated<'buf>>> {
366-
ManuallyDrop::new(Secp256k1 { ctx: NonNull::new_unchecked(raw_ctx), phantom: PhantomData })
353+
ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
367354
}
368355
}
369356

@@ -392,9 +379,9 @@ impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
392379
/// * This list *is not* exhaustive, and any violation may lead to Undefined Behavior.
393380
///
394381
pub unsafe fn from_raw_signing_only(
395-
raw_ctx: *mut ffi::Context,
382+
raw_ctx: NonNull<ffi::Context>,
396383
) -> ManuallyDrop<Secp256k1<SignOnlyPreallocated<'buf>>> {
397-
ManuallyDrop::new(Secp256k1 { ctx: NonNull::new_unchecked(raw_ctx), phantom: PhantomData })
384+
ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
398385
}
399386
}
400387

@@ -423,8 +410,8 @@ impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
423410
/// * This list *is not* exhaustive, and any violation may lead to Undefined Behavior.
424411
///
425412
pub unsafe fn from_raw_verification_only(
426-
raw_ctx: *mut ffi::Context,
413+
raw_ctx: NonNull<ffi::Context>,
427414
) -> ManuallyDrop<Secp256k1<VerifyOnlyPreallocated<'buf>>> {
428-
ManuallyDrop::new(Secp256k1 { ctx: NonNull::new_unchecked(raw_ctx), phantom: PhantomData })
415+
ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
429416
}
430417
}

src/lib.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ impl<C: Context> Drop for Secp256k1<C> {
389389
fn drop(&mut self) {
390390
unsafe {
391391
let size = ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr());
392-
ffi::secp256k1_context_preallocated_destroy(self.ctx.as_ptr());
392+
ffi::secp256k1_context_preallocated_destroy(self.ctx);
393393

394394
C::deallocate(self.ctx.as_ptr() as _, size);
395395
}
@@ -434,7 +434,7 @@ impl<C: Context> Secp256k1<C> {
434434
/// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell.
435435
pub fn seeded_randomize(&mut self, seed: &[u8; 32]) {
436436
unsafe {
437-
let err = ffi::secp256k1_context_randomize(self.ctx.as_ptr(), seed.as_c_ptr());
437+
let err = ffi::secp256k1_context_randomize(self.ctx, seed.as_c_ptr());
438438
// This function cannot fail; it has an error return for future-proofing.
439439
// We do not expose this error since it is impossible to hit, and we have
440440
// precedent for not exposing impossible errors (for example in
@@ -558,12 +558,11 @@ mod tests {
558558
let ctx_sign = unsafe { ffi::secp256k1_context_create(SignOnlyPreallocated::FLAGS) };
559559
let ctx_vrfy = unsafe { ffi::secp256k1_context_create(VerifyOnlyPreallocated::FLAGS) };
560560

561-
let full: Secp256k1<AllPreallocated> =
562-
Secp256k1 { ctx: unsafe { NonNull::new_unchecked(ctx_full) }, phantom: PhantomData };
561+
let full: Secp256k1<AllPreallocated> = Secp256k1 { ctx: ctx_full, phantom: PhantomData };
563562
let sign: Secp256k1<SignOnlyPreallocated> =
564-
Secp256k1 { ctx: unsafe { NonNull::new_unchecked(ctx_sign) }, phantom: PhantomData };
563+
Secp256k1 { ctx: ctx_sign, phantom: PhantomData };
565564
let vrfy: Secp256k1<VerifyOnlyPreallocated> =
566-
Secp256k1 { ctx: unsafe { NonNull::new_unchecked(ctx_vrfy) }, phantom: PhantomData };
565+
Secp256k1 { ctx: ctx_vrfy, phantom: PhantomData };
567566

568567
let (sk, pk) = full.generate_keypair(&mut rand::thread_rng());
569568
let msg = Message::from_slice(&[2u8; 32]).unwrap();
@@ -593,9 +592,9 @@ mod tests {
593592
let ctx_sign = Secp256k1::signing_only();
594593
let ctx_vrfy = Secp256k1::verification_only();
595594

596-
let mut full = unsafe { Secp256k1::from_raw_all(ctx_full.ctx.as_ptr()) };
597-
let mut sign = unsafe { Secp256k1::from_raw_signing_only(ctx_sign.ctx.as_ptr()) };
598-
let mut vrfy = unsafe { Secp256k1::from_raw_verification_only(ctx_vrfy.ctx.as_ptr()) };
595+
let mut full = unsafe { Secp256k1::from_raw_all(ctx_full.ctx) };
596+
let mut sign = unsafe { Secp256k1::from_raw_signing_only(ctx_sign.ctx) };
597+
let mut vrfy = unsafe { Secp256k1::from_raw_verification_only(ctx_vrfy.ctx) };
599598

600599
let (sk, pk) = full.generate_keypair(&mut rand::thread_rng());
601600
let msg = Message::from_slice(&[2u8; 32]).unwrap();

0 commit comments

Comments
 (0)