1/*
2 * Copyright (C) 2016-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WasmValidate.h"
28
29#if ENABLE(WEBASSEMBLY)
30
31#include "JSCJSValueInlines.h"
32#include "WasmFunctionParser.h"
33#include "WasmSignature.h"
34#include <wtf/CommaPrinter.h>
35
36namespace JSC { namespace Wasm {
37
38class Validate {
39public:
40 class ControlData {
41 public:
42 ControlData() = default;
43 ControlData(BlockType type, BlockSignature signature)
44 : m_blockType(type)
45 , m_signature(signature)
46 {
47 }
48
49 void dump(PrintStream& out) const
50 {
51 switch (blockType()) {
52 case BlockType::If:
53 out.print("If: ");
54 break;
55 case BlockType::Block:
56 out.print("Block: ");
57 break;
58 case BlockType::Loop:
59 out.print("Loop: ");
60 break;
61 case BlockType::TopLevel:
62 out.print("TopLevel: ");
63 break;
64 }
65 const Signature& sig = *signature();
66 out.print(sig);
67 }
68
69 BlockType blockType() const { return m_blockType; }
70 BlockSignature signature() const { return m_signature; }
71
72 unsigned branchTargetArity() const { return blockType() == BlockType::Loop ? signature()->argumentCount() : signature()->returnCount(); }
73 Type branchTargetType(unsigned i) const
74 {
75 ASSERT(i < branchTargetArity());
76 return blockType() == BlockType::Loop ? signature()->argument(i) : signature()->returnType(i);
77 }
78
79 private:
80 BlockType m_blockType;
81 BlockSignature m_signature;
82 };
83
84 typedef String ErrorType;
85 typedef Unexpected<ErrorType> UnexpectedResult;
86 typedef Expected<void, ErrorType> Result;
87 using ExpressionType = Type;
88 using ExpressionList = Vector<ExpressionType, 1>;
89 using Stack = ExpressionList;
90 typedef ControlData ControlType;
91 typedef ExpressionList ResultList;
92 typedef FunctionParser<Validate>::ControlEntry ControlEntry;
93
94 static constexpr ExpressionType emptyExpression() { return Void; }
95 Stack createStack() { return Stack(); }
96 bool isControlTypeIf(const ControlType& control) { return control.blockType() == BlockType::If; }
97
98 template <typename ...Args>
99 NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(const Args&... args) const
100 {
101 using namespace FailureHelper; // See ADL comment in WasmParser.h.
102 if (UNLIKELY(!ASSERT_DISABLED && Options::crashOnFailedWebAssemblyValidate()))
103 WTFBreakpointTrap();
104
105 StringPrintStream out;
106 out.print("WebAssembly.Module doesn't validate: "_s, args...);
107 return UnexpectedResult(out.toString());
108 }
109#define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \
110 if (UNLIKELY(condition)) \
111 return fail(__VA_ARGS__); \
112 } while (0)
113
114 Result WARN_UNUSED_RETURN addArguments(const Signature&);
115 Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
116 ExpressionType addConstant(Type type, uint64_t) { return type; }
117
118 // References
119 Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
120 Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
121
122 // Tables
123 Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
124 Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
125 Result WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result);
126 Result WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result);
127 Result WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count);
128 // Locals
129 Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
130 Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
131
132 // Globals
133 Result WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
134 Result WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
135
136 // Memory
137 Result WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
138 Result WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
139
140 // Basic operators
141 template<OpType>
142 Result WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
143 template<OpType>
144 Result WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
145 Result WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
146
147 // Control flow
148 ControlData WARN_UNUSED_RETURN addTopLevel(BlockSignature);
149 Result WARN_UNUSED_RETURN addBlock(BlockSignature, Stack& enclosingStack, ControlType& newBlock, Stack& newStack);
150 Result WARN_UNUSED_RETURN addLoop(BlockSignature, Stack& enclosingStack, ControlType& block, Stack& newStack, uint32_t loopIndex);
151 Result WARN_UNUSED_RETURN addIf(ExpressionType condition, BlockSignature, Stack& enclosingStack, ControlType& result, Stack& newStack);
152 Result WARN_UNUSED_RETURN addElse(ControlData&, const Stack&);
153 Result WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
154
155 Result WARN_UNUSED_RETURN addReturn(ControlData& topLevel, const Stack& returnValues);
156 Result WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const Stack& expressionStack);
157 Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const Stack& expressionStack);
158 Result WARN_UNUSED_RETURN endBlock(ControlEntry&, Stack& expressionStack);
159 Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
160 Result WARN_UNUSED_RETURN addGrowMemory(ExpressionType delta, ExpressionType& result);
161 Result WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
162
163 Result WARN_UNUSED_RETURN addUnreachable() { return { }; }
164
165 // Calls
166 Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature&, const Vector<ExpressionType>& args, ResultList&);
167 Result WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, const Vector<ExpressionType>& args, ResultList&);
168
169 bool hasMemory() const { return !!m_module.memory; }
170
171 Validate(const ModuleInformation& module)
172 : m_module(module)
173 {
174 }
175
176 void dump(const Vector<ControlEntry>&, const Stack*);
177 void setParser(FunctionParser<Validate>*) { }
178 void didFinishParsingLocals() { }
179
180private:
181 Result WARN_UNUSED_RETURN unify(const Stack&, const ControlData&);
182
183 Result WARN_UNUSED_RETURN checkBranchTarget(ControlData& target, const Stack& expressionStack);
184
185 Vector<Type> m_locals;
186 const ModuleInformation& m_module;
187};
188
189auto Validate::addArguments(const Signature& signature) -> Result
190{
191 for (size_t i = 0; i < signature.argumentCount(); ++i)
192 WASM_FAIL_IF_HELPER_FAILS(addLocal(signature.argument(i), 1));
193 return { };
194}
195
196auto Validate::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> Result
197{
198 WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
199 result = m_module.tables[tableIndex].wasmType();
200 WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", makeString(index), " expected ", makeString(Type::I32));
201
202 return { };
203}
204
205auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> Result
206{
207 WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
208 auto type = m_module.tables[tableIndex].wasmType();
209 WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
210 WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
211 RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Anyref || m_module.tables[tableIndex].type() == TableElementType::Funcref);
212
213 return { };
214}
215
216auto Validate::addTableSize(unsigned tableIndex, ExpressionType& result) -> Result
217{
218 result = Type::I32;
219 WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
220
221 return { };
222}
223
224auto Validate::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> Result
225{
226 result = Type::I32;
227 WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
228 WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.grow expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill);
229 WASM_VALIDATOR_FAIL_IF(Type::I32 != delta, "table.grow expects an i32 delta value, got ", makeString(delta));
230
231 return { };
232}
233
234auto Validate::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> Result
235{
236 WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
237 WASM_VALIDATOR_FAIL_IF(!isSubtype(fill, m_module.tables[tableIndex].wasmType()), "table.fill expects fill value of type ", m_module.tables[tableIndex].wasmType(), " got ", fill);
238 WASM_VALIDATOR_FAIL_IF(Type::I32 != offset, "table.fill expects an i32 offset value, got ", makeString(offset));
239 WASM_VALIDATOR_FAIL_IF(Type::I32 != count, "table.fill expects an i32 count value, got ", makeString(count));
240
241 return { };
242}
243
244auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
245{
246 result = Type::I32;
247 WASM_VALIDATOR_FAIL_IF(!isSubtype(value, Type::Anyref), "ref.is_null to type ", makeString(value), " expected ", makeString(Type::Anyref));
248
249 return { };
250}
251
252auto Validate::addRefFunc(uint32_t index, ExpressionType& result) -> Result
253{
254 result = Type::Funcref;
255 WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_module.functionIndexSpaceSize());
256 m_module.addReferencedFunction(index);
257
258 return { };
259}
260
261auto Validate::addLocal(Type type, uint32_t count) -> Result
262{
263 size_t newSize = m_locals.size() + count;
264 ASSERT(!(CheckedUint32(count) + m_locals.size()).hasOverflowed());
265 ASSERT(newSize <= maxFunctionLocals);
266 WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(newSize), "can't allocate memory for ", newSize, " locals");
267
268 for (uint32_t i = 0; i < count; ++i)
269 m_locals.uncheckedAppend(type);
270 return { };
271}
272
273auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result
274{
275 WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
276 result = m_locals[index];
277 return { };
278}
279
280auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result
281{
282 ExpressionType localType;
283 WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
284 WASM_VALIDATOR_FAIL_IF(!isSubtype(value, localType), "set_local to type ", value, " expected ", localType);
285 return { };
286}
287
288auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result
289{
290 WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size());
291 result = m_module.globals[index].type;
292 ASSERT(isValueType(result));
293 return { };
294}
295
296auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result
297{
298 WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size());
299 WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == Global::Immutable, "set_global ", index, " is immutable");
300
301 ExpressionType globalType = m_module.globals[index].type;
302 ASSERT(isValueType(globalType));
303 WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value);
304 return { };
305}
306
307Validate::ControlType Validate::addTopLevel(BlockSignature signature)
308{
309 return ControlData(BlockType::TopLevel, signature);
310}
311
312static Validate::Stack splitStack(BlockSignature signature, Validate::Stack& stack)
313{
314 Validate::Stack result;
315 result.reserveInitialCapacity(signature->argumentCount());
316 ASSERT(stack.size() >= signature->argumentCount());
317 unsigned offset = stack.size() - signature->argumentCount();
318 for (unsigned i = 0; i < signature->argumentCount(); ++i)
319 result.uncheckedAppend(stack[i + offset]);
320 stack.shrink(offset);
321 return result;
322}
323
324auto Validate::addBlock(BlockSignature signature, Stack& enclosingStack, ControlType& newBlock, Stack& newStack) -> Result
325{
326 WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few values on stack for block. Block expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. Block has signature: ", *signature);
327 newStack = splitStack(signature, enclosingStack);
328 newBlock = ControlData(BlockType::Block, signature);
329 for (unsigned i = 0; i < signature->argumentCount(); ++i)
330 WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
331 return { };
332}
333
334auto Validate::addLoop(BlockSignature signature, Stack& enclosingStack, ControlType& loop, Stack& newStack, uint32_t) -> Result
335{
336 WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few values on stack for loop block. Loop expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. Loop has signature: ", *signature);
337 newStack = splitStack(signature, enclosingStack);
338 loop = ControlData(BlockType::Loop, signature);
339 for (unsigned i = 0; i < signature->argumentCount(); ++i)
340 WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
341 return { };
342}
343
344auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result
345{
346 WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition);
347 WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero);
348 result = zero;
349 return { };
350}
351
352auto Validate::addIf(ExpressionType condition, BlockSignature signature, Stack& enclosingStack, ControlType& result, Stack& newStack) -> Result
353{
354 WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", makeString(condition));
355 WASM_VALIDATOR_FAIL_IF(enclosingStack.size() < signature->argumentCount(), "Too few arguments on stack for if block. If expects ", signature->argumentCount(), ", but only ", enclosingStack.size(), " were present. If block has signature: ", *signature);
356 newStack = splitStack(signature, enclosingStack);
357 result = ControlData(BlockType::If, signature);
358 for (unsigned i = 0; i < signature->argumentCount(); ++i)
359 WASM_VALIDATOR_FAIL_IF(!isSubtype(newStack[i], signature->argument(i)), "Loop expects the argument at index", i, " to be a subtype of ", signature->argument(i), " but argument has type ", newStack[i]);
360 return { };
361}
362
363auto Validate::addElse(ControlType& current, const Stack& values) -> Result
364{
365 WASM_FAIL_IF_HELPER_FAILS(unify(values, current));
366 return addElseToUnreachable(current);
367}
368
369auto Validate::addElseToUnreachable(ControlType& current) -> Result
370{
371 WASM_VALIDATOR_FAIL_IF(current.blockType() != BlockType::If, "else block isn't associated to an if");
372 current = ControlData(BlockType::Block, current.signature());
373 return { };
374}
375
376auto Validate::addReturn(ControlType& topLevel, const ExpressionList& returnValues) -> Result
377{
378 ASSERT(topLevel.blockType() == BlockType::TopLevel);
379 return checkBranchTarget(topLevel, returnValues);
380}
381
382auto Validate::checkBranchTarget(ControlType& target, const Stack& expressionStack) -> Result
383{
384 if (!target.branchTargetArity())
385 return { };
386
387 WASM_VALIDATOR_FAIL_IF(expressionStack.size() < target.branchTargetArity(), target.blockType() == BlockType::TopLevel ? "branch out of function" : "branch to block", " on expression stack of size ", expressionStack.size(), ", but block, ", target , " expects ", target.branchTargetArity(), " values");
388
389
390 unsigned expressionStackOffset = expressionStack.size() - target.branchTargetArity();
391 for (unsigned i = 0; i < target.branchTargetArity(); ++i)
392 WASM_VALIDATOR_FAIL_IF(!isSubtype(target.branchTargetType(i), expressionStack[expressionStackOffset + i]), "branch's stack type is not a subtype of block's type branch target type. Stack value has type", expressionStack[expressionStackOffset + i], " but branch target expects a value with subtype of ", target.branchTargetType(i), " at index ", i);
393
394 return { };
395}
396
397auto Validate::addBranch(ControlType& target, ExpressionType condition, const Stack& stack) -> Result
398{
399 // Void means this is an unconditional branch.
400 WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition);
401 return checkBranchTarget(target, stack);
402}
403
404auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const Stack& expressionStack) -> Result
405{
406 WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition);
407
408 for (unsigned i = 0; i < targets.size(); ++i) {
409 auto* target = targets[i];
410 WASM_VALIDATOR_FAIL_IF(defaultTarget.branchTargetArity() != target->branchTargetArity(), "br_table target type size mismatch. Default has size: ", defaultTarget.branchTargetArity(), "but target: ", i, " has size: ", target->branchTargetArity());
411 for (unsigned type = 0; type < defaultTarget.branchTargetArity(); ++type)
412 WASM_VALIDATOR_FAIL_IF(!isSubtype(defaultTarget.branchTargetType(type), target->branchTargetType(type)), "br_table target type mismatch at offset ", type, " expected: ", defaultTarget.branchTargetType(type), " but saw: ", target->branchTargetType(type), " when targeting block", *target);
413 }
414
415 return checkBranchTarget(defaultTarget, expressionStack);
416}
417
418auto Validate::addGrowMemory(ExpressionType delta, ExpressionType& result) -> Result
419{
420 WASM_VALIDATOR_FAIL_IF(delta != I32, "grow_memory with non-i32 delta argument has type: ", delta);
421 result = I32;
422 return { };
423}
424
425auto Validate::addCurrentMemory(ExpressionType& result) -> Result
426{
427 result = I32;
428 return { };
429}
430
431auto Validate::endBlock(ControlEntry& entry, Stack& stack) -> Result
432{
433 WASM_FAIL_IF_HELPER_FAILS(unify(stack, entry.controlData));
434 return addEndToUnreachable(entry);
435}
436
437auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
438{
439 auto block = entry.controlData;
440 RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(block.blockType() != BlockType::If);
441
442 for (unsigned i = 0; i < block.signature()->returnCount(); ++i)
443 entry.enclosedExpressionStack.append(block.signature()->returnType(i));
444 return { };
445}
446
447auto Validate::addCall(unsigned, const Signature& signature, const Vector<ExpressionType>& args, ResultList& results) -> Result
448{
449 RELEASE_ASSERT(signature.argumentCount() == args.size());
450
451 for (unsigned i = 0; i < args.size(); ++i)
452 WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
453
454 for (unsigned i = 0; i < signature.returnCount(); ++i)
455 results.append(signature.returnType(i));
456 return { };
457}
458
459auto Validate::addCallIndirect(unsigned tableIndex, const Signature& signature, const Vector<ExpressionType>& args, ResultList& results) -> Result
460{
461 RELEASE_ASSERT(tableIndex < m_module.tableCount());
462 RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Funcref);
463 const auto argumentCount = signature.argumentCount();
464 RELEASE_ASSERT(argumentCount == args.size() - 1);
465
466 for (unsigned i = 0; i < argumentCount; ++i)
467 WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
468
469 WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
470
471 for (unsigned i = 0; i < signature.returnCount(); ++i)
472 results.append(signature.returnType(i));
473 return { };
474}
475
476auto Validate::unify(const Stack& values, const ControlType& block) -> Result
477{
478 WASM_VALIDATOR_FAIL_IF(block.signature()->returnCount() != values.size(), " block with type: ", *block.signature(), " returns: ", block.signature()->returnCount(), " but stack has: ", values.size(), " values");
479
480 for (unsigned i = 0; i < block.signature()->returnCount(); ++i)
481 WASM_VALIDATOR_FAIL_IF(!isSubtype(values[i], block.signature()->returnType(i)), "control flow returns with unexpected type. ", values[i], " is not a subtype of ", block.signature()->returnType(i));
482
483 // WASM_VALIDATOR_FAIL_IF(values.size() != 1, "block with type: ", makeString(*block.signature()), " ends with a stack containing more than one value");
484 return { };
485}
486
487static void dumpExpressionStack(const CommaPrinter& comma, const Validate::Stack& expressionStack)
488{
489 dataLog(comma, " ExpressionStack:");
490 for (const auto& expression : expressionStack)
491 dataLog(comma, makeString(expression));
492}
493
494void Validate::dump(const Vector<ControlEntry>& controlStack, const Stack* expressionStack)
495{
496 for (size_t i = controlStack.size(); i--;) {
497 dataLog(" ", controlStack[i].controlData);
498 CommaPrinter comma(", ", "");
499 dumpExpressionStack(comma, *expressionStack);
500 expressionStack = &controlStack[i].enclosedExpressionStack;
501 dataLogLn();
502 }
503 dataLogLn();
504}
505
506Expected<void, String> validateFunction(const FunctionData& function, const Signature& signature, const ModuleInformation& module)
507{
508 Validate context(module);
509 FunctionParser<Validate> validator(context, function.data.data(), function.data.size(), signature, module);
510 WASM_FAIL_IF_HELPER_FAILS(validator.parse());
511 return { };
512}
513
514} } // namespace JSC::Wasm
515
516#include "WasmValidateInlines.h"
517
518#endif // ENABLE(WEBASSEMBLY)
519