List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:August 21 2008 4:28pm
Subject:bzr commit into mysql-5.0 branch (kgeorge:2648) Bug#37943
View as plain text  
#At file:///home/kgeorge/mysql/bzr/old-B37943-5.0-bugteam/

 2648 Georgi Kodinov	2008-08-21
      Bug#37943: Reproducible mysqld crash/sigsegv in sel_trees_can_be_ored
      
      When analyzing the possible index use cases the server was re-using an internal
structure.
      This is wrong, as this internal structure gets updated during the analysis.
      Fixed by making a copy of the internal structure for every place it needs to be
used.
      Also stopped the generation of empty structures that unnecessary complicate the
analysis.
modified:
  mysql-test/r/index_merge.result
  mysql-test/t/index_merge.test
  sql/opt_range.cc

per-file messages:
  mysql-test/r/index_merge.result
    Bug#37943: test case
  mysql-test/t/index_merge.test
    Bug#37943: test case
  sql/opt_range.cc
    Bug#37943: 
     - Make copy constructors for SEL_TREE and sub-structures and use them when OR-ing
trees.
     - don't generate empty SEL_TREEs. Return NULL instead.
=== modified file 'mysql-test/r/index_merge.result'
--- a/mysql-test/r/index_merge.result	2007-11-30 05:32:04 +0000
+++ b/mysql-test/r/index_merge.result	2008-08-21 14:27:27 +0000
@@ -518,3 +518,13 @@ a	filler	b
 4	zz	4
 5	qq	4
 drop table t1, t2;
+CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'),
+KEY b(b), KEY a(a));
+INSERT INTO t1 VALUES ('y',''), ('z','');
+SELECT b,a from t1 WHERE (b!='c' AND b!='f' && b!='h') OR 
+(a='pure-S') OR (a='DE80337a') OR (a='DE80799');
+b	a
+	y
+	z
+DROP TABLE t1;
+End of 5.0 tests

=== modified file 'mysql-test/t/index_merge.test'
--- a/mysql-test/t/index_merge.test	2007-07-14 18:02:10 +0000
+++ b/mysql-test/t/index_merge.test	2008-08-21 14:27:27 +0000
@@ -463,3 +463,18 @@ select * from t2 where a=4 or b=4;
 
 drop table t1, t2;
 
+#
+# Bug #37943: Reproducible mysqld crash/sigsegv in sel_trees_can_be_ored
+#
+
+CREATE TABLE t1 (a varchar(8), b set('a','b','c','d','e','f','g','h'),
+                 KEY b(b), KEY a(a));
+INSERT INTO t1 VALUES ('y',''), ('z','');
+
+#should not crash
+SELECT b,a from t1 WHERE (b!='c' AND b!='f' && b!='h') OR 
+  (a='pure-S') OR (a='DE80337a') OR (a='DE80799');
+
+DROP TABLE t1;
+
+--echo End of 5.0 tests

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2008-03-28 18:02:27 +0000
+++ b/sql/opt_range.cc	2008-08-21 14:27:27 +0000
@@ -481,36 +481,6 @@ public:
 
 class SEL_IMERGE;
 
-
-class SEL_TREE :public Sql_alloc
-{
-public:
-  enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
-  SEL_TREE(enum Type type_arg) :type(type_arg) {}
-  SEL_TREE() :type(KEY)
-  {
-    keys_map.clear_all();
-    bzero((char*) keys,sizeof(keys));
-  }
-  SEL_ARG *keys[MAX_KEY];
-  key_map keys_map;        /* bitmask of non-NULL elements in keys */
-
-  /*
-    Possible ways to read rows using index_merge. The list is non-empty only
-    if type==KEY. Currently can be non empty only if keys_map.is_clear_all().
-  */
-  List<SEL_IMERGE> merges;
-
-  /* The members below are filled/used only after get_mm_tree is done */
-  key_map ror_scans_map;   /* bitmask of ROR scan-able elements in keys */
-  uint    n_ror_scans;     /* number of set bits in ror_scans_map */
-
-  struct st_ror_scan_info **ror_scans;     /* list of ROR key scans */
-  struct st_ror_scan_info **ror_scans_end; /* last ROR scan */
-  /* Note that #records for each key scan is stored in table->quick_rows */
-};
-
-
 typedef struct st_qsel_param {
   THD	*thd;
   TABLE *table;
@@ -548,6 +518,37 @@ typedef struct st_qsel_param {
   uint alloced_sel_args; 
 } PARAM;
 
+
+class SEL_TREE :public Sql_alloc
+{
+public:
+  enum Type { IMPOSSIBLE, ALWAYS, MAYBE, KEY, KEY_SMALLER } type;
+  SEL_TREE(enum Type type_arg) :type(type_arg) {}
+  SEL_TREE() :type(KEY)
+  {
+    keys_map.clear_all();
+    bzero((char*) keys,sizeof(keys));
+  }
+  SEL_TREE(SEL_TREE *arg, PARAM *param);
+  SEL_ARG *keys[MAX_KEY];
+  key_map keys_map;        /* bitmask of non-NULL elements in keys */
+
+  /*
+    Possible ways to read rows using index_merge. The list is non-empty only
+    if type==KEY. Currently can be non empty only if keys_map.is_clear_all().
+  */
+  List<SEL_IMERGE> merges;
+
+  /* The members below are filled/used only after get_mm_tree is done */
+  key_map ror_scans_map;   /* bitmask of ROR scan-able elements in keys */
+  uint    n_ror_scans;     /* number of set bits in ror_scans_map */
+
+  struct st_ror_scan_info **ror_scans;     /* list of ROR key scans */
+  struct st_ror_scan_info **ror_scans_end; /* last ROR scan */
+  /* Note that #records for each key scan is stored in table->quick_rows */
+};
+
+
 class TABLE_READ_PLAN;
   class TRP_RANGE;
   class TRP_ROR_INTERSECT;
@@ -648,6 +649,7 @@ public:
     trees_next(trees),
     trees_end(trees + PREALLOCED_TREES)
   {}
+  SEL_IMERGE (SEL_IMERGE *arg, PARAM *param);
   int or_sel_tree(PARAM *param, SEL_TREE *tree);
   int or_sel_tree_with_checks(PARAM *param, SEL_TREE *new_tree);
   int or_sel_imerge_with_checks(PARAM *param, SEL_IMERGE* imerge);
@@ -764,6 +766,40 @@ int SEL_IMERGE::or_sel_imerge_with_check
 }
 
 
+SEL_TREE::SEL_TREE(SEL_TREE *arg, PARAM *param): Sql_alloc()
+{
+  keys_map= arg->keys_map;
+  type= arg->type;
+  for (int idx= 0; idx < MAX_KEY; idx++)
+    if ((keys[idx]= arg->keys[idx]))
+      keys[idx]->increment_use_count(1);
+
+  List_iterator<SEL_IMERGE> it(arg->merges);
+  for (SEL_IMERGE *el= it++; el; el= it++)
+    merges.push_back (new SEL_IMERGE(el, param));
+}
+
+
+SEL_IMERGE::SEL_IMERGE (SEL_IMERGE *arg, PARAM *param) : Sql_alloc()
+{
+  uint elements= (arg->trees_end - arg->trees);
+  if (elements > PREALLOCED_TREES)
+  {
+    uint size= elements * sizeof (SEL_TREE **);
+    trees= (SEL_TREE **)alloc_root(param->mem_root, size);
+  }
+  else
+    trees= &trees_prealloced[0];
+
+  trees_next= trees;
+  trees_end= trees + elements;
+
+  for (SEL_TREE **tree = trees, **arg_tree= arg->trees; tree < trees_end; 
+       tree++, arg_tree++)
+    *tree= new SEL_TREE(*arg_tree, param);
+}
+
+
 /*
   Perform AND operation on two index_merge lists and store result in *im1.
 */
@@ -823,10 +859,15 @@ int imerge_list_or_tree(PARAM *param,
 {
   SEL_IMERGE *imerge;
   List_iterator<SEL_IMERGE> it(*im1);
+  bool tree_used= false;
   while ((imerge= it++))
   {
-    if (imerge->or_sel_tree_with_checks(param, tree))
+    if (imerge->or_sel_tree_with_checks(param, 
+                                        tree_used ? 
+                                          new SEL_TREE(tree, param) : 
+                                          tree))
       it.remove();
+    tree_used= true;
   }
   return im1->is_empty();
 }
@@ -4238,6 +4279,8 @@ get_mm_parts(PARAM *param, COND *cond_fu
     }
   }
 
+  if (tree && tree->merges.is_empty() &&
tree->keys_map.is_clear_all())
+    tree= NULL;
   DBUG_RETURN(tree);
 }
 

Thread
bzr commit into mysql-5.0 branch (kgeorge:2648) Bug#37943Georgi Kodinov21 Aug
  • Re: bzr commit into mysql-5.0 branch (kgeorge:2648) Bug#37943Sergey Petrunia30 Sep