Add bounds checking to Eigen serializer

This commit is contained in:
Lingzhu Xiang
2022-01-01 16:47:22 +08:00
parent ba91839d71
commit 7244a74ab0
3 changed files with 117 additions and 39 deletions

View File

@@ -141,12 +141,14 @@ void run_serialized(index_sequence<Indices...>, index_sequence<OutputIndices...>
using test_detail::tuple;
// Deserialize input size and inputs.
size_t input_size;
uint8_t* buff_ptr = Eigen::deserialize(buffer, input_size);
const uint8_t* read_ptr = buffer;
const uint8_t* read_end = buffer + capacity;
read_ptr = Eigen::deserialize(read_ptr, read_end, input_size);
// Create value-type instances to populate.
auto args = make_tuple(typename std::decay<Args>::type{}...);
EIGEN_UNUSED_VARIABLE(args) // Avoid NVCC compile warning.
// NVCC 9.1 requires us to spell out the template parameters explicitly.
buff_ptr = Eigen::deserialize(buff_ptr, get<Indices, typename std::decay<Args>::type...>(args)...);
read_ptr = Eigen::deserialize(read_ptr, read_end, get<Indices, typename std::decay<Args>::type...>(args)...);
// Call function, with void->Void conversion so we are guaranteed a complete
// output type.
@@ -158,12 +160,15 @@ void run_serialized(index_sequence<Indices...>, index_sequence<OutputIndices...>
output_size += Eigen::serialize_size(result);
// Always serialize required buffer size.
buff_ptr = Eigen::serialize(buffer, output_size);
uint8_t* write_ptr = buffer;
uint8_t* write_end = buffer + capacity;
write_ptr = Eigen::serialize(write_ptr, write_end, output_size);
// Null `write_ptr` can be safely passed along.
// Serialize outputs if they fit in the buffer.
if (output_size <= capacity) {
// Collect outputs and result.
buff_ptr = Eigen::serialize(buff_ptr, get<OutputIndices, typename std::decay<Args>::type...>(args)...);
buff_ptr = Eigen::serialize(buff_ptr, result);
write_ptr = Eigen::serialize(write_ptr, write_end, get<OutputIndices, typename std::decay<Args>::type...>(args)...);
write_ptr = Eigen::serialize(write_ptr, write_end, result);
}
}

View File

@@ -31,15 +31,35 @@ void test_pod_type() {
// Serialize.
std::vector<uint8_t> buffer(buffer_size);
uint8_t* dest = serializer.serialize(buffer.data(), initial);
VERIFY_IS_EQUAL(dest - buffer.data(), buffer_size);
uint8_t* begin = buffer.data();
uint8_t* end = buffer.data() + buffer.size();
uint8_t* dest = serializer.serialize(begin, end, initial);
VERIFY(dest != nullptr);
VERIFY_IS_EQUAL(dest - begin, buffer_size);
// Deserialize.
uint8_t* src = serializer.deserialize(buffer.data(), clone);
VERIFY_IS_EQUAL(src - buffer.data(), buffer_size);
const uint8_t* src = serializer.deserialize(begin, end, clone);
VERIFY(src != nullptr);
VERIFY_IS_EQUAL(src - begin, buffer_size);
VERIFY_IS_EQUAL(clone.x, initial.x);
VERIFY_IS_EQUAL(clone.y, initial.y);
VERIFY_IS_EQUAL(clone.z, initial.z);
// Serialize with bounds checking errors.
dest = serializer.serialize(begin, end - 1, initial);
VERIFY(dest == nullptr);
dest = serializer.serialize(begin, begin, initial);
VERIFY(dest == nullptr);
dest = serializer.serialize(nullptr, nullptr, initial);
VERIFY(dest == nullptr);
// Deserialize with bounds checking errors.
src = serializer.deserialize(begin, end - 1, clone);
VERIFY(src == nullptr);
src = serializer.deserialize(begin, begin, clone);
VERIFY(src == nullptr);
src = serializer.deserialize(nullptr, nullptr, clone);
VERIFY(src == nullptr);
}
// Matrix, Vector, Array
@@ -54,14 +74,34 @@ void test_eigen_type(const T& type) {
Eigen::Serializer<T> serializer;
size_t buffer_size = serializer.size(initial);
std::vector<uint8_t> buffer(buffer_size);
uint8_t* dest = serializer.serialize(buffer.data(), initial);
VERIFY_IS_EQUAL(dest - buffer.data(), buffer_size);
uint8_t* begin = buffer.data();
uint8_t* end = buffer.data() + buffer.size();
uint8_t* dest = serializer.serialize(begin, end, initial);
VERIFY(dest != nullptr);
VERIFY_IS_EQUAL(dest - begin, buffer_size);
// Deserialize.
T clone;
uint8_t* src = serializer.deserialize(buffer.data(), clone);
VERIFY_IS_EQUAL(src - buffer.data(), buffer_size);
const uint8_t* src = serializer.deserialize(begin, end, clone);
VERIFY(src != nullptr);
VERIFY_IS_EQUAL(src - begin, buffer_size);
VERIFY_IS_CWISE_EQUAL(clone, initial);
// Serialize with bounds checking errors.
dest = serializer.serialize(begin, end - 1, initial);
VERIFY(dest == nullptr);
dest = serializer.serialize(begin, begin, initial);
VERIFY(dest == nullptr);
dest = serializer.serialize(nullptr, nullptr, initial);
VERIFY(dest == nullptr);
// Deserialize with bounds checking errors.
src = serializer.deserialize(begin, end - 1, clone);
VERIFY(src == nullptr);
src = serializer.deserialize(begin, begin, clone);
VERIFY(src == nullptr);
src = serializer.deserialize(nullptr, nullptr, clone);
VERIFY(src == nullptr);
}
// Test a collection of dense types.
@@ -76,18 +116,38 @@ void test_dense_types(const T1& type1, const T2& type2, const T3& type3) {
// Allocate buffer and serialize.
size_t buffer_size = Eigen::serialize_size(x1, x2, x3);
std::vector<uint8_t> buffer(buffer_size);
Eigen::serialize(buffer.data(), x1, x2, x3);
uint8_t* begin = buffer.data();
uint8_t* end = buffer.data() + buffer.size();
uint8_t* dest = Eigen::serialize(begin, end, x1, x2, x3);
VERIFY(dest != nullptr);
// Clone everything.
T1 y1;
T2 y2;
T3 y3;
Eigen::deserialize(buffer.data(), y1, y2, y3);
const uint8_t* src = Eigen::deserialize(begin, end, y1, y2, y3);
VERIFY(src != nullptr);
// Verify they equal.
VERIFY_IS_CWISE_EQUAL(y1, x1);
VERIFY_IS_CWISE_EQUAL(y2, x2);
VERIFY_IS_CWISE_EQUAL(y3, x3);
// Serialize everything with bounds checking errors.
dest = Eigen::serialize(begin, end - 1, y1, y2, y3);
VERIFY(dest == nullptr);
dest = Eigen::serialize(begin, begin, y1, y2, y3);
VERIFY(dest == nullptr);
dest = Eigen::serialize(nullptr, nullptr, y1, y2, y3);
VERIFY(dest == nullptr);
// Deserialize everything with bounds checking errors.
src = Eigen::deserialize(begin, end - 1, y1, y2, y3);
VERIFY(src == nullptr);
src = Eigen::deserialize(begin, begin, y1, y2, y3);
VERIFY(src == nullptr);
src = Eigen::deserialize(nullptr, nullptr, y1, y2, y3);
VERIFY(src == nullptr);
}
EIGEN_DECLARE_TEST(serializer)