@@ -4,18 +4,25 @@ use alloc::{borrow::Cow, vec::Vec};
4
4
use core:: {
5
5
fmt:: Debug ,
6
6
marker:: PhantomData ,
7
- ops:: { BitAnd , BitOr , Deref , DerefMut } ,
7
+ ops:: { Deref , DerefMut } ,
8
8
} ;
9
9
10
- #[ rustversion:: nightly]
11
- use libafl_bolts:: simd:: std_covmap_is_interesting;
10
+ #[ cfg( all( feature = "simd" , target_arch = "x86_64" ) ) ]
11
+ use libafl_bolts:: simd:: vector:: u8x16;
12
+ #[ cfg( not( feature = "simd" ) ) ]
13
+ use libafl_bolts:: simd:: { MinReducer , OrReducer } ;
14
+ #[ cfg( feature = "simd" ) ]
15
+ use libafl_bolts:: simd:: { SimdMaxReducer , SimdMinReducer , SimdOrReducer , vector:: u8x32} ;
12
16
use libafl_bolts:: {
13
- AsIter , AsSlice , HasRefCnt , Named ,
17
+ AsIter , HasRefCnt , Named ,
18
+ simd:: { MaxReducer , NopReducer , Reducer } ,
14
19
tuples:: { Handle , Handled , MatchName , MatchNameRef } ,
15
20
} ;
16
21
use num_traits:: PrimInt ;
17
22
use serde:: { Deserialize , Serialize , de:: DeserializeOwned } ;
18
23
24
+ #[ cfg( feature = "simd" ) ]
25
+ use super :: simd:: SimdMapFeedback ;
19
26
#[ cfg( feature = "track_hit_feedbacks" ) ]
20
27
use crate :: feedbacks:: premature_last_result_err;
21
28
use crate :: {
@@ -29,11 +36,27 @@ use crate::{
29
36
state:: HasExecutions ,
30
37
} ;
31
38
39
+ #[ cfg( feature = "simd" ) ]
40
+ /// A [`SimdMapFeedback`] that implements the AFL algorithm using an [`SimdOrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`].
41
+ pub type AflMapFeedback < C , O > = SimdMapFeedback < C , O , SimdOrReducer , u8x32 > ;
42
+ #[ cfg( not( feature = "simd" ) ) ]
32
43
/// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from (`HitcountsMapObserver`)[`crate::observers::HitcountsMapObserver`].
33
44
pub type AflMapFeedback < C , O > = MapFeedback < C , DifferentIsNovel , O , OrReducer > ;
34
45
46
+ #[ cfg( all( feature = "simd" , target_arch = "x86_64" ) ) ]
47
+ /// A [`SimdMapFeedback`] that strives to maximize the map contents.
48
+ pub type MaxMapFeedback < C , O > = SimdMapFeedback < C , O , SimdMaxReducer , u8x16 > ;
49
+ #[ cfg( all( feature = "simd" , not( target_arch = "x86_64" ) ) ) ]
50
+ /// A [`SimdMapFeedback`] that strives to maximize the map contents.
51
+ pub type MaxMapFeedback < C , O > = SimdMapFeedback < C , O , SimdMaxReducer , u8x32 > ;
52
+ #[ cfg( not( feature = "simd" ) ) ]
35
53
/// A [`MapFeedback`] that strives to maximize the map contents.
36
54
pub type MaxMapFeedback < C , O > = MapFeedback < C , DifferentIsNovel , O , MaxReducer > ;
55
+
56
+ #[ cfg( feature = "simd" ) ]
57
+ /// A [`SimdMapFeedback`] that strives to minimize the map contents.
58
+ pub type MinMapFeedback < C , O > = SimdMapFeedback < C , O , SimdMinReducer , u8x32 > ;
59
+ #[ cfg( not( feature = "simd" ) ) ]
37
60
/// A [`MapFeedback`] that strives to minimize the map contents.
38
61
pub type MinMapFeedback < C , O > = MapFeedback < C , DifferentIsNovel , O , MinReducer > ;
39
62
@@ -47,79 +70,6 @@ pub type MaxMapPow2Feedback<C, O> = MapFeedback<C, NextPow2IsNovel, O, MaxReduce
47
70
/// but only, if a value is either `T::one()` or `T::max_value()`.
48
71
pub type MaxMapOneOrFilledFeedback < C , O > = MapFeedback < C , OneOrFilledIsNovel , O , MaxReducer > ;
49
72
50
- /// A `Reducer` function is used to aggregate values for the novelty search
51
- pub trait Reducer < T > {
52
- /// Reduce two values to one value, with the current [`Reducer`].
53
- fn reduce ( first : T , second : T ) -> T ;
54
- }
55
-
56
- /// A [`OrReducer`] reduces the values returning the bitwise OR with the old value
57
- #[ derive( Clone , Debug ) ]
58
- pub struct OrReducer { }
59
-
60
- impl < T > Reducer < T > for OrReducer
61
- where
62
- T : BitOr < Output = T > ,
63
- {
64
- #[ inline]
65
- fn reduce ( history : T , new : T ) -> T {
66
- history | new
67
- }
68
- }
69
-
70
- /// A [`AndReducer`] reduces the values returning the bitwise AND with the old value
71
- #[ derive( Clone , Debug ) ]
72
- pub struct AndReducer { }
73
-
74
- impl < T > Reducer < T > for AndReducer
75
- where
76
- T : BitAnd < Output = T > ,
77
- {
78
- #[ inline]
79
- fn reduce ( history : T , new : T ) -> T {
80
- history & new
81
- }
82
- }
83
-
84
- /// A [`NopReducer`] does nothing, and just "reduces" to the second/`new` value.
85
- #[ derive( Clone , Debug ) ]
86
- pub struct NopReducer { }
87
-
88
- impl < T > Reducer < T > for NopReducer {
89
- #[ inline]
90
- fn reduce ( _history : T , new : T ) -> T {
91
- new
92
- }
93
- }
94
-
95
- /// A [`MaxReducer`] reduces int values and returns their maximum.
96
- #[ derive( Clone , Debug ) ]
97
- pub struct MaxReducer { }
98
-
99
- impl < T > Reducer < T > for MaxReducer
100
- where
101
- T : PartialOrd ,
102
- {
103
- #[ inline]
104
- fn reduce ( first : T , second : T ) -> T {
105
- if first > second { first } else { second }
106
- }
107
- }
108
-
109
- /// A [`MinReducer`] reduces int values and returns their minimum.
110
- #[ derive( Clone , Debug ) ]
111
- pub struct MinReducer { }
112
-
113
- impl < T > Reducer < T > for MinReducer
114
- where
115
- T : PartialOrd ,
116
- {
117
- #[ inline]
118
- fn reduce ( first : T , second : T ) -> T {
119
- if first < second { first } else { second }
120
- }
121
- }
122
-
123
73
/// A `IsNovel` function is used to discriminate if a reduced value is considered novel.
124
74
pub trait IsNovel < T > {
125
75
/// If a new value in the [`MapFeedback`] was found,
@@ -351,7 +301,7 @@ where
351
301
#[ derive( Clone , Debug ) ]
352
302
pub struct MapFeedback < C , N , O , R > {
353
303
/// New indexes observed in the last observation
354
- novelties : Option < Vec < usize > > ,
304
+ pub ( crate ) novelties : Option < Vec < usize > > ,
355
305
/// Name identifier of this instance
356
306
name : Cow < ' static , str > ,
357
307
/// Name identifier of the observer
@@ -360,7 +310,7 @@ pub struct MapFeedback<C, N, O, R> {
360
310
stats_name : Cow < ' static , str > ,
361
311
// The previous run's result of [`Self::is_interesting`]
362
312
#[ cfg( feature = "track_hit_feedbacks" ) ]
363
- last_result : Option < bool > ,
313
+ pub ( crate ) last_result : Option < bool > ,
364
314
/// Phantom Data of Reducer
365
315
#[ expect( clippy:: type_complexity) ]
366
316
phantom : PhantomData < fn ( ) -> ( N , O , R ) > ,
@@ -391,24 +341,6 @@ where
391
341
R : Reducer < O :: Entry > ,
392
342
S : HasNamedMetadata + HasExecutions ,
393
343
{
394
- #[ rustversion:: nightly]
395
- default fn is_interesting (
396
- & mut self ,
397
- state : & mut S ,
398
- _manager : & mut EM ,
399
- _input : & I ,
400
- observers : & OT ,
401
- _exit_kind : & ExitKind ,
402
- ) -> Result < bool , Error > {
403
- let res = self . is_interesting_default ( state, observers) ;
404
- #[ cfg( feature = "track_hit_feedbacks" ) ]
405
- {
406
- self . last_result = Some ( res) ;
407
- }
408
- Ok ( res)
409
- }
410
-
411
- #[ rustversion:: not( nightly) ]
412
344
fn is_interesting (
413
345
& mut self ,
414
346
state : & mut S ,
@@ -528,28 +460,6 @@ where
528
460
}
529
461
}
530
462
531
- /// Specialize for the common coverage map size, maximization of u8s
532
- #[ rustversion:: nightly]
533
- impl < C , O , EM , I , OT , S > Feedback < EM , I , OT , S > for MapFeedback < C , DifferentIsNovel , O , MaxReducer >
534
- where
535
- C : CanTrack + AsRef < O > ,
536
- EM : EventFirer < I , S > ,
537
- O : MapObserver < Entry = u8 > + for < ' a > AsSlice < ' a , Entry = u8 > + for < ' a > AsIter < ' a , Item = u8 > ,
538
- OT : MatchName ,
539
- S : HasNamedMetadata + HasExecutions ,
540
- {
541
- fn is_interesting (
542
- & mut self ,
543
- state : & mut S ,
544
- _manager : & mut EM ,
545
- _input : & I ,
546
- observers : & OT ,
547
- _exit_kind : & ExitKind ,
548
- ) -> Result < bool , Error > {
549
- Ok ( self . is_interesting_u8_simd_optimized ( state, observers, std_covmap_is_interesting) )
550
- }
551
- }
552
-
553
463
impl < C , N , O , R > Named for MapFeedback < C , N , O , R > {
554
464
#[ inline]
555
465
fn name ( & self ) -> & Cow < ' static , str > {
@@ -676,67 +586,6 @@ where
676
586
}
677
587
}
678
588
679
- /// Specialize for the common coverage map size, maximization of u8s
680
- impl < C , O > MapFeedback < C , DifferentIsNovel , O , MaxReducer >
681
- where
682
- O : MapObserver < Entry = u8 > + for < ' a > AsSlice < ' a , Entry = u8 > + for < ' a > AsIter < ' a , Item = u8 > ,
683
- C : CanTrack + AsRef < O > ,
684
- {
685
- #[ allow( dead_code) ] // this is true on stable wihout "stable_simd"
686
- pub ( crate ) fn is_interesting_u8_simd_optimized < S , OT , F > (
687
- & mut self ,
688
- state : & mut S ,
689
- observers : & OT ,
690
- simd : F ,
691
- ) -> bool
692
- where
693
- S : HasNamedMetadata ,
694
- OT : MatchName ,
695
- F : FnOnce ( & [ u8 ] , & [ u8 ] , bool ) -> ( bool , Vec < usize > ) ,
696
- {
697
- // TODO Replace with match_name_type when stable
698
- let observer = observers. get ( & self . map_ref ) . expect ( "MapObserver not found. This is likely because you entered the crash handler with the wrong executor/observer" ) . as_ref ( ) ;
699
-
700
- let map_state = state
701
- . named_metadata_map_mut ( )
702
- . get_mut :: < MapFeedbackMetadata < u8 > > ( & self . name )
703
- . unwrap ( ) ;
704
- let size = observer. usable_count ( ) ;
705
- let len = observer. len ( ) ;
706
- if map_state. history_map . len ( ) < len {
707
- map_state. history_map . resize ( len, u8:: default ( ) ) ;
708
- }
709
-
710
- let map = observer. as_slice ( ) ;
711
- debug_assert ! ( map. len( ) >= size) ;
712
-
713
- let history_map = map_state. history_map . as_slice ( ) ;
714
-
715
- // Non vector implementation for reference
716
- /*for (i, history) in history_map.iter_mut().enumerate() {
717
- let item = map[i];
718
- let reduced = MaxReducer::reduce(*history, item);
719
- if DifferentIsNovel::is_novel(*history, reduced) {
720
- *history = reduced;
721
- interesting = true;
722
- if self.novelties.is_some() {
723
- self.novelties.as_mut().unwrap().push(i);
724
- }
725
- }
726
- }*/
727
-
728
- let ( interesting, novelties) = simd ( history_map, & map, self . novelties . is_some ( ) ) ;
729
- if let Some ( nov) = self . novelties . as_mut ( ) {
730
- * nov = novelties;
731
- }
732
- #[ cfg( feature = "track_hit_feedbacks" ) ]
733
- {
734
- self . last_result = Some ( interesting) ;
735
- }
736
- interesting
737
- }
738
- }
739
-
740
589
#[ cfg( test) ]
741
590
mod tests {
742
591
use crate :: feedbacks:: { AllIsNovel , IsNovel , NextPow2IsNovel } ;
0 commit comments