The following minimal example causes a stack overflow:
use serde::Serialize;
use erased_serde::serialize_trait_object;
serialize_trait_object!(MyTrait);
pub trait MyTrait {}
#[derive(Serialize)]
pub struct MyType { l: Box<dyn MyTrait> }
struct MyTraitImplementor;
impl MyTrait for MyTraitImplementor {}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let m = MyType { l: Box::new(MyTraitImplementor) };
let json_file = std::fs::File::create("/tmp/serde.json")?;
println!(" About to overflow the stack .....");
serde_json::to_writer(&json_file, &m)?;
Ok(())
}
Unfortunately it doesn't work in the playground, because erased_serde
is not available there.
With the help of https://crates.io/crates/backtrace-on-stack-overflow, I can get a backtrace by applying the following change to the original example:
- println!(" About to overflow the stack .....");
- serde_json::to_writer(&json_file, &m)?;
+ let overflow_the_stack = || serde_json::to_writer(&json_file, &m);
+ unsafe { backtrace_on_stack_overflow::enable(overflow_the_stack).unwrap(); }
The most relevant portion of the backtrace
The top two groups (43386 and 43387) are repeated until the stack blows
43386: erased_serde::ser::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:615:9
<dyn mfe::MyTrait as serde::ser::Serialize>::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/macros.rs:92:17
<T as erased_serde::ser::Serialize>::erased_serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:243:9
43387: erased_serde::ser::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:615:9
<dyn mfe::MyTrait as serde::ser::Serialize>::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/macros.rs:92:17
<T as erased_serde::ser::Serialize>::erased_serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:243:9
43388: erased_serde::ser::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:615:9
43389: <dyn mfe::MyTrait as serde::ser::Serialize>::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/macros.rs:92:17
<T as erased_serde::ser::Serialize>::erased_serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:243:9
erased_serde::ser::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/ser.rs:615:9
<dyn mfe::MyTrait as serde::ser::Serialize>::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/erased-serde-0.3.18/src/macros.rs:92:17
serde::ser::impls::<impl serde::ser::Serialize for alloc::boxed::Box<T>>::serialize
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.136/src/ser/impls.rs:390:17
<serde_json::ser::Compound<W,F> as serde::ser::SerializeMap>::serialize_value
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/src/ser.rs:711:22
serde::ser::SerializeMap::serialize_entry
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/serde-1.0.136/src/ser/mod.rs:1845:9
43390: <serde_json::ser::Compound<W,F> as serde::ser::SerializeStruct>::serialize_field
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/src/ser.rs:757:37
mfe::_::<impl serde::ser::Serialize for mfe::MyType>::serialize
at src/bin/mfe.rs:7:10
serde_json::ser::to_writer
at /home/jacg/.cargo/registry/src/github.com-1ecc6299db9ec823/serde_json-1.0.79/src/ser.rs:2161:10
Can you shed any light on what the problem is?
Is it possible to do what I am trying to do (use serde to serialize an object which contains a boxed trait object)?