Commit 7030bc95 authored by unknown's avatar unknown

Bug#21476: (Thread stack overrun not caught, causing SEGV)

The STACK_MIN_SIZE is currently set to 8192, when we actually need 
(emperically discovered) 9236 bytes to raise an fatal error, on Ubuntu 
Dapper Drake, libc6 2.3.6-0ubuntu2, Linux kernel 2.6.15-27-686, on x86.

I'm taking that as a new lower bound, plus 100B of wiggle-room for sundry
word sizes and stack behaviors.

The added test verifies in a cross-platform way that there are no gaps 
between the space that we think we need and what we actually need to report 
an error.

DOCUMENTERS:  This also adds "let" to the mysqltest commands that evaluate
an argument to expand variables therein.  (Only right of the "=", of course.)


client/mysqltest.c:
  Add "let" to the list of mysqltest commands that evaluates its arguments (only
  the right-hand-side of the equals-sign expression).
mysql-test/r/mysqltest.result:
  Added test to show that mysqltest "let" will evaluate the RHS correctly (and 
  expand the backslash test).
mysql-test/t/mysqltest.test:
  Added test to show that mysqltest "let" will evaluate the RHS correctly (and 
  expand the backslash test).
sql/mysql_priv.h:
  Increase the amount we require to be available for the stack, since 
  experience told us that the previous amount was too little by at least
  1044 bytes.
mysql-test/r/execution_constants.result:
  New BitKeeper file ``mysql-test/r/execution_constants.result''
mysql-test/t/execution_constants.test:
  New BitKeeper file ``mysql-test/t/execution_constants.test''
parent 0d9242ce
...@@ -3,3 +3,5 @@ ...@@ -3,3 +3,5 @@
44edb86b1iE5knJ97MbliK_3lCiAXA 44edb86b1iE5knJ97MbliK_3lCiAXA
44f33f3aj5KW5qweQeekY1LU0E9ZCg 44f33f3aj5KW5qweQeekY1LU0E9ZCg
4513d8e4Af4dQWuk13sArwofRgFDQw 4513d8e4Af4dQWuk13sArwofRgFDQw
4519a6c5BVUxEHTf5iJnjZkixMBs8g
451ab499rgdjXyOnUDqHu-wBDoS-OQ
...@@ -1609,7 +1609,10 @@ int do_save_master_pos() ...@@ -1609,7 +1609,10 @@ int do_save_master_pos()
int do_let(struct st_query *query) int do_let(struct st_query *query)
{ {
char *p= query->first_argument; char *p= query->first_argument;
char *var_name, *var_name_end, *var_val_start; char *var_name, *var_name_end;
DYNAMIC_STRING let_rhs_expr;
init_dynamic_string(&let_rhs_expr, "", 512, 2048);
/* Find <var_name> */ /* Find <var_name> */
if (!*p) if (!*p)
...@@ -1628,10 +1631,13 @@ int do_let(struct st_query *query) ...@@ -1628,10 +1631,13 @@ int do_let(struct st_query *query)
/* Find start of <var_val> */ /* Find start of <var_val> */
while (*p && my_isspace(charset_info,*p)) while (*p && my_isspace(charset_info,*p))
p++; p++;
var_val_start= p;
do_eval(&let_rhs_expr, p, FALSE);
query->last_argument= query->end; query->last_argument= query->end;
/* Assign var_val to var_name */ /* Assign var_val to var_name */
return var_set(var_name, var_name_end, var_val_start, query->end); return var_set(var_name, var_name_end, let_rhs_expr.str,
(let_rhs_expr.str + let_rhs_expr.length));
} }
......
CREATE TABLE `t_bug21476` (
`ID_BOARD` smallint(5) unsigned NOT NULL default '0',
`ID_MEMBER` mediumint(8) unsigned NOT NULL default '0',
`logTime` int(10) unsigned NOT NULL default '0',
`ID_MSG` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`ID_MEMBER`,`ID_BOARD`),
KEY `logTime` (`logTime`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 COLLATE=cp1251_bulgarian_ci;
INSERT INTO `t_bug21476` VALUES (2,2,1154870939,0),(1,2,1154870957,0),(2,183,1154941362,0),(2,84,1154904301,0),(1,84,1154905867,0),(2,13,1154947484,10271),(3,84,1154880549,0),(1,6,1154892183,0),(2,25,1154947581,10271),(3,25,1154904760,0),(1,25,1154947373,10271),(1,179,1154899992,0),(2,179,1154899410,0),(5,25,1154901666,0),(2,329,1154902026,0),(3,329,1154902040,0),(1,329,1154902058,0),(1,13,1154930841,0),(3,85,1154904987,0),(1,183,1154929665,0),(3,13,1154931268,0),(1,85,1154936888,0),(1,169,1154937959,0),(2,169,1154941717,0),(3,183,1154939810,0),(3,169,1154941734,0);
Assertion: mysql_errno 1436 == 1436
DROP TABLE `t_bug21476`;
End of 5.0 tests.
...@@ -217,8 +217,11 @@ hej ...@@ -217,8 +217,11 @@ hej
a long variable content a long variable content
a long variable content a long variable content
a long $where variable content a long a long variable content variable content
a long \$where variable content
banana = banana
Not a banana: ba\$cat\$cat
mysqltest: At line 1: Missing arguments to let mysqltest: At line 1: Missing arguments to let
mysqltest: At line 1: Missing variable name in let mysqltest: At line 1: Missing variable name in let
mysqltest: At line 1: Variable name in hi=hi does not start with '$' mysqltest: At line 1: Variable name in hi=hi does not start with '$'
......
#
# Bug#21476: Lost Database Connection During Query
#
# When the amount of stack space we think we need to report an error is
# actually too small, then we can get SEGVs. But, we don't want to reserve
# space that we could use to get real work done. So, we want the reserved
# space small, and this test verifies that the reservation is not too small.
CREATE TABLE `t_bug21476` (
`ID_BOARD` smallint(5) unsigned NOT NULL default '0',
`ID_MEMBER` mediumint(8) unsigned NOT NULL default '0',
`logTime` int(10) unsigned NOT NULL default '0',
`ID_MSG` mediumint(8) unsigned NOT NULL default '0',
PRIMARY KEY (`ID_MEMBER`,`ID_BOARD`),
KEY `logTime` (`logTime`)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251 COLLATE=cp1251_bulgarian_ci;
INSERT INTO `t_bug21476` VALUES (2,2,1154870939,0),(1,2,1154870957,0),(2,183,1154941362,0),(2,84,1154904301,0),(1,84,1154905867,0),(2,13,1154947484,10271),(3,84,1154880549,0),(1,6,1154892183,0),(2,25,1154947581,10271),(3,25,1154904760,0),(1,25,1154947373,10271),(1,179,1154899992,0),(2,179,1154899410,0),(5,25,1154901666,0),(2,329,1154902026,0),(3,329,1154902040,0),(1,329,1154902058,0),(1,13,1154930841,0),(3,85,1154904987,0),(1,183,1154929665,0),(3,13,1154931268,0),(1,85,1154936888,0),(1,169,1154937959,0),(2,169,1154941717,0),(3,183,1154939810,0),(3,169,1154941734,0);
delimiter //;
let $query_head=UPDATE t_bug21476 SET ID_MSG = IF(logTime BETWEEN 1 AND 1101770053, 2, //
let $query_tail =) WHERE logTime BETWEEN 1 AND 1104091539 AND ID_MSG = 0//
# Scan over the possible stack heights, trying to recurse to exactly that
# depth. Eventually, we will reach our imposed limit on height and try to
# raise an error. If the remaining stack space is enough to raise that error,
# we will get an error-number of 1436 and quit the loop. If it's not enough
# space, we should get a SEGV
# Well more than enough recursions to find the end of our stack.
let $i = 100000//
disable_query_log//
disable_result_log//
while ($i)
{
# If we SEGV because the min stack size is exceeded, this would return error
# 2013 .
error 0,1436 //
eval $query_head 0 $query_tail//
if ($mysql_errno != 1436)
{
# We reached the place where we reported an error about the stack limit,
# and we successfully returned the error. That means that at the stack
# limit, we still have enough space reserved to report an error.
let $i = 1//
}
# Multiplying by three stack frames should be fine enough resolution.
# Trading exactness for speed.
# go one more level deep
let $query_head = $query_head IF(logTime <= 1104091$i, $i, //
let $query_tail =) $query_tail//
# go one more level deep
let $query_head = $query_head IF(logTime <= 1105091$i, $i, //
let $query_tail =) $query_tail//
# go one more level deep
let $query_head = $query_head IF(logTime <= 1106091$i, $i, //
let $query_tail =) $query_tail//
dec $i//
}
enable_result_log//
enable_query_log//
echo Assertion: mysql_errno 1436 == $mysql_errno//
delimiter ;//
DROP TABLE `t_bug21476`;
--echo End of 5.0 tests.
...@@ -507,9 +507,21 @@ echo $where2; ...@@ -507,9 +507,21 @@ echo $where2;
let $where3=a long $where variable content; let $where3=a long $where variable content;
echo $where3; echo $where3;
let $where3=a long \\\$where variable content;
echo $where3;
let $novar1= $novar2; let $novar1= $novar2;
echo $novar1; echo $novar1;
let $cat=na;
let $cat=ba$cat$cat;
echo banana = $cat;
# ba\$cat\$cat should have been sufficient.
# ba\\\$cat\\\$cat -> ba\$cat\$cat -> ba$cat$cat -> banana
# Magnus' upcoming patch will fix the missing second interpretation.
let $cat=ba\\\$cat\\\$cat;
echo Not a banana: $cat;
# Test illegal uses of let # Test illegal uses of let
......
...@@ -131,7 +131,18 @@ MY_LOCALE *my_locale_by_name(const char *name); ...@@ -131,7 +131,18 @@ MY_LOCALE *my_locale_by_name(const char *name);
#define MAX_ACCEPT_RETRY 10 // Test accept this many times #define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32 #define MAX_FIELDS_BEFORE_HASH 32
#define USER_VARS_HASH_SIZE 16 #define USER_VARS_HASH_SIZE 16
#define STACK_MIN_SIZE 8192 // Abort if less stack during eval.
/*
Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper
Drake, libc6 2.3.6-0ubuntu2, Linux kernel 2.6.15-27-686, on x86. (Added
100 bytes as reasonable buffer against growth and other environments'
requirements.)
Feel free to raise this by the smallest amount you can to get the
"execution_constants" test to pass.
*/
#define STACK_MIN_SIZE 9336 // Abort if less stack during eval.
#define STACK_MIN_SIZE_FOR_OPEN 1024*80 #define STACK_MIN_SIZE_FOR_OPEN 1024*80
#define STACK_BUFF_ALLOC 256 // For stack overrun checks #define STACK_BUFF_ALLOC 256 // For stack overrun checks
#ifndef MYSQLD_NET_RETRY_COUNT #ifndef MYSQLD_NET_RETRY_COUNT
......
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