diff --git a/mysql-test/main/spatial_utility_function_collect.result b/mysql-test/main/spatial_utility_function_collect.result index 07095862def21..21edda95006a0 100644 --- a/mysql-test/main/spatial_utility_function_collect.result +++ b/mysql-test/main/spatial_utility_function_collect.result @@ -279,4 +279,22 @@ SELECT ST_ASTEXT(ST_ENVELOPE(ST_COLLECT(c))) FROM t; ST_ASTEXT(ST_ENVELOPE(ST_COLLECT(c))) NULL DROP TABLE t; +# +# MDEV-38669 ST_COLLECT reads past the end of a non-geometry argument +# +SELECT ST_COLLECT(''); +ST_COLLECT('') +NULL +SELECT ST_COLLECT('') IS NULL; +ST_COLLECT('') IS NULL +1 +SELECT ST_COLLECT('not wkb'); +ST_COLLECT('not wkb') +NULL +CREATE TABLE t1 (a VARCHAR(16)); +INSERT INTO t1 VALUES (''), ('not wkb'), (NULL); +SELECT ST_COLLECT(a) FROM t1; +ST_COLLECT(a) +NULL +DROP TABLE t1; # End of 12.3 tests diff --git a/mysql-test/main/spatial_utility_function_collect.test b/mysql-test/main/spatial_utility_function_collect.test index f9e6fbd141a70..e3bffb4a20a7e 100644 --- a/mysql-test/main/spatial_utility_function_collect.test +++ b/mysql-test/main/spatial_utility_function_collect.test @@ -240,4 +240,15 @@ SELECT ST_ASTEXT(ST_ENVELOPE(ST_COLLECT(c))) FROM t; DROP TABLE t; +--echo # +--echo # MDEV-38669 ST_COLLECT reads past the end of a non-geometry argument +--echo # +SELECT ST_COLLECT(''); +SELECT ST_COLLECT('') IS NULL; +SELECT ST_COLLECT('not wkb'); +CREATE TABLE t1 (a VARCHAR(16)); +INSERT INTO t1 VALUES (''), ('not wkb'), (NULL); +SELECT ST_COLLECT(a) FROM t1; +DROP TABLE t1; + --echo # End of 12.3 tests diff --git a/sql/item_sum.cc b/sql/item_sum.cc index efc5b9450c3f6..dc970d18c261c 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -4642,6 +4642,13 @@ bool Item_func_collect::add() { if (tmp_arg[0]->null_value) return 0; + /* + A value too short to hold the SRID and WKB header isn't a valid + geometry, so contribute nothing (NULL) to the aggregate. + */ + if (!Geometry::is_valid_geometry_length(wkb->length())) + return 0; + if(is_distinct && list_contains_element(wkb)) return 0; diff --git a/sql/spatial.cc b/sql/spatial.cc index c8ff4d6530502..b516351b8cb6f 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -351,7 +351,7 @@ Geometry *Geometry::construct(Geometry_buffer *buffer, uint32 geom_type; Geometry *result; - if (data_len < SRID_SIZE + WKB_HEADER_SIZE) // < 4 + (1 + 4) + if (!is_valid_geometry_length(data_len)) return NULL; /* + 1 to skip the byte order (stored in position SRID_SIZE). */ geom_type= uint4korr(data + SRID_SIZE + 1); diff --git a/sql/spatial.h b/sql/spatial.h index c36dce735cb59..89051b43a44be 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -325,6 +325,14 @@ class Geometry static Geometry *construct(Geometry_buffer *buffer, const char *data, uint32 data_len); + /* + A WKB starts with a SRID and a WKB header. A buffer shorter than + the length of these together cannot possibly hold a geometry. + */ + static bool is_valid_geometry_length(uint32 data_len) + { + return data_len >= SRID_SIZE + WKB_HEADER_SIZE; + } static Geometry *create_from_wkt(Geometry_buffer *buffer, Gis_read_stream *trs, String *wkt, bool init_stream=1);