diff options
-rw-r--r-- | sql/spatial.cc | 67 | ||||
-rw-r--r-- | sql/spatial.h | 11 |
2 files changed, 55 insertions, 23 deletions
diff --git a/sql/spatial.cc b/sql/spatial.cc index 74fc863a18b..ba1cbbcb85e 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -395,19 +395,13 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, uint offset) const { uint32 points; - size_t points_available; /* read number of points */ if (no_data(data, 4)) return 0; points= uint4korr(data); data+= 4; - /* can't use any of the helper functions due to the offset */ - points_available= - data <= m_data_end ? - (m_data_end - data) / (POINT_DATA_SIZE + offset) : 0; - - if (points_available < points) + if (not_enough_points(data, points, offset)) return 0; /* Calculate MBR for points */ @@ -490,9 +484,16 @@ const Geometry::Class_info *Gis_point::get_class_info() const uint32 Gis_line_string::get_data_size() const { + size_t n_points; if (no_data(m_data, 4)) return GET_SIZE_ERROR; - return 4 + uint4korr(m_data) * POINT_DATA_SIZE; + + n_points= uint4korr(m_data); + + if (not_enough_points(m_data + 4, n_points)) + return GET_SIZE_ERROR; + + return 4 + n_points * POINT_DATA_SIZE; } @@ -705,10 +706,18 @@ uint32 Gis_polygon::get_data_size() const while (n_linear_rings--) { + size_t n_points; if (no_data(data, 4)) return GET_SIZE_ERROR; - data+= 4 + uint4korr(data)*POINT_DATA_SIZE; + n_points= uint4korr(data); + data+= 4; + + if (not_enough_points(data, n_points)) + return GET_SIZE_ERROR; + + data+= n_points * POINT_DATA_SIZE; } + return (uint32) (data - m_data); } @@ -1038,9 +1047,17 @@ const Geometry::Class_info *Gis_polygon::get_class_info() const uint32 Gis_multi_point::get_data_size() const { + size_t n_points; + if (no_data(m_data, 4)) return GET_SIZE_ERROR; - return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE); + + n_points= uint4korr(m_data); + + if (not_enough_points(m_data + 4, n_points, WKB_HEADER_SIZE)) + return GET_SIZE_ERROR; + + return 4 + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE); } @@ -1104,7 +1121,6 @@ uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const { uint32 n_points; - size_t points_available; const char *data= m_data; if (no_data(data, 4)) @@ -1112,13 +1128,11 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const n_points= uint4korr(data); data+= 4; - points_available= data <= m_data_end ? - (m_data_end - data) / (POINT_DATA_SIZE + WKB_HEADER_SIZE) : 0; - /* can't use any of the helper functions due to WKB_HEADER_SIZE */ - if (n_points > points_available || + if (not_enough_points(data, n_points, WKB_HEADER_SIZE) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; + *end= append_points(txt, n_points, data, WKB_HEADER_SIZE); txt->length(txt->length()-1); // Remove end ',' return 0; @@ -1177,10 +1191,18 @@ uint32 Gis_multi_line_string::get_data_size() const while (n_line_strings--) { + size_t n_points; + if (no_data(data, WKB_HEADER_SIZE + 4)) return GET_SIZE_ERROR; - data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * - POINT_DATA_SIZE); + + n_points= uint4korr(data + WKB_HEADER_SIZE); + data+= WKB_HEADER_SIZE + 4; + + if (not_enough_points(data, n_points)) + return GET_SIZE_ERROR; + + data+= n_points * POINT_DATA_SIZE; } return (uint32) (data - m_data); } @@ -1432,9 +1454,16 @@ uint32 Gis_multi_polygon::get_data_size() const while (n_linear_rings--) { + size_t n_points; if (no_data(data, 4)) - return GET_SIZE_ERROR; - data+= 4 + uint4korr(data) * POINT_DATA_SIZE; + return GET_SIZE_ERROR; + n_points= uint4korr(data); + data+= 4; + + if (not_enough_points(data, n_points)) + return GET_SIZE_ERROR; + + data+= n_points * POINT_DATA_SIZE; } } return (uint32) (data - m_data); diff --git a/sql/spatial.h b/sql/spatial.h index 075ae0ecc89..60a34852178 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -335,14 +335,17 @@ protected: Need to perform the calculation in logical units, since multiplication can overflow the size data type. - @arg data pointer to the begining of the points array - @arg expected_points number of points expected + @arg data pointer to the begining of the points array + @arg expected_points number of points expected + @arg extra_point_space extra space for each point element in the array @return true if there are not enough points */ - inline bool not_enough_points(const char *data, uint32 expected_points) const + inline bool not_enough_points(const char *data, uint32 expected_points, + uint32 extra_point_space = 0) const { return (m_data_end < data || - (expected_points > ((m_data_end - data) / POINT_DATA_SIZE))); + (expected_points > ((m_data_end - data) / + (POINT_DATA_SIZE + extra_point_space)))); } const char *m_data; const char *m_data_end; |