DecodingReader::set_encoding panics when the XML declaration is longer than 64 bytes
I maintainer di solito rispondono entro 1 giorno
Valutazione
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Idoneità per principianti
- 30/100
Direzione di ricerca
The panic comes from the assert in set_encoding() in src/encoding.rs (around line 380), which fires once the 64-byte PREFIX_CAP buffer has been drained. Start by reading how that prefix is filled and drained in the DecodingReader fill path. Then run the three repro tests from the issue (long ASCII body, Latin-1 body, UTF-16 with BOM). Done means none of them panic, and the Latin-1 case decodes correctly. Fixing it needs an encoding-design decision, so check with maintainers first.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
DecodingReader::set_encoding can panic on valid input. I found this while working to update rss and atom_syndication to quick-xml v0.42. Below, I have an AI-authored repro that shows how to trigger this panic.
Let me know if you'd like a PR to fix this.
The analysis and repros below were drafted with Claude (claude-fable-5-2) and checked against 0.42.0 and master.
The documented
DecodingReaderloop (callset_encoding()onEvent::Decl) panics when the XML declaration is longer than the 64-byte prefix (PREFIX_CAP). XML allows extra whitespace inside the declaration, so well-formed input can trigger the panic.0.42.0 and master (250824b) give the same result, with the
encodingfeature on.tests/repro.rs:use quick_xml::encoding::DecodingReader; use quick_xml::events::Event; use quick_xml::reader::Reader; /// The documented loop: wrap in `DecodingReader`, `set_encoding()` on `Decl`. fn texts(xml: &[u8]) -> Result<Vec<String>, quick_xml::Error> { let mut reader = Reader::from_reader(DecodingReader::new(xml)); let mut buf = Vec::new(); let mut out = Vec::new(); loop { match reader.read_event_into(&mut buf)? { Event::Decl(d) => { if let Some(enc) = d.encoder() { reader.get_mut().set_encoding(enc); } } Event::Text(t) => out.push(t.to_string()), Event::Eof => return Ok(out), _ => {} } buf.clear(); } } /// The declaration is 68 bytes long, so it does not fit in the 64-byte prefix. #[test] fn long_declaration_ascii_body() { let xml = b"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><a>e</a>"; assert_eq!(texts(xml).unwrap(), ["e"]); } #[test] fn long_declaration_non_ascii_body() { let xml = b"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?><a>\xE9</a>"; assert_eq!(texts(xml).unwrap(), ["\u{e9}"]); } /// UTF-16LE with BOM, declaration says UTF-8 (self-contradicting document). #[test] fn utf16_long_declaration() { let mut xml = vec![0xFF, 0xFE]; for c in "<?xml version=\"1.0\" encoding=\"UTF-8\"?><a>x</a>".encode_utf16() { xml.extend_from_slice(&c.to_le_bytes()); } assert_eq!(texts(&xml).unwrap(), ["x"]); }
cargo testoutput (paths shortened, thread ids removed):---- long_declaration_ascii_body stdout ---- thread 'long_declaration_ascii_body' panicked at src/encoding.rs:380:9: set_encoding() called after prefix buffer was drained; encoding can only be changed while the prefix is still active ---- long_declaration_non_ascii_body stdout ---- thread 'long_declaration_non_ascii_body' panicked at tests/repro.rs:35:27: called `Result::unwrap()` on an `Err` value: Encoding(Other(Encoding { name: "UTF-8", .. })) ---- utf16_long_declaration stdout ---- thread 'utf16_long_declaration' panicked at src/encoding.rs:380:9: set_encoding() called after prefix buffer was drained; encoding can only be changed while the prefix is still activeThe three cases
- ASCII body: the prefix is already drained when the
Declevent arrives, soset_encoding()hits its assert. A 64-byte declaration works; 65 bytes panics.- Non-ASCII Latin-1 body: the same declaration with
\xE9in the body returns a UTF-8 encoding error instead of a panic.- UTF-16: the prefix holds 32 UTF-16 characters, so behind a BOM a declaration of 32 characters or more panics the same way. The test's declaration is 38 characters and names UTF-8, which contradicts the BOM. An error would be fine there, a panic is not.
Context
- 0.41 baseline: 0.41.0 with a plain
Reader(noDecodingReader,encodingfeature) parses both Latin-1 inputs and returnseandé.- The prefix and
set_encoding()came with #956 (6f5d029, 0.40.0).- #1023 (merged) fixed non-ASCII bytes inside the first 64 bytes. This is the case it leaves: the declaration itself runs past the prefix.
- All three tests fail the same way on the branch of open PR #1033.
Impact
rssandatom_syndicationare on quick-xml 0.41 with theencodingfeature. They can't upgrade to 0.42 while a feed they parse today can panic.Suggested fix
Keep
set_encoding()usable until the first>has been decoded, instead of only while the 64-byte prefix lasts. Where a switch is impossible, such as a BOM that contradicts the declaration,set_encoding()could store an error that the nextfill_bufreturns as anio::Error. Its signature stays the same.
- Lingua principale
- Rust
- Stelle
- 1.6k
- Fork
- 299
- Merge medio
- 2g 4h
- PR unite (30g)
- 9
Preparare l'ambiente
- Nessun Dockerfile né file Docker Compose
- Nessun modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di tafia/quick-xml
-
Parser accepts an empty element or attribute nameForse già presa @ychampion l’ha presa oggi. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
encoding optimization
Difficoltà 4/5 3-5 giorni Idoneità per principianti 55/100
tafia/quick-xml#1039 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
optimization question
Difficoltà 4/5 3-5 giorni Idoneità per principianti 52/100
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 4/5 1-2 giorni Idoneità per principianti 53/100
tafia/quick-xml#1035 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 5/5 Più di una settimana Idoneità per principianti 25/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di tafia/quick-xml
Issue simili
-
[Bug]: opencode_go chat route drops reasoning_effort (even 'none'), while the same endpoint honors it via custom_llm_provider=openaiForse già presa @arvindkumar-ship-it l’ha presa oggi. Apertallm translation
Difficoltà 2/5 1-3 ore Idoneità per principianti 70/100
BerriAI/litellm#51871 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
comp-formats
Difficoltà 2/5 Mezza giornata Idoneità per principianti 64/100
ClickHouse/ClickHouse#131694 ·
I maintainer di solito rispondono entro 1 giorno
-
cli: `execCargoMetadata` decodes stdout per chunk, corrupting non-ASCII paths across pipe boundariesAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
enhancement
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
I maintainer di solito rispondono entro 1 giorno
-
C-Bug S-Needs-Triage
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
bevyengine/bevy#26558 ·
I maintainer di solito rispondono entro 2 giorni