diff --git a/mysql-test/main/lotofstack.result b/mysql-test/main/lotofstack.result
index eb51ccd8e04..d619e122a26 100644
--- a/mysql-test/main/lotofstack.result
+++ b/mysql-test/main/lotofstack.result
@@ -116,3 +116,20 @@ ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stac
SELECT ExtractValue('', REPEAT('/n', 100000));
ERROR HY000: Thread stack overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed. Consider increasing the thread_stack system variable.
# End of 10.6 tests
+#
+# MDEV-41622 INSERT crashes on deeply nested GeometryCollection
+#
+set @g=concat(0x00000000, 0x0107000000, repeat(0x010000000107000000, 400000), 0x00000000);
+create table t1 (g geometry);
+create table t2 (g polygon);
+insert t1 values (@g);
+insert t2 values (@g);
+select st_astext(@g);
+select st_asgeojson(@g);
+select st_envelope(@g);
+select st_area(@g);
+select st_length(@g);
+select st_dimension(@g);
+select st_boundary(@g);
+drop table t1, t2;
+# End of 10.11 tests
diff --git a/mysql-test/main/lotofstack.test b/mysql-test/main/lotofstack.test
index 8345ccf8d48..bd5eb89e90f 100644
--- a/mysql-test/main/lotofstack.test
+++ b/mysql-test/main/lotofstack.test
@@ -12,7 +12,7 @@ if (`select count(*) from information_schema.system_variables
where variable_name='have_sanitizer'
and global_value REGEXP '(A|UB)SAN'`)
{
---skip Can't be run in UBSAN/ASAN (stack size predictability)
+--skip Cannot be run in UBSAN/ASAN (stack size predictability)
}
#
@@ -172,3 +172,33 @@ SELECT ExtractValue('', REPEAT('(', 100000));
SELECT ExtractValue('', REPEAT('/n', 100000));
--echo # End of 10.6 tests
+
+--echo #
+--echo # MDEV-41622 INSERT crashes on deeply nested GeometryCollection
+--echo #
+set @g=concat(0x00000000, 0x0107000000, repeat(0x010000000107000000, 400000), 0x00000000);
+create table t1 (g geometry);
+create table t2 (g polygon);
+--disable_result_log
+--error ER_STACK_OVERRUN_NEED_MORE
+insert t1 values (@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+insert t2 values (@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_astext(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_asgeojson(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_envelope(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_area(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_length(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_dimension(@g);
+--error ER_STACK_OVERRUN_NEED_MORE
+select st_boundary(@g);
+--enable_result_log
+drop table t1, t2;
+
+--echo # End of 10.11 tests
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 1484ae3d322..34db0639abb 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -1,6 +1,6 @@
/*
Copyright (c) 2002, 2013, Oracle and/or its affiliates.
- Copyright (c) 2011, 2021, MariaDB Corporation.
+ Copyright (c) 2011, 2026, MariaDB plc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -3359,6 +3359,9 @@ uint32 Gis_geometry_collection::get_data_size() const
n_objects= uint4korr(data);
data+= 4;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return GET_SIZE_ERROR;
+
while (n_objects--)
{
uint32 wkb_type,object_size;
@@ -3491,7 +3494,7 @@ uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len,
n_geom= wkb_get_uint(wkb, bo);
if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&wkb_orig))
- return 1;
+ return 0;
if (res->reserve(4, 512))
return 0;
@@ -3578,6 +3581,9 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt,
n_objects= uint4korr(data);
data+= 4;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
if (n_objects == 0)
{
txt->append(STRING_WITH_LEN(" EMPTY"), 512);
@@ -3622,6 +3628,9 @@ bool Gis_geometry_collection::get_data_as_json(String *txt, uint max_dec_digits,
n_objects= uint4korr(data);
data+= 4;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
bool any_objects= false;
txt->qs_append('[');
while (n_objects--)
@@ -3666,6 +3675,9 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const
if (n_objects == 0)
goto exit;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
while (n_objects--)
{
uint32 wkb_type;
@@ -3704,6 +3716,9 @@ int Gis_geometry_collection::area(double *ar, const char **end) const
if (n_objects == 0)
goto exit;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
while (n_objects--)
{
uint32 wkb_type;
@@ -3744,6 +3759,9 @@ int Gis_geometry_collection::geom_length(double *len, const char **end) const
if (n_objects == 0)
goto exit;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
while (n_objects--)
{
uint32 wkb_type;
@@ -3841,6 +3859,9 @@ bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const
n_objects= uint4korr(data);
data+= 4;
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
*res_dim= 0;
while (n_objects--)
{
@@ -3887,6 +3908,9 @@ int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const
return 0;
}
+ if (check_stack_overrun(current_thd, STACK_MIN_SIZE, (uchar*)&buffer))
+ return 1;
+
if (trn->start_collection(n_objects))
return 1;