Skip to content

Commit

Permalink
Fails on empty doctype
Browse files Browse the repository at this point in the history
The parser was crashing with debug assertions enabled but passing with debug assertions disabled

Closes #608
  • Loading branch information
Tpt authored and Mingun committed Jun 11, 2023
1 parent 358cc58 commit a86340b
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 6 deletions.
3 changes: 3 additions & 0 deletions Changelog.md
Expand Up @@ -21,13 +21,16 @@
- [#603]: Fix a regression from [#581] that an XML comment or a processing
instruction between a <!DOCTYPE> and the root element in the file brokes
deserialization of structs by returning `DeError::ExpectedStart`
- [#608]: Return a new error `Error::EmptyDocType` on empty doctype instead
of crashing because of a debug assertion.

### Misc Changes

[#581]: https://github.com/tafia/quick-xml/pull/581
[#601]: https://github.com/tafia/quick-xml/pull/601
[#603]: https://github.com/tafia/quick-xml/pull/603
[#606]: https://github.com/tafia/quick-xml/pull/606
[#608]: https://github.com/tafia/quick-xml/issues/608


## 0.28.2 -- 2023-04-12
Expand Down
5 changes: 5 additions & 0 deletions src/errors.rs
Expand Up @@ -37,6 +37,10 @@ pub enum Error {
/// `Event::BytesDecl` must start with *version* attribute. Contains the attribute
/// that was found or `None` if an xml declaration doesn't contain attributes.
XmlDeclWithoutVersion(Option<String>),
/// Empty `Event::DocType`. `<!doctype foo>` is correct but `<!doctype > is not.
///
/// See <https://www.w3.org/TR/xml11/#NT-doctypedecl>
EmptyDocType,
/// Attribute parsing error
InvalidAttr(AttrError),
/// Escape error
Expand Down Expand Up @@ -109,6 +113,7 @@ impl fmt::Display for Error {
"XmlDecl must start with 'version' attribute, found {:?}",
e
),
Error::EmptyDocType => write!(f, "DOCTYPE declaration must not be empty"),
Error::InvalidAttr(e) => write!(f, "error while parsing attribute: {}", e),
Error::EscapeError(e) => write!(f, "{}", e),
Error::UnknownPrefix(prefix) => {
Expand Down
4 changes: 3 additions & 1 deletion src/reader/parser.rs
Expand Up @@ -117,7 +117,9 @@ impl Parser {
.iter()
.position(|b| !is_whitespace(*b))
.unwrap_or(len - 8);
debug_assert!(start < len - 8, "DocType must have a name");
if start + 8 >= len {
return Err(Error::EmptyDocType);
}
Ok(Event::DocType(BytesText::wrap(
&buf[8 + start..],
self.decoder(),
Expand Down
20 changes: 15 additions & 5 deletions tests/fuzzing.rs
Expand Up @@ -2,15 +2,14 @@

use quick_xml::events::Event;
use quick_xml::reader::Reader;
use std::io::Cursor;
use quick_xml::Error;

#[test]
fn fuzz_53() {
let data: &[u8] = b"\xe9\x00\x00\x00\x00\x00\x00\x00\x00\
\x00\x00\x00\x00\n(\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\
\x00<>\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00<<\x00\x00\x00";
let cursor = Cursor::new(data);
let mut reader = Reader::from_reader(cursor);
let mut reader = Reader::from_reader(data);
let mut buf = vec![];
loop {
match reader.read_event_into(&mut buf) {
Expand All @@ -25,8 +24,7 @@ fn fuzz_101() {
let data: &[u8] = b"\x00\x00<\x00\x00\x0a>&#44444444401?#\x0a413518\
#\x0a\x0a\x0a;<:<)(<:\x0a\x0a\x0a\x0a;<:\x0a\x0a\
<:\x0a\x0a\x0a\x0a\x0a<\x00*\x00\x00\x00\x00";
let cursor = Cursor::new(data);
let mut reader = Reader::from_reader(cursor);
let mut reader = Reader::from_reader(data);
let mut buf = vec![];
loop {
match reader.read_event_into(&mut buf) {
Expand All @@ -50,3 +48,15 @@ fn fuzz_101() {
buf.clear();
}
}

#[test]
fn fuzz_empty_doctype() {
let data: &[u8] = b"<!doctype \n >";
let mut reader = Reader::from_reader(data);
let mut buf = Vec::new();
assert!(matches!(
reader.read_event_into(&mut buf).unwrap_err(),
Error::EmptyDocType
));
assert_eq!(reader.read_event_into(&mut buf).unwrap(), Event::Eof);
}

0 comments on commit a86340b

Please sign in to comment.