@@ -40,6 +40,7 @@ pub mod types;
40
40
pub mod recovery;
41
41
42
42
use core:: { slice, ptr} ;
43
+ use core:: sync:: atomic:: AtomicPtr ;
43
44
use types:: * ;
44
45
45
46
/// Flag for context to enable no precomputation
@@ -576,6 +577,91 @@ pub unsafe fn secp256k1_context_destroy(ctx: *mut Context) {
576
577
rustsecp256k1_v0_4_1_context_destroy ( ctx)
577
578
}
578
579
580
+ static ABORT_HANDLER : AtomicPtr < fn ( & dyn core:: fmt:: Display ) -> !> = AtomicPtr :: new ( core:: ptr:: null_mut ( ) ) ;
581
+
582
+ /// Registers custom abort handler globally.
583
+ ///
584
+ /// libsecp256k1 may want to abort in case of invalid inputs. These are definitely bugs.
585
+ /// The default handler aborts with `std` and **loops forever without `std`**.
586
+ /// You can provide your own handler if you wish to override this behavior.
587
+ ///
588
+ /// This function is `unsafe` because the supplied handler MUST NOT unwind
589
+ /// since unwinding would cross FFI boundary.
590
+ /// Double panic is *also* wrong!
591
+ ///
592
+ /// Supplying panicking function may be safe if your program is compiled with `panic = "abort"`.
593
+ /// It's **not** recommended to call this function from library crates - only binaries, somewhere
594
+ /// near the beginning of `main()`.
595
+ ///
596
+ /// The parameter passed to the handler is an error message that can be displayed (logged).
597
+ ///
598
+ /// Note that the handler is a reference to function pointer rather than a function pointer itself
599
+ /// because of [a missing Rust feature](https://github.com/rust-lang/rfcs/issues/2481).
600
+ /// It's a bit tricky to use it, so here's an example:
601
+ ///
602
+ /// ```
603
+ /// fn custom_abort(message: &dyn std::fmt::Display) -> ! {
604
+ /// eprintln!("this is a custom abort handler: {}", message);
605
+ /// std::process::abort()
606
+ /// }
607
+ /// // We need to put the function pointer into a static variable because we need a 'static
608
+ /// // reference to variable holding function pointer.
609
+ /// static CUSTOM_ABORT: fn (&dyn std::fmt::Display) -> ! = custom_abort;
610
+ ///
611
+ /// unsafe {
612
+ /// secp256k1_sys::set_abort_handler(&CUSTOM_ABORT);
613
+ /// }
614
+ /// ```
615
+ ///
616
+ /// The function does not guarantee any memory ordering so you MUST NOT abuse it for synchronization!
617
+ /// Use some other synchronization primitive if you need to synchronize.
618
+ pub unsafe fn set_abort_handler ( handler : & ' static fn ( & dyn core:: fmt:: Display ) -> !) {
619
+ ABORT_HANDLER . store ( ptr_const_to_mut_cast ( handler) , core:: sync:: atomic:: Ordering :: Relaxed ) ;
620
+ }
621
+
622
+ /// FFI-safe replacement for panic
623
+ ///
624
+ /// Prints to stderr and aborts with `std`, loops forever without `std`.
625
+ #[ cfg_attr( not( feature = "std" ) , allow( unused) ) ]
626
+ fn abort_fallback ( message : impl core:: fmt:: Display ) -> ! {
627
+ #[ cfg( feature = "std" ) ]
628
+ {
629
+ eprintln ! ( "[libsecp256k1] {}" , message) ;
630
+ std:: process:: abort ( )
631
+ }
632
+ #[ cfg( not( feature = "std" ) ) ]
633
+ {
634
+ // no better way to "abort" without std :(
635
+ loop { }
636
+ }
637
+ }
638
+
639
+ /// Ensures that types both sides of cast stay in sync and only the constness changes.
640
+ ///
641
+ /// This elliminates the risk that if we change the type signature of abort handler the cast
642
+ /// silently converts the types and causes UB.
643
+ fn ptr_mut_to_const_cast < T > ( ptr : * mut T ) -> * const T {
644
+ ptr as _
645
+ }
646
+
647
+ /// Ensures that types both sides of cast stay in sync and only the constness changes.
648
+ ///
649
+ /// This elliminates the risk that if we change the type signature of abort handler the cast
650
+ /// silently converts the types and causes UB.
651
+ fn ptr_const_to_mut_cast < T > ( ptr : * const T ) -> * mut T {
652
+ ptr as _
653
+ }
654
+
655
+ fn abort_with_message ( message : impl core:: fmt:: Display ) -> ! {
656
+ unsafe {
657
+ let handler = ptr_mut_to_const_cast ( ABORT_HANDLER . load ( core:: sync:: atomic:: Ordering :: Relaxed ) ) ;
658
+ if !handler. is_null ( ) {
659
+ ( * handler) ( & message)
660
+ } else {
661
+ abort_fallback ( message)
662
+ }
663
+ }
664
+ }
579
665
580
666
/// **This function is an override for the C function, this is the an edited version of the original description:**
581
667
///
@@ -601,7 +687,7 @@ pub unsafe extern "C" fn rustsecp256k1_v0_4_1_default_illegal_callback_fn(messag
601
687
use core:: str;
602
688
let msg_slice = slice:: from_raw_parts ( message as * const u8 , strlen ( message) ) ;
603
689
let msg = str:: from_utf8_unchecked ( msg_slice) ;
604
- panic ! ( "[libsecp256k1] illegal argument. {}" , msg) ;
690
+ abort_with_message ( format_args ! ( "illegal argument. {}" , msg) ) ;
605
691
}
606
692
607
693
/// **This function is an override for the C function, this is the an edited version of the original description:**
@@ -624,7 +710,7 @@ pub unsafe extern "C" fn rustsecp256k1_v0_4_1_default_error_callback_fn(message:
624
710
use core:: str;
625
711
let msg_slice = slice:: from_raw_parts ( message as * const u8 , strlen ( message) ) ;
626
712
let msg = str:: from_utf8_unchecked ( msg_slice) ;
627
- panic ! ( "[libsecp256k1] internal consistency check failed {}" , msg) ;
713
+ abort_with_message ( format_args ! ( "internal consistency check failed {}" , msg) ) ;
628
714
}
629
715
630
716
#[ cfg( not( rust_secp_no_symbol_renaming) ) ]
@@ -833,7 +919,7 @@ mod fuzz_dummy {
833
919
* output = 4 ;
834
920
ptr:: copy ( ( * pk) . 0 . as_ptr ( ) , output. offset ( 1 ) , 64 ) ;
835
921
} else {
836
- panic ! ( "Bad flags" ) ;
922
+ abort_with_message ( format_args ! ( "Bad flags" ) ) ;
837
923
}
838
924
1
839
925
}
0 commit comments