Index: llvm/trunk/include/llvm/BinaryFormat/Wasm.h =================================================================== --- llvm/trunk/include/llvm/BinaryFormat/Wasm.h +++ llvm/trunk/include/llvm/BinaryFormat/Wasm.h @@ -188,19 +188,20 @@ }; enum : unsigned { - WASM_SEC_CUSTOM = 0, // Custom / User-defined section - WASM_SEC_TYPE = 1, // Function signature declarations - WASM_SEC_IMPORT = 2, // Import declarations - WASM_SEC_FUNCTION = 3, // Function declarations - WASM_SEC_TABLE = 4, // Indirect function table and other tables - WASM_SEC_MEMORY = 5, // Memory attributes - WASM_SEC_GLOBAL = 6, // Global declarations - WASM_SEC_EXPORT = 7, // Exports - WASM_SEC_START = 8, // Start function declaration - WASM_SEC_ELEM = 9, // Elements section - WASM_SEC_CODE = 10, // Function bodies (code) - WASM_SEC_DATA = 11, // Data segments - WASM_SEC_EVENT = 13 // Event declarations + WASM_SEC_CUSTOM = 0, // Custom / User-defined section + WASM_SEC_TYPE = 1, // Function signature declarations + WASM_SEC_IMPORT = 2, // Import declarations + WASM_SEC_FUNCTION = 3, // Function declarations + WASM_SEC_TABLE = 4, // Indirect function table and other tables + WASM_SEC_MEMORY = 5, // Memory attributes + WASM_SEC_GLOBAL = 6, // Global declarations + WASM_SEC_EXPORT = 7, // Exports + WASM_SEC_START = 8, // Start function declaration + WASM_SEC_ELEM = 9, // Elements section + WASM_SEC_CODE = 10, // Function bodies (code) + WASM_SEC_DATA = 11, // Data segments + WASM_SEC_DATACOUNT = 12, // Data segment count + WASM_SEC_EVENT = 13 // Event declarations }; // Type immediate encodings used in various contexts. Index: llvm/trunk/include/llvm/Object/Wasm.h =================================================================== --- llvm/trunk/include/llvm/Object/Wasm.h +++ llvm/trunk/include/llvm/Object/Wasm.h @@ -283,6 +283,49 @@ uint32_t EventSection = 0; }; +class WasmSectionOrderChecker { +public: + // We define orders for all core wasm sections and known custom sections. + enum : int { + // Core sections + // The order of standard sections is precisely given by the spec. + WASM_SEC_ORDER_TYPE = 1, + WASM_SEC_ORDER_IMPORT = 2, + WASM_SEC_ORDER_FUNCTION = 3, + WASM_SEC_ORDER_TABLE = 4, + WASM_SEC_ORDER_MEMORY = 5, + WASM_SEC_ORDER_GLOBAL = 6, + WASM_SEC_ORDER_EVENT = 7, + WASM_SEC_ORDER_EXPORT = 8, + WASM_SEC_ORDER_START = 9, + WASM_SEC_ORDER_ELEM = 10, + WASM_SEC_ORDER_DATACOUNT = 11, + WASM_SEC_ORDER_CODE = 12, + WASM_SEC_ORDER_DATA = 13, + + // Custom sections + // "dylink" should be the very first section in the module + WASM_SEC_ORDER_DYLINK = 0, + // "linking" section requires DATA section in order to validate data symbols + WASM_SEC_ORDER_LINKING = 100, + // Must come after "linking" section in order to validate reloc indexes. + WASM_SEC_ORDER_RELOC = 101, + // "name" section must appear after DATA. Comes after "linking" to allow + // symbol table to set default function name. + WASM_SEC_ORDER_NAME = 102, + // "producers" section must appear after "name" section. + WASM_SEC_ORDER_PRODUCERS = 103 + }; + + bool isValidSectionOrder(unsigned ID, StringRef CustomSectionName = ""); + +private: + int LastOrder = -1; // Lastly seen known section's order + + // Returns -1 for unknown sections. + int getSectionOrder(unsigned ID, StringRef CustomSectionName = ""); +}; + } // end namespace object inline raw_ostream &operator<<(raw_ostream &OS, const object::WasmSymbol &Sym) { Index: llvm/trunk/lib/Object/WasmObjectFile.cpp =================================================================== --- llvm/trunk/lib/Object/WasmObjectFile.cpp +++ llvm/trunk/lib/Object/WasmObjectFile.cpp @@ -24,6 +24,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/LEB128.h" +#include "llvm/Support/ScopedPrinter.h" #include #include #include @@ -207,8 +208,8 @@ return Table; } -static Error readSection(WasmSection &Section, - WasmObjectFile::ReadContext &Ctx) { +static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx, + WasmSectionOrderChecker &Checker) { Section.Offset = Ctx.Ptr - Ctx.Start; Section.Type = readUint8(Ctx); LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n"); @@ -231,6 +232,13 @@ Ctx.Ptr += SectionNameSize; Size -= SectionNameSize; } + + if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) { + return make_error("Out of order section type: " + + llvm::to_string(Section.Type), + object_error::parse_failed); + } + Section.Content = ArrayRef(Ctx.Ptr, Size); Ctx.Ptr += Size; return Error::success(); @@ -265,8 +273,9 @@ } WasmSection Sec; + WasmSectionOrderChecker Checker; while (Ctx.Ptr < Ctx.End) { - if ((Err = readSection(Sec, Ctx))) + if ((Err = readSection(Sec, Ctx, Checker))) return; if ((Err = parseSection(Sec))) return; @@ -1433,3 +1442,58 @@ assert(Ref.d.b < Sec.Relocations.size()); return Sec.Relocations[Ref.d.b]; } + +int WasmSectionOrderChecker::getSectionOrder(unsigned ID, + StringRef CustomSectionName) { + switch (ID) { + case wasm::WASM_SEC_CUSTOM: + return StringSwitch(CustomSectionName) + .Case("dylink", WASM_SEC_ORDER_DYLINK) + .Case("linking", WASM_SEC_ORDER_LINKING) + .StartsWith("reloc.", WASM_SEC_ORDER_RELOC) + .Case("name", WASM_SEC_ORDER_NAME) + .Case("producers", WASM_SEC_ORDER_PRODUCERS) + .Default(-1); + case wasm::WASM_SEC_TYPE: + return WASM_SEC_ORDER_TYPE; + case wasm::WASM_SEC_IMPORT: + return WASM_SEC_ORDER_IMPORT; + case wasm::WASM_SEC_FUNCTION: + return WASM_SEC_ORDER_FUNCTION; + case wasm::WASM_SEC_TABLE: + return WASM_SEC_ORDER_TABLE; + case wasm::WASM_SEC_MEMORY: + return WASM_SEC_ORDER_MEMORY; + case wasm::WASM_SEC_GLOBAL: + return WASM_SEC_ORDER_GLOBAL; + case wasm::WASM_SEC_EXPORT: + return WASM_SEC_ORDER_EXPORT; + case wasm::WASM_SEC_START: + return WASM_SEC_ORDER_START; + case wasm::WASM_SEC_ELEM: + return WASM_SEC_ORDER_ELEM; + case wasm::WASM_SEC_CODE: + return WASM_SEC_ORDER_CODE; + case wasm::WASM_SEC_DATA: + return WASM_SEC_ORDER_DATA; + case wasm::WASM_SEC_DATACOUNT: + return WASM_SEC_ORDER_DATACOUNT; + case wasm::WASM_SEC_EVENT: + return WASM_SEC_ORDER_EVENT; + default: + llvm_unreachable("invalid section"); + } +} + +bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID, + StringRef CustomSectionName) { + int Order = getSectionOrder(ID, CustomSectionName); + if (Order == -1) // Skip unknown sections + return true; + // There can be multiple "reloc." sections. Otherwise there shouldn't be any + // duplicate section orders. + bool IsValid = (LastOrder == Order && Order == WASM_SEC_ORDER_RELOC) || + LastOrder < Order; + LastOrder = Order; + return IsValid; +} Index: llvm/trunk/test/Object/wasm-invalid-section-order.test =================================================================== --- llvm/trunk/test/Object/wasm-invalid-section-order.test +++ llvm/trunk/test/Object/wasm-invalid-section-order.test @@ -0,0 +1,16 @@ +# RUN: not obj2yaml %p/Inputs/WASM/invalid-section-order.wasm 2>&1 | FileCheck %s +# CHECK: {{.*}}: Out of order section type: 10 + +# Inputs/WASM/invalid-section-order.wasm is generated from this ll file, by +# modifying WasmObjectWriter to incorrectly write the data section before the +# code section. +# +# target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +# target triple = "wasm32-unknown-unknown" +# +# @data = global i32 0, align 4 +# +# define void @foo() { +# entry: +# ret void +# } Index: llvm/trunk/test/ObjectYAML/wasm/invalid_section_order.yaml =================================================================== --- llvm/trunk/test/ObjectYAML/wasm/invalid_section_order.yaml +++ llvm/trunk/test/ObjectYAML/wasm/invalid_section_order.yaml @@ -0,0 +1,20 @@ +# RUN: not yaml2obj %s -o /dev/null 2>&1 | FileCheck %s + +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: NORESULT + ParamTypes: [] + - Type: CODE + Functions: + - Index: 0 + Locals: [] + Body: 0B + # CHECK: Out of order section type: 3 + - Type: FUNCTION + FunctionTypes: [ 0 ] +... Index: llvm/trunk/tools/yaml2obj/yaml2wasm.cpp =================================================================== --- llvm/trunk/tools/yaml2obj/yaml2wasm.cpp +++ llvm/trunk/tools/yaml2obj/yaml2wasm.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// // +#include "llvm/Object/Wasm.h" #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/Support/Endian.h" #include "llvm/Support/LEB128.h" @@ -516,7 +517,15 @@ writeUint32(OS, Obj.Header.Version); // Write each section + llvm::object::WasmSectionOrderChecker Checker; for (const std::unique_ptr &Sec : Obj.Sections) { + StringRef SecName = ""; + if (auto S = dyn_cast(Sec.get())) + SecName = S->Name; + if (!Checker.isValidSectionOrder(Sec->Type, SecName)) { + errs() << "Out of order section type: " << Sec->Type << "\n"; + return 1; + } encodeULEB128(Sec->Type, OS); std::string OutString; raw_string_ostream StringStream(OutString);