Skip to content

Commit

Permalink
🐛 fix stackoverflow issue
Browse files Browse the repository at this point in the history
  • Loading branch information
sivizius committed Dec 14, 2023
1 parent 2501444 commit 0cf8542
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 7 deletions.
21 changes: 21 additions & 0 deletions zbus/tests/serde.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use byteorder::LE;
use serde::Deserialize;
use std::collections::HashMap;
use zbus::zvariant::{serialized::Context, to_bytes, OwnedValue, Type};

#[derive(Deserialize, Type)]
#[zvariant(signature = "a{sv}")]
struct Outer {
foo: OwnedValue,
}

#[test_log::test]
fn convert() {
let ctxt = Context::<LE>::new_dbus(0);
let value =
<HashMap<String, OwnedValue>>::from([("foo".into(), 23.into()), ("bar".into(), 42.into())]);
let data = to_bytes(ctxt, &value).unwrap();
eprintln!("{data:02x?}");
let good = data.deserialize::<Outer>().unwrap().0;
eprintln!("{:?}", good.foo);
}
25 changes: 21 additions & 4 deletions zvariant/src/dbus/de.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor};
use core::convert::TryFrom;
use serde::de::{self, Deserialize, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Visitor};
use static_assertions::assert_impl_all;

use std::{marker::PhantomData, str};
Expand Down Expand Up @@ -44,6 +45,7 @@ impl<'de, 'sig, 'f, F> Deserializer<'de, 'sig, 'f, F> {
Ok(Self(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes,
#[cfg(unix)]
fds,
Expand Down Expand Up @@ -98,7 +100,11 @@ impl<'de, 'd, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deseriali
{
let c = self.0.sig_parser.next_char()?;

crate::de::deserialize_any::<Self, V>(self, c, visitor)
if self.0.resolve_variant {
self.deserialize_str(visitor)
} else {
crate::de::deserialize_any::<Self, V>(self, c, visitor)
}
}

fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
Expand Down Expand Up @@ -459,6 +465,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F>
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.de.0.pos..)?,
fds: self.de.0.fds,
pos: 0,
Expand Down Expand Up @@ -617,10 +624,19 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
T: DeserializeSeed<'de>,
{
match self.stage {
ValueParseStage::Signature if self.de.0.resolve_variant => {
self.stage = ValueParseStage::Done;
self.de.0.resolve_variant = false;
let signature = Signature::deserialize(&mut *self.de)?;

seed.deserialize(signature).map(Some)
}
ValueParseStage::Signature => {
self.stage = ValueParseStage::Value;

seed.deserialize(&mut *self.de).map(Some)
self.de.0.resolve_variant = true;
let result = seed.deserialize(&mut *self.de).map(Some);
self.de.0.resolve_variant = false;
result
}
ValueParseStage::Value => {
self.stage = ValueParseStage::Done;
Expand All @@ -644,6 +660,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, value_start..)?,
fds: self.de.0.fds,
pos: 0,
Expand Down
2 changes: 2 additions & 0 deletions zvariant/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub(crate) struct DeserializerCommon<'de, 'sig, 'f, F> {

pub(crate) sig_parser: SignatureParser<'sig>,

pub(crate) resolve_variant: bool,

pub(crate) container_depths: ContainerDepths,
}

Expand Down
9 changes: 9 additions & 0 deletions zvariant/src/gvariant/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ impl<'de, 'sig, 'f, F> Deserializer<'de, 'sig, 'f, F> {
Ok(Self(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes,
#[cfg(unix)]
fds,
Expand All @@ -65,6 +66,7 @@ macro_rules! deserialize_basic {
let mut dbus_de = crate::dbus::Deserializer::<F>(DeserializerCommon::<F> {
ctxt,
sig_parser: self.0.sig_parser.clone(),
resolve_variant: false,
bytes: subslice(self.0.bytes, self.0.pos..)?,
fds: self.0.fds,
pos: 0,
Expand Down Expand Up @@ -226,6 +228,7 @@ impl<'de, 'd, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> de::Deseriali
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser: self.0.sig_parser.clone(),
resolve_variant: false,
bytes: subslice(self.0.bytes, self.0.pos..end)?,
fds: self.0.fds,
pos: 0,
Expand Down Expand Up @@ -538,6 +541,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser: self.de.0.sig_parser.clone(),
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.de.0.pos..end)?,
fds: self.de.0.fds,
pos: 0,
Expand Down Expand Up @@ -604,6 +608,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser: self.de.0.sig_parser.clone(),
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.de.0.pos..key_end)?,
fds: self.de.0.fds,
pos: 0,
Expand Down Expand Up @@ -644,6 +649,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> MapAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.de.0.pos..value_end)?,
fds: self.de.0.fds,
pos: 0,
Expand Down Expand Up @@ -728,6 +734,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.de.0.pos..element_end)?,
fds: self.de.0.fds,
pos: 0,
Expand Down Expand Up @@ -825,6 +832,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
// No padding in signatures so just pass the same context
ctxt: self.de.0.ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.sig_start..self.sig_end)?,
fds: self.de.0.fds,
pos: 0,
Expand All @@ -849,6 +857,7 @@ impl<'d, 'de, 'sig, 'f, #[cfg(unix)] F: AsFd, #[cfg(not(unix))] F> SeqAccess<'de
let mut de = Deserializer::<F>(DeserializerCommon {
ctxt,
sig_parser,
resolve_variant: false,
bytes: subslice(self.de.0.bytes, self.value_start..self.value_end)?,
fds: self.de.0.fds,
pos: 0,
Expand Down
92 changes: 89 additions & 3 deletions zvariant/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use core::{
str,
};
use serde::{
de::{Deserialize, Deserializer},
de::{Deserialize, Deserializer, SeqAccess, Visitor},
ser::{Serialize, Serializer},
};
use static_assertions::assert_impl_all;
Expand Down Expand Up @@ -338,6 +338,61 @@ impl<'a> Signature<'a> {
}
}

macro_rules! deserialize_methods {
($(fn $method:ident($($arg:ident: $type:ty),*);)*) => {
$(
#[inline]
fn $method<V>(self, $($arg: $type,)* visitor: V) -> Result<V::Value>
where
V: Visitor<'de>,
{
visitor.visit_str(self.as_str())
}
)*
}
}

impl<'de> Deserializer<'de> for Signature<'de> {
type Error = Error;

deserialize_methods! {
fn deserialize_any();
fn deserialize_bool();
fn deserialize_i8();
fn deserialize_i16();
fn deserialize_i32();
fn deserialize_i64();
fn deserialize_u8();
fn deserialize_u16();
fn deserialize_u32();
fn deserialize_u64();
fn deserialize_f32();
fn deserialize_f64();
fn deserialize_char();
fn deserialize_str();
fn deserialize_string();
fn deserialize_bytes();
fn deserialize_byte_buf();
fn deserialize_option();
fn deserialize_unit();
fn deserialize_unit_struct(_n: &'static str);
fn deserialize_newtype_struct(_n: &'static str);
fn deserialize_seq();
fn deserialize_map();
fn deserialize_tuple(_l: usize);
fn deserialize_tuple_struct(_n: &'static str, _l: usize);
fn deserialize_struct(_n: &'static str, _f: &'static [&'static str]);
fn deserialize_enum(_n: &'static str, _f: &'static [&'static str]);
fn deserialize_identifier();
fn deserialize_ignored_any();
}

#[inline]
fn is_human_readable(&self) -> bool {
false
}
}

impl<'a> Debug for Signature<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Signature").field(&self.as_str()).finish()
Expand Down Expand Up @@ -499,9 +554,40 @@ impl<'de: 'a, 'a> Deserialize<'de> for Signature<'a> {
where
D: Deserializer<'de>,
{
let val = <std::borrow::Cow<'a, str>>::deserialize(deserializer)?;
let visitor = SignatureVisitor;

deserializer.deserialize_any(visitor)
}
}

struct SignatureVisitor;

impl<'de> Visitor<'de> for SignatureVisitor {
type Value = Signature<'de>;

fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
formatter.write_str("a Signature")
}

#[inline]
fn visit_borrowed_str<E>(self, value: &'de str) -> core::result::Result<Signature<'de>, E>
where
E: serde::de::Error,
{
Signature::try_from(value).map_err(serde::de::Error::custom)
}

#[inline]
fn visit_seq<A>(self, mut seq: A) -> core::result::Result<Self::Value, A::Error>
where
A: SeqAccess<'de>,
{
let signature = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self));
let _value = seq.next_element::<()>();

Self::try_from(val).map_err(serde::de::Error::custom)
signature
}
}

Expand Down

0 comments on commit 0cf8542

Please sign in to comment.