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

crash in Item_func_sec_to_time::get_date

Details

    Description

      Version: '10.2.9-MariaDB'  socket: ''  port: 3306  mariadb.org binary distribution
      mysqld.exe!Item_func_sec_to_time::get_date()[item_timefunc.cc:1855]
      mysqld.exe!Item::get_date_with_conversion()[item.cc:151]
      mysqld.exe!Item_func_to_days::val_int()[item_timefunc.cc:783]
      mysqld.exe!Item::update_null_value()[item.h:1454]
      mysqld.exe!Item_avg_field::is_null()[item_sum.h:1244]
      mysqld.exe!mysql_do()[sql_do.cc:34]
      mysqld.exe!mysql_execute_command()[sql_parse.cc:3495]
      mysqld.exe!mysql_parse()[sql_parse.cc:7880]
      mysqld.exe!dispatch_command()[sql_parse.cc:1814]
      mysqld.exe!do_command()[sql_parse.cc:1359]
      mysqld.exe!threadpool_process_request()[threadpool_common.cc:366]
      mysqld.exe!tp_callback()[threadpool_common.cc:192]
      

      How to repeat

      do to_days(sec_to_time(time(ceiling(uuid())))); #sporadic
      do to_days(sec_to_time(makedate('',rand(~('')))));
      

      Attachments

        Issue Links

          Activity

            Thanks for the report and test case.

            elenst Elena Stepanova added a comment - Thanks for the report and test case.
            bar Alexander Barkov added a comment - - edited

            These simplified queries also crashes the server:

            SELECT TO_DAYS(SEC_TO_TIME(MAKEDATE(0,RAND(~0))));
            SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0)));
            

            bar Alexander Barkov added a comment - - edited These simplified queries also crashes the server: SELECT TO_DAYS(SEC_TO_TIME(MAKEDATE(0,RAND(~0)))); SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0)));
            bar Alexander Barkov added a comment - - edited

            The problem happens because Item_func_sec_to_time::get_date() fetches the value for the second time in case of overflow, using val_str(), which can return NULL when the argument is not deterministic (e.g. uses RAND() directly or indirectly). The code calling make_truncated_value_warning() does not expect this.

            Also, Item_func_sec_to_time::get_date() abuses make_truncate_value_warning() in another way:
            it passes err->ptr() and err->length() directly, without using ErrConvString. This causes unreadable warnings in case of "tricky" charsets such as UCS2:

            SELECT SEC_TO_TIME(CONVERT(900*24*60*60 USING ucs2));
            SHOW WARNINGS;
            

            +---------+------+----------------------------------------------------------------------------+
            | Level   | Code | Message                                                                    |
            +---------+------+----------------------------------------------------------------------------+
            | Warning | 1292 | Truncated incorrect time value: '\x007\x007\x007\x006\x000\x000\x000\x000' |
            +---------+------+----------------------------------------------------------------------------+
            

            The expected warning would be:

            +---------+------+--------------------------------------------+
            | Level   | Code | Message                                    |
            +---------+------+--------------------------------------------+
            | Warning | 1292 | Truncated incorrect time value: '77760000' |
            +---------+------+--------------------------------------------+
            

            bar Alexander Barkov added a comment - - edited The problem happens because Item_func_sec_to_time::get_date() fetches the value for the second time in case of overflow, using val_str(), which can return NULL when the argument is not deterministic (e.g. uses RAND() directly or indirectly). The code calling make_truncated_value_warning() does not expect this. Also, Item_func_sec_to_time::get_date() abuses make_truncate_value_warning() in another way: it passes err->ptr() and err->length() directly, without using ErrConvString. This causes unreadable warnings in case of "tricky" charsets such as UCS2: SELECT SEC_TO_TIME( CONVERT (900*24*60*60 USING ucs2)); SHOW WARNINGS; +---------+------+----------------------------------------------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------------------------------------------+ | Warning | 1292 | Truncated incorrect time value: '\x007\x007\x007\x006\x000\x000\x000\x000' | +---------+------+----------------------------------------------------------------------------+ The expected warning would be: +---------+------+--------------------------------------------+ | Level | Code | Message | +---------+------+--------------------------------------------+ | Warning | 1292 | Truncated incorrect time value: '77760000' | +---------+------+--------------------------------------------+

            Opps, forgot to add the supposed commit comment when pushing:

            Item_func_sec_to_time::get_date() calls an args[0]'s value method two times:
            - once val_int() or val_decimal() inside Item::get_seconds()
            - then val_str() to generate a warning, in case an out-of-range value
             
            This approach was wrong for two reasons:
            1. val_str() in some cases can return NULL even if val_int()/val_decimal()
               previously returned a not-NULL value.
               This is possible when args[0] is not deterministic
               (for instance, uses RAND() directly or indirectly).
               This caused the crash reported in the bug:
               the warning generation code in Item_func_sec_to_time::get_date()
               did not expect val_str() to return NULL.
             
               This patch fixes this problem by checking the result of val_str().
               In case of a non-NULL, the result of val_str() is used as before.
               In case of NULL, the "ulonglong seconds" value is used for the warning.
               Note, "ulong sec_part" value is ignored in the warning for simplicity.
             
            2. Calling val_str() to generate warnings fires the function side effect again.
               For example, consider SEC_TO_TIME(f1()), where f1() is a stored function
               doing some INSERTs as a side effect. If f1() returns an out-of-range value,
               the call for val_str() to generate the warning forces the INSERTs to happen
               again, which is wrong. The side effect must happen only once per call.
               This problem is NOT fixed by this patch to avoid big changes in 5.5.
               This will be fixed separately in 10.3 or 10.4.
             
            Also, passing err->ptr() and err->length() directly to
            make_truncated_value_warning() was wrong, because it did not take
            into account err->charset(). This caused unreadable warnings in case
            of tricky character sets, such as ucs2. This patch fixes this additional
            problem by using "ErrConvStr err2(err)".
            

            bar Alexander Barkov added a comment - Opps, forgot to add the supposed commit comment when pushing: Item_func_sec_to_time::get_date() calls an args[0]'s value method two times: - once val_int() or val_decimal() inside Item::get_seconds() - then val_str() to generate a warning, in case an out-of-range value   This approach was wrong for two reasons: 1. val_str() in some cases can return NULL even if val_int()/val_decimal() previously returned a not-NULL value. This is possible when args[0] is not deterministic (for instance, uses RAND() directly or indirectly). This caused the crash reported in the bug: the warning generation code in Item_func_sec_to_time::get_date() did not expect val_str() to return NULL.   This patch fixes this problem by checking the result of val_str(). In case of a non-NULL, the result of val_str() is used as before. In case of NULL, the "ulonglong seconds" value is used for the warning. Note, "ulong sec_part" value is ignored in the warning for simplicity.   2. Calling val_str() to generate warnings fires the function side effect again. For example, consider SEC_TO_TIME(f1()), where f1() is a stored function doing some INSERTs as a side effect. If f1() returns an out-of-range value, the call for val_str() to generate the warning forces the INSERTs to happen again, which is wrong. The side effect must happen only once per call. This problem is NOT fixed by this patch to avoid big changes in 5.5. This will be fixed separately in 10.3 or 10.4.   Also, passing err->ptr() and err->length() directly to make_truncated_value_warning() was wrong, because it did not take into account err->charset(). This caused unreadable warnings in case of tricky character sets, such as ucs2. This patch fixes this additional problem by using "ErrConvStr err2(err)".

            People

              serg Sergei Golubchik
              sbester1 sbester1
              Votes:
              0 Vote for this issue
              Watchers:
              4 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.