limits.js (9506B)
1 // Tests of limits of memory and table types 2 3 const PageSize = PageSizeInBytes; 4 const MemoryMaxValid = 65536; 5 const MemoryMaxRuntime = MaxPagesIn32BitMemory; 6 7 const TableMaxValid = 0xffff_ffff; 8 const TableMaxRuntime = 10_000_000; 9 10 // Test that a memory type is valid within a module 11 function testMemoryValidate(initial, maximum, shared) { 12 wasmValidateText(`(module 13 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 14 )`); 15 } 16 17 testMemoryValidate(0, undefined, false); 18 testMemoryValidate(1, undefined, false); 19 testMemoryValidate(0, 1, false); 20 testMemoryValidate(0, 1, true); 21 testMemoryValidate(1, 1, false); 22 testMemoryValidate(1, 1, true); 23 testMemoryValidate(MemoryMaxValid, undefined, false); 24 testMemoryValidate(MemoryMaxValid, MemoryMaxValid, false); 25 testMemoryValidate(MemoryMaxValid, MemoryMaxValid, true); 26 27 // Test that a memory type is not valid within a module 28 function testMemoryFailValidate(initial, maximum, shared, pattern) { 29 wasmFailValidateText(`(module 30 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 31 )`, pattern); 32 } 33 34 testMemoryFailValidate(2, 1, false, /size minimum must not be greater than maximum/); 35 testMemoryFailValidate(1, undefined, true, /maximum length required for shared memory/); 36 testMemoryFailValidate(MemoryMaxValid + 1, undefined, false, /initial memory size too big/); 37 testMemoryFailValidate(MemoryMaxValid, MemoryMaxValid + 1, false, /maximum memory size too big/); 38 testMemoryFailValidate(MemoryMaxValid, MemoryMaxValid + 1, true, /maximum memory size too big/); 39 40 // Test that a memory type is invalid for constructing a WebAssembly.Memory 41 function testMemoryFailConstruct(initial, maximum, shared, pattern) { 42 assertErrorMessage(() => new WebAssembly.Memory({ 43 initial, 44 maximum, 45 shared 46 }), RangeError, pattern); 47 } 48 49 // Test initial length, giving a maximum only if required due to being shared 50 testMemoryFailConstruct(MemoryMaxValid + 1, undefined, false, /bad Memory initial size/); 51 testMemoryFailConstruct(MemoryMaxValid + 1, MemoryMaxValid + 1, true, /bad Memory initial size/); 52 // Test maximum length 53 testMemoryFailConstruct(0, MemoryMaxValid + 1, false, /bad Memory maximum size/); 54 testMemoryFailConstruct(0, MemoryMaxValid + 1, true, /bad Memory maximum size/); 55 56 // Test that a memory type can be instantiated within a module or constructed 57 // with a WebAssembly.Memory 58 function testMemoryCreate(initial, maximum, shared) { 59 // May OOM, but must not fail to validate 60 try { 61 wasmEvalText(`(module 62 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 63 )`); 64 } catch (e) { 65 assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`); 66 } 67 try { 68 new WebAssembly.Memory({initial, maximum, shared}); 69 } catch (e) { 70 assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`); 71 } 72 } 73 74 testMemoryCreate(0, undefined, false); 75 testMemoryCreate(1, undefined, false); 76 testMemoryCreate(0, 1, false); 77 testMemoryCreate(0, 1, true); 78 testMemoryCreate(1, 1, false); 79 testMemoryCreate(1, 1, true); 80 testMemoryCreate(MemoryMaxRuntime, undefined, false); 81 testMemoryCreate(MemoryMaxRuntime, MemoryMaxValid, false); 82 testMemoryCreate(MemoryMaxRuntime, MemoryMaxValid, true); 83 84 // Test that a memory type cannot be instantiated within a module or constructed 85 // with a WebAssembly.Memory 86 87 if (MemoryMaxRuntime < 65536) { 88 let testMemoryFailCreate = function(initial, maximum, shared) { 89 assertErrorMessage(() => wasmEvalText(`(module 90 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 91 )`), WebAssembly.RuntimeError, /too many memory pages/); 92 assertErrorMessage(() => new WebAssembly.Memory({ 93 initial, 94 maximum, 95 shared 96 }), WebAssembly.RuntimeError, /too many memory pages/); 97 } 98 99 testMemoryFailCreate(MemoryMaxRuntime + 1, undefined, false); 100 testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, false); 101 testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, true); 102 } else { 103 let testMemoryFailCreate = function(initial, maximum, shared, jsError, jsMsg) { 104 assertErrorMessage(() => wasmEvalText(`(module 105 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 106 )`), WebAssembly.CompileError, /(initial memory size too big)|(memory size minimum must not be greater than maximum)/); 107 assertErrorMessage(() => new WebAssembly.Memory({ 108 initial, 109 maximum, 110 shared 111 }), jsError, jsMsg); 112 } 113 114 testMemoryFailCreate(MemoryMaxRuntime + 1, undefined, false, RangeError, /bad Memory initial size/); 115 testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, false, RangeError, /initial Memory size cannot be greater than maximum/); 116 testMemoryFailCreate(MemoryMaxRuntime + 1, MemoryMaxValid, true, RangeError, /initial Memory size cannot be greater than maximum/); 117 } 118 119 120 // Test that a memory type cannot be grown from initial to a target due to an 121 // implementation limit 122 function testMemoryFailGrow(initial, maximum, target, shared) { 123 let {run} = wasmEvalText(`(module 124 (memory ${initial} ${maximum || ''} ${shared ? 'shared' : ''}) 125 (func (export "run") (result i32) 126 i32.const ${target - initial} 127 memory.grow 128 ) 129 )`).exports; 130 assertEq(run(), -1, 'failed to grow'); 131 132 let mem = new WebAssembly.Memory({ 133 initial, 134 maximum, 135 shared 136 }); 137 assertErrorMessage(() => mem.grow(target - initial), RangeError, /failed to grow memory/); 138 } 139 140 testMemoryFailGrow(1, undefined, MemoryMaxRuntime + 1, false); 141 testMemoryFailGrow(1, MemoryMaxValid, MemoryMaxRuntime + 1, false); 142 testMemoryFailGrow(1, MemoryMaxValid, MemoryMaxRuntime + 1, true); 143 144 // Test that a table type is valid within a module 145 function testTableValidate(initial, maximum) { 146 wasmValidateText(`(module 147 (table ${initial} ${maximum || ''} funcref) 148 )`); 149 } 150 151 testTableValidate(0, undefined); 152 testTableValidate(1, undefined); 153 testTableValidate(0, 1); 154 testTableValidate(1, 1); 155 testTableValidate(TableMaxValid, undefined); 156 testTableValidate(TableMaxValid, TableMaxValid); 157 158 // Test that a table type is not valid within a module 159 function testTableFailValidate(initial, maximum, pattern) { 160 wasmFailValidateText(`(module 161 (table ${initial} ${maximum || ''} funcref) 162 )`, pattern); 163 } 164 165 testTableFailValidate(2, 1, /size minimum must not be greater than maximum/); 166 // The maximum valid table value is equivalent to the maximum encodable limit 167 // value, so we cannot test too large of a table limit in a module. 168 assertEq(TableMaxValid + 1 > 0xffffffff, true); 169 170 // Test that a table type is invalid for constructing a WebAssembly.Table 171 function testTableFailConstruct(initial, maximum, pattern) { 172 assertErrorMessage(() => new WebAssembly.Table({ 173 initial, 174 maximum, 175 element: 'funcref', 176 }), TypeError, pattern); 177 } 178 179 testTableFailConstruct(TableMaxValid + 1, undefined, /bad Table initial size/); 180 testTableFailConstruct(0, TableMaxValid + 1, /bad Table maximum size/); 181 182 // Test that a table type can be instantiated within a module or constructed 183 // with a WebAssembly.Table 184 function testTableCreate(initial, maximum) { 185 // May OOM, but must not fail to validate 186 try { 187 wasmEvalText(`(module 188 (table ${initial} ${maximum || ''} funcref) 189 )`); 190 } catch (e) { 191 assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`); 192 } 193 try { 194 new WebAssembly.Table({ 195 initial, 196 maximum, 197 element: 'funcref', 198 }); 199 } catch (e) { 200 assertEq(String(e).indexOf("out of memory") !== -1, true, `${e}`); 201 } 202 } 203 204 testTableCreate(0, undefined); 205 testTableCreate(1, undefined); 206 testTableCreate(0, 1); 207 testTableCreate(1, 1); 208 testTableCreate(TableMaxRuntime, undefined); 209 testTableCreate(TableMaxRuntime, TableMaxValid); 210 211 // Test that a table type cannot be instantiated within a module or constructed 212 // with a WebAssembly.Table 213 function testTableFailCreate(initial, maximum, pattern) { 214 assertErrorMessage(() => wasmEvalText(`(module 215 (table ${initial} ${maximum || ''} funcref) 216 )`), WebAssembly.RuntimeError, pattern); 217 assertErrorMessage(() => new WebAssembly.Table({ 218 initial, 219 maximum, 220 element: 'funcref', 221 }), WebAssembly.RuntimeError, pattern); 222 } 223 224 testTableFailCreate(TableMaxRuntime + 1, undefined, /too many table elements/); 225 testTableFailCreate(TableMaxRuntime + 1, TableMaxValid, /too many table elements/); 226 227 // Test that a table type cannot be grown from initial to a target due to an 228 // implementation limit 229 function testTableFailGrow(initial, maximum, target) { 230 let {run} = wasmEvalText(`(module 231 (table ${initial} ${maximum || ''} externref) 232 (func (export "run") (result i32) 233 ref.null extern 234 i32.const ${target - initial} 235 table.grow 236 ) 237 )`).exports; 238 assertEq(run(), -1, 'failed to grow'); 239 240 let tab = new WebAssembly.Table({ 241 initial, 242 maximum, 243 element: 'externref', 244 }); 245 assertErrorMessage(() => tab.grow(target - initial), RangeError, /failed to grow table/); 246 } 247 248 testTableFailGrow(1, undefined, TableMaxRuntime + 1); 249 testTableFailGrow(1, TableMaxValid, TableMaxRuntime + 1); 250 251 // Testing the maximum number of memories in a single module. 252 function generateMemories(count) { 253 let lines = ['(module']; 254 for (let i = 0; i < count; i++) { 255 lines.push(` (memory 10 50)`); 256 } 257 lines.push(')'); 258 return lines.join('\n'); 259 } 260 261 wasmValidateText(generateMemories(MaxMemories)); 262 263 assertErrorMessage(() => wasmEvalText(generateMemories(MaxMemories+1)), 264 WebAssembly.CompileError, /too many memories/);