1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-41556 Unexpected error: Incorrect ASSOCIATIVE ARRAY KEY value

my_strntoull10rnd_8bit() did not set *error when a signed negative value
was exactly LONGLONG_MIN (-9223372036854775808): that path returned the
value and left *error untouched. Callers passing an uninitialized
"int error", such as the associative array key conversion in
Type_handler_assoc_array, then read a garbage value and raised a
spurious ER_WRONG_VALUE. Field_num::get_int() and Field_year::store()
also pass an uninitialized error, and my_strntoull10rnd_mb2_or_mb4()
calls this function too.

Fix: initialize *error to 0 at function entry, like the sibling
my_strntoll_8bit() and my_strntoll_mb2_or_mb4() do, so that no exit
path can leave it unset.

The bug was introduced by commit 031f11717d (Fix all warnings given by
UBSAN, 2021-04-18), which started skipping the *error assignment when
the value equals LONGLONG_MIN.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Alexander Barkov
2026-10-15 15:48:47 +04:00
parent a11e0bccdc
commit 9a1123dc45
4 changed files with 84 additions and 1 deletions

View File

@@ -3122,4 +3122,18 @@ $$
DROP PROCEDURE p1;
DROP PROCEDURE p2;
DROP PROCEDURE p_inout;
#
# MDEV-41556 Unexpected error: Incorrect ASSOCIATIVE ARRAY KEY value
#
SET sql_mode=ORACLE;
DECLARE
TYPE t IS TABLE OF INT INDEX BY BIGINT;
a t;
BEGIN
a(-9223372036854775807-1):= 10; -- key is LONGLONG_MIN
SELECT a(-9223372036854775807-1) AS c1;
END;
$$
c1
10
# End of 12.3 tests

View File

@@ -3561,4 +3561,22 @@ DROP PROCEDURE p1;
DROP PROCEDURE p2;
DROP PROCEDURE p_inout;
--echo #
--echo # MDEV-41556 Unexpected error: Incorrect ASSOCIATIVE ARRAY KEY value
--echo #
SET sql_mode=ORACLE;
DELIMITER $$;
DECLARE
TYPE t IS TABLE OF INT INDEX BY BIGINT;
a t;
BEGIN
a(-9223372036854775807-1):= 10; -- key is LONGLONG_MIN
SELECT a(-9223372036854775807-1) AS c1;
END;
$$
DELIMITER ;$$
--echo # End of 12.3 tests

View File

@@ -1693,6 +1693,8 @@ my_strntoull10rnd_8bit(CHARSET_INFO *cs __attribute__((unused)),
uchar ch;
int shift= 0, digits= 0, negative, addon;
*error= 0;
/* Skip leading spaces and tabs */
for ( ; str < end && my_isspace(&my_charset_latin1, *str) ; )
str++;

View File

@@ -1735,13 +1735,58 @@ static int test_mb_wc_filename_truncated()
}
/*
MDEV-41556: my_strntoull10rnd() must always set *error, also when a signed
value equals LONGLONG_MIN exactly. Pre-set "error" to a non-zero value, so
the check does not depend on the caller's uninitialized stack contents.
*/
static int test_strntoull10rnd_error_set()
{
static const struct
{
const char *str;
int unsigned_flag;
int expected_error;
} tests[]=
{
{"-9223372036854775808", 0, 0},
{"-9223372036854775809", 0, ERANGE},
{"9223372036854775807", 0, 0},
{"9223372036854775808", 0, ERANGE},
{"18446744073709551615", 1, 0},
};
CHARSET_INFO *charsets[]= {&my_charset_latin1, &my_charset_bin};
int failed= 0;
size_t i, j;
for (j= 0; j < array_elements(charsets); j++)
{
for (i= 0; i < array_elements(tests); i++)
{
char *endptr;
int error= 12345;
my_ci_strntoull10rnd(charsets[j], tests[i].str, strlen(tests[i].str),
tests[i].unsigned_flag, &endptr, &error);
if (error != tests[i].expected_error)
{
diag("%s: %s unsigned_flag=%d: error=%d, expected %d",
charsets[j]->coll_name.str, tests[i].str,
tests[i].unsigned_flag, error, tests[i].expected_error);
failed++;
}
}
}
return failed;
}
int main(int ac, char **av)
{
size_t i, failed= 0;
MY_INIT(av[0]);
plan(5);
plan(6);
diag("Testing my_like_range_xxx() functions");
for (i= 0; i < array_elements(charset_list); i++)
@@ -1771,6 +1816,10 @@ int main(int ac, char **av)
ok(test_mb_wc_filename_truncated() == 0,
"filename decoder does not read past the end pointer");
diag("Testing my_ci_strntoull10rnd() error output");
ok(test_strntoull10rnd_error_set() == 0,
"my_ci_strntoull10rnd() always sets error");
my_end(0);
return exit_status();