Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-4250

Server crashes on a query with AND and OR conditions

Details

    • Bug
    • Status: Closed (View Workflow)
    • Major
    • Resolution: Fixed
    • None
    • 5.5.30, 5.3.13
    • None
    • None

    Description

      The following query makes the server crash with a long corrupted stack trace:

      SELECT * FROM mysql.time_zone 
      WHERE ( NOT (Use_leap_seconds <= Use_leap_seconds AND Time_zone_id != 1) 
              AND Time_zone_id = Time_zone_id 
           OR Time_zone_id <> Time_zone_id ) 
        AND Use_leap_seconds <> 'N'
      ;

      Reproducible on maria/5.5 tree starting from revision 3671 (merge 5.3=>5.5), however 5.3 does not crash with the same query.

      Stack trace (from a debug build, same picture on two different machines, note 2400+ frames):

      Thread 1 (Thread 0x7f194ae44700 (LWP 30028)):
      #0  __pthread_kill (threadid=<optimized out>, signo=<optimized out>) at ../nptl/sysdeps/unix/sysv/linux/pthread_kill.c:63
      #1  0x0000000000ccf314 in my_write_core (sig=11) at 5.5/mysys/stacktrace.c:457
      #2  0x00000000007c5bc8 in handle_fatal_signal (sig=11) at 5.5/sql/signal_handler.cc:262
      #3  <signal handler called>
      #4  0x00007f194004ada8 in ?? ()
      #5  0xa5a5a5a5a5a5a5a5 in ?? ()
      ...
      #2402 0x00007f1940048fd0 in ?? ()
      #2403 0x0000000000000800 in ?? ()
      #2404 0x0000000000ca006e in init_dynamic_array2 (array=0xff000000ff, element_size=255, init_buffer=0xff000000ff, init_alloc=255, alloc_increment=255) at 5.5/mysys/array.c:65
      Backtrace stopped: previous frame inner to this frame (corrupt stack?)

      revision-id: holyfoot@askmonty.org-20130305214525-2lgv24a11bmeu6iq
      revno: 3682
      branch-nick: 5.5

      Reproducible with the default optimizer_switch as well as with all OFF values.
      EXPLAIN also crashes.

      Attachments

        Activity

          What's happening here:

          In build_equal_items_for_cond() a local copy of cond_equal is created on the stack:

          11608 static COND *build_equal_items_for_cond(THD *thd, COND *cond,
          11609 COND_EQUAL *inherited)
          11610 {
          11611 Item_equal *item_equal;
          11612 COND_EQUAL cond_equal;

          It contains a List inside. When a List is initialized it does this->last = &this->first;
          later it is copied into an item:

          11662 ((Item_cond_and*)cond)->cond_equal= cond_equal;

          when this function returns the item gets cond->cond_equal.current_level.last pointer points somewhere in the middle of the stack.

          Later in Item_equal::merge_into_list():

          5766 if (!merge_into)
          5767 list->push_back(this);

          this *last pointer is written into, which corrupts the stack.

          serg Sergei Golubchik added a comment - What's happening here: In build_equal_items_for_cond() a local copy of cond_equal is created on the stack: 11608 static COND *build_equal_items_for_cond(THD *thd, COND *cond, 11609 COND_EQUAL *inherited) 11610 { 11611 Item_equal *item_equal; 11612 COND_EQUAL cond_equal; It contains a List inside. When a List is initialized it does this->last = &this->first; later it is copied into an item: 11662 ((Item_cond_and*)cond)->cond_equal= cond_equal; when this function returns the item gets cond->cond_equal.current_level.last pointer points somewhere in the middle of the stack. Later in Item_equal::merge_into_list(): 5766 if (!merge_into) 5767 list->push_back(this); this *last pointer is written into, which corrupts the stack.

          This bug manifests itself already in the current build of mariadb 5.3.
          The returned result for the reported query is incorrect:

          MariaDB [test]> SELECT * FROM mysql.time_zone
          -> WHERE ( NOT (Use_leap_seconds <= Use_leap_seconds AND Time_zone_id != 1)
          -> AND Time_zone_id = Time_zone_id
          -> OR Time_zone_id <> Time_zone_id )
          -> AND Use_leap_seconds <> 'N'
          -> ;
          ------------------------------+

          Time_zone_id Use_leap_seconds

          ------------------------------+

          4 Y

          ------------------------------+

          The expected result is an empty set.

          The problem is seen for the following simplified query:

          MariaDB [test]> SELECT * FROM mysql.time_zone WHERE (FALSE OR Time_zone_id = 1) AND Use_leap_seconds <> 'N';
          ------------------------------+

          Time_zone_id Use_leap_seconds

          ------------------------------+

          4 Y

          ------------------------------+
          1 row in set (0.00 sec)

          EXPLAIN EXTENDED for this query returns:

          MariaDB [test]> EXPLAIN EXTENDED SELECT * FROM mysql.time_zone WHERE (FALSE OR Time_zone_id = 1) AND Use_leap_seconds <> 'N';
          -------------------------------------------------------------------------------

          id select_type table type possible_keys key key_len ref rows filtered Extra

          -------------------------------------------------------------------------------

          1 SIMPLE time_zone ALL NULL NULL NULL NULL 5 100.00 Using where

          -------------------------------------------------------------------------------

          MariaDB [test]> show warnings;
          ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

          Level Code Message

          ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

          Note 1003 select `mysql`.`time_zone`.`Time_zone_id` AS `Time_zone_id`,`mysql`.`time_zone`.`Use_leap_seconds` AS `Use_leap_seconds` from `mysql`.`time_zone` where (`mysql`.`time_zone`.`Use_leap_seconds` <> 'N')

          ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

          It can be seen that the WHERE condition has been converted to a condition that isn't equivalent to the original condition.

          This bug appeared after the patch for mdev-4177 had been pushed into the 5.3 tree (rev 3628). The bug existed before this patch, but bug mdev-4177
          masked it.

          igor Igor Babaev (Inactive) added a comment - This bug manifests itself already in the current build of mariadb 5.3. The returned result for the reported query is incorrect: MariaDB [test] > SELECT * FROM mysql.time_zone -> WHERE ( NOT (Use_leap_seconds <= Use_leap_seconds AND Time_zone_id != 1) -> AND Time_zone_id = Time_zone_id -> OR Time_zone_id <> Time_zone_id ) -> AND Use_leap_seconds <> 'N' -> ; ------------- -----------------+ Time_zone_id Use_leap_seconds ------------- -----------------+ 4 Y ------------- -----------------+ The expected result is an empty set. The problem is seen for the following simplified query: MariaDB [test] > SELECT * FROM mysql.time_zone WHERE (FALSE OR Time_zone_id = 1) AND Use_leap_seconds <> 'N'; ------------- -----------------+ Time_zone_id Use_leap_seconds ------------- -----------------+ 4 Y ------------- -----------------+ 1 row in set (0.00 sec) EXPLAIN EXTENDED for this query returns: MariaDB [test] > EXPLAIN EXTENDED SELECT * FROM mysql.time_zone WHERE (FALSE OR Time_zone_id = 1) AND Use_leap_seconds <> 'N'; --- ----------- --------- ---- ------------- ---- ------- ---- ---- -------- ------------ id select_type table type possible_keys key key_len ref rows filtered Extra --- ----------- --------- ---- ------------- ---- ------- ---- ---- -------- ------------ 1 SIMPLE time_zone ALL NULL NULL NULL NULL 5 100.00 Using where --- ----------- --------- ---- ------------- ---- ------- ---- ---- -------- ------------ MariaDB [test] > show warnings; ------ ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Level Code Message ------ ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Note 1003 select `mysql`.`time_zone`.`Time_zone_id` AS `Time_zone_id`,`mysql`.`time_zone`.`Use_leap_seconds` AS `Use_leap_seconds` from `mysql`.`time_zone` where (`mysql`.`time_zone`.`Use_leap_seconds` <> 'N') ------ ---- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- It can be seen that the WHERE condition has been converted to a condition that isn't equivalent to the original condition. This bug appeared after the patch for mdev-4177 had been pushed into the 5.3 tree (rev 3628). The bug existed before this patch, but bug mdev-4177 masked it.

          The fix has been pushed into the 5.3 tree.

          igor Igor Babaev (Inactive) added a comment - The fix has been pushed into the 5.3 tree.

          People

            igor Igor Babaev (Inactive)
            elenst Elena Stepanova
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved:

              Git Integration

                Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.