diff --git a/cpp/src/parquet/geospatial/util_internal.cc b/cpp/src/parquet/geospatial/util_internal.cc index 59551ae87035..54e82f6c0458 100644 --- a/cpp/src/parquet/geospatial/util_internal.cc +++ b/cpp/src/parquet/geospatial/util_internal.cc @@ -21,6 +21,7 @@ #include #include "arrow/util/endian.h" +#include "arrow/util/int_util_overflow.h" #include "arrow/util/macros.h" #include "arrow/util/ubsan.h" #include "parquet/exception.h" @@ -64,8 +65,11 @@ class WKBBuffer { template void ReadCoords(uint32_t n_coords, bool swap, Visit&& visit) { - size_t total_bytes = n_coords * sizeof(Coord); - if (size_ < total_bytes) { + uint64_t total_bytes = 0; + if (::arrow::internal::MultiplyWithOverflow(static_cast(n_coords), + static_cast(sizeof(Coord)), + &total_bytes) || + size_ < total_bytes) { throw ParquetException("Can't read coordinate sequence of ", total_bytes, " bytes from WKBBuffer with ", size_, " remaining"); } diff --git a/cpp/src/parquet/geospatial/util_internal_test.cc b/cpp/src/parquet/geospatial/util_internal_test.cc index 527bcc505051..c12d9d53c237 100644 --- a/cpp/src/parquet/geospatial/util_internal_test.cc +++ b/cpp/src/parquet/geospatial/util_internal_test.cc @@ -166,6 +166,23 @@ TEST_P(WKBTestFixture, TestWKBBounderErrorForInputWithTooManyBytes) { ASSERT_THROW(bounder.MergeGeometry(wkb_with_extra_byte), ParquetException); } +TEST(TestGeometryUtil, TestWKBBounderErrorForCoordinateSequenceSizeOverflow) { + WKBGeometryBounder bounder; + + // LINESTRING with 0x10000001 XY coordinates but only one coordinate in the buffer. + // On 32-bit targets, 0x10000001 * sizeof(XY) would overflow to 16 bytes. + std::vector wkb = { + 0x01, // little endian + 0x02, 0x00, 0x00, 0x00, // LINESTRING + 0x01, 0x00, 0x00, 0x10, // 0x10000001 coordinates + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // x = 0 + 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // y = 0 + 0x00}; + + ASSERT_THROW(bounder.MergeGeometry(wkb), ParquetException); +} + INSTANTIATE_TEST_SUITE_P( TestGeometryUtil, WKBTestFixture, ::testing::Values(