Skip to content

Test failing deserialization of invalid sequence length (backport #261) #263

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

Merged
merged 1 commit into from
Jul 18, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions test_rmw_implementation/test/test_serialize_deserialize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
// limitations under the License.

#include <gtest/gtest.h>
#include <cstring>

#include "osrf_testing_tools_cpp/scope_exit.hpp"

Expand All @@ -31,8 +32,87 @@
#include "test_msgs/msg/bounded_plain_sequences.h"
#include "test_msgs/msg/bounded_plain_sequences.hpp"

#include "test_msgs/msg/unbounded_sequences.h"
#include "test_msgs/msg/unbounded_sequences.hpp"

#include "./allocator_testing_utils.h"

static void check_bad_cdr_sequence_cases(
const rosidl_message_type_support_t * ts,
void * message)
{
// Serialized CDR buffer for a data with all sequences empty.
constexpr size_t kBufferSize = 132;
const uint8_t valid_data[kBufferSize] = {
0x01, 0x00, 0x00, 0x00, // representation header (CDR little endian)
0x00, 0x00, 0x00, 0x00, // bool[] bool_values
0x00, 0x00, 0x00, 0x00, // byte[] byte_values
0x00, 0x00, 0x00, 0x00, // char[] char_values
0x00, 0x00, 0x00, 0x00, // float32[] float32_values
0x00, 0x00, 0x00, 0x00, // float64[] float64_values
0x00, 0x00, 0x00, 0x00, // int8[] int8_values
0x00, 0x00, 0x00, 0x00, // uint8[] uint8_values
0x00, 0x00, 0x00, 0x00, // int16[] int16_values
0x00, 0x00, 0x00, 0x00, // uint16[] uint16_values
0x00, 0x00, 0x00, 0x00, // int32[] int32_values
0x00, 0x00, 0x00, 0x00, // uint32[] uint32_values
0x00, 0x00, 0x00, 0x00, // int64[] int64_values
0x00, 0x00, 0x00, 0x00, // uint64[] uint64_values
0x00, 0x00, 0x00, 0x00, // string[] string_values
0x00, 0x00, 0x00, 0x00, // BasicTypes[] basic_types_values
0x00, 0x00, 0x00, 0x00, // Constants[] constants_values
0x00, 0x00, 0x00, 0x00, // Defaults[] defaults_values
0x00, 0x00, 0x00, 0x00, // bool[] bool_values_default
0x00, 0x00, 0x00, 0x00, // byte[] byte_values_default
0x00, 0x00, 0x00, 0x00, // char[] char_values_default
0x00, 0x00, 0x00, 0x00, // float32[] float32_values_default
0x00, 0x00, 0x00, 0x00, // float64[] float64_values_default
0x00, 0x00, 0x00, 0x00, // int8[] int8_values_default
0x00, 0x00, 0x00, 0x00, // uint8[] uint8_values_default
0x00, 0x00, 0x00, 0x00, // int16[] int16_values_default
0x00, 0x00, 0x00, 0x00, // uint16[] uint16_values_default
0x00, 0x00, 0x00, 0x00, // int32[] int32_values_default
0x00, 0x00, 0x00, 0x00, // uint32[] uint32_values_default
0x00, 0x00, 0x00, 0x00, // int64[] int64_values_default
0x00, 0x00, 0x00, 0x00, // uint64[] uint64_values_default
0x00, 0x00, 0x00, 0x00, // string[] string_values_default
0x00, 0x00, 0x00, 0x00 // int32 alignment_check
};

uint8_t buffer[kBufferSize];
memcpy(buffer, valid_data, kBufferSize);

// The first 4 bytes are the CDR representation header, which we don't modify.
constexpr size_t kFirstSequenceOffset = 4;
// The last 4 bytes are the alignment check, which we also don't modify.
constexpr size_t kLastSequenceOffset = kBufferSize - 4;
// Each sequence length is stored as a 4-byte unsigned integer.
constexpr size_t kSequenceLengthSize = 4;

for (size_t i = kFirstSequenceOffset; i < kLastSequenceOffset; i += kSequenceLengthSize) {
// Corrupt the buffer by changing the size of a sequence to an invalid value.
buffer[i] = 0xFF;
buffer[i + 1] = 0xFF;
buffer[i + 2] = 0xFF;
buffer[i + 3] = 0xFF;

// Expect the deserialization to fail.
rmw_serialized_message_t serialized_message = rmw_get_zero_initialized_serialized_message();
serialized_message.buffer = const_cast<uint8_t *>(buffer);
serialized_message.buffer_length = sizeof(buffer);
serialized_message.buffer_capacity = sizeof(buffer);
rmw_ret_t ret = rmw_deserialize(&serialized_message, ts, message);
EXPECT_NE(RMW_RET_OK, ret);
rmw_reset_error();

// Restore the buffer to a valid state.
buffer[i] = 0x00;
buffer[i + 1] = 0x00;
buffer[i + 2] = 0x00;
buffer[i + 3] = 0x00;
}
}

TEST(TestSerializeDeserialize, get_serialization_format) {
const char * serialization_format = rmw_get_serialization_format();
EXPECT_NE(nullptr, serialization_format);
Expand Down Expand Up @@ -171,6 +251,26 @@ TEST(TestSerializeDeserialize, clean_round_trip_for_c_bounded_message) {
EXPECT_EQ(input_message.uint16_values.data[0], output_message.uint16_values.data[0]);
}

TEST(TestSerializeDeserialize, bad_cdr_sequence_correctly_fails_for_c) {
{
const char * serialization_format = rmw_get_serialization_format();
if (0 != strcmp(serialization_format, "cdr")) {
GTEST_SKIP();
}
}

const rosidl_message_type_support_t * ts{
ROSIDL_GET_MSG_TYPE_SUPPORT(test_msgs, msg, UnboundedSequences)};
test_msgs__msg__UnboundedSequences output_message{};
ASSERT_TRUE(test_msgs__msg__UnboundedSequences__init(&output_message));
OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT(
{
test_msgs__msg__UnboundedSequences__fini(&output_message);
});

check_bad_cdr_sequence_cases(ts, &output_message);
}

TEST(TestSerializeDeserialize, clean_round_trip_for_cpp_message) {
const rosidl_message_type_support_t * ts =
rosidl_typesupport_cpp::get_message_type_support_handle<test_msgs::msg::BasicTypes>();
Expand Down Expand Up @@ -244,6 +344,22 @@ TEST(TestSerializeDeserialize, clean_round_trip_for_cpp_bounded_message) {
EXPECT_EQ(input_message, output_message);
}

TEST(TestSerializeDeserialize, bad_cdr_sequence_correctly_fails_for_cpp) {
{
const char * serialization_format = rmw_get_serialization_format();
if (0 != strcmp(serialization_format, "cdr")) {
GTEST_SKIP();
}
}

using TestMessage = test_msgs::msg::UnboundedSequences;
const rosidl_message_type_support_t * ts =
rosidl_typesupport_cpp::get_message_type_support_handle<TestMessage>();
TestMessage output_message{};

check_bad_cdr_sequence_cases(ts, &output_message);
}

TEST(TestSerializeDeserialize, rmw_get_serialized_message_size)
{
if (rmw_get_serialized_message_size(nullptr, nullptr, nullptr) != RMW_RET_UNSUPPORTED) {
Expand Down