Skip to content

Commit 1142da4

Browse files
Mingundralley
andcommitted
seq: Move has_value_field into MapAccess, because it is not used outside it
This fixes a data race with nested maps in sequence fields. Also, top-level sequences always have `has_value_field == false`, so no need to check it Co-authored-by: Daniel Alley <[email protected]>
1 parent 6a52ecc commit 1142da4

File tree

4 files changed

+17
-21
lines changed

4 files changed

+17
-21
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
- [#9]: Deserialization erroneously was successful in some cases where error is expected.
1616
This broke deserialization of untagged enums which rely on error if variant cannot be parsed
1717
- [#387]: Allow to have an ordinary elements together with a `$value` field
18+
- [#387]: Internal deserializer state can be broken when deserializing a map with
19+
a sequence field (such as `Vec<T>`), where elements of this sequence contains
20+
another sequence. This error affects only users with the `serialize` feature enabled
1821

1922
### Misc Changes
2023

src/de/map.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,14 @@ where
173173
source: ValueSource,
174174
/// List of field names of the struct. It is empty for maps
175175
fields: &'static [&'static str],
176+
/// If `true`, then the deserialized struct has a field with a special name:
177+
/// [`INNER_VALUE`]. That field should be deserialized from the text content
178+
/// of an XML node:
179+
///
180+
/// ```xml
181+
/// <tag>value for INNER_VALUE field<tag>
182+
/// ```
183+
has_value_field: bool,
176184
/// list of fields yet to unflatten (defined as starting with $unflatten=)
177185
unflatten_fields: Vec<&'static [u8]>,
178186
}
@@ -193,6 +201,7 @@ where
193201
iter: IterState::new(0, false),
194202
source: ValueSource::Unknown,
195203
fields,
204+
has_value_field: fields.contains(&INNER_VALUE),
196205
unflatten_fields: fields
197206
.iter()
198207
.filter(|f| f.starts_with(UNFLATTEN_PREFIX))
@@ -217,7 +226,6 @@ where
217226
// FIXME: There error positions counted from end of tag name - need global position
218227
let slice = self.start.attributes_raw();
219228
let decoder = self.de.reader.decoder();
220-
let has_value_field = self.de.has_value_field;
221229

222230
if let Some(a) = self.iter.next(slice).transpose()? {
223231
// try getting map from attributes (key= "value")
@@ -255,7 +263,7 @@ where
255263
// }
256264
// TODO: This should be handled by #[serde(flatten)]
257265
// See https://github.com/serde-rs/serde/issues/1905
258-
DeEvent::Start(e) if has_value_field && not_in(self.fields, e, decoder)? => {
266+
DeEvent::Start(e) if self.has_value_field && not_in(self.fields, e, decoder)? => {
259267
self.source = ValueSource::Content;
260268
seed.deserialize(INNER_VALUE.into_deserializer()).map(Some)
261269
}

src/de/mod.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -255,14 +255,6 @@ where
255255
{
256256
reader: R,
257257
peek: Option<DeEvent<'de>>,
258-
/// Special sing that deserialized struct have a field with the special
259-
/// name (see constant `INNER_VALUE`). That field should be deserialized
260-
/// from the text content of the XML node:
261-
///
262-
/// ```xml
263-
/// <tag>value for INNER_VALUE field<tag>
264-
/// ```
265-
has_value_field: bool,
266258
}
267259

268260
/// Deserialize an instance of type `T` from a string of XML text.
@@ -354,7 +346,6 @@ where
354346
Deserializer {
355347
reader,
356348
peek: None,
357-
has_value_field: false,
358349
}
359350
}
360351

@@ -544,10 +535,8 @@ where
544535
// Try to go to the next `<tag ...>...</tag>` or `<tag .../>`
545536
if let Some(e) = self.next_start()? {
546537
let name = e.name().to_vec();
547-
self.has_value_field = fields.contains(&INNER_VALUE);
548538
let map = map::MapAccess::new(self, e, fields)?;
549539
let value = visitor.visit_map(map)?;
550-
self.has_value_field = false;
551540
self.read_to_end(&name)?;
552541
Ok(value)
553542
} else {

src/de/seq.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,11 @@ where
9292
{
9393
/// Creates a new accessor to a top-level sequence of XML elements.
9494
pub fn new(de: &'a mut Deserializer<'de, R>) -> Result<Self, DeError> {
95-
let filter = if de.has_value_field {
96-
TagFilter::Exclude(&[])
95+
let filter = if let DeEvent::Start(e) = de.peek()? {
96+
// Clone is cheap if event borrows from the input
97+
TagFilter::Include(e.clone())
9798
} else {
98-
if let DeEvent::Start(e) = de.peek()? {
99-
// Clone is cheap if event borrows from the input
100-
TagFilter::Include(e.clone())
101-
} else {
102-
TagFilter::Exclude(&[])
103-
}
99+
TagFilter::Exclude(&[])
104100
};
105101
Ok(Self { de, filter })
106102
}

0 commit comments

Comments
 (0)