9db08c849e717ad6bde718031790dcae82c02f20
[WebKit-https.git] / Source / JavaScriptCore / wasm / WasmModuleParser.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 "WasmModuleParser.h"
28
29 #if ENABLE(WEBASSEMBLY)
30
31 #include "IdentifierInlines.h"
32 #include "WasmFormat.h"
33 #include "WasmMemoryInformation.h"
34 #include "WasmOps.h"
35 #include "WasmSections.h"
36
37 #include <sys/mman.h>
38
39 namespace JSC { namespace Wasm {
40
41 static const bool verbose = false;
42
43 bool ModuleParser::parse()
44 {
45     m_module = std::make_unique<ModuleInformation>();
46
47     const size_t minSize = 8;
48     if (length() < minSize) {
49         m_errorMessage = "Module is " + String::number(length()) + " bytes, expected at least " + String::number(minSize) + " bytes";
50         return false;
51     }
52     if (!consumeCharacter(0) || !consumeString("asm")) {
53         m_errorMessage = "Modules doesn't start with '\\0asm'";
54         return false;
55     }
56
57     uint32_t versionNumber;
58     if (!parseUInt32(versionNumber)) {
59         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
60         m_errorMessage = "couldn't parse version number";
61         return false;
62     }
63
64     if (versionNumber != expectedVersionNumber) {
65         // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
66         m_errorMessage = "unexpected version number";
67         return false;
68     }
69
70
71     if (verbose)
72         dataLogLn("Passed processing header.");
73
74     Sections::Section previousSection = Sections::Unknown;
75     while (m_offset < length()) {
76         if (verbose)
77             dataLogLn("Starting to parse next section at offset: ", m_offset);
78
79         uint8_t sectionByte;
80         if (!parseUInt7(sectionByte)) {
81             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
82             m_errorMessage = "couldn't get section byte";
83             return false;
84         }
85
86         if (verbose)
87             dataLogLn("Section byte: ", sectionByte);
88
89         Sections::Section section = Sections::Unknown;
90         if (sectionByte) {
91             if (sectionByte < Sections::Unknown)
92                 section = static_cast<Sections::Section>(sectionByte);
93         }
94
95         if (!Sections::validateOrder(previousSection, section)) {
96             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
97             m_errorMessage = "invalid section order";
98             return false;
99         }
100
101         uint32_t sectionLength;
102         if (!parseVarUInt32(sectionLength)) {
103             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
104             m_errorMessage = "couldn't get section length";
105             return false;
106         }
107
108         if (sectionLength > length() - m_offset) {
109             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
110             m_errorMessage = "section content would overflow Module's size";
111             return false;
112         }
113
114         auto end = m_offset + sectionLength;
115
116         switch (section) {
117         // FIXME improve error message in macro below https://bugs.webkit.org/show_bug.cgi?id=163919
118 #define WASM_SECTION_PARSE(NAME, ID, DESCRIPTION) \
119         case Sections::NAME: { \
120             if (verbose) \
121                 dataLogLn("Parsing " DESCRIPTION); \
122             if (!parse ## NAME()) { \
123                 m_errorMessage = "couldn't parse section " #NAME ": " DESCRIPTION; \
124                 return false; \
125             } \
126             break; \
127         }
128         FOR_EACH_WASM_SECTION(WASM_SECTION_PARSE)
129 #undef WASM_SECTION_PARSE
130
131         case Sections::Unknown: {
132             if (verbose)
133                 dataLogLn("Unknown section, skipping.");
134             // Ignore section's name LEB and bytes: they're already included in sectionLength.
135             m_offset += sectionLength;
136             break;
137         }
138         }
139
140         if (verbose)
141             dataLogLn("Finished parsing section.");
142
143         if (end != m_offset) {
144             // FIXME improve error message https://bugs.webkit.org/show_bug.cgi?id=163919
145             m_errorMessage = "parsing ended before the end of the section";
146             return false;
147         }
148
149         previousSection = section;
150     }
151
152     // TODO
153     m_failed = false;
154     return true;
155 }
156
157 bool ModuleParser::parseType()
158 {
159     uint32_t count;
160     if (!parseVarUInt32(count))
161         return false;
162     if (verbose)
163         dataLogLn("count: ", count);
164     if (!m_module->signatures.tryReserveCapacity(count))
165         return false;
166
167     for (uint32_t i = 0; i < count; ++i) {
168         int8_t type;
169         if (!parseInt7(type))
170             return false;
171         if (type != Func)
172             return false;
173
174         if (verbose)
175             dataLogLn("Got function type.");
176
177         uint32_t argumentCount;
178         if (!parseVarUInt32(argumentCount))
179             return false;
180
181         if (verbose)
182             dataLogLn("argumentCount: ", argumentCount);
183
184         Vector<Type> argumentTypes;
185         if (!argumentTypes.tryReserveCapacity(argumentCount))
186             return false;
187
188         for (unsigned i = 0; i != argumentCount; ++i) {
189             Type argumentType;
190             if (!parseResultType(argumentType))
191                 return false;
192             argumentTypes.uncheckedAppend(argumentType);
193         }
194
195         uint8_t returnCount;
196         if (!parseVarUInt1(returnCount))
197             return false;
198         Type returnType;
199
200         if (verbose)
201             dataLogLn(returnCount);
202
203         if (returnCount) {
204             Type value;
205             if (!parseValueType(value))
206                 return false;
207             returnType = static_cast<Type>(value);
208         } else
209             returnType = Type::Void;
210
211         m_module->signatures.uncheckedAppend({ returnType, WTFMove(argumentTypes) });
212     }
213     return true;
214 }
215
216 bool ModuleParser::parseImport()
217 {
218     uint32_t importCount;
219     if (!parseVarUInt32(importCount))
220         return false;
221     if (!m_module->imports.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
222         || !m_module->importFunctions.tryReserveCapacity(importCount) // FIXME this over-allocates when we fix the FIXMEs below.
223         || !m_functionIndexSpace.tryReserveCapacity(importCount)) // FIXME this over-allocates when we fix the FIXMEs below. We'll allocate some more here when we know how many functions to expect.
224         return false;
225
226     for (uint32_t importNumber = 0; importNumber != importCount; ++importNumber) {
227         Import imp;
228         uint32_t moduleLen;
229         uint32_t fieldLen;
230         String moduleString;
231         String fieldString;
232         if (!parseVarUInt32(moduleLen)
233             || !consumeUTF8String(moduleString, moduleLen))
234             return false;
235         imp.module = Identifier::fromString(m_vm, moduleString);
236         if (!parseVarUInt32(fieldLen)
237             || !consumeUTF8String(fieldString, fieldLen))
238             return false;
239         imp.field = Identifier::fromString(m_vm, fieldString);
240         if (!parseExternalKind(imp.kind))
241             return false;
242         switch (imp.kind) {
243         case External::Function: {
244             uint32_t functionSignatureIndex;
245             if (!parseVarUInt32(functionSignatureIndex)
246                 || functionSignatureIndex >= m_module->signatures.size())
247                 return false;
248             imp.kindIndex = m_module->importFunctions.size();
249             Signature* signature = &m_module->signatures[functionSignatureIndex];
250             m_module->importFunctions.uncheckedAppend(signature);
251             m_functionIndexSpace.uncheckedAppend(signature);
252             break;
253         }
254         case External::Table: {
255             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
256             break;
257         }
258         case External::Memory: {
259             bool isImport = true;
260             if (!parseMemoryHelper(isImport))
261                 return false;
262             break;
263         }
264         case External::Global: {
265             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
266             // In the MVP, only immutable global variables can be imported.
267             break;
268         }
269         }
270
271         m_module->imports.uncheckedAppend(imp);
272     }
273
274     return true;
275 }
276
277 bool ModuleParser::parseFunction()
278 {
279     uint32_t count;
280     if (!parseVarUInt32(count)
281         || !m_module->internalFunctionSignatures.tryReserveCapacity(count)
282         || !m_functionLocationInBinary.tryReserveCapacity(count)
283         || !m_functionIndexSpace.tryReserveCapacity(m_functionIndexSpace.size() + count))
284         return false;
285
286     for (uint32_t i = 0; i != count; ++i) {
287         uint32_t typeNumber;
288         if (!parseVarUInt32(typeNumber)
289             || typeNumber >= m_module->signatures.size())
290             return false;
291
292         Signature* signature = &m_module->signatures[typeNumber];
293         // The Code section fixes up start and end.
294         size_t start = 0;
295         size_t end = 0;
296         m_module->internalFunctionSignatures.uncheckedAppend(signature);
297         m_functionLocationInBinary.uncheckedAppend({ start, end });
298         m_functionIndexSpace.uncheckedAppend(signature);
299     }
300
301     return true;
302 }
303
304 bool ModuleParser::parseTable()
305 {
306     // FIXME implement table https://bugs.webkit.org/show_bug.cgi?id=164135
307     RELEASE_ASSERT_NOT_REACHED();
308     return true;
309 }
310
311 bool ModuleParser::parseMemoryHelper(bool isImport)
312 {
313     // We don't allow redeclaring memory. Either via import or definition.
314     if (m_module->memory)
315         return false;
316
317     uint8_t flags;
318     if (!parseVarUInt1(flags))
319         return false;
320
321     uint32_t initial;
322     if (!parseVarUInt32(initial))
323         return false;
324
325     if (!PageCount::isValid(initial))
326         return false;
327
328     PageCount initialPageCount(initial);
329
330     PageCount maximumPageCount;
331     if (flags) {
332         uint32_t maximum;
333         if (!parseVarUInt32(maximum))
334             return false;
335
336         if (!PageCount::isValid(maximum))
337             return false;
338
339         maximumPageCount = PageCount(maximum);
340         if (initialPageCount > maximumPageCount)
341             return false;
342     }
343
344     Vector<unsigned> pinnedSizes = { 0 };
345     m_module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
346     return true;
347 }
348
349 bool ModuleParser::parseMemory()
350 {
351     uint8_t count;
352     if (!parseVarUInt1(count))
353         return false;
354
355     if (!count)
356         return true;
357
358     // We only allow one memory for now.
359     if (count != 1)
360         return false;
361
362     bool isImport = false;
363     return parseMemoryHelper(isImport);
364 }
365
366 bool ModuleParser::parseGlobal()
367 {
368     // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
369     RELEASE_ASSERT_NOT_REACHED();
370     return true;
371 }
372
373 bool ModuleParser::parseExport()
374 {
375     uint32_t exportCount;
376     if (!parseVarUInt32(exportCount)
377         || !m_module->exports.tryReserveCapacity(exportCount))
378         return false;
379
380     for (uint32_t exportNumber = 0; exportNumber != exportCount; ++exportNumber) {
381         Export exp;
382         uint32_t fieldLen;
383         String fieldString;
384         if (!parseVarUInt32(fieldLen)
385             || !consumeUTF8String(fieldString, fieldLen))
386             return false;
387         exp.field = Identifier::fromString(m_vm, fieldString);
388         if (!parseExternalKind(exp.kind))
389             return false;
390         switch (exp.kind) {
391         case External::Function: {
392             if (!parseVarUInt32(exp.functionIndex)
393                 || exp.functionIndex >= m_functionIndexSpace.size())
394                 return false;
395             break;
396         }
397         case External::Table: {
398             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
399             break;
400         }
401         case External::Memory: {
402             // FIXME: https://bugs.webkit.org/show_bug.cgi?id=165671
403             break;
404         }
405         case External::Global: {
406             // FIXME https://bugs.webkit.org/show_bug.cgi?id=164133
407             // In the MVP, only immutable global variables can be exported.
408             break;
409         }
410         }
411
412         m_module->exports.uncheckedAppend(exp);
413     }
414
415     return true;
416 }
417
418 bool ModuleParser::parseStart()
419 {
420     uint32_t startFunctionIndex;
421     if (!parseVarUInt32(startFunctionIndex)
422         || startFunctionIndex >= m_functionIndexSpace.size())
423         return false;
424     Signature* signature = m_functionIndexSpace[startFunctionIndex].signature;
425     if (signature->arguments.size() != 0
426         || signature->returnType != Void)
427         return false;
428     m_module->startFunctionIndexSpace = startFunctionIndex;
429     return true;
430 }
431
432 bool ModuleParser::parseElement()
433 {
434     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
435     RELEASE_ASSERT_NOT_REACHED();
436     return true;
437 }
438
439 bool ModuleParser::parseCode()
440 {
441     uint32_t count;
442     if (!parseVarUInt32(count)
443         || count != m_functionLocationInBinary.size())
444         return false;
445
446     for (uint32_t i = 0; i != count; ++i) {
447         uint32_t functionSize;
448         if (!parseVarUInt32(functionSize)
449             || functionSize > length()
450             || functionSize > length() - m_offset)
451             return false;
452
453         m_functionLocationInBinary[i].start = m_offset;
454         m_functionLocationInBinary[i].end = m_offset + functionSize;
455         m_offset = m_functionLocationInBinary[i].end;
456     }
457
458     return true;
459 }
460
461 bool ModuleParser::parseData()
462 {
463     // FIXME https://bugs.webkit.org/show_bug.cgi?id=161709
464     RELEASE_ASSERT_NOT_REACHED();
465     return true;
466 }
467
468 } } // namespace JSC::Wasm
469
470 #endif // ENABLE(WEBASSEMBLY)