eProsima / Fast-DDS-Gen

Fast-DDS IDL code generator tool. Looking for commercial support? Contact info@eprosima.com
Apache License 2.0
82 stars 62 forks source link

[XTypes/PL_CDR2] Member header issue for sequences with an inner type of 2 bytes length (short, unsigned short) #334

Open lexamor opened 7 months ago

lexamor commented 7 months ago

In some cases NEXTINT is not serialized for a sequence with an inner type of 2 bytes length (short, unsigned short), also the incorrect Length code value is assigned.

According to XTypes spec (7.4.3.4.2 Member Header (EMHEADER), Length Code (LC) and NEXTINT).

LC = 4 = 0b100 indicates serialized member length is NEXTINT

The Member header for the sequences of (unsigned) shorts should always be 8 bytes in length (i.e include NEXTINT) and has a Length code of 4, but in some cases depending on the sequence length NEXTINT is not serialized at all, and incorrect LC code value is assigned.

// IDL 
module test 
{
    @mutable
    struct with_short_seq
    {
        sequence<short> the_shorts_;
    };
};

// empty seq 000b0000080000000000002000000000 Screenshot from 2024-05-01 09-27-47

// single el 000b00000a00000000000000010000002a000000 Screenshot from 2024-05-01 09-29-39

//two elements 000b00000c00000000000030020000002a002b00 Screenshot from 2024-05-01 09-31-17

//three elements 000b000012000000000000400a000000030000002a002b002c000000 Screenshot from 2024-05-01 09-32-46

// four elements 000b000014000000000000400c000000040000002a002b002c002d00 Screenshot from 2024-05-01 09-41-07

Looks like that the proper encoding started from the sequences with a length of three elements (correct length code + nextint).

//Reproducible example //DataWriter

typename test::with_short_seqPubSubType::type data;
for (int i = 0; i < 5; ++i)
{
    std::cout << "Pub: " << i << " seq lenght: " << data.the_shorts_().size() <<"\n";
    writer_->write(&data);
    data.the_shorts_().emplace_back(i + 42);
    std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}

Screenshot from 2024-05-01 09-46-34

//DataReader void on_data_available(fastdds::DataReader* reader) override

{
    fastdds::SampleInfo info;
    while (reader->take_next_sample(&msg_, &info) == ReturnCode_t::RETCODE_OK)
    {
        if (info.valid_data)
        {
            std::cout << "Rec seq length: " << msg_.the_shorts_().size() << std::endl;
        }
    }
}

Screenshot from 2024-05-01 09-46-20

*Subscriber cannot handle the sequence with a single element, because of malformed member header.

Seems it happened because the generated code calls serialize_member function (from << op) with subsequent xcdr2_begin_serialize_member always with default header_selerction (XCdrHeaderSelection header_selection = XCdrHeaderSelection::AUTO_WITH_SHORT_HEADER_BY_DEFAULT). Later on in the xcdr2_end_serialize_member not switched to the long header because the member length is less or equal than 8 bytes for sequence < 3 elements (8 bytes - length (uint32_t) + 2 * 2B).