Skip to content

Commit 1dcc70e

Browse files
authored
Patch serde content detection hack (#580)
1 parent 29e244a commit 1dcc70e

3 files changed

Lines changed: 42 additions & 19 deletions

File tree

fuzz/fuzz_targets/bench/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const ARRAY_UNINIT_LEN: usize = usize::MAX;
2222

2323
const FLATTEN_CONFLICT_MSG: &str = "ron::fuzz::FlattenFieldConflict";
2424

25-
pub fn roundtrip_arbitrary_typed_ron_or_panic(data: &[u8]) -> Option<TypedSerdeData> {
25+
pub fn roundtrip_arbitrary_typed_ron_or_panic(data: &[u8]) -> Option<TypedSerdeData<'_>> {
2626
if let Ok(typed_value) = TypedSerdeData::arbitrary(&mut Unstructured::new(data)) {
2727
let options = ron::Options::default().with_recursion_limit(RECURSION_LIMIT);
2828

src/de/mod.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ mod tag;
2828
mod tests;
2929
mod value;
3030

31-
const SERDE_CONTENT_CANARY: &str = "serde::__private::de::content::Content";
32-
const SERDE_TAG_KEY_CANARY: &str = "serde::__private::de::content::TagOrContent";
33-
3431
/// The RON deserializer.
3532
///
3633
/// If you just want to simply deserialize a value,
@@ -179,8 +176,8 @@ impl<'de> Deserializer<'de> {
179176
{
180177
// HACK: switch to JSON enum semantics for JSON content
181178
// Robust impl blocked on https://github.com/serde-rs/serde/pull/2420
182-
let is_serde_content = core::any::type_name::<V::Value>() == SERDE_CONTENT_CANARY
183-
|| core::any::type_name::<V::Value>() == SERDE_TAG_KEY_CANARY;
179+
let is_serde_content =
180+
is_serde_content::<V::Value>() || is_serde_tag_or_content::<V::Value>();
184181

185182
let old_serde_content_newtype = self.serde_content_newtype;
186183
self.serde_content_newtype = false;
@@ -857,8 +854,7 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
857854
K: DeserializeSeed<'de>,
858855
{
859856
if self.has_element()? {
860-
self.inside_internally_tagged_enum =
861-
core::any::type_name::<K::Value>() == SERDE_TAG_KEY_CANARY;
857+
self.inside_internally_tagged_enum = is_serde_tag_or_content::<K::Value>();
862858

863859
match self.terminator {
864860
Terminator::Struct => guard_recursion! { self.de =>
@@ -883,9 +879,7 @@ impl<'de, 'a> de::MapAccess<'de> for CommaSeparated<'a, 'de> {
883879
if self.de.parser.consume_char(':') {
884880
self.de.parser.skip_ws()?;
885881

886-
let res = if self.inside_internally_tagged_enum
887-
&& core::any::type_name::<V::Value>() != SERDE_CONTENT_CANARY
888-
{
882+
let res = if self.inside_internally_tagged_enum && !is_serde_content::<V::Value>() {
889883
guard_recursion! { self.de =>
890884
seed.deserialize(&mut tag::Deserializer::new(&mut *self.de))?
891885
}
@@ -1052,3 +1046,19 @@ impl<'de, 'a> de::MapAccess<'de> for SerdeEnumContent<'a, 'de> {
10521046
result
10531047
}
10541048
}
1049+
1050+
// ensure that these are the same as in the 449_tagged_enum test
1051+
fn is_serde_content<T>() -> bool {
1052+
matches!(
1053+
core::any::type_name::<T>(),
1054+
"serde::__private::de::content::Content" | "serde::__private::de::content::Content<'_>"
1055+
)
1056+
}
1057+
1058+
fn is_serde_tag_or_content<T>() -> bool {
1059+
matches!(
1060+
core::any::type_name::<T>(),
1061+
"serde::__private::de::content::TagOrContent"
1062+
| "serde::__private::de::content::TagOrContent<'_>"
1063+
)
1064+
}

tests/449_tagged_enum.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,29 @@ enum OuterEnumUntagged {
4343

4444
#[test]
4545
fn test_serde_content_hack() {
46-
assert_eq!(
46+
assert!(matches!(
4747
std::any::type_name::<serde::__private::de::Content>(),
48-
"serde::__private::de::content::Content"
49-
);
48+
"serde::__private::de::content::Content" | "serde::__private::de::content::Content<'_>"
49+
));
5050
}
5151

5252
#[test]
5353
fn test_serde_internally_tagged_hack() {
54-
const SERDE_CONTENT_CANARY: &str = "serde::__private::de::content::Content";
55-
const SERDE_TAG_KEY_CANARY: &str = "serde::__private::de::content::TagOrContent";
54+
// ensure that these are the same as in ron::de module
55+
fn is_serde_content<T>() -> bool {
56+
matches!(
57+
core::any::type_name::<T>(),
58+
"serde::__private::de::content::Content" | "serde::__private::de::content::Content<'_>"
59+
)
60+
}
61+
62+
fn is_serde_tag_or_content<T>() -> bool {
63+
matches!(
64+
core::any::type_name::<T>(),
65+
"serde::__private::de::content::TagOrContent"
66+
| "serde::__private::de::content::TagOrContent<'_>"
67+
)
68+
}
5669

5770
struct Deserializer {
5871
tag_key: Option<String>,
@@ -87,7 +100,7 @@ fn test_serde_internally_tagged_hack() {
87100
where
88101
K: serde::de::DeserializeSeed<'de>,
89102
{
90-
assert_eq!(std::any::type_name::<K::Value>(), SERDE_TAG_KEY_CANARY);
103+
assert!(is_serde_tag_or_content::<K::Value>());
91104

92105
if let Some(tag_key) = self.tag_key.take() {
93106
return seed
@@ -109,11 +122,11 @@ fn test_serde_internally_tagged_hack() {
109122
V: serde::de::DeserializeSeed<'de>,
110123
{
111124
if self.field_key.is_some() {
112-
assert_ne!(std::any::type_name::<V::Value>(), SERDE_CONTENT_CANARY);
125+
assert!(!is_serde_content::<V::Value>());
113126
return seed.deserialize(serde::de::value::StrDeserializer::new(&self.tag_value));
114127
}
115128

116-
assert_eq!(std::any::type_name::<V::Value>(), SERDE_CONTENT_CANARY);
129+
assert!(is_serde_content::<V::Value>());
117130

118131
seed.deserialize(serde::de::value::I32Deserializer::new(self.field_value))
119132
}

0 commit comments

Comments
 (0)