blob: 7e45febf727f7dc7581a8d318f6b2f833a8cceec [file] [log] [blame] [edit]
(module
(type $struct (sub (struct (mut i32))))
(type $extendedstruct (sub $struct (struct (mut i32) f64)))
(type $bytes (array (mut i8)))
(type $void_func (func))
(type $int_func (func (result i32)))
(import "fuzzing-support" "log-i32" (func $log (param i32)))
(func $structs (export "structs")
(local $x (ref null $struct))
(local $y (ref null $struct))
(local.set $x
(struct.new_default $struct)
)
;; The value is initialized to 0
;; Note: We cannot optimize these to constants without either immutability or
;; some kind of escape analysis (to verify that the GC data referred to is not
;; written to elsewhere).
(call $log
(struct.get $struct 0 (local.get $x))
)
;; Assigning a value works
(struct.set $struct 0
(local.get $x)
(i32.const 42)
)
(call $log
(struct.get $struct 0 (local.get $x))
)
;; References are references, so writing to one's value affects the other's
(local.set $y (local.get $x))
(struct.set $struct 0
(local.get $y)
(i32.const 100)
)
(call $log
(struct.get $struct 0 (local.get $x))
)
(call $log
(struct.get $struct 0 (local.get $y))
)
)
(func $arrays (export "arrays")
(local $x (ref null $bytes))
(local.set $x
(array.new $bytes
(i32.const 42) ;; value to splat into the array
(i32.const 50) ;; size
)
)
;; The length should be 50
(call $log
(array.len (local.get $x))
)
;; The value should be 42
(call $log
(array.get_u $bytes (local.get $x) (i32.const 10))
)
;; Write a value that will be truncated into an i8
(array.set $bytes (local.get $x) (i32.const 10) (i32.const 0xff80))
;; The value should be 0x80 (-128 or 128 depending on signed/unsigned)
(call $log
(array.get_u $bytes (local.get $x) (i32.const 10))
)
(call $log
(array.get_s $bytes (local.get $x) (i32.const 10))
)
;; Other items than the one at index 10 are unaffected.
(call $log
(array.get_s $bytes (local.get $x) (i32.const 20))
)
)
(func $br_on_cast (export "br_on_cast")
(local $any anyref)
;; create a simple $struct, store it in an anyref
(local.set $any
(struct.new_default $struct)
)
(drop
(block $block (result (ref $struct))
(drop
(block $extendedblock (result (ref $extendedstruct))
(drop
;; second, try to cast our simple $struct to what it is, which will work
(br_on_cast $block anyref (ref $struct)
;; first, try to cast our simple $struct to an extended, which will fail
(br_on_cast $extendedblock anyref (ref $extendedstruct)
(local.get $any)
)
)
)
(call $log (i32.const -1)) ;; we should never get here
(return)
)
)
(call $log (i32.const -2)) ;; we should never get here either
(return)
)
)
(call $log (i32.const 3)) ;; we should get here
)
(func $br_on_failed_cast-1 (export "br_on_failed_cast-1")
(local $any anyref)
;; create a simple $struct, store it in an anyref
(local.set $any
(struct.new_default $struct)
)
(drop
(block $any (result (ref null any))
(call $log (i32.const 1))
(drop
;; try to cast our simple $struct to an extended, which will fail, and
;; so we will branch, skipping the next logging.
(br_on_cast_fail $any anyref (ref $extendedstruct)
(local.get $any)
)
)
(call $log (i32.const 999)) ;; we should skip this
(ref.null any)
)
)
)
(func $br_on_failed_cast-2 (export "br_on_failed_cast-2")
(local $any anyref)
;; create an $extendedstruct, store it in an anyref
(local.set $any
(struct.new_default $extendedstruct)
)
(drop
(block $any (result (ref null any))
(call $log (i32.const 1))
(drop
;; try to cast our simple $struct to an extended, which will succeed, and
;; so we will continue to the next logging.
(br_on_cast_fail $any anyref (ref $extendedstruct)
(local.get $any)
)
)
(call $log (i32.const 999))
(ref.null any)
)
)
)
(func $cast-null-anyref-to-gc (export "cast-null-anyref-to-gc")
;; a null anyref is a literal which is not even of GC data, as it's not an
;; array or a struct, so our casting code should not assume it is. it is ok
;; to try to cast it, and the result should be 0.
(call $log
(ref.test (ref $struct)
(ref.null any)
)
)
)
(func $get_struct (result structref)
(struct.new_default $struct)
)
(func $br-on_non_null (export "br-on_non_null")
(drop
(block $non-null (result (ref any))
(br_on_non_null $non-null (ref.i31 (i32.const 0)))
;; $x refers to an i31, which is not null, so we will branch, and not
;; log
(call $log (i32.const 1))
(unreachable)
)
)
)
(func $br-on_non_null-2 (export "br-on_non_null-2")
(drop
(block $non-null (result (ref any))
(br_on_non_null $non-null (ref.null any))
;; $x is null, and so we will not branch, and log and then trap
(call $log (i32.const 1))
(unreachable)
)
)
)
(func $ref-as-func-of-func (export "ref-as-func-of-func")
(drop
(ref.cast (ref func)
(ref.func $structs)
)
)
)
(func $a-void-func
(call $log (i32.const 1337))
)
(func $cast-on-func (export "cast-on-func")
(call $log (i32.const 0))
;; a valid cast
(call_ref $void_func
(ref.cast (ref $void_func) (ref.func $a-void-func))
)
(call $log (i32.const 1))
;; an invalid cast
(drop (call_ref $int_func
(ref.cast (ref $int_func) (ref.func $a-void-func))
))
;; will never be reached
(call $log (i32.const 2))
)
(func $array-alloc-failure (export "array-alloc-failure")
(drop
(array.new_default $bytes
(i32.const -1) ;; un-allocatable size (4GB * sizeof(Literal))
)
)
)
(func $init-array-packed (export "init-array-packed") (result i32)
(local $x (ref null $bytes))
(local.set $x
(array.new $bytes
(i32.const -43) ;; initialize the i8 values with a negative i32
(i32.const 50)
)
)
;; read the value, which should be -43 & 255 ==> 213
(array.get_u $bytes
(local.get $x)
(i32.const 10)
)
)
(func $call-target (param $0 eqref)
(nop)
)
(func $array-copy (export "array-copy")
(local $x (ref null $bytes))
(local $y (ref null $bytes))
;; Create an array of 10's, of size 100.
(local.set $x
(array.new $bytes
(i32.const 10)
(i32.const 100)
)
)
;; Create an array of zeros of size 200, and also set one index there.
(local.set $y
(array.new_default $bytes
(i32.const 200)
)
)
(array.set $bytes
(local.get $y)
(i32.const 42)
(i32.const 99)
)
;; Log out a value from $x before.
(call $log
(array.get_u $bytes (local.get $x) (i32.const 10))
)
(array.copy $bytes $bytes
(local.get $x)
(i32.const 10)
(local.get $y)
(i32.const 42)
(i32.const 2)
)
;; Log out some value from $x after. Indexes 10 and 11 should be modified.
(call $log
(array.get_u $bytes (local.get $x) (i32.const 9))
)
(call $log
(array.get_u $bytes (local.get $x) (i32.const 10))
)
(call $log
(array.get_u $bytes (local.get $x) (i32.const 11))
)
(call $log
(array.get_u $bytes (local.get $x) (i32.const 12))
)
)
(func $array.new_fixed (export "array.new_fixed")
(local $x (ref null $bytes))
(local.set $x
(array.new_fixed $bytes 2
(i32.const 42) ;; first value
(i32.const 50) ;; second value
)
)
;; The length should be 2
(call $log
(array.len (local.get $x))
)
;; The first value should be 42
(call $log
(array.get_u $bytes (local.get $x) (i32.const 0))
)
;; The second value should be 50
(call $log
(array.get_u $bytes (local.get $x) (i32.const 1))
)
)
(func $array.new_fixed-packed (export "array.new_fixed-packed")
(local $x (ref null $bytes))
(local.set $x
(array.new_fixed $bytes 1
(i32.const -11512)
)
)
;; The value should be be -11512 & 255 => 8
(call $log
(array.get_u $bytes (local.get $x) (i32.const 0))
)
)
(func $static-casts (export "static-casts")
;; Casting null returns null.
(call $log (ref.is_null
(ref.cast (ref null $struct) (ref.null $struct))
))
;; Testing null returns 0.
(call $log
(ref.test (ref $struct) (ref.null $struct))
)
;; Testing something completely wrong (struct vs array) returns 0.
(call $log
(ref.test (ref $struct)
(array.new $bytes
(i32.const 20)
(i32.const 10)
)
)
)
;; Testing a thing with the same type returns 1.
(call $log
(ref.test (ref $struct)
(struct.new_default $struct)
)
)
;; A bad downcast returns 0: we create a struct, which is not a extendedstruct.
(call $log
(ref.test (ref $extendedstruct)
(struct.new_default $struct)
)
)
;; Casting to a supertype works.
(call $log
(ref.test (ref $struct)
(struct.new_default $extendedstruct)
)
)
)
(func $static-br_on_cast (export "static-br_on_cast")
(local $any anyref)
;; create a simple $struct, store it in an anyref
(local.set $any
(struct.new_default $struct)
)
(drop
(block $block (result (ref $struct))
(drop
(block $extendedblock (result (ref $extendedstruct))
(drop
;; second, try to cast our simple $struct to what it is, which will work
(br_on_cast $block anyref (ref $struct)
;; first, try to cast our simple $struct to an extended, which will fail
(br_on_cast $extendedblock anyref (ref $extendedstruct)
(local.get $any)
)
)
)
(call $log (i32.const -1)) ;; we should never get here
(return)
)
)
(call $log (i32.const -2)) ;; we should never get here either
(return)
)
)
(call $log (i32.const 3)) ;; we should get here
)
(func $static-br_on_cast_fail (export "static-br_on_cast_fail")
(local $any anyref)
;; create a simple $struct, store it in an anyref
(local.set $any
(struct.new_default $struct)
)
(drop
(block $failblock (result anyref)
(drop
;; try to cast our simple $struct to an extended, which will fail
(br_on_cast_fail $failblock anyref (ref $extendedstruct)
(local.get $any)
)
)
(call $log (i32.const -1)) ;; we should never get here
(return)
)
)
(call $log (i32.const -2)) ;; we should get here.
(return)
)
)
(module
(type $"[mut:i8]" (array (mut i8)))
(func $foo (export "foo") (result i32)
;; before opts this will trap on failing to allocate -1 >>> 0 bytes. after
;; opts the unused value is removed so there is no trap, and a value is
;; returned, which should not confuse the fuzzer.
(drop
(array.new_default $"[mut:i8]"
(i32.const -1)
)
)
(i32.const 0)
)
)