From b0f3a8b909e66f44adaf06b6db6cb8bfa2e6d8b9 Mon Sep 17 00:00:00 2001 From: dualfroz Date: Thu, 3 Sep 2026 14:32:13 +0200 Subject: [PATCH] fix(xml): panic when encoding a sequence tagged as a map The pre-pass that emits processing instructions first walks Content in key/value pairs, which is only valid for a mapping, but it gated on node.Tag instead of node.Kind. A sequence tagged !!map can have an odd Content length, so Content[i+1] ran off the end: printf '!!map [cat, dog, fish]\n' | yq -o=xml panic: runtime error: index out of range [3] with length 3 That pre-pass runs before the switch on node.Kind, which would otherwise have returned the usual 'cannot encode ... to XML' error. The same check also skipped well formed mappings that carry a custom tag, so their processing instructions were dropped: encodeTopLevelMap then skipped the key as already processed and it disappeared from the output altogether. Gate the pre-pass on Kind, as the rest of the file already does in the switch in Encode, in doEncode and in encodeMap. --- pkg/yqlib/encoder_xml.go | 2 +- pkg/yqlib/xml_test.go | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/yqlib/encoder_xml.go b/pkg/yqlib/encoder_xml.go index 652d574..0e605c7 100644 --- a/pkg/yqlib/encoder_xml.go +++ b/pkg/yqlib/encoder_xml.go @@ -46,7 +46,7 @@ func (e *xmlEncoder) Encode(writer io.Writer, node *CandidateNode) error { encoder.Indent("", e.indentString) var newLine xml.CharData = []byte("\n") - if node.Tag == "!!map" { + if node.Kind == MappingNode { // make sure processing instructions are encoded first for i := 0; i < len(node.Content); i += 2 { key := node.Content[i] diff --git a/pkg/yqlib/xml_test.go b/pkg/yqlib/xml_test.go index 7628ae1..9320f6d 100644 --- a/pkg/yqlib/xml_test.go +++ b/pkg/yqlib/xml_test.go @@ -557,6 +557,20 @@ var xmlScenarios = []formatScenario{ expectedError: "cannot encode !!seq to XML - only maps can be encoded", scenarioType: "encode-error", }, + { + description: "arrays tagged as maps cannot be encoded", + skipDoc: true, + input: "!!map [cat, dog, fish]", + expectedError: "cannot encode !!map to XML - only maps can be encoded", + scenarioType: "encode-error", + }, + { + description: "proc instructions of a map with a custom tag", + skipDoc: true, + input: "!custom\n+p_xml: version=\"1.0\"\na: b\n", + expected: "\nb\n", + scenarioType: "encode", + }, { description: "Encode xml: attributes with content", subdescription: "Fields with the matching xml-content-name is assumed to be content.",