@@ -146,6 +146,11 @@ pub struct Module {
146146
147147 /// What the maximum type index that can be referenced is.
148148 max_type_limit : MaxTypeLimit ,
149+
150+ /// Some known-interesting values, such as powers of two, values just before
151+ /// or just after a memory size, etc...
152+ interesting_values32 : Vec < u32 > ,
153+ interesting_values64 : Vec < u64 > ,
149154}
150155
151156impl < ' a > Arbitrary < ' a > for Module {
@@ -232,6 +237,8 @@ impl Module {
232237 export_names : HashSet :: new ( ) ,
233238 const_expr_choices : Vec :: new ( ) ,
234239 max_type_limit : MaxTypeLimit :: ModuleTypes ,
240+ interesting_values32 : Vec :: new ( ) ,
241+ interesting_values64 : Vec :: new ( ) ,
235242 }
236243 }
237244}
@@ -2039,6 +2046,8 @@ impl Module {
20392046 }
20402047
20412048 fn arbitrary_code ( & mut self , u : & mut Unstructured ) -> Result < ( ) > {
2049+ self . compute_interesting_values ( ) ;
2050+
20422051 self . code . reserve ( self . num_defined_funcs ) ;
20432052 let mut allocs = CodeBuilderAllocations :: new ( self , self . config . exports . is_some ( ) ) ;
20442053 for ( _, ty) in self . funcs [ self . funcs . len ( ) - self . num_defined_funcs ..] . iter ( ) {
@@ -2224,6 +2233,170 @@ impl Module {
22242233 }
22252234 } )
22262235 }
2236+
2237+ fn compute_interesting_values ( & mut self ) {
2238+ debug_assert ! ( self . interesting_values32. is_empty( ) ) ;
2239+ debug_assert ! ( self . interesting_values64. is_empty( ) ) ;
2240+
2241+ let mut interesting_values32 = HashSet :: new ( ) ;
2242+ let mut interesting_values64 = HashSet :: new ( ) ;
2243+
2244+ let mut interesting = |val : u64 | {
2245+ interesting_values32. insert ( val as u32 ) ;
2246+ interesting_values64. insert ( val) ;
2247+ } ;
2248+
2249+ // Zero is always interesting.
2250+ interesting ( 0 ) ;
2251+
2252+ // Max values are always interesting.
2253+ interesting ( u8:: MAX as _ ) ;
2254+ interesting ( u16:: MAX as _ ) ;
2255+ interesting ( u32:: MAX as _ ) ;
2256+ interesting ( u64:: MAX ) ;
2257+
2258+ // Min values are always interesting.
2259+ interesting ( i8:: MIN as _ ) ;
2260+ interesting ( i16:: MIN as _ ) ;
2261+ interesting ( i32:: MIN as _ ) ;
2262+ interesting ( i64:: MIN as _ ) ;
2263+
2264+ for i in 0 ..64 {
2265+ // Powers of two.
2266+ interesting ( 1 << i) ;
2267+
2268+ // Inverted powers of two.
2269+ interesting ( !( 1 << i) ) ;
2270+
2271+ // Powers of two minus one, AKA high bits unset and low bits set.
2272+ interesting ( ( 1 << i) - 1 ) ;
2273+
2274+ // Negative powers of two, AKA high bits set and low bits unset.
2275+ interesting ( ( ( 1_i64 << 63 ) >> i) as _ ) ;
2276+ }
2277+
2278+ // Some repeating bit patterns.
2279+ for pattern in [ 0b01010101 , 0b00010001 , 0b00010001 , 0b00000001 ] {
2280+ for b in [ pattern, !pattern] {
2281+ interesting ( u64:: from_ne_bytes ( [ b, b, b, b, b, b, b, b] ) ) ;
2282+ }
2283+ }
2284+
2285+ // Interesting float values.
2286+ let mut interesting_f64 = |x : f64 | interesting ( x. to_bits ( ) ) ;
2287+ interesting_f64 ( 0.0 ) ;
2288+ interesting_f64 ( -0.0 ) ;
2289+ interesting_f64 ( f64:: INFINITY ) ;
2290+ interesting_f64 ( f64:: NEG_INFINITY ) ;
2291+ interesting_f64 ( f64:: EPSILON ) ;
2292+ interesting_f64 ( -f64:: EPSILON ) ;
2293+ interesting_f64 ( f64:: MIN ) ;
2294+ interesting_f64 ( f64:: MIN_POSITIVE ) ;
2295+ interesting_f64 ( f64:: MAX ) ;
2296+ interesting_f64 ( f64:: NAN ) ;
2297+ let mut interesting_f32 = |x : f32 | interesting ( x. to_bits ( ) as _ ) ;
2298+ interesting_f32 ( 0.0 ) ;
2299+ interesting_f32 ( -0.0 ) ;
2300+ interesting_f32 ( f32:: INFINITY ) ;
2301+ interesting_f32 ( f32:: NEG_INFINITY ) ;
2302+ interesting_f32 ( f32:: EPSILON ) ;
2303+ interesting_f32 ( -f32:: EPSILON ) ;
2304+ interesting_f32 ( f32:: MIN ) ;
2305+ interesting_f32 ( f32:: MIN_POSITIVE ) ;
2306+ interesting_f32 ( f32:: MAX ) ;
2307+ interesting_f32 ( f32:: NAN ) ;
2308+
2309+ // Interesting values related to table bounds.
2310+ for t in self . tables . iter ( ) {
2311+ interesting ( t. minimum as _ ) ;
2312+ if let Some ( x) = t. minimum . checked_add ( 1 ) {
2313+ interesting ( x as _ ) ;
2314+ }
2315+
2316+ if let Some ( x) = t. maximum {
2317+ interesting ( x as _ ) ;
2318+ if let Some ( y) = x. checked_add ( 1 ) {
2319+ interesting ( y as _ ) ;
2320+ }
2321+ }
2322+ }
2323+
2324+ // Interesting values related to memory bounds.
2325+ for m in self . memories . iter ( ) {
2326+ let min = m. minimum . saturating_mul ( crate :: WASM_PAGE_SIZE ) ;
2327+ interesting ( min) ;
2328+ for i in 0 ..5 {
2329+ if let Some ( x) = min. checked_add ( 1 << i) {
2330+ interesting ( x) ;
2331+ }
2332+ if let Some ( x) = min. checked_sub ( 1 << i) {
2333+ interesting ( x) ;
2334+ }
2335+ }
2336+
2337+ if let Some ( max) = m. maximum {
2338+ let max = max. saturating_mul ( crate :: WASM_PAGE_SIZE ) ;
2339+ interesting ( max) ;
2340+ for i in 0 ..5 {
2341+ if let Some ( x) = max. checked_add ( 1 << i) {
2342+ interesting ( x) ;
2343+ }
2344+ if let Some ( x) = max. checked_sub ( 1 << i) {
2345+ interesting ( x) ;
2346+ }
2347+ }
2348+ }
2349+ }
2350+
2351+ self . interesting_values32 . extend ( interesting_values32) ;
2352+ self . interesting_values64 . extend ( interesting_values64) ;
2353+
2354+ // Sort for determinism.
2355+ self . interesting_values32 . sort ( ) ;
2356+ self . interesting_values64 . sort ( ) ;
2357+ }
2358+
2359+ fn arbitrary_const_instruction (
2360+ & self ,
2361+ ty : ValType ,
2362+ u : & mut Unstructured < ' _ > ,
2363+ ) -> Result < Instruction > {
2364+ debug_assert ! ( self . interesting_values32. len( ) > 0 ) ;
2365+ debug_assert ! ( self . interesting_values64. len( ) > 0 ) ;
2366+ match ty {
2367+ ValType :: I32 => Ok ( Instruction :: I32Const ( if u. arbitrary ( ) ? {
2368+ * u. choose ( & self . interesting_values32 ) ? as i32
2369+ } else {
2370+ u. arbitrary ( ) ?
2371+ } ) ) ,
2372+ ValType :: I64 => Ok ( Instruction :: I64Const ( if u. arbitrary ( ) ? {
2373+ * u. choose ( & self . interesting_values64 ) ? as i64
2374+ } else {
2375+ u. arbitrary ( ) ?
2376+ } ) ) ,
2377+ ValType :: F32 => Ok ( Instruction :: F32Const ( if u. arbitrary ( ) ? {
2378+ f32:: from_bits ( * u. choose ( & self . interesting_values32 ) ?)
2379+ } else {
2380+ u. arbitrary ( ) ?
2381+ } ) ) ,
2382+ ValType :: F64 => Ok ( Instruction :: F64Const ( if u. arbitrary ( ) ? {
2383+ f64:: from_bits ( * u. choose ( & self . interesting_values64 ) ?)
2384+ } else {
2385+ u. arbitrary ( ) ?
2386+ } ) ) ,
2387+ ValType :: V128 => Ok ( Instruction :: V128Const ( if u. arbitrary ( ) ? {
2388+ let upper = ( * u. choose ( & self . interesting_values64 ) ? as i128 ) << 64 ;
2389+ let lower = * u. choose ( & self . interesting_values64 ) ? as i128 ;
2390+ upper | lower
2391+ } else {
2392+ u. arbitrary ( ) ?
2393+ } ) ) ,
2394+ ValType :: Ref ( ty) => {
2395+ assert ! ( ty. nullable) ;
2396+ Ok ( Instruction :: RefNull ( ty. heap_type ) )
2397+ }
2398+ }
2399+ }
22272400}
22282401
22292402pub ( crate ) fn arbitrary_limits32 (
0 commit comments