Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -214,6 +214,8 @@ WasmSection* findSectionByType(uint32_t Type); const uint8_t *getPtr(size_t Offset) const; + Error checkSectionOrder(const WasmSection &Section, int &LastSecOrder); + Error checkCodeSection(); Error parseSection(WasmSection &Sec); Error parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, const uint8_t *End); @@ -254,14 +256,14 @@ std::vector Symbols; std::vector Comdats; std::vector DebugNames; - uint32_t StartFunction = -1; + uint32_t StartFunction = UINT32_MAX; bool HasLinkingSection = false; wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; - uint32_t CodeSection = 0; - uint32_t DataSection = 0; - uint32_t GlobalSection = 0; + uint32_t CodeSection = UINT32_MAX; + uint32_t DataSection = UINT32_MAX; + uint32_t GlobalSection = UINT32_MAX; }; } // end namespace object Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -178,11 +178,70 @@ if (Ptr + Size > Eof) return make_error("Section too large", object_error::parse_failed); + if (Section.Type == wasm::WASM_SEC_CUSTOM) { + const uint8_t* NamePtr = Ptr; + Section.Name = readString(NamePtr); + if (NamePtr > Ptr + Size) + return make_error("Section name too large", + object_error::parse_failed); + } Section.Content = ArrayRef(Ptr, Size); Ptr += Size; return Error::success(); } +// For core Wasm sections, there is a defined order for all sections, and custom +// sections also (should) define where they fit into that order. We return -1 +// for custom sections whose order we don't know. +enum : unsigned { + // The order of standard sections is precisely given by the spec. + WASM_SEC_ORDER_TYPE = 10, + WASM_SEC_ORDER_IMPORT = 20, +// WASM_SEC_ORDER_EXCEPTION = 30, + WASM_SEC_ORDER_FUNCTION = 40, + WASM_SEC_ORDER_TABLE = 50, + WASM_SEC_ORDER_MEMORY = 60, + WASM_SEC_ORDER_GLOBAL = 70, + WASM_SEC_ORDER_EXPORT = 80, + WASM_SEC_ORDER_START = 90, + WASM_SEC_ORDER_ELEM = 100, + WASM_SEC_ORDER_CODE = 110, + WASM_SEC_ORDER_DATA = 120, + // "linking" requires DATA section in order to validate data symbols + WASM_SEC_ORDER_LINKING = 125, + // Must come after "linking" in order to validate reloc indexes. + WASM_SEC_ORDER_RELOC = 126, + // Spec: "name" MUST appear after DATA. Comes after "linking" to allow + // symbol table to set default function name. + WASM_SEC_ORDER_NAME = 130, +}; +static int getSectionOrder(const WasmSection &Sec) { + switch (Sec.Type) { + case wasm::WASM_SEC_CUSTOM: + if (Sec.Name == "linking") + return WASM_SEC_ORDER_LINKING; + if (Sec.Name.startswith("reloc.")) + return WASM_SEC_ORDER_RELOC; + if (Sec.Name == "name") + return WASM_SEC_ORDER_NAME; + return -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_EXCEPTION: return WASM_SEC_ORDER_EXCEPTION; + 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; + default: + llvm_unreachable("invalid section"); + } +} + WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) : ObjectFile(Binary::ID_Wasm, Buffer) { ErrorAsOutParameter ErrAsOutParam(&Err); @@ -210,14 +269,51 @@ } WasmSection Sec; + int LastSecOrder = 0; while (Ptr < Eof) { if ((Err = readSection(Sec, Ptr, getPtr(0), Eof))) return; + if ((Err = checkSectionOrder(Sec, LastSecOrder))) + return; if ((Err = parseSection(Sec))) return; Sections.push_back(Sec); } + + Err = checkCodeSection(); +} + +Error WasmObjectFile::checkSectionOrder(const WasmSection &Section, + int &LastSecOrder) { + int SecOrder = getSectionOrder(Section); + if (SecOrder != -1) { + // Disallow duplicate sections (except for "reloc.") as well as + // out-of-order sections. + if (SecOrder < LastSecOrder || + (SecOrder != (int)WASM_SEC_ORDER_RELOC && SecOrder == LastSecOrder)) + return make_error("Illegal section order", + object_error::parse_failed); + // If an empty FUNCTION section is present, there's no need for an empty + // CODE section to match, the vectors just have to be the same length. + // We must check the CODE section was present if required after skipping + // past it. + if (LastSecOrder < (int)WASM_SEC_ORDER_CODE && + SecOrder > (int)WASM_SEC_ORDER_CODE) { + if (Error Err = checkCodeSection()) + return Err; + } + + LastSecOrder = SecOrder; + } + return Error::success(); +} + +Error WasmObjectFile::checkCodeSection() { + if (FunctionTypes.size() != Functions.size()) + return make_error("Expected CODE section", + object_error::parse_failed); + return Error::success(); } Error WasmObjectFile::parseSection(WasmSection &Sec) { @@ -256,11 +352,6 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { llvm::DenseSet Seen; - if (Functions.size() != FunctionTypes.size()) { - return make_error("Names must come after code section", - object_error::parse_failed); - } - while (Ptr < End) { uint8_t Type = readUint8(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -306,11 +397,6 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; - if (Functions.size() != FunctionTypes.size()) { - return make_error( - "Linking data must come after code section", object_error::parse_failed); - } - while (Ptr < End) { uint8_t Type = readUint8(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -581,7 +667,7 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, const uint8_t *End) { - Sec.Name = readString(Ptr); + Ptr = Sec.Name.bytes_end(); if (Sec.Name == "name") { if (Error Err = parseNameSection(Ptr, End)) return Err;