[MDEV-5954] MySQL Bug#13996639 CRASH IN ITEM_REF::FIX_FIELDS ON EXEC OF STORED FUNCTION WITH ONLY_FULL_GROUP_BY Created: 2014-03-26  Updated: 2014-09-10  Resolved: 2014-09-10

Status: Closed
Project: MariaDB Server
Component/s: None
Affects Version/s: 10.0.9
Fix Version/s: N/A

Type: Bug Priority: Minor
Reporter: Sergey Vojtovich Assignee: Sergei Golubchik
Resolution: Cannot Reproduce Votes: 0
Labels: None

Issue Links:
PartOf
is part of MDEV-4784 merge test cases from 5.6 Stalled

 Description   

The following revision doesn't seem to be merged into 10.0. Found while analyzing result difference in ps_ddl1.test:

revno: 4591.1.70
committer: Guilhem Bichot <guilhem.bichot@oracle.com>
branch nick: 5.6-3
timestamp: Sat 2012-11-24 15:45:56 +0100
message:
  fix for Bug#13996639 CRASH IN ITEM_REF::FIX_FIELDS ON EXEC OF STORED
  FUNCTION WITH ONLY_FULL_GROUP_BY. See per-file comments.
 
  mysql-test/r/ps_ddl1.result:
    side affect of the bugfix; this is a good change, as the removed comment says.
  sql/sql_lex.cc:
    LEX starts clean
  sql/sql_optimizer.cc:
    If optimize () fails, tag the Lex as "broken"
  sql/sql_parse.cc:
    At first execution of:
     SELECT stored_func()
    this happens:
    1) body of stored_func is read from mysql.proc
    2) body is parsed (sp_compile()) (for each substatement a LEX and some
    Items are created)
    3) parsing went ok so parse trees are cached (sp_cache_insert())
    4) substatement starts executing (SELECT with a NOT IN (subq))
    4.1) Item_in_subselect::fix_fields():
      if (!(res= engine->prepare()))
      {
          (*ref)= substitution;
    engine->prepare() calls JOIN::prepare() on subq, which calls
    resolve_subquery() which starts IN2EXISTS transformation: adds
    conditions (using some new Item_ref) to the subquery's WHERE, creates
    Item_in_optimizer and puts it in 'substitution'. After
    resolve_subquery(), JOIN::prepare() of subq fails in:
 
        my_message(ER_MIX_OF_GROUP_FUNC_AND_FIELDS,
                   ER(ER_MIX_OF_GROUP_FUNC_AND_FIELDS), MYF(0));
        DBUG_RETURN(-1);
 
    So far, so good.
    Thus engine->prepare() fails. Thus we don't do:
      (*ref)= substitution;
    i.e. the parent of the subquery continues to have its WHERE point to
    Item_in_subselect. At this stage we have a broken parse tree, because
    subq has been transformed but parent query points to pre-transform
    subq. This mess is not rolled back (IN2EXISTS is a complex transform
    which does not use change_item_tree()).
    ER_MIX_OF_GROUP_FUNC_AND_FIELDS is sent to client.
    So far, so good.
 
    At 2nd execution of:
     SELECT stored_func()
    this happens:
    1) cached parse trees of stored_func is read from cache
    2) but this is the broken parse tree!
    3) as the Item_ref depends on Item_in_optimizer::fix_fields() to set
    its '*ref', and as Item_in_optimizer was not stored in parent query,
    Item_in_optimizer::fix_fields() is not called, so
    Item_ref::fix_fields() crashes.
 
    Summary: first execution broke Item_in_subselect/LEX, 2nd execution reused it.
 
    Solution: first execution marks the fact that it
    broke LEX; 2nd execution sees the mark and asks for a
    reprepare, which creates new parse trees, and thus works as the first
    execution.
    A new member m_broken is added to class LEX. It is set to "true" when
    JOIN:: prepare () or JOIN:: optimize () fail, because it is possible
    that those functions were doing transformations. It is set to "false"
    when the Lex is initialized.
  sql/sql_resolver.cc:
    If prepare () fails, tag the Lex as "broken"



 Comments   
Comment by Sergei Golubchik [ 2014-03-26 ]

MariaDB doesn't seem to be vulnerable, I mean, there's no crash in this case.

Generated at Thu Feb 08 07:08:17 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.