signal-null-check.js (5576B)
1 // Checks if null dereference works. 2 3 for (let [fieldType, signedness, defaultValue] of [ 4 ['i8', '_u', 'i32.const 42'], 5 ['i8', '_s', 'i32.const -42'], 6 ['i16', '_u', 'i32.const 1'], 7 ['i16', '_s', 'i32.const -1'], 8 ['i32', '', 'i32.const 3'], 9 ['i64', '', 'i64.const -77777777777'], 10 ['f32', '', 'f32.const 1.4'], 11 ['f64', '', 'f64.const 3.14'], 12 ['externref', '', 'ref.null extern'], 13 ].concat( 14 wasmSimdEnabled() ? [['v128', '', 'v128.const i32x4 1 2 -3 4']] : [] 15 )) { 16 // Check struct.get from null struct of a field of fieldType works 17 // Check struct.set similarly 18 testStructGetSet(fieldType, signedness, defaultValue, 4); 19 // - Also when the field is in the outline_ data area? 20 testStructGetSet(fieldType, signedness, defaultValue, 1000); 21 // Check array.get similarly 22 // Check array.set from null array with element of type fieldType 23 testArrayGetSet(fieldType, signedness, defaultValue, 100); 24 } 25 26 function testStructGetSet(fieldType, signedness, defaultValue, numFields) { 27 const ins = wasmEvalText(` 28 (module 29 (type $t (struct ${ 30 Array(numFields).fill("(field (mut " + fieldType + "))").join(' ') 31 })) 32 (global $g (mut (ref null $t)) (ref.null $t)) 33 (func (export "init-null") 34 ref.null $t 35 global.set $g 36 ) 37 (func (export "init-non-null") 38 ${ Array(numFields).fill(defaultValue).join('\n ') } 39 struct.new $t 40 global.set $g 41 ) 42 (func (export "test_get_first") 43 global.get $g 44 struct.get${signedness} $t 0 45 drop 46 ) 47 (func (export "test_set_first") 48 global.get $g 49 ${defaultValue} 50 struct.set $t 0 51 ) 52 (func (export "test_get_mid") 53 global.get $g 54 struct.get${signedness} $t ${numFields >> 1} 55 drop 56 ) 57 (func (export "test_set_mid") 58 global.get $g 59 ${defaultValue} 60 struct.set $t ${numFields >> 1} 61 ) 62 (func (export "test_get_last") 63 global.get $g 64 struct.get${signedness} $t ${numFields - 1} 65 drop 66 ) 67 (func (export "test_set_last") 68 global.get $g 69 ${defaultValue} 70 struct.set $t ${numFields - 1} 71 ) 72 )`); 73 ins.exports["init-non-null"](); 74 ins.exports["test_get_first"](); 75 ins.exports["test_get_mid"](); 76 ins.exports["test_get_last"](); 77 ins.exports["test_set_first"](); 78 ins.exports["test_set_mid"](); 79 ins.exports["test_set_last"](); 80 81 ins.exports["init-null"](); 82 assertDereferenceNull(() => ins.exports["test_get_first"]()); 83 assertDereferenceNull(() => ins.exports["test_get_mid"]()); 84 assertDereferenceNull(() => ins.exports["test_get_last"]()); 85 assertDereferenceNull(() => ins.exports["test_set_first"]()); 86 assertDereferenceNull(() => ins.exports["test_set_mid"]()); 87 assertDereferenceNull(() => ins.exports["test_set_last"]()); 88 89 ins.exports["init-non-null"](); 90 ins.exports["test_set_last"](); 91 ins.exports["test_get_first"](); 92 } 93 94 function testArrayGetSet(fieldType, signedness, defaultValue, numItems) { 95 const ins = wasmEvalText(` 96 (module 97 (type $t (array (mut ${fieldType}))) 98 (global $g (mut (ref null $t)) (ref.null $t)) 99 (func (export "init-null") 100 ref.null $t 101 global.set $g 102 ) 103 (func (export "init-non-null") 104 ${defaultValue} 105 i32.const ${numItems} 106 array.new $t 107 global.set $g 108 ) 109 (func (export "test_get") (param i32) 110 global.get $g 111 local.get 0 112 array.get${signedness} $t 113 drop 114 ) 115 (func (export "test_set") (param i32) 116 global.get $g 117 local.get 0 118 ${defaultValue} 119 array.set $t 120 ) 121 )`); 122 ins.exports["init-non-null"](); 123 ins.exports["test_get"](0); 124 ins.exports["test_get"](numItems >> 1); 125 ins.exports["test_get"](numItems - 1); 126 ins.exports["test_set"](0); 127 ins.exports["test_set"](numItems >> 1); 128 ins.exports["test_set"](numItems - 1); 129 130 ins.exports["init-null"](); 131 assertDereferenceNull(() => ins.exports["test_get"](0)); 132 assertDereferenceNull(() => ins.exports["test_get"](numItems >> 1)); 133 assertDereferenceNull(() => ins.exports["test_get"](numItems - 1)); 134 assertDereferenceNull(() => ins.exports["test_set"](0)); 135 assertDereferenceNull(() => ins.exports["test_set"](numItems >> 1)); 136 assertDereferenceNull(() => ins.exports["test_set"](numItems - 1)); 137 138 ins.exports["init-non-null"](); 139 ins.exports["test_set"](3); 140 ins.exports["test_get"](0); 141 } 142 143 144 function assertDereferenceNull(fun) { 145 assertErrorMessage(fun, WebAssembly.RuntimeError, /dereferencing null pointer/); 146 } 147 148 // Linear memory loads/stores from small constant addresses also require 149 // trapsites, it seems. So check that the following is compilable -- in 150 // particular, that it doesn't produce any TrapSite placement validation errors. 151 152 const ins = wasmEvalText(` 153 (module 154 (memory 1) 155 (func (result i32) (i32.load8_s (i32.const 17))) 156 (func (result i32) (i32.load8_u (i32.const 17))) 157 (func (result i32) (i32.load16_s (i32.const 17))) 158 (func (result i32) (i32.load16_u (i32.const 17))) 159 160 (func (result i64) (i64.load8_s (i32.const 17))) 161 (func (result i64) (i64.load8_u (i32.const 17))) 162 (func (result i64) (i64.load16_s (i32.const 17))) 163 (func (result i64) (i64.load16_u (i32.const 17))) 164 165 (func (result i64) (i64.load32_s (i32.const 17))) 166 (func (result i64) (i64.load32_u (i32.const 17))) 167 168 (func (param i32) (i32.store8 (i32.const 17) (local.get 0))) 169 (func (param i32) (i32.store16 (i32.const 17) (local.get 0))) 170 171 (func (param i64) (i64.store8 (i32.const 17) (local.get 0))) 172 (func (param i64) (i64.store16 (i32.const 17) (local.get 0))) 173 (func (param i64) (i64.store32 (i32.const 17) (local.get 0))) 174 175 (func (export "leet") (result i32) (i32.const 1337)) 176 )`); 177 178 assertEq(ins.exports["leet"](), 1337);