tor-browser

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

structs2.js (12179B)


      1 // |jit-test| test-also=--gc-zeal=2
      2 
      3 // This tests 8- and 16-bit field accesses for structs.
      4 
      5 // Check that struct.new writes for 8-bit fields do not overwrite subsequent
      6 // data.  Because the writes happen forwards in the address space, the only
      7 // way I could think to do this is to force an 8-bit field to occupy the last
      8 // byte of the OOL malloc'd block, and then hope that ASan runs in automation
      9 // will pick up any overrun.  I think it's impossible to test this from inside
     10 // the JS+wasm universe.  Hence the test is pretty pointless from a purely
     11 // JS+wasm interpretation.
     12 {
     13    let txt =
     14    `(module
     15        (type $hasOOL (struct
     16                      ;; In-line storage; 16 fields that preserve 16-alignment
     17                      (field i64) (field i64) (field i64) (field i64) ;; 32
     18                      (field i64) (field i64) (field i64) (field i64) ;; 64
     19                      (field i64) (field i64) (field i64) (field i64) ;; 96
     20                      (field i64) (field i64) (field i64) (field i64) ;; 128
     21                      ;; Out-of-line storage (or maybe it starts earlier, but
     22                      ;; definitely not after this point).  16 bytes on the
     23                      ;; basis that StructLayout::close will round the requested
     24                      ;; block size up to at max the next 16 byte boundary.
     25                      ;; The goal is that the last (field i8) is right at the
     26                      ;; end of the resulting malloc'd block, so that, if the
     27                      ;; struct.new initialisation code mistakenly initialises
     28                      ;; that field with a write larger than 8 bits, then we'll
     29                      ;; have a write off the end of the malloc'd block, which
     30                      ;; ASan automation runs should detect.
     31                      (field i8) (field i8) (field i8) (field i8)
     32                      (field i8) (field i8) (field i8) (field i8)
     33                      (field i8) (field i8) (field i8) (field i8)
     34                      (field i8) (field i8) (field i8) (field i8))
     35        )
     36        (func (export "build8")
     37              (param $filler i64) (param $interesting i32) (result eqref)
     38          (struct.new $hasOOL
     39                      (local.get $filler) (local.get $filler)
     40                      (local.get $filler) (local.get $filler)
     41                      (local.get $filler) (local.get $filler)
     42                      (local.get $filler) (local.get $filler)
     43                      (local.get $filler) (local.get $filler)
     44                      (local.get $filler) (local.get $filler)
     45                      (local.get $filler) (local.get $filler)
     46                      (local.get $filler) (local.get $filler)
     47                      (local.get $interesting) (local.get $interesting)
     48                      (local.get $interesting) (local.get $interesting)
     49                      (local.get $interesting) (local.get $interesting)
     50                      (local.get $interesting) (local.get $interesting)
     51                      (local.get $interesting) (local.get $interesting)
     52                      (local.get $interesting) (local.get $interesting)
     53                      (local.get $interesting) (local.get $interesting)
     54                      (local.get $interesting) (local.get $interesting)
     55          )
     56        )
     57     )`;
     58    let exports = wasmEvalText(txt).exports;
     59    let obj8 = exports.build8(0x1234n, 0x5678);
     60    // The above call should trigger OOB writes if the struct.new field
     61    // writes are too large, but those will only be visible if we're running
     62    // on ASan or Valgrind.  In any case, add a fake data dependency below, so
     63    // that the construction of the object can't (so easily) be optimised away.
     64    assertEq(wasmGcReadField(obj8, 0) + BigInt(wasmGcReadField(obj8, 31)), 0x12ACn); // == 0x1234 + 0x78
     65 }
     66 
     67 // And exactly the same, except for 16 bit fields.
     68 {
     69    let txt =
     70    `(module
     71        (type $hasOOL (struct
     72                      ;; in-line storage
     73                      (field i64) (field i64) (field i64) (field i64) ;; 32
     74                      (field i64) (field i64) (field i64) (field i64) ;; 64
     75                      (field i64) (field i64) (field i64) (field i64) ;; 96
     76                      (field i64) (field i64) (field i64) (field i64) ;; 128
     77                      (field i16) (field i16) (field i16) (field i16)
     78                      (field i16) (field i16) (field i16) (field i16))
     79        )
     80        (func (export "build16")
     81              (param $filler i64) (param $interesting i32) (result eqref)
     82          (struct.new $hasOOL
     83                      (local.get $filler) (local.get $filler)
     84                      (local.get $filler) (local.get $filler)
     85                      (local.get $filler) (local.get $filler)
     86                      (local.get $filler) (local.get $filler)
     87                      (local.get $filler) (local.get $filler)
     88                      (local.get $filler) (local.get $filler)
     89                      (local.get $filler) (local.get $filler)
     90                      (local.get $filler) (local.get $filler)
     91                      (local.get $interesting) (local.get $interesting)
     92                      (local.get $interesting) (local.get $interesting)
     93                      (local.get $interesting) (local.get $interesting)
     94                      (local.get $interesting) (local.get $interesting)
     95          )
     96        )
     97     )`;
     98    let exports = wasmEvalText(txt).exports;
     99    let obj16 = exports.build16(0x4321n, 0x7865);
    100    assertEq(wasmGcReadField(obj16, 0) + BigInt(wasmGcReadField(obj16, 23)), 0xBB86n); // == 0x4321 + 0x7865
    101 }
    102 
    103 // Test that 8-bit field writes do not overwrite adjacent fields.
    104 {
    105    let txt =
    106    `(module
    107        (type $struct8x8
    108           (struct (field i8) (field i8) (field i8) (field (mut i8))
    109                   (field i8) (field i8) (field i8) (field i8)
    110        ))
    111        (func (export "create") (result eqref)
    112           (struct.new $struct8x8 (i32.const 0x55) (i32.const 0x55)
    113                                  (i32.const 0x55) (i32.const 0x55)
    114                                  (i32.const 0x55) (i32.const 0x55)
    115                                  (i32.const 0x55) (i32.const 0x55)
    116        ))
    117        (func (export "writeField8x8_3") (param $p eqref) (param $v i32)
    118           (struct.set $struct8x8 3 (ref.cast (ref null $struct8x8) (local.get $p))
    119                                    (local.get $v))
    120        )
    121     )`;
    122    let exports = wasmEvalText(txt).exports;
    123    let theObject = exports.create();
    124    exports.writeField8x8_3(theObject, 0x77);
    125    assertEq(wasmGcReadField(theObject, 0), 0x55);
    126    assertEq(wasmGcReadField(theObject, 1), 0x55);
    127    assertEq(wasmGcReadField(theObject, 2), 0x55);
    128    assertEq(wasmGcReadField(theObject, 3), 0x77);
    129    assertEq(wasmGcReadField(theObject, 4), 0x55);
    130    assertEq(wasmGcReadField(theObject, 5), 0x55);
    131    assertEq(wasmGcReadField(theObject, 6), 0x55);
    132    assertEq(wasmGcReadField(theObject, 7), 0x55);
    133 }
    134 
    135 // Test that 16-bit field writes do not overwrite adjacent fields.
    136 {
    137    let txt =
    138    `(module
    139        (type $struct16x8
    140           (struct (field i16) (field i16) (field i16) (field (mut i16))
    141                   (field i16) (field i16) (field i16) (field i16)
    142        ))
    143        (func (export "create") (result eqref)
    144           (struct.new $struct16x8 (i32.const 0x5555) (i32.const 0x5555)
    145                                   (i32.const 0x5555) (i32.const 0x5555)
    146                                   (i32.const 0x5555) (i32.const 0x5555)
    147                                   (i32.const 0x5555) (i32.const 0x5555)
    148        ))
    149        (func (export "writeField16x8_3") (param $p eqref) (param $v i32)
    150           (struct.set $struct16x8 3 (ref.cast (ref null $struct16x8) (local.get $p))
    151                                    (local.get $v))
    152        )
    153     )`;
    154    let exports = wasmEvalText(txt).exports;
    155    let theObject = exports.create();
    156    exports.writeField16x8_3(theObject, 0x7766);
    157    assertEq(wasmGcReadField(theObject, 0), 0x5555);
    158    assertEq(wasmGcReadField(theObject, 1), 0x5555);
    159    assertEq(wasmGcReadField(theObject, 2), 0x5555);
    160    assertEq(wasmGcReadField(theObject, 3), 0x7766);
    161    assertEq(wasmGcReadField(theObject, 4), 0x5555);
    162    assertEq(wasmGcReadField(theObject, 5), 0x5555);
    163    assertEq(wasmGcReadField(theObject, 6), 0x5555);
    164    assertEq(wasmGcReadField(theObject, 7), 0x5555);
    165 }
    166 
    167 // Test that 8-bit field reads sign/zero extend correctly.
    168 {
    169    let txt =
    170    `(module
    171        (type $struct8x8
    172           (struct (field i8) (field i8) (field i8) (field i8)
    173                   (field i8) (field i8) (field i8) (field i8)
    174        ))
    175        (func (export "create") (result eqref)
    176           (struct.new $struct8x8 (i32.const 0x11) (i32.const 0x82)
    177                                  (i32.const 0x23) (i32.const 0x94)
    178                                  (i32.const 0x35) (i32.const 0xA6)
    179                                  (i32.const 0x47) (i32.const 0xB8)
    180        ))
    181        ;; read i8 from a field, unsigned extend, read value has top bit 0
    182        (func (export "readU8hi0") (param $p eqref) (result i32)
    183           (struct.get_u $struct8x8 2 (ref.cast (ref null $struct8x8) (local.get $p)))
    184        )
    185        ;; read i8 from a field, unsigned extend, read value has top bit 1
    186        (func (export "readU8hi1") (param $p eqref) (result i32)
    187           (struct.get_u $struct8x8 3 (ref.cast (ref null $struct8x8) (local.get $p)))
    188        )
    189        ;; read i8 from a field, signed extend, read value has top bit 0
    190        (func (export "readS8hi0") (param $p eqref) (result i32)
    191           (struct.get_s $struct8x8 4 (ref.cast (ref null $struct8x8) (local.get $p)))
    192        )
    193        ;; read i8 from a field, signed extend, read value has top bit 1
    194        (func (export "readS8hi1") (param $p eqref) (result i32)
    195           (struct.get_s $struct8x8 5 (ref.cast (ref null $struct8x8) (local.get $p)))
    196        )
    197     )`;
    198    let exports = wasmEvalText(txt).exports;
    199    let theObject = exports.create();
    200    assertEq(exports.readU8hi0(theObject), 0x23);  // zx of 0x23
    201    assertEq(exports.readU8hi1(theObject), 0x94);  // zx of 0x94
    202    assertEq(exports.readS8hi0(theObject), 0x35);  // sx of 0x35
    203    assertEq(exports.readS8hi1(theObject), -0x5A); // sx of 0xA6
    204 }
    205 
    206 // Test that 16-bit field reads sign/zero extend correctly.
    207 {
    208    let txt =
    209    `(module
    210        (type $struct16x8
    211           (struct (field i16) (field i16) (field i16) (field i16)
    212                   (field i16) (field i16) (field i16) (field i16)
    213        ))
    214        (func (export "create") (result eqref)
    215           (struct.new $struct16x8 (i32.const 0x11FF) (i32.const 0x82FE)
    216                                   (i32.const 0x23FD) (i32.const 0x94FC)
    217                                   (i32.const 0x35FB) (i32.const 0xA6FA)
    218                                   (i32.const 0x47F9) (i32.const 0xB8F8)
    219        ))
    220        ;; read i16 from a field, unsigned extend, read value has top bit 0
    221        (func (export "readU16hi0") (param $p eqref) (result i32)
    222           (struct.get_u $struct16x8 2 (ref.cast (ref null $struct16x8) (local.get $p)))
    223        )
    224        ;; read i16 from a field, unsigned extend, read value has top bit 1
    225        (func (export "readU16hi1") (param $p eqref) (result i32)
    226           (struct.get_u $struct16x8 3 (ref.cast (ref null $struct16x8) (local.get $p)))
    227        )
    228        ;; read i16 from a field, signed extend, read value has top bit 0
    229        (func (export "readS16hi0") (param $p eqref) (result i32)
    230           (struct.get_s $struct16x8 4 (ref.cast (ref null $struct16x8) (local.get $p)))
    231        )
    232        ;; read i16 from a field, signed extend, read value has top bit 1
    233        (func (export "readS16hi1") (param $p eqref) (result i32)
    234           (struct.get_s $struct16x8 5 (ref.cast (ref null $struct16x8) (local.get $p)))
    235        )
    236     )`;
    237    let exports = wasmEvalText(txt).exports;
    238    let theObject = exports.create();
    239    assertEq(exports.readU16hi0(theObject), 0x23FD);  // zx of 0x23FD
    240    assertEq(exports.readU16hi1(theObject), 0x94FC);  // zx of 0x94FC
    241    assertEq(exports.readS16hi0(theObject), 0x35FB);  // sx of 0x35FB
    242    assertEq(exports.readS16hi1(theObject), -0x5906); // sx of 0xA6FC
    243 }