Skip to content

Commit ca2dd93

Browse files
committed
Merge #551: secp-sys: Use NonNull in API instead of *mut T
9b07e8e secp-sys: Use NonNull in API instead of *mut T (Tobin C. Harding) Pull request description: 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 ### Note The description above fully explains the issue to the best of my knowledge, if the description is not spot on then I'm not fully understanding the issue. Please correct me if this is the case. > One unfortunate thing is that this means that we wouldn't be able to implement CPtr for secp256k1::Context, which is our designated "expose types from secp256k1-sys which is not stable" semver escape hatch. You've lost me here? `secp256k1::Context` is a trait did you mean `secp256k1::Secp256k1` or `secp256k1_sys::Context`? ACKs for top commit: apoelstra: ACK 9b07e8e Tree-SHA512: 37aceebfa62e590ce8cc282c35b014ad018e5cfbea99402ed3aa1fcbaa69e01a01c1c1f32351f5f15a7d270e31da5b239ee5bc11d2343cf866082ad85df6a622
2 parents 5256139 + 9b07e8e commit ca2dd93

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)