From 6c6e2ad62b20f810b54f5a567e66fc55241514b2 Mon Sep 17 00:00:00 2001 From: morluto <76467478+morluto@users.noreply.github.com> Date: Sat, 24 Oct 2026 00:27:57 +0800 Subject: [PATCH] fix(wasm): preserve core inspection with optional metadata warnings Retain warnings from validator, objdump and decoder through one diagnostic owner. Keep uninterpretable name bytes and explicit name-metadata coverage in complete results and summaries. Fixes #6812 --- docs/wasm-artifacts.md | 25 ++++--- src/contracts/wasm/wasmToolContracts.ts | 2 +- src/domain/analysisView/wasmArtifactView.ts | 4 ++ src/domain/wasm/wasmArtifact.ts | 20 +++++- src/wasm/WabtArtifactProvider.test.ts | 71 +++++++++++++++++++ src/wasm/WabtArtifactProvider.ts | 70 +++++++++++++++--- src/wasm/WabtOutput.test.ts | 8 ++- src/wasm/WabtWat.ts | 50 ++++++++----- .../wasmInterfaceComparison.test.ts | 16 ++++- tests/boundary/mcp/wasmArtifactMcp.test.ts | 11 +++ tests/fixtures/wasm/README.md | 3 +- tests/fixtures/wasm/artifact.ts | 4 +- 12 files changed, 239 insertions(+), 45 deletions(-) diff --git a/docs/wasm-artifacts.md b/docs/wasm-artifacts.md index 12bedbd379..75b2f5c878 100644 --- a/docs/wasm-artifacts.md +++ b/docs/wasm-artifacts.md @@ -62,14 +62,23 @@ returns `resource_constraint` with resource `file-size` and its fixed byte allowance in `reported_limits.maximum_input_bytes`; retrying the unchanged file does not raise that allowance. WASM bytes are copied into a private workspace as read-only `module.wasm`; its digest is rechecked -before and after each tool. WABT validates with `--enable-all`, -reports sections through `wasm-objdump -h -x`, and decodes through -`wasm2wat --enable-all`. The result retains selected byte SHA-256 and size, -section payload ranges, full header/detail output (including module-name -preambles), exact import/export WAT -forms, decoded WAT and its UTF-8 SHA-256. Producer format drift and invalid or -truncated modules are failures, with validation diagnostics and partial Evidence -retaining selected byte identity and tool provenance. +before and after each tool. WABT validates with +`wasm-validate --enable-all --ignore-custom-section-errors`, reports sections +through `wasm-objdump -h -x`, and decodes through +`wasm2wat --enable-all --ignore-custom-section-errors`. The result retains +selected byte SHA-256 and size, section payload ranges, full header/detail output +(including module-name preambles), exact import/export WAT forms, decoded WAT +and its UTF-8 SHA-256. Producer format drift and invalid or truncated modules +are failures, with validation diagnostics and partial Evidence retaining +selected byte identity and tool provenance. + +Core validation remains authoritative when an optional custom section cannot +be interpreted. WABT warning output is preserved in `custom_section_warnings`; +`debug_name_metadata` reports whether the optional name section was absent, +fully interpreted, or uninterpretable. Older portable reports retain their +original strict command profile; missing metadata coverage is `unknown` and +missing warning history is `null`. The raw custom section remains in the +decoded WAT. An uninterpretable name section leaves debug module names unknown. The tool profile preserves upstream release/source identity, resolved executable paths, executable digests, exact banners and arguments. Executable digests are diff --git a/src/contracts/wasm/wasmToolContracts.ts b/src/contracts/wasm/wasmToolContracts.ts index 06abd7d784..c8f931df7d 100644 --- a/src/contracts/wasm/wasmToolContracts.ts +++ b/src/contracts/wasm/wasmToolContracts.ts @@ -22,7 +22,7 @@ export const INSPECT_WASM_ARTIFACT_CONTRACT = { ...toolContractMetadata("inspect_wasm_artifact"), kind: "artifact-provider", description: - 'Validate an explicit local WASM artifact with caller-supplied WABT 1.0.42. Omitted or complete detail returns exact byte SHA-256, sections, upstream import/export WAT forms and decoded WAT inline as Evidence. For counts, validation and WAT identity without WAT text, pass detail: "summary" on this first call; it retains the complete original Evidence and returns the same typed summary as inspect_analysis_view, avoiding oversized complete delivery. Read exact imports/exports or WAT pages with inspect_analysis_view using normalized_result.parent_evidence_id. Delivery selection does not change analysis, provider inputs or source identity. Adjust command_timeout_ms for each WABT command (default 30000 ms), separately from the client deadline; input/output safety limits stay fixed. Optionally associate selected JavaScript glue literals with explicit local candidates while preserving ambiguous URL/basename matches. Configure absolute REA_WABT_BIN_DIRECTORY. No installation, implicit fetch, WASM execution or original-source claim.', + 'Validate an explicit local WASM artifact with caller-supplied WABT 1.0.42. Optional custom-section interpretation errors do not invalidate the core module; warnings and name-section interpretation status remain in the result. Omitted or complete detail returns exact byte SHA-256, sections, upstream import/export WAT forms and decoded WAT inline as Evidence. For counts, validation and WAT identity without WAT text, pass detail: "summary" on this first call; it retains the complete original Evidence and returns the same typed summary as inspect_analysis_view, avoiding oversized complete delivery. Read exact imports/exports or WAT pages with inspect_analysis_view using normalized_result.parent_evidence_id. Delivery selection does not change analysis, provider inputs or source identity. Adjust command_timeout_ms for each WABT command (default 30000 ms), separately from the client deadline; input/output safety limits stay fixed. Optionally associate selected JavaScript glue literals with explicit local candidates while preserving ambiguous URL/basename matches. Configure absolute REA_WABT_BIN_DIRECTORY. No installation, implicit fetch, WASM execution or original-source claim.', inputSchema: wasmArtifactInspectionInputSchema, outputSchema: analysisDetailOutputSchemaOf( wasmArtifactSchema, diff --git a/src/domain/analysisView/wasmArtifactView.ts b/src/domain/analysisView/wasmArtifactView.ts index 2ac21012bb..ef62fac0a4 100644 --- a/src/domain/analysisView/wasmArtifactView.ts +++ b/src/domain/analysisView/wasmArtifactView.ts @@ -50,6 +50,8 @@ export const wasmViewItemSchema = z.union([ export const wasmSummarySchema = z.strictObject({ bytes: wasmArtifactSchema.shape.artifact.shape.bytes, validation: wasmArtifactSchema.shape.validation, + debug_name_metadata: wasmArtifactSchema.shape.debug_name_metadata, + custom_section_warnings: wasmArtifactSchema.shape.custom_section_warnings, available_counts: z.strictObject({ sections: z.int().nonnegative(), imports: z.int().nonnegative(), @@ -133,6 +135,8 @@ export const projectWasmArtifactView = ( summary: { bytes: report.artifact.bytes, validation: report.validation, + debug_name_metadata: report.debug_name_metadata, + custom_section_warnings: report.custom_section_warnings, available_counts: { sections: report.sections.length, imports: report.imports.length, diff --git a/src/domain/wasm/wasmArtifact.ts b/src/domain/wasm/wasmArtifact.ts index bc2efad138..887a163143 100644 --- a/src/domain/wasm/wasmArtifact.ts +++ b/src/domain/wasm/wasmArtifact.ts @@ -48,6 +48,18 @@ export const wasmArtifactSchema = z interface: wasmInterfaceSchema.exactOptional(), imports: z.array(z.string()), exports: z.array(z.string()), + debug_name_metadata: z + .enum(["unknown", "not-present", "complete", "uninterpretable"]) + .default("unknown"), + custom_section_warnings: z + .array( + z.strictObject({ + tool: z.enum(["wasm-validate", "wasm-objdump", "wasm2wat"]), + text: z.string().min(1), + }), + ) + .nullable() + .default(null), headers: z.string(), details: z.string(), wat: z.strictObject({ @@ -119,12 +131,18 @@ export const wasmArtifactSchema = z path: ["candidates"], message: "Selected candidate does not match artifact identity.", }); + const tolerantCustomSections = + value.tool_profile.commands[0]?.arguments.includes( + "--ignore-custom-section-errors", + ); for (const [index, command] of value.tool_profile.commands.entries()) { const expected = ["wasm-validate", "wasm-objdump", "wasm2wat"][index]; const argumentsExpected = command.tool === "wasm-objdump" ? ["-h", "-x", "module.wasm"] - : ["--enable-all", "module.wasm"]; + : tolerantCustomSections + ? ["--enable-all", "--ignore-custom-section-errors", "module.wasm"] + : ["--enable-all", "module.wasm"]; if ( command.tool !== expected || command.version_banner.trim() !== "1.0.42" || diff --git a/src/wasm/WabtArtifactProvider.test.ts b/src/wasm/WabtArtifactProvider.test.ts index 54f7f9751c..b047bfad09 100644 --- a/src/wasm/WabtArtifactProvider.test.ts +++ b/src/wasm/WabtArtifactProvider.test.ts @@ -207,6 +207,77 @@ const createWabtArtifactFixture = async () => { return { selectedRoot, path, bytes, dump }; }; +it("keeps core WASM usable when optional name-section metadata is malformed", async () => { + const fixture = await createWabtArtifactFixture(); + const diagnostic = + "0000011: warning: invalid sub-section size: extends past end\n"; + const dump = [ + "", + "module.wasm:\tfile format wasm 0x1", + "", + "Sections:", + "", + ' Custom start=0x0000000a end=0x0000004c (size=0x00000042) "name"', + "", + "Section Details:", + "", + ].join("\n"); + const provider = new WabtArtifactProvider( + { REA_WABT_BIN_DIRECTORY: fixture.selectedRoot }, + (input) => { + const version = input.arguments[0] === "--version"; + const isObjdump = input.command.includes("wasm-objdump"); + const isDecoder = input.command.includes("wasm2wat"); + const stdout = version + ? "1.0.42\n" + : isObjdump + ? dump + : isDecoder + ? '(module (@custom "name" "abc"))\n' + : ""; + const stderr = version ? "" : diagnostic; + return spawnOwnedProviderProcess({ + ...input, + hostEnvironment: nodeHostEnvironment(input.hostEnvironment), + command: process.execPath, + arguments: [ + "-e", + `process.stdout.write(${JSON.stringify(stdout)}); process.stderr.write(${JSON.stringify(stderr)});`, + ], + expectedCommand: null, + }); + }, + ); + try { + const result = await provider.inspect({ + path: fixture.path, + glue_paths: [], + candidate_paths: [], + }); + if (!result.ok) throw result.error; + expect(result.value.result).toMatchObject({ + validation: "valid", + debug_name_metadata: "uninterpretable", + custom_section_warnings: [ + { tool: "wasm-validate", text: diagnostic }, + { tool: "wasm-objdump", text: diagnostic }, + { tool: "wasm2wat", text: diagnostic }, + ], + sections: [{ kind: "Custom", start: 10, end: 76, description: '"name"' }], + limitations: expect.arrayContaining([ + expect.stringContaining("optional WebAssembly name custom section"), + ]), + }); + expect( + wasmArtifactSchema.parse(result.value.result).tool_profile.commands[0] + ?.arguments, + ).toContain("--ignore-custom-section-errors"); + expect(await readFile(fixture.path)).toEqual(fixture.bytes); + } finally { + await provider.close(); + } +}); + const assertModeOutcome = ( mode: OutcomeMode, result: Awaited>, diff --git a/src/wasm/WabtArtifactProvider.ts b/src/wasm/WabtArtifactProvider.ts index b5d7aee30a..546cede40f 100644 --- a/src/wasm/WabtArtifactProvider.ts +++ b/src/wasm/WabtArtifactProvider.ts @@ -59,6 +59,11 @@ type Launcher = NonNullable[2]>["launcher"]; const OPERATION = "inspect_wasm_artifact"; const digest = (text: string) => createHash("sha256").update(text).digest("hex"); +const warningOutput = (text: string): readonly string[] | null => { + if (text === "") return []; + const lines = text.trimEnd().split("\n"); + return lines.every((line) => /^\S+: warning: /u.test(line)) ? lines : null; +}; /** Run caller-supplied WABT against private copies of exactly selected bytes. */ export class WabtArtifactProvider implements WasmArtifactPort { readonly #resources = new ArtifactResourceScope(); @@ -123,13 +128,17 @@ export class WabtArtifactProvider implements WasmArtifactPort { "REA_WABT_BIN_DIRECTORY must be an absolute tool directory.", ); const commands: { - tool: string; + tool: "wasm-validate" | "wasm-objdump" | "wasm2wat"; path: string; sha256: string; version_banner: string; arguments: string[]; }[] = []; - for (const tool of ["wasm-validate", "wasm-objdump", "wasm2wat"]) { + for (const tool of [ + "wasm-validate", + "wasm-objdump", + "wasm2wat", + ] as const) { const path = await realpath( join( directory, @@ -152,7 +161,11 @@ export class WabtArtifactProvider implements WasmArtifactPort { arguments: tool === "wasm-objdump" ? ["-h", "-x", "module.wasm"] - : ["--enable-all", "module.wasm"], + : [ + "--enable-all", + "--ignore-custom-section-errors", + "module.wasm", + ], }); } const root = await this.createRuntime(); @@ -349,7 +362,7 @@ export class WabtArtifactProvider implements WasmArtifactPort { confidence: "observed", locations: [{ kind: "artifact-path", path: input.path }], limitations: [ - "WABT rejected these exact selected bytes with --enable-all; no complete inspection or target execution occurred.", + "WABT rejected these exact selected bytes with --enable-all and --ignore-custom-section-errors; no complete inspection or target execution occurred.", ], }, ), @@ -364,28 +377,51 @@ export class WabtArtifactProvider implements WasmArtifactPort { path: ["path"], reason: "invalid_format", message: - "Selected bytes failed WABT validation with --enable-all; inspect retained upstream diagnostics.", + "Selected bytes failed WABT validation with --enable-all and --ignore-custom-section-errors; inspect retained upstream diagnostics.", }, ], ); + const customSectionWarnings: { + tool: (typeof commands)[number]["tool"]; + text: string; + }[] = []; + const optionalLimitations: string[] = []; + const retainWarnings = ( + tool: (typeof commands)[number]["tool"], + output: typeof validation, + ) => { + const warnings = warningOutput(output.stderr.text); + if (warnings === null) + throw new AnalysisOutputError( + OPERATION, + "Unexpected WABT diagnostic output.", + { + capturedOutput: { + stdout: output.stdout.text, + stderr: output.stderr.text, + truncated: false, + }, + }, + ); + if (warnings.length > 0) + customSectionWarnings.push({ tool, text: output.stderr.text }); + }; + retainWarnings("wasm-validate", validation); const dump = await execute(objdump, objdump.arguments); capturedOutput = { stdout: dump.stdout.text, stderr: dump.stderr.text, truncated: false, }; - if (dump.stderr.text !== "") - throw new AnalysisOutputError( - OPERATION, - "Unexpected WABT section output.", - ); + retainWarnings("wasm-objdump", dump); const wat = await execute(decode, decode.arguments); capturedOutput = { stdout: wat.stdout.text, stderr: wat.stderr.text, truncated: false, }; - if (!wat.stdout.text.startsWith("(module") || wat.stderr.text !== "") + retainWarnings("wasm2wat", wat); + if (!wat.stdout.text.startsWith("(module")) throw new AnalysisOutputError( OPERATION, "Unexpected WABT decoding output.", @@ -395,8 +431,17 @@ export class WabtArtifactProvider implements WasmArtifactPort { exports, customSectionNames, debugModuleNames, + debugNameMetadata, interface: interfaceFacts, } = parseWabtWat(wat.stdout.text); + if (debugNameMetadata === "uninterpretable") + optionalLimitations.push( + "The optional WebAssembly name custom section could not be interpreted; its original custom-section payload remains in decoded WAT, while debug module names are unavailable.", + ); + if (customSectionWarnings.length > 0) + optionalLimitations.push( + "WABT reported optional custom-section interpretation warnings; exact warning output is retained in custom_section_warnings.", + ); capturedOutput = { stdout: dump.stdout.text, stderr: dump.stderr.text, @@ -414,6 +459,7 @@ export class WabtArtifactProvider implements WasmArtifactPort { "JavaScript references are AST-observed static literals only. Candidate matches are associations, not proven data flow, URL-to-file identity or runtime loading. Computed references and aliases are not resolved.", "No target execution or implicit fetch. WABT tools are trusted caller-supplied executables; SHA-256 identifies their bytes, not publisher authenticity. No OS memory sandbox is claimed.", `Each WABT command has a ${String(commandTimeoutMs)} ms deadline and a fixed 32 MiB combined output budget. The deadline is not a whole-inspection budget. Oversized output fails instead of producing truncated success.`, + ...optionalLimitations, ]; const report = wasmArtifactSchema.parse({ artifact, @@ -422,6 +468,8 @@ export class WabtArtifactProvider implements WasmArtifactPort { imports, exports, interface: interfaceFacts, + debug_name_metadata: debugNameMetadata, + custom_section_warnings: customSectionWarnings, headers, details, wat: { diff --git a/src/wasm/WabtOutput.test.ts b/src/wasm/WabtOutput.test.ts index 9fc83b987e..4c50dc0bae 100644 --- a/src/wasm/WabtOutput.test.ts +++ b/src/wasm/WabtOutput.test.ts @@ -196,8 +196,12 @@ it.each([ it.each([ '(module (@custom "name" "\\00\\06\\05name"))', '(module (@custom "name" "\\00\\05\\05name"))', -])("rejects incomplete decoded module-name metadata: %s", (text) => { - expect(() => parseWabtWat(text)).toThrow(/metadata/u); +])("retains an uninterpretable optional name section: %s", (text) => { + expect(parseWabtWat(text)).toMatchObject({ + customSectionNames: ["name"], + debugModuleNames: [], + debugNameMetadata: "uninterpretable", + }); }); it("frames custom section names at their NUL-terminated objdump display", async () => { const text = await golden(); diff --git a/src/wasm/WabtWat.ts b/src/wasm/WabtWat.ts index 669c04c8e5..648a6cf39b 100644 --- a/src/wasm/WabtWat.ts +++ b/src/wasm/WabtWat.ts @@ -2,7 +2,7 @@ import { parseWabtInterface } from "./WabtInterface.js"; import { watString, watStringEnd } from "./WabtString.js"; /** Read only module-name metadata from WABT's preserved name-section payload. */ -const moduleNames = (bytes: Uint8Array): string[] => { +const moduleNames = (bytes: Uint8Array): string[] | null => { const names: string[] = []; let offset = 0; const uint32 = (end: number): number => { @@ -16,23 +16,27 @@ const moduleNames = (bytes: Uint8Array): string[] => { } throw new Error("Incomplete WABT name-section metadata."); }; - while (offset < bytes.length) { - const type = uint32(bytes.length); - const size = uint32(bytes.length); - const end = offset + size; - if (end > bytes.length) - throw new Error("Incomplete WABT name-section metadata."); - if (type === 0 && size !== 0) { - const length = uint32(end); - if (offset + length !== end) - throw new Error("Incomplete WABT module-name metadata."); - names.push( - new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode( - bytes.subarray(offset, end), - ), - ); + try { + while (offset < bytes.length) { + const type = uint32(bytes.length); + const size = uint32(bytes.length); + const end = offset + size; + if (end > bytes.length) + throw new Error("Incomplete WABT name-section metadata."); + if (type === 0 && size !== 0) { + const length = uint32(end); + if (offset + length !== end) + throw new Error("Incomplete WABT module-name metadata."); + names.push( + new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode( + bytes.subarray(offset, end), + ), + ); + } + offset = end; } - offset = end; + } catch { + return null; } return names; }; @@ -46,6 +50,8 @@ export const parseWabtWat = (text: string) => { const exports: string[] = []; const customSectionNames: string[] = []; const debugModuleNames: string[] = []; + let debugNameMetadata: "not-present" | "complete" | "uninterpretable" = + "not-present"; let depth = 0; let start = 0; let commentDepth = 0; @@ -126,7 +132,14 @@ export const parseWabtWat = (text: string) => { form, nameString.end + payloadPrefix[0].length, ); - debugModuleNames.push(...moduleNames(payload.bytes)); + const names = moduleNames(payload.bytes); + if (names === null) { + debugNameMetadata = "uninterpretable"; + debugModuleNames.length = 0; + } else if (debugNameMetadata !== "uninterpretable") { + debugNameMetadata = "complete"; + debugModuleNames.push(...names); + } } } } @@ -142,6 +155,7 @@ export const parseWabtWat = (text: string) => { exports, customSectionNames, debugModuleNames, + debugNameMetadata, interface: parseWabtInterface(forms), }; }; diff --git a/tests/acceptance/wasmInterfaceComparison.test.ts b/tests/acceptance/wasmInterfaceComparison.test.ts index 77f6c43192..4fd5eeb2cd 100644 --- a/tests/acceptance/wasmInterfaceComparison.test.ts +++ b/tests/acceptance/wasmInterfaceComparison.test.ts @@ -15,7 +15,7 @@ import { createTestTempDirectory } from "../fixtures/temporaryDirectory.js"; cliTest( "compares portable Evidence identically through CLI and retained MCP with schema/provenance", async ({ cli }) => { - const sources = (["i32", "i64"] as const).map((parameter) => { + const sources = (["i32", "i64"] as const).map((parameter, index) => { const report = wasmArtifactFixture(); report.interface = { state: "complete", @@ -33,6 +33,18 @@ cliTest( }, ], }; + // The left source predates optional-metadata coverage fields and the + // tolerant custom-section profile. Portable Evidence remains readable. + const { + debug_name_metadata: _debugNames, + custom_section_warnings: _warnings, + ...legacyReport + } = report; + if (index === 0) + for (const command of legacyReport.tool_profile.commands) + command.arguments = command.arguments.filter( + (argument) => argument !== "--ignore-custom-section-errors", + ); return createEvidence( { path: report.artifact.path, @@ -43,7 +55,7 @@ cliTest( { operation: "inspect_wasm_artifact", parameters: { path: report.artifact.path }, - result: report, + result: index === 0 ? legacyReport : report, confidence: "observed", }, ); diff --git a/tests/boundary/mcp/wasmArtifactMcp.test.ts b/tests/boundary/mcp/wasmArtifactMcp.test.ts index ba378bd5d9..cf51d0bacb 100644 --- a/tests/boundary/mcp/wasmArtifactMcp.test.ts +++ b/tests/boundary/mcp/wasmArtifactMcp.test.ts @@ -60,6 +60,10 @@ const assertFirstSummaryDelivery = async ( code_units: value.wat.text.length, }); expect(summary.summary.wat).not.toHaveProperty("text"); + expect(summary.summary).toMatchObject({ + debug_name_metadata: value.debug_name_metadata, + custom_section_warnings: value.custom_section_warnings, + }); const retained = harness.session.evidenceById(summary.parent_evidence_id); if (retained === undefined) throw new Error("Summary lost original Evidence"); expect(retained.normalized_result).toEqual(value); @@ -424,6 +428,13 @@ it("reads an oversized completed WASM result through its reported retained refer ...wasmArtifactFixture(), imports: ['(import "env" "memory.with punctuation" (memory 1))'], exports: ['(export "first" (func 0))', '(export "second" (func 1))'], + debug_name_metadata: "uninterpretable" as const, + custom_section_warnings: [ + { + tool: "wasm-validate" as const, + text: "0000011: warning: invalid sub-section size: extends past end\n", + }, + ], wat: { text, sha256: createHash("sha256").update(text, "utf8").digest("hex"), diff --git a/tests/fixtures/wasm/README.md b/tests/fixtures/wasm/README.md index 9b433c038a..79233ad3da 100644 --- a/tests/fixtures/wasm/README.md +++ b/tests/fixtures/wasm/README.md @@ -2,7 +2,8 @@ `module.wat` is source-owned. WABT 1.0.42 `wat2wasm module.wat -o module.wasm` produced the binary used for `wasm-objdump -h -x module.wasm` (`objdump.txt`) and -`wasm2wat --enable-all module.wasm` (`decoded.wat`). No binary is checked in. +`wasm2wat --enable-all --ignore-custom-section-errors module.wasm` +(`decoded.wat`). No binary is checked in. The module has an imported function, exported memory/function and a `test` custom section. The custom payload is retained as an `@custom` annotation in decoded WAT. diff --git a/tests/fixtures/wasm/artifact.ts b/tests/fixtures/wasm/artifact.ts index 3b615ca063..c64aac8632 100644 --- a/tests/fixtures/wasm/artifact.ts +++ b/tests/fixtures/wasm/artifact.ts @@ -11,6 +11,8 @@ export const wasmArtifactFixture = ( sections: [], imports: [], exports: [], + debug_name_metadata: "not-present", + custom_section_warnings: [], headers: "", details: "", wat: { @@ -31,7 +33,7 @@ export const wasmArtifactFixture = ( arguments: tool === "wasm-objdump" ? ["-h", "-x", "module.wasm"] - : ["--enable-all", "module.wasm"], + : ["--enable-all", "--ignore-custom-section-errors", "module.wasm"], }), ), timeout_ms: 30_000,