Skip to content
Open
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions tuple/include/tuple_sketch_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,11 @@ compact_tuple_sketch<S, A> compact_tuple_sketch<S, A>::deserialize(const void* b
(*summary).~S();
}
}
const size_t bytes_consumed = ptr - base;
if (bytes_consumed != size) {
throw std::out_of_range("Unexpected buffer size: bytes consumed "
+ std::to_string(bytes_consumed) + ", bytes available " + std::to_string(size));
}
const bool is_ordered = flags_byte & (1 << flags::IS_ORDERED);
return compact_tuple_sketch(is_empty, is_ordered, seed_hash, theta, std::move(entries));
}
Expand Down
12 changes: 12 additions & 0 deletions tuple/test/tuple_sketch_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,4 +430,16 @@ TEST_CASE("tuple sketch: deserialize bounds-checks each entry key", "[tuple_sket
std::out_of_range);
}

TEST_CASE("tuple sketch: deserialize rejects unconsumed bytes", "[tuple_sketch]") {
// A compact sketch serialized with a wider summary (double, 8 bytes) and then
// deserialized as a narrower summary (float, 4 bytes). The reader consumes less
// data than the entries occupy, so deserialization must fail if bytes remain
// after the last entry.
auto update_sketch = update_tuple_sketch<double>::builder().build();
update_sketch.update(1, 1.0);
auto bytes = update_sketch.compact().serialize();
REQUIRE_THROWS_AS(compact_tuple_sketch<float>::deserialize(bytes.data(), bytes.size()),
std::out_of_range);
}

} /* namespace datasketches */