Skip to content

Commit 3151352

Browse files
authored
Merge pull request #233 from elichai/alloc-AlignedType2
Making sure everything is aligned correctly. Succeeder of #141
2 parents 11e9641 + 0638107 commit 3151352

File tree

6 files changed

+100
-64
lines changed

6 files changed

+100
-64
lines changed

no_std_test/src/main.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ use core::intrinsics;
5353
use core::panic::PanicInfo;
5454

5555
use secp256k1::ecdh::SharedSecret;
56+
use secp256k1::ffi::types::AlignedType;
5657
use secp256k1::rand::{self, RngCore};
5758
use secp256k1::serde::Serialize;
5859
use secp256k1::*;
@@ -82,7 +83,7 @@ impl RngCore for FakeRng {
8283

8384
#[start]
8485
fn start(_argc: isize, _argv: *const *const u8) -> isize {
85-
let mut buf = [0u8; 600_000];
86+
let mut buf = [AlignedType::zeroed(); 37_000];
8687
let size = Secp256k1::preallocate_size();
8788
unsafe { libc::printf("needed size: %d\n\0".as_ptr() as _, size) };
8889

@@ -161,5 +162,5 @@ fn panic(info: &PanicInfo) -> ! {
161162
let mut buf = Print::new();
162163
write(&mut buf, *msg).unwrap();
163164
buf.print();
164-
unsafe { intrinsics::abort() }
165+
intrinsics::abort()
165166
}

secp256k1-sys/Cargo.toml

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ features = [ "recovery", "endomorphism", "lowmemory" ]
2121
[build-dependencies]
2222
cc = "1.0.28"
2323

24+
[dev-dependencies]
25+
libc = "0.2"
26+
2427
[features]
2528
default = ["std"]
2629
recovery = []

secp256k1-sys/src/lib.rs

+20-19
Original file line numberDiff line numberDiff line change
@@ -534,19 +534,21 @@ extern "C" {
534534
#[no_mangle]
535535
#[cfg(all(feature = "std", not(feature = "external-symbols")))]
536536
pub unsafe extern "C" fn rustsecp256k1_v0_3_1_context_create(flags: c_uint) -> *mut Context {
537-
use std::mem;
538-
assert!(mem::align_of::<usize>() >= mem::align_of::<u8>());
539-
assert_eq!(mem::size_of::<usize>(), mem::size_of::<&usize>());
540-
541-
let word_size = mem::size_of::<usize>();
542-
let n_words = (secp256k1_context_preallocated_size(flags) + word_size - 1) / word_size;
543-
544-
let buf = vec![0usize; n_words + 1].into_boxed_slice();
545-
let ptr = Box::into_raw(buf) as *mut usize;
546-
::core::ptr::write(ptr, n_words);
547-
let ptr: *mut usize = ptr.offset(1);
548-
549-
secp256k1_context_preallocated_create(ptr as *mut c_void, flags)
537+
use core::mem;
538+
use std::alloc;
539+
assert!(ALIGN_TO >= mem::align_of::<usize>());
540+
assert!(ALIGN_TO >= mem::align_of::<&usize>());
541+
assert!(ALIGN_TO >= mem::size_of::<usize>());
542+
543+
// We need to allocate `ALIGN_TO` more bytes in order to write the amount of bytes back.
544+
let bytes = secp256k1_context_preallocated_size(flags) + ALIGN_TO;
545+
let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap();
546+
let ptr = alloc::alloc(layout);
547+
(ptr as *mut usize).write(bytes);
548+
// We must offset a whole ALIGN_TO in order to preserve the same alignment
549+
// this means we "lose" ALIGN_TO-size_of(usize) for padding.
550+
let ptr = ptr.add(ALIGN_TO) as *mut c_void;
551+
secp256k1_context_preallocated_create(ptr, flags)
550552
}
551553

552554
#[cfg(all(feature = "std", not(feature = "external-symbols")))]
@@ -563,13 +565,12 @@ pub unsafe fn secp256k1_context_create(flags: c_uint) -> *mut Context {
563565
#[no_mangle]
564566
#[cfg(all(feature = "std", not(feature = "external-symbols")))]
565567
pub unsafe extern "C" fn rustsecp256k1_v0_3_1_context_destroy(ctx: *mut Context) {
568+
use std::alloc;
566569
secp256k1_context_preallocated_destroy(ctx);
567-
let ctx: *mut usize = ctx as *mut usize;
568-
569-
let n_words_ptr: *mut usize = ctx.offset(-1);
570-
let n_words: usize = ::core::ptr::read(n_words_ptr);
571-
let slice: &mut [usize] = slice::from_raw_parts_mut(n_words_ptr , n_words+1);
572-
let _ = Box::from_raw(slice as *mut [usize]);
570+
let ptr = (ctx as *mut u8).sub(ALIGN_TO);
571+
let bytes = (ptr as *mut usize).read();
572+
let layout = alloc::Layout::from_size_align(bytes, ALIGN_TO).unwrap();
573+
alloc::dealloc(ptr, layout);
573574
}
574575

575576
#[cfg(all(feature = "std", not(feature = "external-symbols")))]

secp256k1-sys/src/types.rs

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#![allow(non_camel_case_types)]
2-
use core::fmt;
2+
use core::{fmt, mem};
33

44
pub type c_int = i32;
55
pub type c_uchar = u8;
@@ -26,18 +26,39 @@ impl fmt::Debug for c_void {
2626
}
2727
}
2828

29+
/// A type that is as aligned as the biggest alignment for fundamental types in C
30+
/// since C11 that means as aligned as `max_align_t` is.
31+
/// the exact size/alignment is unspecified.
32+
// 16 matches is as big as the biggest alignment in any arch that rust currently supports https://github.com/rust-lang/rust/blob/2c31b45ae878b821975c4ebd94cc1e49f6073fd0/library/std/src/sys_common/alloc.rs
33+
#[repr(align(16))]
34+
#[derive(Default, Copy, Clone)]
35+
pub struct AlignedType([u8; 16]);
36+
37+
impl AlignedType {
38+
pub fn zeroed() -> Self {
39+
AlignedType([0u8; 16])
40+
}
41+
}
42+
43+
pub(crate) const ALIGN_TO: usize = mem::align_of::<AlignedType>();
44+
45+
2946
#[cfg(test)]
3047
mod tests {
48+
extern crate libc;
3149
use std::os::raw;
50+
use std::mem;
3251
use std::any::TypeId;
33-
use types;
52+
use {types, AlignedType};
3453

3554
#[test]
3655
fn verify_types() {
3756
assert_eq!(TypeId::of::<types::c_int>(), TypeId::of::<raw::c_int>());
3857
assert_eq!(TypeId::of::<types::c_uchar>(), TypeId::of::<raw::c_uchar>());
3958
assert_eq!(TypeId::of::<types::c_uint>(), TypeId::of::<raw::c_uint>());
4059
assert_eq!(TypeId::of::<types::c_char>(), TypeId::of::<raw::c_char>());
60+
61+
assert!(mem::align_of::<AlignedType>() >= mem::align_of::<self::libc::max_align_t>());
4162
}
4263
}
4364

src/context.rs

+34-28
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use core::marker::PhantomData;
2-
use core::mem::ManuallyDrop;
3-
use ptr;
4-
use ffi::{self, CPtr};
2+
use core::mem::{self, ManuallyDrop};
3+
use ffi::{self, CPtr, types::AlignedType};
54
use ffi::types::{c_uint, c_void};
65
use Error;
76
use Secp256k1;
@@ -50,7 +49,7 @@ pub unsafe trait Context : private::Sealed {
5049
/// A constant description of the context.
5150
const DESCRIPTION: &'static str;
5251
/// A function to deallocate the memory when the context is dropped.
53-
unsafe fn deallocate(ptr: *mut [u8]);
52+
unsafe fn deallocate(ptr: *mut u8, size: usize);
5453
}
5554

5655
/// Marker trait for indicating that an instance of `Secp256k1` can be used for signing.
@@ -93,6 +92,8 @@ mod std_only {
9392
impl private::Sealed for VerifyOnly {}
9493

9594
use super::*;
95+
use std::alloc;
96+
const ALIGN_TO: usize = mem::align_of::<AlignedType>();
9697

9798
/// Represents the set of capabilities needed for signing.
9899
pub enum SignOnly {}
@@ -113,26 +114,29 @@ mod std_only {
113114
const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
114115
const DESCRIPTION: &'static str = "signing only";
115116

116-
unsafe fn deallocate(ptr: *mut [u8]) {
117-
let _ = Box::from_raw(ptr);
117+
unsafe fn deallocate(ptr: *mut u8, size: usize) {
118+
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
119+
alloc::dealloc(ptr, layout);
118120
}
119121
}
120122

121123
unsafe impl Context for VerifyOnly {
122124
const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
123125
const DESCRIPTION: &'static str = "verification only";
124126

125-
unsafe fn deallocate(ptr: *mut [u8]) {
126-
let _ = Box::from_raw(ptr);
127+
unsafe fn deallocate(ptr: *mut u8, size: usize) {
128+
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
129+
alloc::dealloc(ptr, layout);
127130
}
128131
}
129132

130133
unsafe impl Context for All {
131134
const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS;
132135
const DESCRIPTION: &'static str = "all capabilities";
133136

134-
unsafe fn deallocate(ptr: *mut [u8]) {
135-
let _ = Box::from_raw(ptr);
137+
unsafe fn deallocate(ptr: *mut u8, size: usize) {
138+
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
139+
alloc::dealloc(ptr, layout);
136140
}
137141
}
138142

@@ -142,12 +146,13 @@ mod std_only {
142146
#[cfg(target_arch = "wasm32")]
143147
ffi::types::sanity_checks_for_wasm();
144148

145-
let buf = vec![0u8; Self::preallocate_size_gen()].into_boxed_slice();
146-
let ptr = Box::into_raw(buf);
149+
let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
150+
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
151+
let ptr = unsafe {alloc::alloc(layout)};
147152
Secp256k1 {
148153
ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS) },
149154
phantom: PhantomData,
150-
buf: ptr,
155+
size,
151156
}
152157
}
153158
}
@@ -181,12 +186,13 @@ mod std_only {
181186

182187
impl<C: Context> Clone for Secp256k1<C> {
183188
fn clone(&self) -> Secp256k1<C> {
184-
let clone_size = unsafe {ffi::secp256k1_context_preallocated_clone_size(self.ctx)};
185-
let ptr_buf = Box::into_raw(vec![0u8; clone_size].into_boxed_slice());
189+
let size = unsafe {ffi::secp256k1_context_preallocated_clone_size(self.ctx as _)};
190+
let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
191+
let ptr = unsafe {alloc::alloc(layout)};
186192
Secp256k1 {
187-
ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx, ptr_buf as *mut c_void) },
193+
ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx, ptr as *mut c_void) },
188194
phantom: PhantomData,
189-
buf: ptr_buf,
195+
size,
190196
}
191197
}
192198
}
@@ -202,7 +208,7 @@ unsafe impl<'buf> Context for SignOnlyPreallocated<'buf> {
202208
const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
203209
const DESCRIPTION: &'static str = "signing only";
204210

205-
unsafe fn deallocate(_ptr: *mut [u8]) {
211+
unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
206212
// Allocated by the user
207213
}
208214
}
@@ -211,7 +217,7 @@ unsafe impl<'buf> Context for VerifyOnlyPreallocated<'buf> {
211217
const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
212218
const DESCRIPTION: &'static str = "verification only";
213219

214-
unsafe fn deallocate(_ptr: *mut [u8]) {
220+
unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
215221
// Allocated by the user
216222
}
217223
}
@@ -220,14 +226,14 @@ unsafe impl<'buf> Context for AllPreallocated<'buf> {
220226
const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS;
221227
const DESCRIPTION: &'static str = "all capabilities";
222228

223-
unsafe fn deallocate(_ptr: *mut [u8]) {
229+
unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
224230
// Allocated by the user
225231
}
226232
}
227233

228234
impl<'buf, C: Context + 'buf> Secp256k1<C> {
229235
/// Lets you create a context with preallocated buffer in a generic manner(sign/verify/all)
230-
pub fn preallocated_gen_new(buf: &'buf mut [u8]) -> Result<Secp256k1<C>, Error> {
236+
pub fn preallocated_gen_new(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<C>, Error> {
231237
#[cfg(target_arch = "wasm32")]
232238
ffi::types::sanity_checks_for_wasm();
233239

@@ -241,14 +247,14 @@ impl<'buf, C: Context + 'buf> Secp256k1<C> {
241247
C::FLAGS)
242248
},
243249
phantom: PhantomData,
244-
buf: buf as *mut [u8],
250+
size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
245251
})
246252
}
247253
}
248254

249255
impl<'buf> Secp256k1<AllPreallocated<'buf>> {
250256
/// Creates a new Secp256k1 context with all capabilities
251-
pub fn preallocated_new(buf: &'buf mut [u8]) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
257+
pub fn preallocated_new(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
252258
Secp256k1::preallocated_gen_new(buf)
253259
}
254260
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context
@@ -271,14 +277,14 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> {
271277
ManuallyDrop::new(Secp256k1 {
272278
ctx: raw_ctx,
273279
phantom: PhantomData,
274-
buf: ptr::null_mut::<[u8;0]>() as *mut [u8] ,
280+
size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
275281
})
276282
}
277283
}
278284

279285
impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
280286
/// Creates a new Secp256k1 context that can only be used for signing
281-
pub fn preallocated_signing_only(buf: &'buf mut [u8]) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
287+
pub fn preallocated_signing_only(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
282288
Secp256k1::preallocated_gen_new(buf)
283289
}
284290

@@ -303,14 +309,14 @@ impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
303309
ManuallyDrop::new(Secp256k1 {
304310
ctx: raw_ctx,
305311
phantom: PhantomData,
306-
buf: ptr::null_mut::<[u8;0]>() as *mut [u8] ,
312+
size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
307313
})
308314
}
309315
}
310316

311317
impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
312318
/// Creates a new Secp256k1 context that can only be used for verification
313-
pub fn preallocated_verification_only(buf: &'buf mut [u8]) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
319+
pub fn preallocated_verification_only(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
314320
Secp256k1::preallocated_gen_new(buf)
315321
}
316322

@@ -335,7 +341,7 @@ impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
335341
ManuallyDrop::new(Secp256k1 {
336342
ctx: raw_ctx,
337343
phantom: PhantomData,
338-
buf: ptr::null_mut::<[u8;0]>() as *mut [u8] ,
344+
size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
339345
})
340346
}
341347
}

0 commit comments

Comments
 (0)