-
Notifications
You must be signed in to change notification settings - Fork 791
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DataReader::read() reads invalid data #5136
Comments
(Reopened from #5127 because I couldn't add comments to that issue anymore.) For clarification, this does not read previous samples but invents a totally new sample which is compromised of the data of multiple previous samples (see the log output above). This seems to happen if the message contains a Also when changing the callback to use
|
So I tried to figure this out a little bit more and I'm not really sure how it's supposed to work. It seems to come down to the void return_loan(
void* sample)
{
OutstandingLoanItem* item = find_by_sample(sample);
assert(nullptr != item);
item->num_refs -= 1;
if (item->num_refs == 0)
{
CacheChange_t tmp;
tmp.payload_owner(item->owner);
tmp.serializedPayload = item->payload;
item->owner->release_payload(tmp);
item->payload.data = nullptr;
item->owner = nullptr;
item = free_loans_.push_back(*item);
assert(nullptr != item);
used_loans_.remove(*item);
}
} But it doesn't really change the Later it reuses the same loan (with the sample still attached to it) from the list of available loans in void get_loan(
CacheChange_t* change,
void*& sample)
{
// ...
else
{
// Reuse a free entry
item = used_loans_.push_back(free_loans_.back());
assert(nullptr != item);
free_loans_.pop_back();
}
// ...
if (is_plain_)
{
// ...
}
else
{
type_->deserialize(&item->payload, item->sample);
}
// ...
} However, this function also does not change the sample (unless it's plain which is isn't), which at this point is still attached to the item. Because of the way, I saw that in some cases, |
This comment was marked as outdated.
This comment was marked as outdated.
I think the actual issue lies in the generated type support which, when deserializing, should clear the map before adding elements to it. If you use Could you look at the generated |
@MiguelCompany No, there's nothing of the sort in template<>
eProsima_user_DllExport void deserialize(
eprosima::fastcdr::Cdr& cdr,
ComplexMessage& data)
{
cdr.deserialize_type(eprosima::fastcdr::CdrVersion::XCDRv2 == cdr.get_cdr_version() ?
eprosima::fastcdr::EncodingAlgorithmFlag::DELIMIT_CDR2 :
eprosima::fastcdr::EncodingAlgorithmFlag::PLAIN_CDR,
[&data](eprosima::fastcdr::Cdr& dcdr, const eprosima::fastcdr::MemberId& mid) -> bool
{
bool ret_value = true;
switch (mid.id)
{
case 0:
dcdr >> data.dict();
break;
default:
ret_value = false;
break;
}
return ret_value;
});
} |
Same for the other bool ComplexMessagePubSubType::deserialize(
SerializedPayload_t* payload,
void* data)
{
try
{
// Convert DATA to pointer of your type
ComplexMessage* p_type = static_cast<ComplexMessage*>(data);
// Object that manages the raw buffer.
eprosima::fastcdr::FastBuffer fastbuffer(reinterpret_cast<char*>(payload->data), payload->length);
// Object that deserializes the data.
eprosima::fastcdr::Cdr deser(fastbuffer, eprosima::fastcdr::Cdr::DEFAULT_ENDIAN
#if FASTCDR_VERSION_MAJOR == 1
, eprosima::fastcdr::Cdr::CdrType::DDS_CDR
#endif // FASTCDR_VERSION_MAJOR == 1
);
// Deserialize encapsulation.
deser.read_encapsulation();
payload->encapsulation = deser.endianness() == eprosima::fastcdr::Cdr::BIG_ENDIANNESS ? CDR_BE : CDR_LE;
// Deserialize the object.
deser >> *p_type;
}
catch (eprosima::fastcdr::exception::Exception& /*exception*/)
{
return false;
}
return true;
} |
@MiguelCompany Ok, seems like there's missing a template<class _K, class _T, typename std::enable_if<!std::is_enum<_T>::value &&
!std::is_arithmetic<_T>::value>::type* = nullptr>
Cdr& deserialize(
std::map<_K, _T>& map_t)
{
if (CdrVersion::XCDRv2 == cdr_version_)
{
uint32_t dheader {0};
deserialize(dheader);
auto offset = offset_;
uint32_t map_length {0};
deserialize(map_length);
map_t.clear();
uint32_t count {0};
while (offset_ - offset < dheader && count < map_length)
{
_K key;
_T val;
deserialize(key);
deserialize(val);
map_t.emplace(std::pair<_K, _T>(std::move(key), std::move(val)));
++count;
}
if (offset_ - offset != dheader)
{
throw exception::BadParamException("Member size greater than size specified by DHEADER");
}
}
else
{
uint32_t sequence_length = 0;
state state_(*this);
deserialize(sequence_length);
try
{
for (uint32_t i = 0; i < sequence_length; ++i)
{
_K key;
_T value;
deserialize(key);
deserialize(value);
map_t.emplace(std::pair<_K, _T>(std::move(key), std::move(value)));
}
}
catch (exception::Exception& ex)
{
set_state(state_);
ex.raise();
}
}
return *this;
} The |
Is there an already existing issue for this?
Expected behavior
Receive the messages exactly as they are sent. (According to https://fast-dds.docs.eprosima.com/en/latest/fastdds/dds_layer/subscriber/dataReader/readingData.html).
Current behavior
DataReader::read()
seems to invent data or merges received data from multiple messages.We have a simple publisher/subscriber scenario with a message type that contains a
map
/std::map
. When publishing multiple messages, subsequent messages don't receive the message that has been sent but message contents of multiple messages are merged into one:This seems to happen when using
DataReader::read()
(withDataReader::read_next_sample()
it seems to work correctly but that is not our use case so I haven't investigated a lot).Steps to reproduce
Here's a hopefully complete reproduction scenario. Code from IDL is generated with
fastddsgen -d idl msg.idl
.main.cpp
msg.idl
CMakeLists.txt
Fast DDS version/commit
2.14.2
Platform/Architecture
Windows 10 Visual Studio 2019
Transport layer
Default configuration, UDPv4 & SHM
Additional context
n/a
XML configuration file
Relevant log output
Network traffic capture
n/a
Originally posted by @fschoenm in #5134
The text was updated successfully, but these errors were encountered: