kpumuk commented on PR #3414:
URL: https://github.com/apache/thrift/pull/3414#issuecomment-4339750874

   There are two remaining edge cases that look unsafe.
   
   ### 1. Nested forward typedefs still lose the `Box`
   
   Minimal IDL:
   
   ```thrift
   typedef FutureUnion ForwardAlias
   typedef ForwardAlias NestedForwardAlias
   
   struct Wrapper {
     1: optional NestedForwardAlias value
   }
   
   union FutureUnion {
     1: i32 n
   }
   ```
   
   The Rust generator emits aliases like:
   
   ```rust
   pub type ForwardAlias = Box<FutureUnion>;
   pub type NestedForwardAlias = ForwardAlias;
   ```
   
   But the new special-case union read path reads the resolved union type 
directly and assigns it into the field temp:
   
   ```rust
   let mut f_1: Option<NestedForwardAlias> = None;
   
   match FutureUnion::read_from_in_protocol(i_prot) {
       Ok(val) => { f_1 = Some(val); },
       Err(thrift::Error::Protocol(ref e))
           if e.kind == ProtocolErrorKind::UnknownUnionVariant => {}
       Err(e) => return Err(e),
   }
   ```
   
   That is a generated-code compile error: `val` is `FutureUnion`, while 
`NestedForwardAlias` is `Box<FutureUnion>`.
   
   ```text
   error[E0308]: mismatched types
   expected `Box<FutureUnion>`, found `FutureUnion`
   ```
   
   The boxing decision needs to preserve boxing through the typedef chain, not 
only inspect the outer field typedef.
   
   ### 2. Multiple unknown union fields are treated as ignorable
   
   The union reader currently maps `received_field_count == 0` to 
`UnknownUnionVariant` before rejecting multi-field unions. That also matches a 
union payload with two unknown fields. The parent struct reader then catches 
`UnknownUnionVariant` and silently leaves the optional union field as `None`.
   
   Regression test shape:
   
   ```rust
   let mut write_buf = Vec::new();
   {
       let cursor = Cursor::new(&mut write_buf);
       let mut prot = TBinaryOutputProtocol::new(cursor, false);
   
       prot.write_struct_begin(&TStructIdentifier::new("Wrapper")).unwrap();
       prot.write_field_begin(&TFieldIdentifier::new("u", TType::Struct, 
1)).unwrap();
   
       prot.write_struct_begin(&TStructIdentifier::new("U")).unwrap();
       prot.write_field_begin(&TFieldIdentifier::new("future_a", TType::I32, 
99)).unwrap();
       prot.write_i32(1).unwrap();
       prot.write_field_end().unwrap();
   
       prot.write_field_begin(&TFieldIdentifier::new("future_b", TType::I32, 
100)).unwrap();
       prot.write_i32(2).unwrap();
       prot.write_field_end().unwrap();
   
       prot.write_field_stop().unwrap();
       prot.write_struct_end().unwrap();
   
       prot.write_field_end().unwrap();
       prot.write_field_stop().unwrap();
       prot.write_struct_end().unwrap();
   }
   
   let read_cursor = Cursor::new(write_buf);
   let mut rprot = TBinaryInputProtocol::new(read_cursor, false);
   let err = Wrapper::read_from_in_protocol(&mut rprot)
       .expect_err("multi-field union should stay invalid");
   ```
   
   A union with multiple fields is invalid even if none of those fields are 
known locally. The checks should preserve that:
   
   ```text
   total_field_count == 0                         => EmptyUnion
   total_field_count > 1                          => InvalidData
   total_field_count == 1 && received_count == 0  => UnknownUnionVariant
   ```
   


-- 
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]

Reply via email to