@@ -19,7 +19,6 @@ use binaryninjacore_sys::*;
19
19
pub use binaryninjacore_sys:: BNModificationStatus as ModificationStatus ;
20
20
21
21
use std:: marker:: PhantomData ;
22
- use std:: mem;
23
22
use std:: mem:: MaybeUninit ;
24
23
use std:: os:: raw:: c_void;
25
24
use std:: ptr;
@@ -454,17 +453,34 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
454
453
return Err ( ( ) ) ;
455
454
}
456
455
457
- // wildly unsafe struct representing the context of a BNCustomBinaryView
458
- // this type should *never* be allowed to drop as the fields are in varying
459
- // states of uninitialized/already consumed throughout the life of the object.
456
+ // struct representing the context of a BNCustomBinaryView. Can be safely
457
+ // dropped at any moment.
460
458
struct CustomViewContext < V >
461
459
where
462
460
V : CustomBinaryView ,
463
461
{
464
- view : mem:: MaybeUninit < V > ,
465
462
raw_handle : * mut BNBinaryView ,
466
- initialized : bool ,
467
- args : V :: Args ,
463
+ state : CustomViewContextState < V > ,
464
+ }
465
+
466
+ enum CustomViewContextState < V >
467
+ where
468
+ V : CustomBinaryView ,
469
+ {
470
+ Uninitialized { args : V :: Args } ,
471
+ Initialized { view : V } ,
472
+ // dummy state, used as a helper to change states, only happen if the
473
+ // `new` or `init` function fails.
474
+ None ,
475
+ }
476
+
477
+ impl < V : CustomBinaryView > CustomViewContext < V > {
478
+ fn assume_init_ref ( & self ) -> & V {
479
+ let CustomViewContextState :: Initialized { view } = & self . state else {
480
+ panic ! ( "CustomViewContextState in invalid state" ) ;
481
+ } ;
482
+ view
483
+ }
468
484
}
469
485
470
486
extern "C" fn cb_init < V > ( ctxt : * mut c_void ) -> bool
@@ -475,23 +491,24 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
475
491
let context = & mut * ( ctxt as * mut CustomViewContext <V >) ;
476
492
let handle = BinaryView :: ref_from_raw( context. raw_handle) ;
477
493
478
- match V :: new( handle. as_ref( ) , & context. args) {
479
- Ok ( v) => {
480
- ptr:: write( & mut context. view, mem:: MaybeUninit :: new( v) ) ;
481
- context. initialized = true ;
482
-
483
- match context
484
- . view
485
- . assume_init_mut( )
486
- . init( ptr:: read( & context. args) )
487
- {
488
- Ok ( _) => true ,
489
- Err ( _) => {
490
- error!( "CustomBinaryView::init failed; custom view returned Err" ) ;
491
- false
492
- }
494
+ // take the uninitialized state and use the args to call init
495
+ let mut state = CustomViewContextState :: None ;
496
+ core:: mem:: swap( & mut context. state, & mut state) ;
497
+ let CustomViewContextState :: Uninitialized { args } = state else {
498
+ panic!( "CustomViewContextState in invalid state" ) ;
499
+ } ;
500
+ match V :: new( handle. as_ref( ) , & args) {
501
+ Ok ( mut view) => match view. init( args) {
502
+ Ok ( _) => {
503
+ // put the initialized state
504
+ context. state = CustomViewContextState :: Initialized { view } ;
505
+ true
493
506
}
494
- }
507
+ Err ( _) => {
508
+ error!( "CustomBinaryView::init failed; custom view returned Err" ) ;
509
+ false
510
+ }
511
+ } ,
495
512
Err ( _) => {
496
513
error!( "CustomBinaryView::new failed; custom view returned Err" ) ;
497
514
false
@@ -506,48 +523,43 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
506
523
{
507
524
ffi_wrap ! ( "BinaryViewBase::freeObject" , unsafe {
508
525
let context = ctxt as * mut CustomViewContext <V >;
509
- let context = * Box :: from_raw( context) ;
510
-
511
- if context. initialized {
512
- mem:: forget( context. args) ; // already consumed
513
- // mem::drop(context.view); // cb_init was called
514
- } else {
515
- mem:: drop( context. args) ; // never consumed
516
- // mem::forget(context.view); // cb_init was not called, is uninit
517
-
518
- if context. raw_handle. is_null( ) {
519
- // being called here is essentially a guarantee that BNCreateBinaryViewOfType
520
- // is above above us on the call stack somewhere -- no matter what we do, a crash
521
- // is pretty much certain at this point.
522
- //
523
- // this has been observed when two views of the same BinaryViewType are created
524
- // against the same BNFileMetaData object, and one of the views gets freed while
525
- // the second one is being initialized -- somehow the partially initialized one
526
- // gets freed before BNCreateBinaryViewOfType returns.
527
- //
528
- // multiples views of the same BinaryViewType in a BNFileMetaData object are
529
- // prohibited, so an API contract was violated in order to get here.
530
- //
531
- // if we're here, it's too late to do anything about it, though we can at least not
532
- // run the destructor on the custom view since that memory is unitialized.
533
- error!(
534
- "BinaryViewBase::freeObject called on partially initialized object! crash imminent!"
535
- ) ;
536
- } else if !context. initialized {
537
- // making it here means somebody went out of their way to leak a BinaryView
538
- // after calling BNCreateCustomView and never gave the BNBinaryView handle
539
- // to the core (which would have called cb_init)
540
- //
541
- // the result is a half-initialized BinaryView that the core will happily hand out
542
- // references to via BNGetFileViewofType even though it was never initialized
543
- // all the way.
544
- //
545
- // TODO update when this corner case gets fixed in the core?
546
- //
547
- // we can't do anything to prevent this, but we can at least have the crash
548
- // not be our fault.
549
- error!( "BinaryViewBase::freeObject called on leaked/never initialized custom view!" ) ;
550
- }
526
+ let context = Box :: from_raw( context) ;
527
+
528
+ if context. raw_handle. is_null( ) {
529
+ // being called here is essentially a guarantee that BNCreateBinaryViewOfType
530
+ // is above above us on the call stack somewhere -- no matter what we do, a crash
531
+ // is pretty much certain at this point.
532
+ //
533
+ // this has been observed when two views of the same BinaryViewType are created
534
+ // against the same BNFileMetaData object, and one of the views gets freed while
535
+ // the second one is being initialized -- somehow the partially initialized one
536
+ // gets freed before BNCreateBinaryViewOfType returns.
537
+ //
538
+ // multiples views of the same BinaryViewType in a BNFileMetaData object are
539
+ // prohibited, so an API contract was violated in order to get here.
540
+ //
541
+ // if we're here, it's too late to do anything about it, though we can at least not
542
+ // run the destructor on the custom view since that memory is unitialized.
543
+ error!(
544
+ "BinaryViewBase::freeObject called on partially initialized object! crash imminent!"
545
+ ) ;
546
+ } else if matches!(
547
+ & context. state,
548
+ CustomViewContextState :: None | CustomViewContextState :: Uninitialized { .. }
549
+ ) {
550
+ // making it here means somebody went out of their way to leak a BinaryView
551
+ // after calling BNCreateCustomView and never gave the BNBinaryView handle
552
+ // to the core (which would have called cb_init)
553
+ //
554
+ // the result is a half-initialized BinaryView that the core will happily hand out
555
+ // references to via BNGetFileViewofType even though it was never initialized
556
+ // all the way.
557
+ //
558
+ // TODO update when this corner case gets fixed in the core?
559
+ //
560
+ // we can't do anything to prevent this, but we can at least have the crash
561
+ // not be our fault.
562
+ error!( "BinaryViewBase::freeObject called on leaked/never initialized custom view!" ) ;
551
563
}
552
564
} )
553
565
}
@@ -564,8 +576,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
564
576
ffi_wrap ! ( "BinaryViewBase::read" , unsafe {
565
577
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
566
578
let dest = slice:: from_raw_parts_mut( dest as * mut u8 , len) ;
567
-
568
- context. view. assume_init_ref( ) . read( dest, offset)
579
+ context. assume_init_ref( ) . read( dest, offset)
569
580
} )
570
581
}
571
582
@@ -582,7 +593,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
582
593
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
583
594
let src = slice:: from_raw_parts( src as * const u8 , len) ;
584
595
585
- context. view . assume_init_ref( ) . write( offset, src)
596
+ context. assume_init_ref( ) . write( offset, src)
586
597
} )
587
598
}
588
599
@@ -599,7 +610,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
599
610
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
600
611
let src = slice:: from_raw_parts( src as * const u8 , len) ;
601
612
602
- context. view . assume_init_ref( ) . insert( offset, src)
613
+ context. assume_init_ref( ) . insert( offset, src)
603
614
} )
604
615
}
605
616
@@ -610,7 +621,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
610
621
ffi_wrap ! ( "BinaryViewBase::remove" , unsafe {
611
622
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
612
623
613
- context. view . assume_init_ref( ) . remove( offset, len as usize )
624
+ context. assume_init_ref( ) . remove( offset, len as usize )
614
625
} )
615
626
}
616
627
@@ -621,7 +632,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
621
632
ffi_wrap ! ( "BinaryViewBase::modification_status" , unsafe {
622
633
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
623
634
624
- context. view . assume_init_ref( ) . modification_status( offset)
635
+ context. assume_init_ref( ) . modification_status( offset)
625
636
} )
626
637
}
627
638
@@ -632,7 +643,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
632
643
ffi_wrap ! ( "BinaryViewBase::offset_valid" , unsafe {
633
644
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
634
645
635
- context. view . assume_init_ref( ) . offset_valid( offset)
646
+ context. assume_init_ref( ) . offset_valid( offset)
636
647
} )
637
648
}
638
649
@@ -643,7 +654,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
643
654
ffi_wrap ! ( "BinaryViewBase::readable" , unsafe {
644
655
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
645
656
646
- context. view . assume_init_ref( ) . offset_readable( offset)
657
+ context. assume_init_ref( ) . offset_readable( offset)
647
658
} )
648
659
}
649
660
@@ -654,7 +665,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
654
665
ffi_wrap ! ( "BinaryViewBase::writable" , unsafe {
655
666
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
656
667
657
- context. view . assume_init_ref( ) . offset_writable( offset)
668
+ context. assume_init_ref( ) . offset_writable( offset)
658
669
} )
659
670
}
660
671
@@ -665,7 +676,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
665
676
ffi_wrap ! ( "BinaryViewBase::offset_executable" , unsafe {
666
677
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
667
678
668
- context. view . assume_init_ref( ) . offset_executable( offset)
679
+ context. assume_init_ref( ) . offset_executable( offset)
669
680
} )
670
681
}
671
682
@@ -676,7 +687,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
676
687
ffi_wrap ! ( "BinaryViewBase::offset_backed_by_file" , unsafe {
677
688
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
678
689
679
- context. view . assume_init_ref( ) . offset_backed_by_file( offset)
690
+ context. assume_init_ref( ) . offset_backed_by_file( offset)
680
691
} )
681
692
}
682
693
@@ -687,10 +698,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
687
698
ffi_wrap ! ( "BinaryViewBase::next_valid_offset_after" , unsafe {
688
699
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
689
700
690
- context
691
- . view
692
- . assume_init_ref( )
693
- . next_valid_offset_after( offset)
701
+ context. assume_init_ref( ) . next_valid_offset_after( offset)
694
702
} )
695
703
}
696
704
@@ -701,7 +709,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
701
709
ffi_wrap ! ( "BinaryViewBase::start" , unsafe {
702
710
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
703
711
704
- context. view . assume_init_ref( ) . start( )
712
+ context. assume_init_ref( ) . start( )
705
713
} )
706
714
}
707
715
@@ -712,7 +720,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
712
720
ffi_wrap ! ( "BinaryViewBase::len" , unsafe {
713
721
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
714
722
715
- context. view . assume_init_ref( ) . len( ) as u64
723
+ context. assume_init_ref( ) . len( ) as u64
716
724
} )
717
725
}
718
726
@@ -723,7 +731,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
723
731
ffi_wrap ! ( "BinaryViewBase::entry_point" , unsafe {
724
732
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
725
733
726
- context. view . assume_init_ref( ) . entry_point( )
734
+ context. assume_init_ref( ) . entry_point( )
727
735
} )
728
736
}
729
737
@@ -734,7 +742,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
734
742
ffi_wrap ! ( "BinaryViewBase::executable" , unsafe {
735
743
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
736
744
737
- context. view . assume_init_ref( ) . executable( )
745
+ context. assume_init_ref( ) . executable( )
738
746
} )
739
747
}
740
748
@@ -745,7 +753,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
745
753
ffi_wrap ! ( "BinaryViewBase::default_endianness" , unsafe {
746
754
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
747
755
748
- context. view . assume_init_ref( ) . default_endianness( )
756
+ context. assume_init_ref( ) . default_endianness( )
749
757
} )
750
758
}
751
759
@@ -756,7 +764,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
756
764
ffi_wrap ! ( "BinaryViewBase::relocatable" , unsafe {
757
765
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
758
766
759
- context. view . assume_init_ref( ) . relocatable( )
767
+ context. assume_init_ref( ) . relocatable( )
760
768
} )
761
769
}
762
770
@@ -767,7 +775,7 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
767
775
ffi_wrap ! ( "BinaryViewBase::address_size" , unsafe {
768
776
let context = & * ( ctxt as * mut CustomViewContext <V >) ;
769
777
770
- context. view . assume_init_ref( ) . address_size( )
778
+ context. assume_init_ref( ) . address_size( )
771
779
} )
772
780
}
773
781
@@ -782,10 +790,8 @@ impl<'a, T: CustomBinaryViewType> CustomViewBuilder<'a, T> {
782
790
}
783
791
784
792
let ctxt = Box :: new ( CustomViewContext :: < V > {
785
- view : mem:: MaybeUninit :: uninit ( ) ,
786
793
raw_handle : ptr:: null_mut ( ) ,
787
- initialized : false ,
788
- args : view_args,
794
+ state : CustomViewContextState :: Uninitialized { args : view_args } ,
789
795
} ) ;
790
796
791
797
let ctxt = Box :: into_raw ( ctxt) ;
0 commit comments