Commit 9952f1aa authored by Sergey Vojtovich's avatar Sergey Vojtovich

BUG#51877 - HANDLER interface causes invalid memory read

Invalid memory read if HANDLER ... READ NEXT is executed
after failed (e.g. empty table) HANDLER ... READ FIRST.

The problem was that we attempted to perform READ NEXT,
whereas there is no pivot available from failed READ FIRST.

With this fix READ NEXT after failed READ FIRST equals
to READ FIRST.

This bug affects MyISAM tables only.

mysql-test/r/gis-rtree.result:
  Restore a test case for BUG51357.
mysql-test/r/handler_myisam.result:
  A test case for BUG#51877.
mysql-test/t/gis-rtree.test:
  Restore a test case for BUG51357.
mysql-test/t/handler_myisam.test:
  A test case for BUG#51877.
storage/myisam/mi_rnext.c:
  "search first" failed. This means we have no pivot for
  "search next", or in other words MI_INFO::lastkey is
  likely uninitialized.
  
  Normally SQL layer would never request "search next" if
  "search first" failed. But HANDLER may do anything.
  
  As mi_rnext() without preceeding mi_rkey()/mi_rfirst()
  equals to mi_rfirst(), we must restore original state
  as if failing mi_rfirst() was not called.
parent 90e14a66
...@@ -1540,5 +1540,12 @@ a ...@@ -1540,5 +1540,12 @@ a
HANDLER t1 READ a LAST; HANDLER t1 READ a LAST;
a a
HANDLER t1 CLOSE; HANDLER t1 CLOSE;
HANDLER t1 OPEN;
HANDLER t1 READ a FIRST;
a
INSERT INTO t1 VALUES (GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
# should not crash
HANDLER t1 READ a NEXT;
HANDLER t1 CLOSE;
DROP TABLE t1; DROP TABLE t1;
End of 5.0 tests. End of 5.0 tests.
...@@ -756,4 +756,17 @@ TRUNCATE t1; ...@@ -756,4 +756,17 @@ TRUNCATE t1;
HANDLER t1 READ FIRST; HANDLER t1 READ FIRST;
ERROR 42S02: Unknown table 't1' in HANDLER ERROR 42S02: Unknown table 't1' in HANDLER
DROP TABLE t1; DROP TABLE t1;
#
# BUG#51877 - HANDLER interface causes invalid memory read
#
CREATE TABLE t1(a INT, KEY(a));
HANDLER t1 OPEN;
HANDLER t1 READ a FIRST;
a
INSERT INTO t1 VALUES(1);
HANDLER t1 READ a NEXT;
a
1
HANDLER t1 CLOSE;
DROP TABLE t1;
End of 5.1 tests End of 5.1 tests
...@@ -914,14 +914,15 @@ HANDLER t1 READ a PREV; ...@@ -914,14 +914,15 @@ HANDLER t1 READ a PREV;
HANDLER t1 READ a LAST; HANDLER t1 READ a LAST;
HANDLER t1 CLOSE; HANDLER t1 CLOSE;
#TODO: re-enable this test please when bug #51877 is solved
# second crash fixed when the tree has changed since the last search. # second crash fixed when the tree has changed since the last search.
#HANDLER t1 OPEN; HANDLER t1 OPEN;
#HANDLER t1 READ a FIRST; HANDLER t1 READ a FIRST;
#INSERT INTO t1 VALUES (GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))')); INSERT INTO t1 VALUES (GeomFromText('Polygon((40 40,60 40,60 60,40 60,40 40))'));
#HANDLER t1 READ a NEXT; --echo # should not crash
#HANDLER t1 CLOSE; --disable_result_log
#TODO: end of the 51877 dependent section HANDLER t1 READ a NEXT;
--enable_result_log
HANDLER t1 CLOSE;
DROP TABLE t1; DROP TABLE t1;
......
...@@ -37,4 +37,15 @@ TRUNCATE t1; ...@@ -37,4 +37,15 @@ TRUNCATE t1;
HANDLER t1 READ FIRST; HANDLER t1 READ FIRST;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # BUG#51877 - HANDLER interface causes invalid memory read
--echo #
CREATE TABLE t1(a INT, KEY(a));
HANDLER t1 OPEN;
HANDLER t1 READ a FIRST;
INSERT INTO t1 VALUES(1);
HANDLER t1 READ a NEXT;
HANDLER t1 CLOSE;
DROP TABLE t1;
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -28,6 +28,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx) ...@@ -28,6 +28,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
{ {
int error,changed; int error,changed;
uint flag; uint flag;
uint update_mask= HA_STATE_NEXT_FOUND;
DBUG_ENTER("mi_rnext"); DBUG_ENTER("mi_rnext");
if ((inx = _mi_check_index(info,inx)) < 0) if ((inx = _mi_check_index(info,inx)) < 0)
...@@ -55,6 +56,20 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx) ...@@ -55,6 +56,20 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
info->s->state.key_root[inx]); info->s->state.key_root[inx]);
break; break;
} }
/*
"search first" failed. This means we have no pivot for
"search next", or in other words MI_INFO::lastkey is
likely uninitialized.
Normally SQL layer would never request "search next" if
"search first" failed. But HANDLER may do anything.
As mi_rnext() without preceeding mi_rkey()/mi_rfirst()
equals to mi_rfirst(), we must restore original state
as if failing mi_rfirst() was not called.
*/
if (error)
update_mask|= HA_STATE_PREV_FOUND;
} }
else else
{ {
...@@ -100,7 +115,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx) ...@@ -100,7 +115,7 @@ int mi_rnext(MI_INFO *info, uchar *buf, int inx)
} }
/* Don't clear if database-changed */ /* Don't clear if database-changed */
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
info->update|= HA_STATE_NEXT_FOUND; info->update|= update_mask;
if (error) if (error)
{ {
......
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