juusirantala opened a new issue, #3996: URL: https://github.com/apache/fory/issues/3996
### Search before asking - [x] I had searched in the [issues](https://github.com/apache/fory/issues) and found no similar issues. ### Version fory-core 1.7.0 ### Component(s) Rust ### Minimal reproduce step `TypeResolver` holds `Rc<TypeInfo>` and `Rc<MetaString>` in most of its fields, but: ```rust // rust/fory-core/src/resolver/type_resolver.rs unsafe impl Send for TypeResolver {} unsafe impl Sync for TypeResolver {} ``` `get_type_info_by_id`, `get_type_info_by_name`, `get_provider_type_info` and `get_target_type_info` all take `&self` and clone one of those `Rc`s out. `WriteContext` and `ReadContext` own a resolver, hand it out through `get_type_resolver(&self)`, and are `Send + Sync` themselves, so a custom serializer that parallelises hits this. ## Repro `fory-core = "=1.7.0"`, otherwise an empty lib crate. ```rust use fory_core::{Error, Fory, ReadContext, Serializer, WriteContext}; struct Blob(Vec<i32>); struct BlobSerializer; impl Serializer for BlobSerializer { type Target = Blob; fn write_data(_value: &Blob, context: &mut WriteContext) -> Result<(), Error> { let ctx: &WriteContext = context; std::thread::scope(|s| { s.spawn(|| { ctx.get_type_resolver().get_type_info_by_id(1); }); ctx.get_type_resolver().get_type_info_by_id(1); }); Ok(()) } fn read_data(_context: &mut ReadContext) -> Result<Blob, Error> { Ok(Blob(Vec::new())) } } #[test] fn realistic_parallel_custom_serializer() { let mut fory = Fory::default(); fory.register_serializer::<BlobSerializer>(500).unwrap(); fory.serialize_with::<BlobSerializer>(&Blob(vec![1, 2, 3])).unwrap(); } ``` `cargo +nightly miri test --lib`, nightly-2026-08-28: ``` error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `realistic_paral` and (2) non-atomic read on thread `unnamed-2` --> library/core/src/cell.rs:558:18 help: and (1) occurred earlier here --> src/lib.rs:19:59 = note: stack backtrace: 2: <RcInner<fory_core::TypeInfo> as RcInnerPtr>::inc_strong 3: <Rc<fory_core::TypeInfo> as Clone>::clone 5: fory_core::TypeResolver::get_type_info_by_id at fory-core-1.7.0/src/resolver/type_resolver.rs:795 6: <BlobSerializer as Serializer>::write_data::{closure#0}::{closure#0} ``` Shorter version of the same thing, no serializer needed: ```rust #[test] fn minimal_shared_type_resolver() { let r = std::sync::Arc::new(fory_core::TypeResolver::default()); let r2 = std::sync::Arc::clone(&r); std::thread::scope(|s| { s.spawn(move || { r2.get_type_info_by_id(1); }); r.get_type_info_by_id(1); }); } ``` ## Scope Sharing a `Fory` and serializing from several threads does not race on 1.7.0. `with_write_context` deep-clones the resolver into a thread-local context (`Rc::new(rc.deep_clone())` in `TypeResolver::clone`), and the `register*` methods all take `&mut self`. So the documented "share one instance across threads" pattern is fine today. It's the deep clone doing that work, though, not the type system. ### What did you expect to see? Sharing a `&WriteContext` across threads shouldn't compile: `TypeResolver` holds `Rc`, so neither it nor the contexts that own it are actually Sync. Failing that, if it does compile, no data race. ### What did you see instead? It compiles, and the two threads race the Rc strong count. Miri: ``` error: Undefined Behavior: Data race detected between (1) non-atomic write on thread `realistic_paral` and (2) non-atomic read on thread `unnamed-2` --> library/core/src/cell.rs:558:18 3: <Rc<fory_core::TypeInfo> as Clone>::clone 5: fory_core::TypeResolver::get_type_info_by_id ``` ### Anything Else? Haven't tested these, just noticed them nearby: - `RefReader` is `Send + Sync` holding a `Vec<Box<dyn Any>>`, which is neither. Comment above it already says `// danger but useful for multi-thread`. - `ReadContext` / `WriteContext` have a safety comment saying concurrent access is UB, which sits oddly on a type declaring `Sync`. - `Reader` is back to `&'a [u8]` + `usize`, so its asserts look redundant rather than wrong. Looks like the set came in with #2737, when `Reader` still used raw pointers.. ### Are you willing to submit a PR? - [ ] I'm willing to submit a PR! -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
