Commit 2739ee38 authored by Georgi Kodinov's avatar Georgi Kodinov

Addendum #1 to the fix for bug #16451878 : GEOMETRY QUERY CRASHES SERVER

Fixed the get_data_size() methods for multi-point features to check properly for end 
of their respective data arrays.
Extended the point checking function to take a 3d optional argument so cases where
there's additional data in each array element (besides the point data itself) can be
covered by the helper function.
Fixed the 3 cases where such offset was present to use the proper checking helper 
function.
Test cases added.
Fixed review comments.
parent 0de30479
...@@ -395,19 +395,13 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, ...@@ -395,19 +395,13 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data,
uint offset) const uint offset) const
{ {
uint32 points; uint32 points;
size_t points_available;
/* read number of points */ /* read number of points */
if (no_data(data, 4)) if (no_data(data, 4))
return 0; return 0;
points= uint4korr(data); points= uint4korr(data);
data+= 4; data+= 4;
/* can't use any of the helper functions due to the offset */ if (not_enough_points(data, points, offset))
points_available=
data <= m_data_end ?
(m_data_end - data) / (POINT_DATA_SIZE + offset) : 0;
if (points_available < points)
return 0; return 0;
/* Calculate MBR for points */ /* Calculate MBR for points */
...@@ -490,9 +484,16 @@ const Geometry::Class_info *Gis_point::get_class_info() const ...@@ -490,9 +484,16 @@ const Geometry::Class_info *Gis_point::get_class_info() const
uint32 Gis_line_string::get_data_size() const uint32 Gis_line_string::get_data_size() const
{ {
size_t n_points;
if (no_data(m_data, 4)) if (no_data(m_data, 4))
return GET_SIZE_ERROR; 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 ...@@ -705,10 +706,18 @@ uint32 Gis_polygon::get_data_size() const
while (n_linear_rings--) while (n_linear_rings--)
{ {
size_t n_points;
if (no_data(data, 4)) if (no_data(data, 4))
return GET_SIZE_ERROR; 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); return (uint32) (data - m_data);
} }
...@@ -1038,9 +1047,17 @@ const Geometry::Class_info *Gis_polygon::get_class_info() const ...@@ -1038,9 +1047,17 @@ const Geometry::Class_info *Gis_polygon::get_class_info() const
uint32 Gis_multi_point::get_data_size() const uint32 Gis_multi_point::get_data_size() const
{ {
size_t n_points;
if (no_data(m_data, 4)) if (no_data(m_data, 4))
return GET_SIZE_ERROR; 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, ...@@ -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 bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
{ {
uint32 n_points; uint32 n_points;
size_t points_available;
const char *data= m_data; const char *data= m_data;
if (no_data(data, 4)) if (no_data(data, 4))
...@@ -1112,13 +1128,11 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const ...@@ -1112,13 +1128,11 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const
n_points= uint4korr(data); n_points= uint4korr(data);
data+= 4; 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 (not_enough_points(data, n_points, WKB_HEADER_SIZE) ||
if (n_points > points_available ||
txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points))
return 1; return 1;
*end= append_points(txt, n_points, data, WKB_HEADER_SIZE); *end= append_points(txt, n_points, data, WKB_HEADER_SIZE);
txt->length(txt->length()-1); // Remove end ',' txt->length(txt->length()-1); // Remove end ','
return 0; return 0;
...@@ -1177,10 +1191,18 @@ uint32 Gis_multi_line_string::get_data_size() const ...@@ -1177,10 +1191,18 @@ uint32 Gis_multi_line_string::get_data_size() const
while (n_line_strings--) while (n_line_strings--)
{ {
size_t n_points;
if (no_data(data, WKB_HEADER_SIZE + 4)) if (no_data(data, WKB_HEADER_SIZE + 4))
return GET_SIZE_ERROR; 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); return (uint32) (data - m_data);
} }
...@@ -1432,9 +1454,16 @@ uint32 Gis_multi_polygon::get_data_size() const ...@@ -1432,9 +1454,16 @@ uint32 Gis_multi_polygon::get_data_size() const
while (n_linear_rings--) while (n_linear_rings--)
{ {
size_t n_points;
if (no_data(data, 4)) if (no_data(data, 4))
return GET_SIZE_ERROR; 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); return (uint32) (data - m_data);
......
...@@ -335,14 +335,17 @@ class Geometry ...@@ -335,14 +335,17 @@ class Geometry
Need to perform the calculation in logical units, since multiplication Need to perform the calculation in logical units, since multiplication
can overflow the size data type. can overflow the size data type.
@arg data pointer to the begining of the points array @arg data pointer to the begining of the points array
@arg expected_points number of points expected @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 @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 || 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;
const char *m_data_end; const char *m_data_end;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment