diff --git a/mysql-test/main/lotofstack.result b/mysql-test/main/lotofstack.result
index dfe12c3f796d3..eb51ccd8e0472 100644
--- a/mysql-test/main/lotofstack.result
+++ b/mysql-test/main/lotofstack.result
@@ -108,4 +108,11 @@ SELECT ST_GeomFromText(CONCAT(REPEAT('GEOMETRYCOLLECTION(',5000),'POINT(1 1)',RE
#
set @a=concat(0x0107000000, repeat(0x010000000107000000, 120000), 0x00000000);
SELECT ST_GeomFromWKB(@a);
+#
+# MDEV-39750 ExtractValue does not control recursion depth.
+#
+SELECT ExtractValue(' ', REPEAT('(', 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.
+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
diff --git a/mysql-test/main/lotofstack.test b/mysql-test/main/lotofstack.test
index 768c87160b62f..7c8dfa21271e2 100644
--- a/mysql-test/main/lotofstack.test
+++ b/mysql-test/main/lotofstack.test
@@ -149,4 +149,15 @@ set @a=concat(0x0107000000, repeat(0x010000000107000000, 120000), 0x00000000);
SELECT ST_GeomFromWKB(@a);
--enable_result_log
+--echo #
+--echo # MDEV-39750 ExtractValue does not control recursion depth.
+--echo #
+--replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT ExtractValue(' ', REPEAT('(', 100000));
+
+--replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
+--error ER_STACK_OVERRUN_NEED_MORE
+SELECT ExtractValue(' ', REPEAT('/n', 100000));
+
--echo # End of 10.6 tests
diff --git a/mysql-test/main/mysqld--help,win.rdiff b/mysql-test/main/mysqld--help,win.rdiff
index 07b7c87b5d4c6..7594959fb07ec 100644
--- a/mysql-test/main/mysqld--help,win.rdiff
+++ b/mysql-test/main/mysqld--help,win.rdiff
@@ -1,6 +1,6 @@
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
-@@ -180,6 +180,7 @@ The following specify which files/extra groups are read (specified before remain
+@@ -190,6 +190,7 @@ The following specify which files/extra groups are read (specified before remain
--console Write error output on screen; don't remove the console
window on windows.
--core-file Write core on crashes
@@ -8,7 +8,7 @@
-h, --datadir=name Path to the database root directory
--date-format=name The DATE format (ignored)
--datetime-format=name
-@@ -649,6 +650,7 @@ The following specify which files/extra groups are read (specified before remain
+@@ -677,6 +678,7 @@ The following specify which files/extra groups are read (specified before remain
Use MySQL-5.6 (instead of MariaDB-5.3) format for TIME,
DATETIME, TIMESTAMP columns.
(Defaults to on; use --skip-mysql56-temporal-format to disable.)
@@ -16,7 +16,17 @@
--net-buffer-length=#
Buffer length for TCP/IP and socket communication
--net-read-timeout=#
-@@ -1280,6 +1282,10 @@ The following specify which files/extra groups are read (specified before remain
+@@ -1192,8 +1194,7 @@ The following specify which files/extra groups are read (specified before remain
+ (Defaults to on; use --skip-secure-auth to disable.)
+ --secure-file-priv=name
+ Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to
+- files within specified directory. Empty value means no
+- limits except /proc
++ files within specified directory.
+ --secure-timestamp=name
+ Restricts direct setting of a session timestamp. Possible
+ levels are: YES - timestamp cannot deviate from the
+@@ -1346,6 +1347,10 @@ The following specify which files/extra groups are read (specified before remain
Log slow queries to given log file. Defaults logging to
'hostname'-slow.log. Must be enabled to activate other
slow log options
@@ -27,7 +37,7 @@
--socket=name Socket file to use for connection
--sort-buffer-size=#
Each thread that needs to do a sort allocates a buffer of
-@@ -1304,6 +1310,7 @@ The following specify which files/extra groups are read (specified before remain
+@@ -1371,6 +1376,7 @@ The following specify which files/extra groups are read (specified before remain
deleting or updating every row in a table.
--stack-trace Print a symbolic stack trace on failure
(Defaults to on; use --skip-stack-trace to disable.)
@@ -35,7 +45,7 @@
--standard-compliant-cte
Allow only CTEs compliant to SQL standard
(Defaults to on; use --skip-standard-compliant-cte to disable.)
-@@ -1379,6 +1386,12 @@ The following specify which files/extra groups are read (specified before remain
+@@ -1446,6 +1452,12 @@ The following specify which files/extra groups are read (specified before remain
--thread-pool-max-threads=#
Maximum allowed number of worker threads in the thread
pool
@@ -48,7 +58,7 @@
--thread-pool-oversubscribe=#
How many additional active worker threads in a group are
allowed.
-@@ -1417,8 +1430,8 @@ The following specify which files/extra groups are read (specified before remain
+@@ -1485,8 +1497,8 @@ The following specify which files/extra groups are read (specified before remain
automatically convert it to an on-disk MyISAM or Aria
table.
-t, --tmpdir=name Path for temporary files. Several paths may be specified,
@@ -59,7 +69,7 @@
--transaction-alloc-block-size=#
Allocation block size for transactions to be stored in
binary log
-@@ -1633,6 +1646,7 @@ myisam-sort-buffer-size 134216704
+@@ -1704,6 +1716,7 @@ myisam-sort-buffer-size 134216704
myisam-stats-method NULLS_UNEQUAL
myisam-use-mmap FALSE
mysql56-temporal-format TRUE
@@ -67,7 +77,7 @@
net-buffer-length 16384
net-read-timeout 30
net-retry-count 10
-@@ -1787,6 +1801,7 @@ slave-transaction-retry-interval 0
+@@ -1862,6 +1875,7 @@ slave-transaction-retry-interval 0
slave-type-conversions
slow-launch-time 2
slow-query-log FALSE
@@ -75,7 +85,7 @@
sort-buffer-size 2097152
sql-mode STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
sql-safe-updates FALSE
-@@ -1813,6 +1828,8 @@ thread-pool-dedicated-listener FALSE
+@@ -1888,6 +1902,8 @@ thread-pool-dedicated-listener FALSE
thread-pool-exact-stats FALSE
thread-pool-idle-timeout 60
thread-pool-max-threads 65536
diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result
index 7ce8ef6cd9709..451e474c66e22 100644
--- a/mysql-test/main/mysqld--help.result
+++ b/mysql-test/main/mysqld--help.result
@@ -1192,7 +1192,8 @@ The following specify which files/extra groups are read (specified before remain
(Defaults to on; use --skip-secure-auth to disable.)
--secure-file-priv=name
Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to
- files within specified directory
+ files within specified directory. Empty value means no
+ limits except /proc
--secure-timestamp=name
Restricts direct setting of a session timestamp. Possible
levels are: YES - timestamp cannot deviate from the
diff --git a/mysql-test/main/xml.result b/mysql-test/main/xml.result
index 1cf232e547506..e699a8fb10850 100644
--- a/mysql-test/main/xml.result
+++ b/mysql-test/main/xml.result
@@ -1414,11 +1414,4 @@ ExtractValue(@xml, '/employee/dt3')
NULL
Warnings:
Warning 1525 Incorrect XML value: 'parse error at line 10 pos 27: unexpected END-OF-INPUT'
-#
-# MDEV-39750 ExtractValue does not control recursion depth.
-#
-SELECT ExtractValue(' ', REPEAT('(', 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.
-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
diff --git a/mysql-test/main/xml.test b/mysql-test/main/xml.test
index f849e81d974a9..bc1e36a0eb838 100644
--- a/mysql-test/main/xml.test
+++ b/mysql-test/main/xml.test
@@ -899,17 +899,5 @@ set @xml= '
SELECT ExtractValue(@xml, '/employee/dt3');
---echo #
---echo # MDEV-39750 ExtractValue does not control recursion depth.
---echo #
-
---replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
---error ER_STACK_OVERRUN_NEED_MORE
-SELECT ExtractValue(' ', REPEAT('(', 100000));
-
---replace_regex /overrun: [0-9]* bytes used of a [0-9]* byte stack, and [0-9]* bytes needed/overrun: 'used bytes' used of a 'available' byte stack, and 'X' bytes needed/
---error ER_STACK_OVERRUN_NEED_MORE
-SELECT ExtractValue(' ', REPEAT('/n', 100000));
-
--echo # End of 10.6 tests
diff --git a/mysql-test/suite/sys_vars/r/secure_file_priv.result b/mysql-test/suite/sys_vars/r/secure_file_priv.result
index 74f816df59d88..06968a185e773 100644
--- a/mysql-test/suite/sys_vars/r/secure_file_priv.result
+++ b/mysql-test/suite/sys_vars/r/secure_file_priv.result
@@ -6,14 +6,17 @@ INSERT INTO t1 VALUES ("one"),("two"),("three"),("four"),("five");
SHOW VARIABLES LIKE 'secure_file_priv';
Variable_name Value
secure_file_priv
-Warnings:
-Warning 1287 ' INTO ;' is deprecated and will be removed in a future release. Please use 'SELECT INTO FROM...' instead
+SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/../bug50373.txt' FROM t1;
+DELETE FROM t1;
+LOAD DATA INFILE '$MYSQLTEST_VARDIR/../bug50373.txt' INTO TABLE t1;
+SELECT * FROM t1;
c1
one
two
three
four
five
+SELECT load_file('$MYSQLTEST_VARDIR/../bug50373.txt') AS loaded_file;
loaded_file
one
two
@@ -22,3 +25,11 @@ four
five
DROP TABLE t1;
+#
+# MDEV-40589 default exclude list for secure-file-priv
+#
+CREATE TABLE t1 (c1 VARCHAR(50));
+LOAD DATA INFILE '/proc/cpuinfo' INTO TABLE t1;
+ERROR HY000: The MariaDB server is running with the --secure-file-priv option so it cannot execute this statement
+DROP TABLE t1;
+# End of 10.6 tests
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
index e180131318374..dc70fd1d09e3d 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result
@@ -3115,7 +3115,7 @@ COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SECURE_FILE_PRIV
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
-VARIABLE_COMMENT Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory
+VARIABLE_COMMENT Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory. Empty value means no limits except /proc
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
index 5add3ed05dc70..e6516a59b3a95 100644
--- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
+++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result
@@ -3565,7 +3565,7 @@ COMMAND_LINE_ARGUMENT OPTIONAL
VARIABLE_NAME SECURE_FILE_PRIV
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
-VARIABLE_COMMENT Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory
+VARIABLE_COMMENT Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files within specified directory. Empty value means no limits except /proc
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
diff --git a/mysql-test/suite/sys_vars/t/secure_file_priv-master.opt b/mysql-test/suite/sys_vars/t/secure_file_priv.opt
similarity index 100%
rename from mysql-test/suite/sys_vars/t/secure_file_priv-master.opt
rename to mysql-test/suite/sys_vars/t/secure_file_priv.opt
diff --git a/mysql-test/suite/sys_vars/t/secure_file_priv.test b/mysql-test/suite/sys_vars/t/secure_file_priv.test
index 395bdaed34379..a46afb313a37f 100644
--- a/mysql-test/suite/sys_vars/t/secure_file_priv.test
+++ b/mysql-test/suite/sys_vars/t/secure_file_priv.test
@@ -4,7 +4,6 @@
CREATE TABLE t1 (c1 VARCHAR(50));
INSERT INTO t1 VALUES ("one"),("two"),("three"),("four"),("five");
SHOW VARIABLES LIKE 'secure_file_priv';
---disable_query_log
# Atempt to create a file where we normally aren't allowed to create one.
#
@@ -17,37 +16,26 @@ SHOW VARIABLES LIKE 'secure_file_priv';
# If we run tests with --mem, it will be /dev/shm.
# If we run tests with --parallel, it will be mysql-test/var
# (because MYSQLTEST_VARDIR in this case is mysql-test/var/N).
---disable_cursor_protocol
-
---perl
-use File::Basename;
-my $protected_file= dirname($ENV{MYSQLTEST_VARDIR}).'/bug50373.txt';
-# Ensure bug50373.txt does not exist (e.g. leftover from previous
-# test runs).
-unlink $protected_file;
-open(FILE, ">", "$ENV{MYSQL_TMP_DIR}/bug50373.inc") or die;
-print FILE "--disable_ps2_protocol\n";
-print FILE "SELECT * FROM t1 INTO OUTFILE '".$protected_file."';\n";
-print FILE "--enable_ps2_protocol\n";
-print FILE "DELETE FROM t1;\n";
-print FILE "LOAD DATA INFILE '".$protected_file."' INTO TABLE t1;\n";
-print FILE "SELECT * FROM t1;\n";
-print FILE "SELECT load_file('",$protected_file,"') AS loaded_file;\n";
-close(FILE);
-EOF
-
---enable_prepare_warnings
---source $MYSQL_TMP_DIR/bug50373.inc
---disable_prepare_warnings
---remove_file $MYSQL_TMP_DIR/bug50373.inc
---enable_query_log
+--disable_cursor_protocol
+--disable_ps2_protocol
+evalp SELECT * INTO OUTFILE '$MYSQLTEST_VARDIR/../bug50373.txt' FROM t1;
+--enable_ps2_protocol
--enable_cursor_protocol
-
+DELETE FROM t1;
+evalp LOAD DATA INFILE '$MYSQLTEST_VARDIR/../bug50373.txt' INTO TABLE t1;
+SELECT * FROM t1;
+evalp SELECT load_file('$MYSQLTEST_VARDIR/../bug50373.txt') AS loaded_file;
DROP TABLE t1;
---perl
-use File::Basename;
-unlink dirname($ENV{MYSQLTEST_VARDIR}).'/bug50373.txt';
-EOF
+--remove_file $MYSQLTEST_VARDIR/../bug50373.txt
+
+--echo #
+--echo # MDEV-40589 default exclude list for secure-file-priv
+--echo #
+CREATE TABLE t1 (c1 VARCHAR(50));
+--error ER_OPTION_PREVENTS_STATEMENT
+LOAD DATA INFILE '/proc/cpuinfo' INTO TABLE t1;
+DROP TABLE t1;
+--echo # End of 10.6 tests
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f4f0ba33938dd..9f4a48c6d5af0 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -8860,45 +8860,39 @@ fn_format_relative_to_data_home(char * to, const char *name,
bool is_secure_file_path(char *path)
{
- char buff1[FN_REFLEN], buff2[FN_REFLEN];
- size_t opt_secure_file_priv_len;
- /*
- All paths are secure if opt_secure_file_path is 0
- */
- if (!opt_secure_file_priv)
- return TRUE;
+ char buf1[FN_REFLEN], buf2[FN_REFLEN];
+ const char *cmp;
- opt_secure_file_priv_len= strlen(opt_secure_file_priv);
+ if (opt_secure_file_priv)
+ cmp= opt_secure_file_priv;
+ else
+#ifdef _WIN32
+ return TRUE; // All paths are secure if opt_secure_file_priv is unset
+#else
+ cmp= "/proc/"; // Check that it doesn't start with this prefix
+#endif
if (strlen(path) >= FN_REFLEN)
return FALSE;
- if (my_realpath(buff1, path, 0))
- {
- /*
- The supplied file path might have been a file and not a directory.
- */
- size_t length= dirname_length(path); // Guaranteed to be < FN_REFLEN
- memcpy(buff2, path, length);
- buff2[length]= '\0';
- if (length == 0 || my_realpath(buff1, buff2, 0))
- return FALSE;
- }
- convert_dirname(buff2, buff1, NullS);
- if (!lower_case_file_system)
+ if (my_realpath(buf1, path, 0))
{
- if (strncmp(opt_secure_file_priv, buff2, opt_secure_file_priv_len))
+ /* The supplied file path might have been a file and not a directory. */
+ size_t length= dirname_length(path); // Guaranteed to be < FN_REFLEN
+ memcpy(buf2, path, length);
+ buf2[length]= '\0';
+ if (length == 0 || my_realpath(buf1, buf2, 0))
return FALSE;
}
+ convert_dirname(buf2, buf1, NullS);
+
+ size_t cmp_len= strlen(cmp);
+ bool matched;
+ if (lower_case_file_system)
+ matched= !files_charset_info->strnncoll(buf2, strlen(buf2), cmp, cmp_len, 1);
else
- {
- if (files_charset_info->strnncoll(buff2, strlen(buff2),
- opt_secure_file_priv,
- opt_secure_file_priv_len,
- TRUE))
- return FALSE;
- }
- return TRUE;
+ matched= !strncmp(cmp, buf2, cmp_len);
+ return opt_secure_file_priv ? matched : !matched;
}
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index eaa099e65ab06..08b826c8ea638 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -3357,11 +3357,15 @@ static Sys_var_mybool Sys_require_secure_transport(
ON_CHECK(check_require_secure_transport), ON_UPDATE(0));
static Sys_var_charptr_fscs Sys_secure_file_priv(
- "secure_file_priv",
- "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files "
- "within specified directory",
- PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv),
- CMD_LINE(REQUIRED_ARG), DEFAULT(0));
+ "secure_file_priv",
+ "Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to files "
+ "within specified directory."
+#ifndef _WIN32
+ " Empty value means no limits except /proc"
+#endif
+ ,
+ PREALLOCATED READ_ONLY GLOBAL_VAR(opt_secure_file_priv),
+ CMD_LINE(REQUIRED_ARG), DEFAULT(0));
static bool check_server_id(sys_var *self, THD *thd, set_var *var)
{
diff --git a/sql/table.cc b/sql/table.cc
index a14580c6fad1f..166842e8a1b1b 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -113,10 +113,8 @@ static std::atomic last_table_id;
/* Functions defined in this file */
-static bool fix_type_pointers(const char ***typelib_value_names,
- uint **typelib_value_lengths,
- TYPELIB *point_to_type, uint types,
- char *names, size_t names_length);
+static bool fix_type_pointers(const char ***, const char **, uint **,
+ TYPELIB *, uint, char *, size_t);
static field_index_t find_field(Field **fields, uchar *record, uint start,
uint length);
@@ -767,7 +765,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
uint i, j, n_length;
KEY_PART_INFO *key_part= NULL;
ulong *rec_per_key= NULL;
- KEY_PART_INFO *first_key_part= NULL;
+ KEY_PART_INFO *first_key_part= NULL, *key_part_end;
uint first_key_parts= 0;
if (!keys)
@@ -775,7 +773,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
if (!(keyinfo = (KEY*) alloc_root(&share->mem_root, len)))
return 1;
bzero((char*) keyinfo, len);
- key_part= reinterpret_cast (keyinfo);
+ key_part_end= key_part= reinterpret_cast (keyinfo);
}
/*
@@ -831,6 +829,7 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
sizeof(ulong) * *ext_key_parts)))
return 1;
first_key_part= key_part;
+ key_part_end= key_part + *ext_key_parts;
first_key_parts= first_keyinfo->user_defined_key_parts;
keyinfo->flags= first_keyinfo->flags;
keyinfo->key_length= first_keyinfo->key_length;
@@ -844,6 +843,8 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
keyinfo->rec_per_key= rec_per_key;
for (j=keyinfo->user_defined_key_parts ; j-- ; key_part++)
{
+ if (key_part >= key_part_end)
+ return 1;
if (strpos + (new_frm_ver >= 1 ? 9 : 7) >= frm_image_end)
return 1;
if (!(keyinfo->algorithm == HA_KEY_ALG_LONG_HASH))
@@ -901,6 +902,8 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
}
if (curr_key_part == curr_key_part_end)
{
+ if (key_part >= key_part_end)
+ return 1;
*key_part++= first_key_part[j];
*rec_per_key++= 0;
keyinfo->ext_key_parts++;
@@ -914,13 +917,17 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
share->ext_key_parts++;
share->ext_key_parts+= keyinfo->ext_key_parts;
}
+ if (key_part > key_part_end)
+ return 1;
+ size_t max_keyname_len= MY_MIN(len, (uint)(frm_image_end - strpos));
keynames->str= (char*) key_part;
- keynames->length= strnmov(keynames->str, (char *) strpos,
- frm_image_end - strpos) - keynames->str;
+ keynames->length= strnmov(keynames->str, (char *)strpos,
+ max_keyname_len) - keynames->str;
+ if (keynames->length >= max_keyname_len)
+ return 1; // meaning key name was not \0-terminated
+ keynames->length++; // include '\0', to make fix_type_pointers() happy.
strpos+= keynames->length;
- if (*strpos++) // key names are \0-terminated
- return 1;
- keynames->length++; // Include '\0', to make fix_type_pointers() happy.
+ len-= (uint)keynames->length;
//reading index comments
for (keyinfo= share->key_info, i=0; i < keys; i++, keyinfo++)
@@ -932,11 +939,13 @@ static bool create_key_infos(const uchar *strpos, const uchar *frm_image_end,
keyinfo->comment.length= uint2korr(strpos);
strpos+= 2;
- if (strpos + keyinfo->comment.length >= frm_image_end)
+ if (strpos + keyinfo->comment.length >= frm_image_end ||
+ keyinfo->comment.length > len)
return 1;
keyinfo->comment.str= strmake_root(&share->mem_root, (char*) strpos,
keyinfo->comment.length);
strpos+= keyinfo->comment.length;
+ len-= (uint)keyinfo->comment.length;
}
DBUG_ASSERT(MY_TEST(keyinfo->flags & HA_USES_COMMENT) ==
(keyinfo->comment.length > 0));
@@ -1055,7 +1064,8 @@ static void mysql57_calculate_null_position(TABLE_SHARE *share,
uchar **null_pos,
uint *null_bit_pos,
const uchar *strpos,
- const uchar *vcol_screen_pos)
+ const uchar *vcol_screen_pos,
+ const uchar *vcol_screen_end)
{
uint field_pack_length= 17;
@@ -1066,6 +1076,8 @@ static void mysql57_calculate_null_position(TABLE_SHARE *share,
if ((strpos[10] & MYSQL57_GENERATED_FIELD))
{
+ if (vcol_screen_pos + MYSQL57_GCOL_HEADER_SIZE >= vcol_screen_end)
+ return;
/* Skip virtual (not stored) generated field */
bool stored_in_db= vcol_screen_pos[3];
vcol_screen_pos+= (uint2korr(vcol_screen_pos + 1) +
@@ -1786,6 +1798,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
const uchar *forminfo;
const uchar *frm_image_end = frm_image + frm_length;
uchar *record, *null_flags, *null_pos, *UNINIT_VAR(mysql57_vcol_null_pos);
+ uchar *data_start, *data_end;
+ uchar *first_stored= 0, *first_virtual= 0, *next_stored= 0, *next_virtual= 0;
const uchar *disk_buff, *strpos;
ulong pos, record_offset;
ulong rec_buff_length;
@@ -1793,13 +1807,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
KEY *keyinfo;
KEY_PART_INFO *key_part= NULL;
Field **field_ptr, *reg_field;
- const char **interval_array;
+ const char **interval_array, **interval_array_end;
uint *typelib_value_lengths= NULL;
enum legacy_db_type legacy_db_type;
my_bitmap_map *bitmaps;
bool null_bits_are_used;
uint vcol_screen_length;
- uchar *vcol_screen_pos;
+ uchar *vcol_screen_pos, *vcol_screen_end;
LEX_CUSTRING options;
LEX_CSTRING se_name= empty_clex_str;
KEY first_keyinfo;
@@ -1809,7 +1823,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
bool vers_can_native= false, frm_created= 0;
Field_data_type_info_array field_data_type_info_array;
MEM_ROOT *old_root= thd->mem_root;
- Virtual_column_info **table_check_constraints;
+ Virtual_column_info **table_check_constr;
bool *interval_unescaped= NULL;
extra2_fields extra2;
bool extra_index_flags_present= FALSE;
@@ -1850,6 +1864,14 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* Length of the MariaDB extra2 segment in the form file. */
len = uint2korr(frm_image+4);
+ if (frm_length < FRM_HEADER_SIZE + len ||
+ !(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len)))
+ goto err;
+
+ forminfo= frm_image + pos;
+ if (forminfo + FRM_FORMINFO_SIZE >= frm_image_end)
+ goto err;
+
if (read_extra2(frm_image, len, &extra2))
goto err;
@@ -1869,17 +1891,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!share->default_part_plugin)
goto err;
}
-#endif
-
- if (frm_length < FRM_HEADER_SIZE + len ||
- !(pos= uint4korr(frm_image + FRM_HEADER_SIZE + len)))
- goto err;
- forminfo= frm_image + pos;
- if (forminfo + FRM_FORMINFO_SIZE >= frm_image_end)
- goto err;
-
-#ifdef WITH_PARTITION_STORAGE_ENGINE
if (frm_image[61] && !share->default_part_plugin)
{
enum legacy_db_type db_type= (enum legacy_db_type) (uint) frm_image[61];
@@ -1971,6 +1983,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->keys_in_use.init(keys);
ext_key_parts= key_parts;
+ if ((key_parts && !keys) || key_parts < keys)
+ goto err;
+
if (extra2.index_flags.str && extra2.index_flags.length != keys)
goto err;
@@ -2127,12 +2142,10 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{
//reading long table comment
if (next_chunk + 2 > buff_end)
- {
- DBUG_PRINT("error",
- ("long table comment is not defined in .frm"));
goto err;
- }
share->comment.length = uint2korr(next_chunk);
+ if (next_chunk + 2 + share->comment.length > buff_end)
+ goto err;
if (! (share->comment.str= strmake_root(&share->mem_root,
(char*)next_chunk + 2, share->comment.length)))
{
@@ -2141,17 +2154,18 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
next_chunk+= 2 + share->comment.length;
}
- DBUG_ASSERT(next_chunk <= buff_end);
-
if (share->db_create_options & HA_OPTION_TEXT_CREATE_OPTIONS_legacy)
{
if (options.str)
goto err;
+ if (next_chunk + 4 > buff_end)
+ goto err;
options.length= uint4korr(next_chunk);
options.str= next_chunk + 4;
next_chunk+= options.length + 4;
+ if (next_chunk > buff_end)
+ goto err;
}
- DBUG_ASSERT(next_chunk <= buff_end);
}
else
{
@@ -2163,7 +2177,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->key_block_size= uint2korr(frm_image+62);
keyinfo= share->key_info;
-
if (extra2.index_flags.str)
extra_index_flags_present= TRUE;
@@ -2208,6 +2221,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
disk_buff= frm_image + pos + FRM_FORMINFO_SIZE;
share->fields= uint2korr(forminfo+258);
+ if (share->fields > MAX_FIELDS)
+ goto err;
if (extra2.field_flags.str && extra2.field_flags.length != share->fields)
goto err;
pos= uint2korr(forminfo+260); /* Length of all screens */
@@ -2229,6 +2244,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->comment.length);
}
+ if (hash_fields > share->fields || share->null_fields > share->fields)
+ goto err;
+
DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d vcol_screen_length: %d", interval_count,interval_parts, keys,n_length,int_length, com_length, vcol_screen_length));
/*
@@ -2253,12 +2271,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
&share->field, (uint)(share->fields+1)*sizeof(Field*),
&share->intervals, (uint)interval_count*sizeof(TYPELIB),
&share->check_constraints, (uint) share->table_check_constraints * sizeof(Virtual_column_info*),
- /*
- This looks wrong: shouldn't it be (+2+interval_count)
- instread of (+3) ?
- */
- &interval_array, (uint) (share->fields+interval_parts+ keys+3)*sizeof(char *),
- &typelib_value_lengths, total_typelib_value_count * sizeof(uint *),
+ &interval_array, (uint)total_typelib_value_count * sizeof(char *),
+ &typelib_value_lengths, (uint)total_typelib_value_count * sizeof(uint),
&names, (uint) (n_length+int_length),
&comment_pos, (uint) com_length,
&vcol_screen_pos, vcol_screen_length,
@@ -2274,10 +2288,13 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
field_ptr= share->field;
- table_check_constraints= share->check_constraints;
+ interval_array_end= interval_array + total_typelib_value_count;
+ table_check_constr= share->check_constraints;
read_length=(uint) (share->fields * field_pack_length +
pos+ (uint) (n_length+int_length+com_length+
vcol_screen_length));
+ if (disk_buff + read_length > frm_image_end)
+ goto err;
strpos= disk_buff+pos;
if (!interval_count)
@@ -2291,21 +2308,24 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
com_length);
memcpy(vcol_screen_pos, disk_buff+read_length-vcol_screen_length,
vcol_screen_length);
+ vcol_screen_end= vcol_screen_pos + vcol_screen_length;
- if (fix_type_pointers(&interval_array, &typelib_value_lengths,
- &share->fieldnames, 1, names, n_length) ||
+ if (fix_type_pointers(&interval_array, interval_array_end,
+ &typelib_value_lengths, &share->fieldnames, 1, names,
+ n_length) ||
share->fieldnames.count != share->fields)
goto err;
- if (fix_type_pointers(&interval_array, &typelib_value_lengths,
- share->intervals, interval_count,
- names + n_length, int_length))
+ if (fix_type_pointers(&interval_array, interval_array_end,
+ &typelib_value_lengths, share->intervals,
+ interval_count, names + n_length, int_length))
goto err;
- if (keynames.length &&
- (fix_type_pointers(&interval_array, &typelib_value_lengths,
- &share->keynames, 1, keynames.str, keynames.length) ||
- share->keynames.count != keys))
+ if ((keynames.length &&
+ fix_type_pointers(&interval_array, interval_array_end,
+ &typelib_value_lengths, &share->keynames, 1,
+ keynames.str, keynames.length)) ||
+ share->keynames.count != keys)
goto err;
/* Allocate handler */
@@ -2329,14 +2349,12 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
*/
share->null_bytes= (share->null_fields + null_bit_pos + 7) / 8;
}
-#ifndef WE_WANT_TO_SUPPORT_VERY_OLD_FRM_FILES
else
{
share->null_bytes= (share->null_fields+7)/8;
null_flags= null_pos= record + 1 + share->reclength - share->null_bytes;
null_bit_pos= 0;
}
-#endif
use_hash= share->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
@@ -2357,7 +2375,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
mysql57_vcol_null_bit_pos= null_bit_pos;
mysql57_calculate_null_position(share, &mysql57_vcol_null_pos,
&mysql57_vcol_null_bit_pos,
- strpos, vcol_screen_pos);
+ strpos, vcol_screen_pos, vcol_screen_end);
}
/* Set system versioning information. */
@@ -2406,20 +2424,22 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (extra2.without_overlaps.str)
{
- if (extra2.application_period.str == NULL)
+ if (extra2.application_period.str == NULL ||
+ extra2.without_overlaps.length < frm_keyno_size)
goto err;
const uchar *key_pos= extra2.without_overlaps.str;
period.unique_keys= read_frm_keyno(key_pos);
+ if (period.unique_keys > keys ||
+ extra2.without_overlaps.length != (period.unique_keys+1)*frm_keyno_size)
+ goto err;
for (uint k= 0; k < period.unique_keys; k++)
{
key_pos+= frm_keyno_size;
uint key_nr= read_frm_keyno(key_pos);
+ if (key_nr >= keys)
+ goto err;
key_info[key_nr].without_overlaps= true;
}
-
- if ((period.unique_keys + 1) * frm_keyno_size
- != extra2.without_overlaps.length)
- goto err;
}
if (extra2.field_data_type_info.length &&
@@ -2453,6 +2473,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
comment.str= (char*) comment_pos;
comment.length= comment_length;
comment_pos+= comment_length;
+ if (com_length < comment_length)
+ goto err;
+ com_length-= comment_length;
}
if (strpos[13] == MYSQL_TYPE_VIRTUAL &&
@@ -2465,7 +2488,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
*/
uint vcol_info_length= (uint) strpos[12];
- if (!vcol_info_length) // Expect non-null expression
+ if (vcol_info_length < 4 ||
+ vcol_screen_pos + vcol_info_length > vcol_screen_end)
goto err;
attr.frm_unpack_basic(strpos);
@@ -2567,15 +2591,17 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
byte 4 = stored_in_db
byte 5.. = expr
*/
- if ((uint)(vcol_screen_pos)[0] != 1)
+ if (vcol_screen_pos + MYSQL57_GCOL_HEADER_SIZE > vcol_screen_end ||
+ vcol_screen_pos[0] != 1)
goto err;
vcol_info= new (&share->mem_root) Virtual_column_info();
uint vcol_info_length= uint2korr(vcol_screen_pos + 1);
- if (!vcol_info_length) // Expect non-empty expression
- goto err;
vcol_info->stored_in_db= vcol_screen_pos[3];
vcol_info->utf8= 0;
vcol_screen_pos+= vcol_info_length + MYSQL57_GCOL_HEADER_SIZE;;
+ if (!vcol_info_length || // Expect non-empty expression
+ vcol_screen_pos > vcol_screen_end)
+ goto err;
share->virtual_fields++;
}
}
@@ -2632,6 +2658,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
attr.pack_flag&= ~FIELDFLAG_LONG_DECIMAL;
}
+ if (interval_nr > interval_count)
+ goto err;
+
if (interval_nr && attr.charset->mbminlen > 1 &&
!interval_unescaped[interval_nr - 1])
{
@@ -2727,6 +2756,52 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (!reg_field) // Not supported field type
goto err;
+ /*
+ Verify that fields follow one another in the record without overlaps.
+ That is the next field starts where the previous field ended.
+ Virtual fields complicate the check. Stored fields follow each other in
+ the record order, virtual fields also follow each in the record order
+ but they're always at the end of the record, and can be interleaved
+ with normal fields in the table.
+
+ We detect this dynamically - as long as the next field starts where the
+ previous ended, assume they're normal fields. When the next field starts
+ with a gap - it's the first virtual (and the future virtual fields must
+ follow that field). If the next field starts before the previous - it
+ means the table started from virtual fields and this is the first stored
+ field. Either ("gap" or "before") can happen only once.
+ */
+ if (!next_stored) // first field, i == 0
+ {
+ first_stored= reg_field->ptr;
+ next_stored= first_stored + reg_field->pack_length_in_rec();
+ }
+ else if (reg_field->ptr == next_stored) // next stored field
+ next_stored+= reg_field->pack_length_in_rec();
+ else if (reg_field->ptr > next_stored) // virtual
+ {
+ if (next_virtual)
+ {
+ if (reg_field->ptr != next_virtual)
+ goto err;
+ next_virtual+= reg_field->pack_length_in_rec();
+ }
+ else
+ {
+ first_virtual= reg_field->ptr;
+ next_virtual= first_virtual + reg_field->pack_length_in_rec();
+ }
+ }
+ else // reg_field < next_stored. can happen if the i=0 field was virtual
+ {
+ if (next_virtual)
+ goto err;
+ first_virtual= first_stored;
+ next_virtual= next_stored;
+ first_stored= reg_field->ptr;
+ next_stored= first_stored + reg_field->pack_length_in_rec();
+ }
+
if (attr.unireg_check == Field::TIMESTAMP_DNUN_FIELD ||
attr.unireg_check == Field::TIMESTAMP_DN_FIELD)
{
@@ -2810,7 +2885,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* We want to store the value for the last bits */
swap_variables(uchar*, null_pos, mysql57_vcol_null_pos);
swap_variables(uint, null_bit_pos, mysql57_vcol_null_bit_pos);
- DBUG_ASSERT((null_pos + (null_bit_pos + 7) / 8) <= share->field[0]->ptr);
+ if ((null_pos + (null_bit_pos + 7) / 8) > share->field[0]->ptr)
+ goto err;
}
/* Fix key->name and key_part->field */
@@ -2838,7 +2914,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
hash_keypart->fieldnr= hash_field_used_no + 1;
hash_field= share->field[hash_field_used_no];
hash_field->flags|= LONG_UNIQUE_HASH_FIELD;//Used in parse_vcol_defs
- DBUG_ASSERT(hash_field->invisible == INVISIBLE_FULL);
+ if (hash_field->invisible != INVISIBLE_FULL ||
+ hash_field->pack_length() != HA_HASH_FIELD_LENGTH)
+ goto err;
keyinfo->flags|= HA_NOSAME;
share->virtual_fields++;
share->stored_fields--;
@@ -2867,7 +2945,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
key_part= keyinfo->key_part;
for (i=0 ; i < keyinfo->user_defined_key_parts ;i++)
{
- DBUG_ASSERT(key_part[i].fieldnr > 0);
+ if (key_part[i].fieldnr <= 0 || key_part[i].fieldnr > share->fields)
+ goto err;
// Table field corresponding to the i'th key part.
Field *table_field= share->field[key_part[i].fieldnr - 1];
@@ -2935,6 +3014,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
for (i= 0; i < first_keyinfo.user_defined_key_parts; i++)
{
uint fieldnr= keyinfo[0].key_part[i].fieldnr;
+ if (fieldnr <= 0 || fieldnr > share->fields)
+ goto err;
if (share->field[fieldnr-1]->key_length() !=
keyinfo[0].key_part[i].length)
{
@@ -2982,6 +3063,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
{
uint length_bytes= 0;
uint fieldnr= keyinfo->key_part[i].fieldnr;
+ if (fieldnr <= 0 || fieldnr > share->fields)
+ goto err;
field= share->field[fieldnr-1];
if (field->null_ptr)
@@ -3059,7 +3142,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->default_values,
(uint) key_part->offset,
(uint) key_part->length);
- if (!key_part->fieldnr)
+ if (key_part->fieldnr <= 0 || key_part->fieldnr > share->fields)
goto err;
field= key_part->field= share->field[key_part->fieldnr-1];
@@ -3211,7 +3294,7 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
}
else
share->primary_key= MAX_KEY;
- if (new_field_pack_flag <= 1)
+ if (new_field_pack_flag <= 1 && share->null_fields)
{
/* Old file format with default as not null */
uint null_length= (share->null_fields+7)/8;
@@ -3224,8 +3307,6 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
/* Handle virtual expressions */
if (vcol_screen_length && share->frm_version >= FRM_VER_EXPRESSSIONS)
{
- uchar *vcol_screen_end= vcol_screen_pos + vcol_screen_length;
-
/* Skip header */
vcol_screen_pos+= FRM_VCOL_NEW_BASE_SIZE;
share->vcol_defs.str+= FRM_VCOL_NEW_BASE_SIZE;
@@ -3238,6 +3319,9 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
while (vcol_screen_pos < vcol_screen_end)
{
Virtual_column_info *vcol_info;
+ if (vcol_screen_end - vcol_screen_pos < FRM_VCOL_NEW_HEADER_SIZE)
+ goto err;
+
uint type= (uint) vcol_screen_pos[0];
uint field_nr= uint2korr(vcol_screen_pos+1);
uint expr_length= uint2korr(vcol_screen_pos+3);
@@ -3250,17 +3334,21 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (field_nr != UINT_MAX16)
{
- DBUG_ASSERT(field_nr < share->fields);
+ if (field_nr >= share->fields)
+ goto err;
reg_field= share->field[field_nr];
}
else
{
reg_field= 0;
- DBUG_ASSERT(name_length);
+ if (!name_length || type != VCOL_CHECK_TABLE)
+ goto err;
}
vcol_screen_pos+= FRM_VCOL_NEW_HEADER_SIZE;
vcol_info->set_vcol_type((enum_vcol_info_type) type);
+ if ((uint)(vcol_screen_end-vcol_screen_pos) < name_length+expr_length)
+ goto err;
if (name_length)
{
vcol_info->name.str= strmake_root(&share->mem_root,
@@ -3274,7 +3362,8 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
switch (type) {
case VCOL_GENERATED_VIRTUAL:
{
- uint recpos;
+ if (reg_field->vcol_info)
+ goto err;
reg_field->vcol_info= vcol_info;
share->virtual_fields++;
share->stored_fields--;
@@ -3283,37 +3372,43 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
if (reg_field->flags & PART_KEY_FLAG)
vcol_info->set_vcol_type(VCOL_GENERATED_VIRTUAL_INDEXED);
/* Correct stored_rec_length as non stored fields are last */
- recpos= (uint) (reg_field->ptr - record);
+ uint recpos= (uint) (reg_field->ptr - record);
if (share->stored_rec_length >= recpos)
share->stored_rec_length= recpos-1;
break;
}
case VCOL_GENERATED_STORED:
vcol_info->stored_in_db= 1;
- DBUG_ASSERT(!reg_field->vcol_info);
+ if (reg_field->vcol_info)
+ goto err;
reg_field->vcol_info= vcol_info;
share->virtual_fields++;
break;
case VCOL_DEFAULT:
vcol_info->stored_in_db= 1;
- DBUG_ASSERT(!reg_field->default_value);
+ if (reg_field->default_value)
+ goto err;
reg_field->default_value= vcol_info;
share->default_expressions++;
break;
case VCOL_CHECK_FIELD:
- DBUG_ASSERT(!reg_field->check_constraint);
+ if (reg_field->check_constraint)
+ goto err;
reg_field->check_constraint= vcol_info;
share->field_check_constraints++;
break;
case VCOL_CHECK_TABLE:
- *(table_check_constraints++)= vcol_info;
+ if ((uint)(table_check_constr - share->check_constraints) >=
+ share->table_check_constraints)
+ goto err;
+ *(table_check_constr++)= vcol_info;
break;
}
}
}
- DBUG_ASSERT((uint) (table_check_constraints - share->check_constraints) ==
- (uint) (share->table_check_constraints -
- share->field_check_constraints));
+ if (table_check_constr - share->check_constraints !=
+ (int)share->table_check_constraints - (int)share->field_check_constraints)
+ goto err;
if (options.str)
{
@@ -3366,6 +3461,19 @@ int TABLE_SHARE::init_from_binary_frm_image(THD *thd, bool write,
share->can_cmp_whole_record= (share->blob_fields == 0 &&
share->varchar_fields == 0);
+ data_start= share->default_values;
+ data_end= data_start + share->reclength;
+ if (share->null_field_first)
+ data_start+= share->null_bytes;
+ else
+ data_end-= share->null_bytes;
+
+ if (data_end < data_start ||
+ (first_virtual && first_virtual != next_stored) ||
+ first_stored < data_start ||
+ (next_virtual ? next_virtual : next_stored) > data_end)
+ goto err;
+
share->column_bitmap_size= bitmap_buffer_size(share->fields);
bitmap_count= 1;
@@ -4817,19 +4925,20 @@ void open_table_error(TABLE_SHARE *share, enum open_frm_error error,
} /* open_table_error */
- /*
- ** fix a str_type to a array type
- ** typeparts separated with some char. differents types are separated
- ** with a '\0'
- */
+/*
+ fix a str_type to a array type
+ typeparts separated with some char. differents types are separated
+ with a '\0'
+*/
static bool
-fix_type_pointers(const char ***typelib_value_names,
+fix_type_pointers(const char ***typelib_value_names, const char **names_end,
uint **typelib_value_lengths,
TYPELIB *point_to_type, uint types,
char *ptr, size_t length)
{
const char *end= ptr + length;
+ names_end--; // simplify the check below, reserve place for 0 at the end
while (types--)
{
@@ -4861,7 +4970,7 @@ fix_type_pointers(const char ***typelib_value_names,
{
// Now scan the next value+sep pair
char *vend= (char*) memchr(ptr, sep, end - ptr);
- if (!vend)
+ if (!vend || *typelib_value_names >= names_end)
return true; // Bad format
*((*typelib_value_names)++)= ptr;
*((*typelib_value_lengths)++)= (uint) (vend - ptr);
diff --git a/storage/connect/mysql-test/connect/r/drop-open-error.result b/storage/connect/mysql-test/connect/r/drop-open-error.result
index f9b9b7e87d29f..8f5341bbcceb0 100644
--- a/storage/connect/mysql-test/connect/r/drop-open-error.result
+++ b/storage/connect/mysql-test/connect/r/drop-open-error.result
@@ -5,11 +5,3 @@ drop table mdev9949;
Warnings:
Warning 1017 Can't find file: 'DATADIR/test/mdev9949.dos' (errno: 2 "No such file or directory")
drop table t1;
-select @@secure_file_priv 'must be NULL';
-must be NULL
-NULL
-create table t1 (a char(16)) engine=myisam;
-insert into t1 values('Hello World!');
-create table t2 engine=connect file_name='foo/bar.txt' as select * from t1;
-ERROR HY000: Got error 174 'Open(a+b) error 2 on foo/bar.txt: No such file or directory' from CONNECT
-drop table t1;
diff --git a/storage/connect/mysql-test/connect/t/drop-open-error.opt b/storage/connect/mysql-test/connect/t/drop-open-error.opt
deleted file mode 100644
index 22520f0aa9901..0000000000000
--- a/storage/connect/mysql-test/connect/t/drop-open-error.opt
+++ /dev/null
@@ -1 +0,0 @@
---secure-file-priv=""
diff --git a/storage/connect/mysql-test/connect/t/drop-open-error.test b/storage/connect/mysql-test/connect/t/drop-open-error.test
index dd286c9646606..97d938e431087 100644
--- a/storage/connect/mysql-test/connect/t/drop-open-error.test
+++ b/storage/connect/mysql-test/connect/t/drop-open-error.test
@@ -18,14 +18,3 @@ copy_file $MTR_SUITE_DIR/std_data/mdev9949.frm $datadir/test/mdev9949.frm;
--replace_result $MARIADB_DATADIR DATADIR/ './' 'DATADIR/'
drop table mdev9949;
drop table t1;
-
-#
-# MDEV-7935 CREATE TABLE ... AS SELECT ... can cause a Server crash (Assertion `0' in Protocol::end_statement)
-#
-select @@secure_file_priv 'must be NULL'; # otherwise foo/bar.txt won't be allowed
-create table t1 (a char(16)) engine=myisam;
-insert into t1 values('Hello World!');
-replace_regex @on .*/foo/@on foo/@;
-error ER_GET_ERRMSG;
-create table t2 engine=connect file_name='foo/bar.txt' as select * from t1;
-drop table t1;