tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ref-struct.js (11876B)


      1 // |jit-test| test-also=--gc-zeal=2
      2 
      3 // We'll be running some binary-format tests shortly.
      4 
      5 load(libdir + "wasm-binary.js");
      6 
      7 const v2vSigSection = sigSection([{args:[], ret:VoidCode}]);
      8 
      9 function checkInvalid(body, errorMessage) {
     10    assertErrorMessage(() => new WebAssembly.Module(
     11        moduleWithSections([v2vSigSection,
     12                            declSection([0]),
     13                            bodySection([body])])),
     14                       WebAssembly.CompileError,
     15                       errorMessage);
     16 }
     17 
     18 // General test case for struct.new, struct.get, and struct.set: binary tree
     19 // manipulation.
     20 
     21 {
     22    let bin = wasmTextToBinary(
     23        `(module
     24          (import "" "print_lp" (func $print_lp))
     25          (import "" "print_rp" (func $print_rp))
     26          (import "" "print_int" (func $print_int (param i32)))
     27 
     28          (type $wabbit (struct
     29                         (field $x (mut i32))
     30                         (field $left (mut (ref null $wabbit)))
     31                         (field $right (mut (ref null $wabbit)))))
     32 
     33          (global $g (mut (ref null $wabbit)) (ref.null $wabbit))
     34 
     35          (global $k (mut i32) (i32.const 0))
     36 
     37          (func (export "init") (param $n i32)
     38                (global.set $g (call $make (local.get $n))))
     39 
     40          (func $make (param $n i32) (result (ref null $wabbit))
     41                (local $tmp i32)
     42                (local.set $tmp (global.get $k))
     43                (global.set $k (i32.add (local.get $tmp) (i32.const 1)))
     44                (if (result (ref null $wabbit)) (i32.le_s (local.get $n) (i32.const 2))
     45                    (then (struct.new $wabbit (local.get $tmp) (ref.null $wabbit) (ref.null $wabbit)))
     46                    (else
     47                      (block (result (ref null $wabbit))
     48                      (struct.new $wabbit
     49                                  (local.get $tmp)
     50                                  (call $make (i32.sub (local.get $n) (i32.const 1)))
     51                                  (call $make (i32.sub (local.get $n) (i32.const 2))))))))
     52 
     53          (func (export "accumulate") (result i32)
     54                (call $accum (global.get $g)))
     55 
     56          (func $accum (param $w (ref null $wabbit)) (result i32)
     57                (if (result i32) (ref.is_null (local.get $w))
     58                    (then (i32.const 0))
     59                    (else
     60                      (i32.add (struct.get $wabbit 0 (local.get $w))
     61                             (i32.sub (call $accum (struct.get $wabbit 1 (local.get $w)))
     62                                      (call $accum (struct.get $wabbit 2 (local.get $w))))))))
     63 
     64          (func (export "reverse")
     65                (call $reverse (global.get $g)))
     66 
     67          (func $reverse (param $w (ref null $wabbit))
     68                (local $tmp (ref null $wabbit))
     69                (if (i32.eqz (ref.is_null (local.get $w)))
     70                    (then
     71                      (block
     72                        (struct.set $wabbit 0 (local.get $w) (i32.mul (i32.const 2) (struct.get $wabbit 0 (local.get $w))))
     73                        (local.set $tmp (struct.get $wabbit 1 (local.get $w)))
     74                        (struct.set $wabbit 1 (local.get $w) (struct.get $wabbit 2 (local.get $w)))
     75                        (struct.set $wabbit 2 (local.get $w) (local.get $tmp))
     76                        (call $reverse (struct.get $wabbit 1 (local.get $w)))
     77                        (call $reverse (struct.get $wabbit 2 (local.get $w)))))))
     78 
     79          (func (export "print")
     80                (call $pr (global.get $g)))
     81 
     82          (func $pr (param $w (ref null $wabbit))
     83                (if (i32.eqz (ref.is_null (local.get $w)))
     84                    (then 
     85                      (block
     86                        (call $print_lp)
     87                        (call $print_int (struct.get $wabbit 0 (local.get $w)))
     88                        (call $pr (struct.get $wabbit 1 (local.get $w)))
     89                        (call $pr (struct.get $wabbit 2 (local.get $w)))
     90                        (call $print_rp)))))
     91         )`);
     92 
     93    let s = "";
     94    function pr_int(k) { s += k + " "; }
     95    function pr_lp() { s += "(" };
     96    function pr_rp() { s += ")" }
     97 
     98    let mod = new WebAssembly.Module(bin);
     99    let ins = new WebAssembly.Instance(mod, {"":{print_int:pr_int,print_lp:pr_lp,print_rp:pr_rp}}).exports;
    100 
    101    ins.init(6);
    102    s = ""; ins.print(); assertEq(s, "(0 (1 (2 (3 (4 )(5 ))(6 ))(7 (8 )(9 )))(10 (11 (12 )(13 ))(14 )))");
    103    assertEq(ins.accumulate(), -13);
    104 
    105    ins.reverse();
    106    s = ""; ins.print(); assertEq(s, "(0 (20 (28 )(22 (26 )(24 )))(2 (14 (18 )(16 ))(4 (12 )(6 (10 )(8 )))))");
    107    assertEq(ins.accumulate(), 14);
    108 
    109    for (let i=10; i < 22; i++ ) {
    110        ins.init(i);
    111        ins.reverse();
    112        gc();
    113        ins.reverse();
    114    }
    115 }
    116 
    117 // Sanity check for struct.set: we /can/ store a (ref null T) into a (ref null U) field
    118 // with struct.set if T <: U; this should fall out of normal coercion but good
    119 // to test.
    120 
    121 wasmEvalText(
    122    `(module
    123      (type $node (sub (struct (field (mut (ref null $node))))))
    124      (type $nix (sub $node (struct (field (mut (ref null $node))) (field i32))))
    125      (func $f (param $p (ref null $node)) (param $q (ref null $nix))
    126       (struct.set $node 0 (local.get $p) (local.get $q))))`);
    127 
    128 // ref.cast: if the downcast succeeds we get the original pointer
    129 
    130 assertEq(wasmEvalText(
    131  `(module
    132    (type $node (sub (struct (field i32))))
    133    (type $node2 (sub $node (struct (field i32) (field f32))))
    134    (func $f (param $p (ref null $node)) (result (ref null $node2))
    135     (ref.cast (ref null $node2) (local.get $p)))
    136    (func (export "test") (result i32)
    137     (local $n (ref null $node))
    138     (local.set $n (struct.new $node2 (i32.const 0) (f32.const 12)))
    139     (ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
    140       1);
    141 
    142 // ref.cast: if the pointer is null we trap
    143 
    144 assertErrorMessage(() => wasmEvalText(
    145    `(module
    146      (type $node (struct (field i32)))
    147      (type $node2 (struct (field i32) (field f32)))
    148      (func $f (param $p (ref null $node)) (result (ref null $node2))
    149       (ref.cast (ref $node2) (local.get $p)))
    150      (func (export "test") (result eqref)
    151       (call $f (ref.null $node))))`).exports.test(),
    152    WebAssembly.RuntimeError,
    153    /bad cast/,
    154 );
    155 
    156 // ref.cast null: if the pointer is null we do not trap
    157 
    158 wasmEvalText(
    159  `(module
    160    (type $node (struct (field i32)))
    161    (type $node2 (struct (field i32) (field f32)))
    162    (func $f (param $p (ref null $node)) (result (ref null $node2))
    163     (ref.cast (ref null $node2) (local.get $p)))
    164    (func (export "test") (result eqref)
    165     (call $f (ref.null $node))))`).exports.test();
    166 
    167 
    168 // And once more with mutable fields
    169 
    170 assertEq(wasmEvalText(
    171    `(module
    172      (type $node (sub (struct (field (mut i32)))))
    173      (type $node2 (sub $node (struct (field (mut i32)) (field f32))))
    174      (func $f (param $p (ref null $node)) (result (ref null $node2))
    175       (ref.cast (ref null $node2) (local.get $p)))
    176      (func (export "test") (result i32)
    177       (local $n (ref null $node))
    178       (local.set $n (struct.new $node2 (i32.const 0) (f32.const 12)))
    179       (ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
    180         1);
    181 
    182 // ref.cast: eqref -> struct when the eqref is the right struct;
    183 // special case since eqref requires unboxing
    184 
    185 assertEq(wasmEvalText(
    186    `(module
    187      (type $node (struct (field i32)))
    188      (func $f (param $p eqref) (result (ref null $node))
    189       (ref.cast (ref null $node) (local.get $p)))
    190      (func (export "test") (result i32)
    191       (local $n (ref null $node))
    192       (local.set $n (struct.new $node (i32.const 0)))
    193       (ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
    194         1);
    195 
    196 // Can default initialize a struct which zero initializes
    197 
    198 {
    199  let {makeA, makeB, makeC} = wasmEvalText(`
    200  (module
    201   (type $a (struct))
    202   (type $b (struct (field i32) (field f32)))
    203   (type $c (struct (field eqref)))
    204 
    205   (func (export "makeA") (result eqref)
    206     struct.new_default $a
    207   )
    208   (func (export "makeB") (result eqref)
    209     struct.new_default $b
    210   )
    211   (func (export "makeC") (result eqref)
    212     struct.new_default $c
    213   )
    214  )`).exports;
    215  let a = makeA();
    216 
    217  let b = makeB();
    218  assertEq(wasmGcReadField(b, 0), 0);
    219  assertEq(wasmGcReadField(b, 1), 0);
    220 
    221  let c = makeC();
    222  assertEq(wasmGcReadField(c, 0), null);
    223 }
    224 
    225 // struct.new_default: valid if all struct fields are defaultable
    226 
    227 wasmFailValidateText(`(module
    228  (type $a (struct (field (ref $a))))
    229  (func
    230    struct.new_default $a
    231  )
    232 )`, /defaultable/);
    233 
    234 wasmFailValidateText(`(module
    235  (type $a (struct (field i32) (field i32) (field (ref $a))))
    236  (func
    237    struct.new_default $a
    238  )
    239 )`, /defaultable/);
    240 
    241 // Negative tests
    242 
    243 // Attempting to mutate immutable field with struct.set
    244 
    245 assertErrorMessage(() => wasmEvalText(
    246    `(module
    247      (type $node (struct (field i32)))
    248      (func $f (param $p (ref null $node))
    249       (struct.set $node 0 (local.get $p) (i32.const 37))))`),
    250                   WebAssembly.CompileError,
    251                   /field is not mutable/);
    252 
    253 // Attempting to store incompatible value in mutable field with struct.set
    254 
    255 assertErrorMessage(() => wasmEvalText(
    256    `(module
    257      (type $node (struct (field (mut i32))))
    258      (func $f (param $p (ref null $node))
    259       (struct.set $node 0 (local.get $p) (f32.const 37))))`),
    260                   WebAssembly.CompileError,
    261                   /expression has type f32 but expected i32/);
    262 
    263 // Out-of-bounds reference for struct.get
    264 
    265 assertErrorMessage(() => wasmEvalText(
    266    `(module
    267      (type $node (struct (field i32)))
    268      (func $f (param $p (ref null $node)) (result i32)
    269       (struct.get $node 1 (local.get $p))))`),
    270                   WebAssembly.CompileError,
    271                   /field index out of range/);
    272 
    273 // Out-of-bounds reference for struct.set
    274 
    275 assertErrorMessage(() => wasmEvalText(
    276    `(module
    277      (type $node (struct (field (mut i32))))
    278      (func $f (param $p (ref null $node))
    279       (struct.set $node 1 (local.get $p) (i32.const 37))))`),
    280                   WebAssembly.CompileError,
    281                   /field index out of range/);
    282 
    283 // Base pointer is of unrelated type to stated type in struct.get
    284 
    285 assertErrorMessage(() => wasmEvalText(
    286    `(module
    287      (type $node (struct (field i32)))
    288      (type $snort (struct (field f64)))
    289      (func $f (param $p (ref null $snort)) (result i32)
    290       (struct.get $node 0 (local.get $p))))`),
    291                   WebAssembly.CompileError,
    292                   /expression has type.*but expected.*/);
    293 
    294 // Base pointer is of unrelated type to stated type in struct.set
    295 
    296 assertErrorMessage(() => wasmEvalText(
    297    `(module
    298      (type $node (struct (field (mut i32))))
    299      (type $snort (struct (field f64)))
    300      (func $f (param $p (ref null $snort)) (result i32)
    301       (struct.set $node 0 (local.get $p) (i32.const 0))))`),
    302                   WebAssembly.CompileError,
    303                   /expression has type.*but expected.*/);
    304 
    305 // Null pointer dereference in struct.get
    306 
    307 assertErrorMessage(function() {
    308    let ins = wasmEvalText(
    309        `(module
    310          (type $node (struct (field i32)))
    311          (func (export "test")
    312           (drop (call $f (ref.null $node))))
    313          (func $f (param $p (ref null $node)) (result i32)
    314           (struct.get $node 0 (local.get $p))))`);
    315    ins.exports.test();
    316 },
    317                   WebAssembly.RuntimeError,
    318                   /dereferencing null pointer/);
    319 
    320 // Null pointer dereference in struct.set
    321 
    322 assertErrorMessage(function() {
    323    let ins = wasmEvalText(
    324        `(module
    325          (type $node (struct (field (mut i32))))
    326          (func (export "test")
    327           (call $f (ref.null $node)))
    328          (func $f (param $p (ref null $node))
    329           (struct.set $node 0 (local.get $p) (i32.const 0))))`);
    330    ins.exports.test();
    331 },
    332                   WebAssembly.RuntimeError,
    333                   /dereferencing null pointer/);