Hi!
On Nov 13, eugene@stripped wrote:
> ChangeSet@stripped, 2007-11-13 18:03:08+00:00, evgen@stripped +4 -0
> Bug#31048: Many nested subqueries may cause server crash.
>
> This bug is actually two. The first one manifests itself on an EXPLAIN
> SELECT query with nested subqueries that employs the filesort algorithm.
> The whole SELECT under explain is marked as UNCACHEABLE_EXPLAIN to preserve
> some temporary structures for explain. As a side-effect of this values of
> nested subqueries weren't cached and subqueries were re-evaluated many
> times. Each time buffer for filesort was allocated but wasn't freed because
> freeing occurs at the end of topmost SELECT. Thus all available memory was
> eaten up step by step and OOM event occur.
> The second bug manifests itself on SELECT queries with conditions where
> a subquery result is compared with a key field and the subquery itself also
> has such condition. When a long chain of such nested subqueries is present
> the stack overrun occur. This happens because at some point the range optimizer
> temporary puts the PARAM structure on the stack. Its size if about 8K and
> the stack is exhausted very fast.
>
> Now the subselect_single_select_engine::exec function allows subquery result
> caching when the UNCACHEABLE_EXPLAIN flag is set.
> Now the SQL_SELECT::test_quick_select function allocates the PARAM structure
> on the heap and frees it on exit. Also now it calls the check_stack_overrun
> function for stack checking purposes.
>
> diff -Nrup a/sql/opt_range.cc b/sql/opt_range.cc
> --- a/sql/opt_range.cc 2007-10-23 11:32:03 +00:00
> +++ b/sql/opt_range.cc 2007-11-13 18:02:36 +00:00
> @@ -1978,37 +1978,49 @@ int SQL_SELECT::test_quick_select(THD *t
> keys_to_use.intersect(head->keys_in_use_for_query);
> if (!keys_to_use.is_clear_all())
> {
> +#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
> + char buff[STACK_BUFF_ALLOC];
> +#endif
> MEM_ROOT alloc;
> SEL_TREE *tree= NULL;
> KEY_PART *key_parts;
> KEY *key_info;
> - PARAM param;
> + PARAM *param;
> +
> + if (check_stack_overrun(thd, STACK_MIN_SIZE, buff))
> + DBUG_RETURN(0); // Fatal error flag is set
> +
> + param= (PARAM*)my_malloc(sizeof(PARAM),MYF(0));
> + if (!param)
> + DBUG_RETURN(0); // Can't use range
Eh, no exactly :(
If you can detect a stack overflow here, as we do elsewhere, you can
allocate param on the stack, just as it was done before.
Try it please, you don't want to use malloc, if it can be avoided.
Regards / Mit vielen Grüssen,
Sergei
--
__ ___ ___ ____ __
/ |/ /_ __/ __/ __ \/ / Sergei Golubchik <serg@stripped>
/ /|_/ / // /\ \/ /_/ / /__ Principal Software Developer
/_/ /_/\_, /___/\___\_\___/ MySQL GmbH, Dachauer Str. 37, D-80335 München
<___/ Geschäftsführer: Kaj Arnö - HRB
München 162140