6a0bd9ffb2f9c36e87c2e15fe1043d6a57c52ee2
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmValidate.cpp
1 /*
2  * Copyright (C) 2016 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 <wtf/CommaPrinter.h>
34
35 namespace JSC { namespace Wasm {
36
37 class Validate {
38 public:
39     class ControlData {
40     public:
41         ControlData(BlockType type, Type signature)
42             : m_blockType(type)
43             , m_signature(signature)
44         {
45         }
46
47         ControlData()
48         {
49         }
50
51         void dump(PrintStream& out) const
52         {
53             switch (type()) {
54             case BlockType::If:
55                 out.print("If:       ");
56                 break;
57             case BlockType::Block:
58                 out.print("Block:    ");
59                 break;
60             case BlockType::Loop:
61                 out.print("Loop:     ");
62                 break;
63             case BlockType::TopLevel:
64                 out.print("TopLevel: ");
65                 break;
66             }
67             out.print(makeString(signature()));
68         }
69
70         bool hasNonVoidSignature() const { return m_signature != Void; }
71
72         BlockType type() const { return m_blockType; }
73         Type signature() const { return m_signature; }
74         Type branchTargetSignature() const { return type() == BlockType::Loop ? Void : signature(); }
75     private:
76         BlockType m_blockType;
77         Type m_signature;
78     };
79     typedef String ErrorType;
80     typedef Unexpected<ErrorType> UnexpectedResult;
81     typedef Expected<void, ErrorType> Result;
82     typedef Type ExpressionType;
83     typedef ControlData ControlType;
84     typedef Vector<ExpressionType, 1> ExpressionList;
85     typedef FunctionParser<Validate>::ControlEntry ControlEntry;
86
87     static constexpr ExpressionType emptyExpression() { return Void; }
88
89     template <typename ...Args>
90     NEVER_INLINE UnexpectedResult WARN_UNUSED_RETURN fail(Args... args) const
91     {
92         using namespace FailureHelper; // See ADL comment in WasmParser.h.
93         return UnexpectedResult(makeString("WebAssembly.Module doesn't validate: "_s, makeString(args)...));
94     }
95 #define WASM_VALIDATOR_FAIL_IF(condition, ...) do { \
96         if (UNLIKELY(condition))                    \
97         return fail(__VA_ARGS__);                   \
98     } while (0)
99
100     Result WARN_UNUSED_RETURN addArguments(const Signature&);
101     Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
102     ExpressionType addConstant(Type type, uint64_t) { return type; }
103
104     // References
105     Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
106     Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
107
108     // Tables
109     Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
110     Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
111     Result WARN_UNUSED_RETURN addTableSize(unsigned, ExpressionType& result);
112     Result WARN_UNUSED_RETURN addTableGrow(unsigned, ExpressionType& fill, ExpressionType& delta, ExpressionType& result);
113     Result WARN_UNUSED_RETURN addTableFill(unsigned, ExpressionType& offset, ExpressionType& fill, ExpressionType& count);
114     // Locals
115     Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
116     Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
117
118     // Globals
119     Result WARN_UNUSED_RETURN getGlobal(uint32_t index, ExpressionType& result);
120     Result WARN_UNUSED_RETURN setGlobal(uint32_t index, ExpressionType value);
121
122     // Memory
123     Result WARN_UNUSED_RETURN load(LoadOpType, ExpressionType pointer, ExpressionType& result, uint32_t offset);
124     Result WARN_UNUSED_RETURN store(StoreOpType, ExpressionType pointer, ExpressionType value, uint32_t offset);
125
126     // Basic operators
127     template<OpType>
128     Result WARN_UNUSED_RETURN addOp(ExpressionType arg, ExpressionType& result);
129     template<OpType>
130     Result WARN_UNUSED_RETURN addOp(ExpressionType left, ExpressionType right, ExpressionType& result);
131     Result WARN_UNUSED_RETURN addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result);
132
133     // Control flow
134     ControlData WARN_UNUSED_RETURN addTopLevel(Type signature);
135     ControlData WARN_UNUSED_RETURN addBlock(Type signature);
136     ControlData WARN_UNUSED_RETURN addLoop(Type signature);
137     Result WARN_UNUSED_RETURN addIf(ExpressionType condition, Type signature, ControlData& result);
138     Result WARN_UNUSED_RETURN addElse(ControlData&, const ExpressionList&);
139     Result WARN_UNUSED_RETURN addElseToUnreachable(ControlData&);
140
141     Result WARN_UNUSED_RETURN addReturn(ControlData& topLevel, const ExpressionList& returnValues);
142     Result WARN_UNUSED_RETURN addBranch(ControlData&, ExpressionType condition, const ExpressionList& expressionStack);
143     Result WARN_UNUSED_RETURN addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack);
144     Result WARN_UNUSED_RETURN endBlock(ControlEntry&, ExpressionList& expressionStack);
145     Result WARN_UNUSED_RETURN addEndToUnreachable(ControlEntry&);
146     Result WARN_UNUSED_RETURN addGrowMemory(ExpressionType delta, ExpressionType& result);
147     Result WARN_UNUSED_RETURN addCurrentMemory(ExpressionType& result);
148
149     Result WARN_UNUSED_RETURN addUnreachable() { return { }; }
150
151     // Calls
152     Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
153     Result WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
154
155     ALWAYS_INLINE void didKill(ExpressionType) { }
156
157     bool hasMemory() const { return !!m_module.memory; }
158
159     Validate(const ModuleInformation& module)
160         : m_module(module)
161     {
162     }
163
164     void dump(const Vector<ControlEntry>&, const ExpressionList*);
165     void setParser(FunctionParser<Validate>*) { }
166
167 private:
168     Result WARN_UNUSED_RETURN unify(const ExpressionList&, const ControlData&);
169
170     Result WARN_UNUSED_RETURN checkBranchTarget(ControlData& target, const ExpressionList& expressionStack);
171
172     Vector<Type> m_locals;
173     const ModuleInformation& m_module;
174 };
175
176 auto Validate::addArguments(const Signature& signature) -> Result
177 {
178     for (size_t i = 0; i < signature.argumentCount(); ++i)
179         WASM_FAIL_IF_HELPER_FAILS(addLocal(signature.argument(i), 1));
180     return { };
181 }
182
183 auto Validate::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> Result
184 {
185     WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
186     result = m_module.tables[tableIndex].wasmType();
187     WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", index, " expected ", Type::I32);
188
189     return { };
190 }
191
192 auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> Result
193 {
194     WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
195     auto type = m_module.tables[tableIndex].wasmType();
196     WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
197     WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
198     RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Anyref || m_module.tables[tableIndex].type() == TableElementType::Funcref);
199
200     return { };
201 }
202
203 auto Validate::addTableSize(unsigned tableIndex, ExpressionType& result) -> Result
204 {
205     result = Type::I32;
206     WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
207
208     return { };
209 }
210
211 auto Validate::addTableGrow(unsigned tableIndex, ExpressionType& fill, ExpressionType& delta, ExpressionType& result) -> Result
212 {
213     result = Type::I32;
214     WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
215     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);
216     WASM_VALIDATOR_FAIL_IF(Type::I32 != delta, "table.grow expects an i32 delta value, got ", delta);
217
218     return { };
219 }
220
221 auto Validate::addTableFill(unsigned tableIndex, ExpressionType& offset, ExpressionType& fill, ExpressionType& count) -> Result
222 {
223     WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
224     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);
225     WASM_VALIDATOR_FAIL_IF(Type::I32 != offset, "table.fill expects an i32 offset value, got ", offset);
226     WASM_VALIDATOR_FAIL_IF(Type::I32 != count, "table.fill expects an i32 count value, got ", count);
227
228     return { };
229 }
230
231 auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
232 {
233     result = Type::I32;
234     WASM_VALIDATOR_FAIL_IF(!isSubtype(value, Type::Anyref), "ref.is_null to type ", value, " expected ", Type::Anyref);
235
236     return { };
237 }
238
239 auto Validate::addRefFunc(uint32_t index, ExpressionType& result) -> Result
240 {
241     result = Type::Anyfunc;
242     WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_module.functionIndexSpaceSize());
243     m_module.addReferencedFunction(index);
244
245     return { };
246 }
247
248 auto Validate::addLocal(Type type, uint32_t count) -> Result
249 {
250     size_t size = m_locals.size() + count;
251     WASM_VALIDATOR_FAIL_IF(!m_locals.tryReserveCapacity(size), "can't allocate memory for ", size, " locals");
252
253     for (uint32_t i = 0; i < count; ++i)
254         m_locals.uncheckedAppend(type);
255     return { };
256 }
257
258 auto Validate::getLocal(uint32_t index, ExpressionType& result) -> Result
259 {
260     WASM_VALIDATOR_FAIL_IF(index >= m_locals.size(), "attempt to use unknown local ", index, " last one is ", m_locals.size());
261     result = m_locals[index];
262     return { };
263 }
264
265 auto Validate::setLocal(uint32_t index, ExpressionType value) -> Result
266 {
267     ExpressionType localType;
268     WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
269     WASM_VALIDATOR_FAIL_IF(!isSubtype(value, localType), "set_local to type ", value, " expected ", localType);
270     return { };
271 }
272
273 auto Validate::getGlobal(uint32_t index, ExpressionType& result) -> Result
274 {
275     WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "get_global ", index, " of unknown global, limit is ", m_module.globals.size());
276     result = m_module.globals[index].type;
277     ASSERT(isValueType(result));
278     return { };
279 }
280
281 auto Validate::setGlobal(uint32_t index, ExpressionType value) -> Result
282 {
283     WASM_VALIDATOR_FAIL_IF(index >= m_module.globals.size(), "set_global ", index, " of unknown global, limit is ", m_module.globals.size());
284     WASM_VALIDATOR_FAIL_IF(m_module.globals[index].mutability == Global::Immutable, "set_global ", index, " is immutable");
285
286     ExpressionType globalType = m_module.globals[index].type;
287     ASSERT(isValueType(globalType));
288     WASM_VALIDATOR_FAIL_IF(globalType != value, "set_global ", index, " with type ", globalType, " with a variable of type ", value);
289     return { };
290 }
291
292 Validate::ControlType Validate::addTopLevel(Type signature)
293 {
294     return ControlData(BlockType::TopLevel, signature);
295 }
296
297 Validate::ControlType Validate::addBlock(Type signature)
298 {
299     return ControlData(BlockType::Block, signature);
300 }
301
302 Validate::ControlType Validate::addLoop(Type signature)
303 {
304     return ControlData(BlockType::Loop, signature);
305 }
306
307 auto Validate::addSelect(ExpressionType condition, ExpressionType nonZero, ExpressionType zero, ExpressionType& result) -> Result
308 {
309     WASM_VALIDATOR_FAIL_IF(condition != I32, "select condition must be i32, got ", condition);
310     WASM_VALIDATOR_FAIL_IF(nonZero != zero, "select result types must match, got ", nonZero, " and ", zero);
311     result = zero;
312     return { };
313 }
314
315 auto Validate::addIf(ExpressionType condition, Type signature, ControlType& result) -> Result
316 {
317     WASM_VALIDATOR_FAIL_IF(condition != I32, "if condition must be i32, got ", condition);
318     result = ControlData(BlockType::If, signature);
319     return { };
320 }
321
322 auto Validate::addElse(ControlType& current, const ExpressionList& values) -> Result
323 {
324     WASM_FAIL_IF_HELPER_FAILS(unify(values, current));
325     return addElseToUnreachable(current);
326 }
327
328 auto Validate::addElseToUnreachable(ControlType& current) -> Result
329 {
330     WASM_VALIDATOR_FAIL_IF(current.type() != BlockType::If, "else block isn't associated to an if");
331     current = ControlData(BlockType::Block, current.signature());
332     return { };
333 }
334
335 auto Validate::addReturn(ControlType& topLevel, const ExpressionList& returnValues) -> Result
336 {
337     ASSERT(topLevel.type() == BlockType::TopLevel);
338     if (topLevel.signature() == Void)
339         return { };
340     ASSERT(returnValues.size() == 1);
341     WASM_VALIDATOR_FAIL_IF(topLevel.signature() != returnValues[0], "return type ", returnValues[0], " doesn't match function's return type ", topLevel.signature());
342     return { };
343 }
344
345 auto Validate::checkBranchTarget(ControlType& target, const ExpressionList& expressionStack) -> Result
346 {
347     if (target.branchTargetSignature() == Void)
348         return { };
349
350     WASM_VALIDATOR_FAIL_IF(expressionStack.isEmpty(), target.type() == BlockType::TopLevel ? "branch out of function" : "branch to block", " on empty expression stack, but expected ", target.signature());
351     WASM_VALIDATOR_FAIL_IF(target.branchTargetSignature() != expressionStack.last(), "branch's stack type doesn't match block's type");
352
353     return { };
354 }
355
356 auto Validate::addBranch(ControlType& target, ExpressionType condition, const ExpressionList& stack) -> Result
357 {
358     // Void means this is an unconditional branch.
359     WASM_VALIDATOR_FAIL_IF(condition != Void && condition != I32, "conditional branch with non-i32 condition ", condition);
360     return checkBranchTarget(target, stack);
361 }
362
363 auto Validate::addSwitch(ExpressionType condition, const Vector<ControlData*>& targets, ControlData& defaultTarget, const ExpressionList& expressionStack) -> Result
364 {
365     WASM_VALIDATOR_FAIL_IF(condition != I32, "br_table with non-i32 condition ", condition);
366
367     for (auto target : targets)
368         WASM_VALIDATOR_FAIL_IF(defaultTarget.branchTargetSignature() != target->branchTargetSignature(), "br_table target type mismatch");
369
370     return checkBranchTarget(defaultTarget, expressionStack);
371 }
372
373 auto Validate::addGrowMemory(ExpressionType delta, ExpressionType& result) -> Result
374 {
375     WASM_VALIDATOR_FAIL_IF(delta != I32, "grow_memory with non-i32 delta");
376     result = I32;
377     return { };
378 }
379
380 auto Validate::addCurrentMemory(ExpressionType& result) -> Result
381 {
382     result = I32;
383     return { };
384 }
385
386 auto Validate::endBlock(ControlEntry& entry, ExpressionList& stack) -> Result
387 {
388     WASM_FAIL_IF_HELPER_FAILS(unify(stack, entry.controlData));
389     return addEndToUnreachable(entry);
390 }
391
392 auto Validate::addEndToUnreachable(ControlEntry& entry) -> Result
393 {
394     auto block = entry.controlData;
395     if (block.signature() != Void) {
396         WASM_VALIDATOR_FAIL_IF(block.type() == BlockType::If, "If-block had a non-void result type: ", block.signature(), " but had no else-block");
397         entry.enclosedExpressionStack.append(block.signature());
398     }
399     return { };
400 }
401
402 auto Validate::addCall(unsigned, const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
403 {
404     WASM_VALIDATOR_FAIL_IF(signature.argumentCount() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature.argumentCount());
405
406     for (unsigned i = 0; i < args.size(); ++i)
407         WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
408
409     result = signature.returnType();
410     return { };
411 }
412
413 auto Validate::addCallIndirect(unsigned tableIndex, const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
414 {
415     RELEASE_ASSERT(tableIndex < m_module.tableCount());
416     RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Funcref);
417     const auto argumentCount = signature.argumentCount();
418     WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
419
420     for (unsigned i = 0; i < argumentCount; ++i)
421         WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
422
423     WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
424
425     result = signature.returnType();
426     return { };
427 }
428
429 auto Validate::unify(const ExpressionList& values, const ControlType& block) -> Result
430 {
431     if (block.signature() == Void) {
432         WASM_VALIDATOR_FAIL_IF(!values.isEmpty(), "void block should end with an empty stack");
433         return { };
434     }
435
436     WASM_VALIDATOR_FAIL_IF(values.size() != 1, "block with type: ", block.signature(), " ends with a stack containing more than one value");
437     WASM_VALIDATOR_FAIL_IF(values[0] != block.signature(), "control flow returns with unexpected type");
438     return { };
439 }
440
441 static void dumpExpressionStack(const CommaPrinter& comma, const Validate::ExpressionList& expressionStack)
442 {
443     dataLog(comma, " ExpressionStack:");
444     for (const auto& expression : expressionStack)
445         dataLog(comma, makeString(expression));
446 }
447
448 void Validate::dump(const Vector<ControlEntry>& controlStack, const ExpressionList* expressionStack)
449 {
450     for (size_t i = controlStack.size(); i--;) {
451         dataLog("  ", controlStack[i].controlData);
452         CommaPrinter comma(", ", "");
453         dumpExpressionStack(comma, *expressionStack);
454         expressionStack = &controlStack[i].enclosedExpressionStack;
455         dataLogLn();
456     }
457     dataLogLn();
458 }
459
460 Expected<void, String> validateFunction(const uint8_t* source, size_t length, const Signature& signature, const ModuleInformation& module)
461 {
462     Validate context(module);
463     FunctionParser<Validate> validator(context, source, length, signature, module);
464     WASM_FAIL_IF_HELPER_FAILS(validator.parse());
465     return { };
466 }
467
468 } } // namespace JSC::Wasm
469
470 #include "WasmValidateInlines.h"
471
472 #endif // ENABLE(WEBASSEMBLY)