From: Tor Didriksen Date: May 30 2011 10:44am Subject: bzr commit into mysql-trunk branch (tor.didriksen:3128) Bug#12590211 List-Archive: http://lists.mysql.com/commits/138414 X-Bug: 12590211 Message-Id: <20110530104410.D53A426A@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2896752961140822213==" --===============2896752961140822213== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/trunk-bug11765255-arraycheck/ based on revid:alexander.nozdrin@stripped 3128 Tor Didriksen 2011-05-30 Bug#12590211 - ADD BOUNDS CHECK ON REF_POINTER_ARRAY AND FRIENDS Cleanup the Item** and Item*** code for ref_pointer_array. Wrap the array(s) in a container, so we can do bounds checks. @ sql/sql_array.h New, templatized, array class. @ sql/sql_lex.cc In setup_ref_array(), add sanity check that that the size of ref_pointer_array does not change. @ sql/sql_select.cc Changed several functions from xx_(.. Item ** ..) to xx_(.. Ref_ptr_array ..) @ sql/sql_select.h Document usage of ref_pointer_array. Change from Item** to Ref_ptr_array. Re-wrote setter functions. @ unittest/gunit/bounds_checked_array-t.cc New unit test. added: unittest/gunit/bounds_checked_array-t.cc modified: sql/item.cc sql/item_subselect.cc sql/item_sum.cc sql/sql_array.h sql/sql_base.cc sql/sql_base.h sql/sql_do.cc sql/sql_insert.cc sql/sql_lex.cc sql/sql_lex.h sql/sql_load.cc sql/sql_prepare.cc sql/sql_select.cc sql/sql_select.h sql/sql_update.cc unittest/gunit/CMakeLists.txt === modified file 'sql/item.cc' --- a/sql/item.cc 2011-05-26 15:20:09 +0000 +++ b/sql/item.cc 2011-05-30 10:44:01 +0000 @@ -4346,7 +4346,7 @@ resolve_ref_in_select_and_group(THD *thd return NULL; } DBUG_ASSERT((*select_ref)->fixed); - return (select->ref_pointer_array + counter); + return &select->ref_pointer_array[counter]; } if (group_by_ref) return group_by_ref; @@ -6234,13 +6234,13 @@ Item *Item_field::update_value_transform type() != Item::TRIGGER_FIELD_ITEM) { List *all_fields= &select->join->all_fields; - Item **ref_pointer_array= select->ref_pointer_array; + Ref_ptr_array &ref_pointer_array= select->ref_pointer_array; int el= all_fields->elements; Item_ref *ref; ref_pointer_array[el]= (Item*)this; all_fields->push_front((Item*)this); - ref= new Item_ref(&select->context, ref_pointer_array + el, + ref= new Item_ref(&select->context, &ref_pointer_array[el], table_name, field_name); return ref; } === modified file 'sql/item_subselect.cc' --- a/sql/item_subselect.cc 2011-05-24 09:36:11 +0000 +++ b/sql/item_subselect.cc 2011-05-30 10:44:01 +0000 @@ -1126,7 +1126,7 @@ Item_in_subselect::single_value_transfor (ALL && (> || =>)) || (ANY && (< || =<)) for ALL condition is inverted */ - item= new Item_sum_max(*select_lex->ref_pointer_array); + item= new Item_sum_max(select_lex->ref_pointer_array[0]); } else { @@ -1134,11 +1134,11 @@ Item_in_subselect::single_value_transfor (ALL && (< || =<)) || (ANY && (> || =>)) for ALL condition is inverted */ - item= new Item_sum_min(*select_lex->ref_pointer_array); + item= new Item_sum_min(select_lex->ref_pointer_array[0]); } if (upper_item) upper_item->set_sum_test(item); - *select_lex->ref_pointer_array= item; + select_lex->ref_pointer_array[0]= item; { List_iterator it(select_lex->item_list); it++; @@ -1220,7 +1220,8 @@ Item_in_subselect::single_value_transfor DBUG_RETURN(RES_OK); /* Perform the IN=>EXISTS transformation. */ - DBUG_RETURN(single_value_in_to_exists_transformer(join, func)); + const trans_res retval= single_value_in_to_exists_transformer(join, func); + DBUG_RETURN(retval); } @@ -1274,8 +1275,8 @@ Item_in_subselect::single_value_in_to_ex Item *item= func->create(expr, new Item_ref_null_helper(&select_lex->context, this, - select_lex-> - ref_pointer_array, + &select_lex-> + ref_pointer_array[0], (char *)"", this->full_name())); if (!abort_on_null && left_expr->maybe_null) @@ -1393,7 +1394,7 @@ Item_in_subselect::single_value_in_to_ex Item *new_having= func->create(expr, new Item_ref_null_helper(&select_lex->context, this, - select_lex->ref_pointer_array, + &select_lex->ref_pointer_array[0], (char *)"", (char *)"")); if (!abort_on_null && left_expr->maybe_null) @@ -1570,14 +1571,14 @@ Item_in_subselect::row_value_in_to_exist (char *)in_left_expr_name), new Item_ref(&select_lex->context, - select_lex->ref_pointer_array + i, + &select_lex->ref_pointer_array[i], (char *)"", (char *)"") ); Item *item_isnull= new Item_func_isnull(new Item_ref(&select_lex->context, - select_lex->ref_pointer_array+i, + &select_lex->ref_pointer_array[i], (char *)"", (char *)"") ); @@ -1592,8 +1593,8 @@ Item_in_subselect::row_value_in_to_exist Item *item_nnull_test= new Item_is_not_null_test(this, new Item_ref(&select_lex->context, - select_lex-> - ref_pointer_array + i, + &select_lex-> + ref_pointer_array[i], (char *)"", (char *)"")); if (!abort_on_null && left_expr->element_index(i)->maybe_null) @@ -1648,8 +1649,8 @@ Item_in_subselect::row_value_in_to_exist (char *)in_left_expr_name), new Item_direct_ref(&select_lex->context, - select_lex-> - ref_pointer_array+i, + &select_lex-> + ref_pointer_array[i], (char *)"", (char *)"") ); @@ -1659,7 +1660,7 @@ Item_in_subselect::row_value_in_to_exist new Item_is_not_null_test(this, new Item_ref(&select_lex->context, - select_lex->ref_pointer_array + i, + &select_lex->ref_pointer_array[i], (char *)"", (char *)"")); @@ -1667,8 +1668,8 @@ Item_in_subselect::row_value_in_to_exist item_isnull= new Item_func_isnull(new Item_direct_ref(&select_lex->context, - select_lex-> - ref_pointer_array+i, + &select_lex-> + ref_pointer_array[i], (char *)"", (char *)"") ); === modified file 'sql/item_sum.cc' --- a/sql/item_sum.cc 2011-05-26 15:20:09 +0000 +++ b/sql/item_sum.cc 2011-05-30 10:44:01 +0000 @@ -3306,7 +3306,8 @@ bool Item_func_group_concat::setup(THD * tmp table columns. */ if (arg_count_order && - setup_order(thd, args, context->table_list, list, all_fields, *order)) + setup_order(thd, Ref_ptr_array(args, arg_count), + context->table_list, list, all_fields, *order)) DBUG_RETURN(TRUE); count_field_types(select_lex, tmp_table_param, all_fields, 0); === modified file 'sql/sql_array.h' --- a/sql/sql_array.h 2011-05-18 13:12:02 +0000 +++ b/sql/sql_array.h 2011-05-30 10:44:01 +0000 @@ -1,7 +1,7 @@ #ifndef SQL_ARRAY_INCLUDED #define SQL_ARRAY_INCLUDED -/* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -18,6 +18,60 @@ #include +/** + A wrapper class which provides array bounds checking. + We do *not* own the array, we simply have a pointer to the first element, + and a length. + + @remark + We want the compiler-generated versions of: + - the copy CTOR (memberwise initialization) + - the assignment operator (memberwise assignment) + + @param Element_type The type of the elements of the container. + */ +template class Bounds_checked_array +{ +public: + Bounds_checked_array() : m_array(NULL), m_size(0) {} + + Bounds_checked_array(Element_type *el, size_t size) + : m_array(el), m_size(size) + {} + + void reset() { m_array= NULL; m_size= 0; } + + Element_type &operator[](size_t n) + { + DBUG_ASSERT(n < m_size); + return m_array[n]; + } + + const Element_type &operator[](size_t n) const + { + DBUG_ASSERT(n < m_size); + return m_array[n]; + } + + size_t element_size() const { return sizeof(Element_type); } + size_t size() const { return m_size; } + + operator bool() const { return m_array != NULL; } + + void pop_front() + { + DBUG_ASSERT(m_size > 0); + m_array+= 1; + m_size-= 1; + } + + Element_type *array() const { return m_array; } + +private: + Element_type *m_array; + size_t m_size; +}; + /* A typesafe wrapper around DYNAMIC_ARRAY */ === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_base.cc 2011-05-30 10:44:01 +0000 @@ -8022,7 +8022,7 @@ int setup_wild(THD *thd, TABLE_LIST *tab ** Check that all given fields exists and fill struct with current data ****************************************************************************/ -bool setup_fields(THD *thd, Item **ref_pointer_array, +bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &fields, enum_mark_columns mark_used_columns, List *sum_func_list, bool allow_sum_func) { @@ -8053,7 +8053,10 @@ bool setup_fields(THD *thd, Item **ref_p ref_pointer_array */ if (ref_pointer_array) - memset(ref_pointer_array, 0, sizeof(Item *) * fields.elements); + { + DBUG_ASSERT(ref_pointer_array.size() >= fields.elements); + memset(ref_pointer_array.array(), 0, sizeof(Item *) * fields.elements); + } /* We call set_entry() there (before fix_fields() of the whole list of field @@ -8071,7 +8074,7 @@ bool setup_fields(THD *thd, Item **ref_p while ((var= li++)) var->set_entry(thd, FALSE); - Item **ref= ref_pointer_array; + Ref_ptr_array ref= ref_pointer_array; thd->lex->current_select->cur_pos_in_select_list= 0; while ((item= it++)) { @@ -8085,10 +8088,13 @@ bool setup_fields(THD *thd, Item **ref_p DBUG_RETURN(TRUE); /* purecov: inspected */ } if (ref) - *(ref++)= item; + { + ref[0]= item; + ref.pop_front(); + } if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && sum_func_list) - item->split_sum_func(thd, ref_pointer_array, *sum_func_list); + item->split_sum_func(thd, ref_pointer_array.array(), *sum_func_list); thd->used_tables|= item->used_tables(); thd->lex->current_select->cur_pos_in_select_list++; } === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2011-05-04 07:51:15 +0000 +++ b/sql/sql_base.h 2011-05-30 10:44:01 +0000 @@ -184,7 +184,7 @@ bool insert_fields(THD *thd, Name_resolu List_iterator *it, bool any_privileges); int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); -bool setup_fields(THD *thd, Item** ref_pointer_array, +bool setup_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &item, enum_mark_columns mark_used_columns, List *sum_func_list, bool allow_sum_func); bool fill_record(THD *thd, Field **field, List &values, @@ -350,7 +350,7 @@ inline TABLE_LIST *find_table_in_local_l } -inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array, +inline bool setup_fields_with_no_wrap(THD *thd, Ref_ptr_array ref_pointer_array, List &item, enum_mark_columns mark_used_columns, List *sum_func_list, === modified file 'sql/sql_do.cc' --- a/sql/sql_do.cc 2010-07-27 15:01:56 +0000 +++ b/sql/sql_do.cc 2011-05-30 10:44:01 +0000 @@ -28,7 +28,7 @@ bool mysql_do(THD *thd, List &valu List_iterator li(values); Item *value; DBUG_ENTER("mysql_do"); - if (setup_fields(thd, 0, values, MARK_COLUMNS_NONE, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_NONE, 0, 0)) DBUG_RETURN(TRUE); while ((value = li++)) value->val_int(); === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2011-05-30 06:25:47 +0000 +++ b/sql/sql_insert.cc 2011-05-30 10:44:01 +0000 @@ -256,7 +256,7 @@ static int check_insert_fields(THD *thd, */ table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - res= setup_fields(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0); + res= setup_fields(thd, Ref_ptr_array(), fields, MARK_COLUMNS_WRITE, 0, 0); /* Restore the current context. */ ctx_state.restore_state(context, table_list); @@ -347,7 +347,8 @@ static int check_update_fields(THD *thd, } /* Check the fields we are going to modify */ - if (setup_fields(thd, 0, update_fields, MARK_COLUMNS_WRITE, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), + update_fields, MARK_COLUMNS_WRITE, 0, 0)) return -1; if (insert_table_list->effective_algorithm == VIEW_ALGORITHM_MERGE && @@ -762,7 +763,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto abort; } - if (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_READ, 0, 0)) goto abort; } its.rewind (); @@ -1377,7 +1378,8 @@ bool mysql_prepare_insert(THD *thd, TABL table_list->next_local= 0; context->resolve_in_table_list_only(table_list); - res= (setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0) || + res= (setup_fields(thd, Ref_ptr_array(), + *values, MARK_COLUMNS_READ, 0, 0) || check_insert_fields(thd, context->table_list, fields, *values, !insert_into_view, 0, &map)); @@ -1393,7 +1395,8 @@ bool mysql_prepare_insert(THD *thd, TABL } if (!res) - res= setup_fields(thd, 0, update_values, MARK_COLUMNS_READ, 0, 0); + res= setup_fields(thd, Ref_ptr_array(), + update_values, MARK_COLUMNS_READ, 0, 0); if (!res && duplic == DUP_UPDATE) { @@ -3231,7 +3234,7 @@ select_insert::prepare(List &value /* Errors during check_insert_fields() should not be ignored. */ lex->current_select->no_error= FALSE; - res= (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0) || + res= (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0) || check_insert_fields(thd, table_list, *fields, values, !insert_into_view, 1, &map)); @@ -3279,7 +3282,7 @@ select_insert::prepare(List &value table_list->next_name_resolution_table= ctx_state.get_first_name_resolution_table(); - res= res || setup_fields(thd, 0, *info.update_values, + res= res || setup_fields(thd, Ref_ptr_array(), *info.update_values, MARK_COLUMNS_READ, 0, 0); if (!res) { === modified file 'sql/sql_lex.cc' --- a/sql/sql_lex.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_lex.cc 2011-05-30 10:44:01 +0000 @@ -1732,6 +1732,8 @@ void st_select_lex_unit::init_query() void st_select_lex::init_query() { + DBUG_ENTER("st_select_lex::init_query"); + DBUG_PRINT("info", ("this %p", this)); st_select_lex_node::init_query(); table_list.empty(); top_join_list.empty(); @@ -1757,7 +1759,7 @@ void st_select_lex::init_query() parent_lex->push_context(&context); cond_count= between_count= with_wild= 0; max_equal_elems= 0; - ref_pointer_array= 0; + ref_pointer_array.reset(); select_n_where_fields= 0; select_n_having_items= 0; subquery_in_having= explicit_limit= 0; @@ -1769,10 +1771,13 @@ void st_select_lex::init_query() exclude_from_table_unique_test= no_wrap_view_item= FALSE; nest_level= 0; link_next= 0; + DBUG_VOID_RETURN; } void st_select_lex::init_select() { + DBUG_ENTER("st_select_lex::init_select"); + DBUG_PRINT("info", ("this %p", this)); st_select_lex_node::init_select(); sj_nests.empty(); group_list.empty(); @@ -1800,6 +1805,7 @@ void st_select_lex::init_select() cond_value= having_value= Item::COND_UNDEF; inner_refs_list.empty(); full_group_by_flag= 0; + DBUG_VOID_RETURN; } /* @@ -2132,20 +2138,38 @@ ulong st_select_lex::get_table_join_opti bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num) { +#ifdef DBUG_OFF if (ref_pointer_array) return 0; +#endif + + DBUG_ENTER("st_select_lex::setup_ref_array"); /* We have to create array in prepared statement memory if it is prepared statement */ Query_arena *arena= thd->stmt_arena; - return (ref_pointer_array= - (Item **)arena->alloc(sizeof(Item*) * (n_child_sum_items + - item_list.elements + - select_n_having_items + - select_n_where_fields + - order_group_num)*5)) == 0; + uint n_elems= (n_child_sum_items + + item_list.elements + + select_n_having_items + + select_n_where_fields + + order_group_num) * 5; + DBUG_PRINT("info", ("setup_ref_array %4u : %4u %4u %4u %4u %4u", + n_elems, + n_child_sum_items, + item_list.elements, + select_n_having_items, + select_n_where_fields, + order_group_num)); + if (ref_pointer_array) { + DBUG_ASSERT(ref_pointer_array.size() == n_elems); + DBUG_RETURN(0); + } + Item **array= (Item **)arena->alloc(sizeof(Item*) * n_elems); + ref_pointer_array= Ref_ptr_array(array, n_elems); + + DBUG_RETURN(array == NULL); } === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2011-05-12 17:29:19 +0000 +++ b/sql/sql_lex.h 2011-05-30 10:44:01 +0000 @@ -24,6 +24,7 @@ #include "sql_trigger.h" #include "item.h" /* From item_subselect.h: subselect_union_engine */ #include "thr_lock.h" /* thr_lock_type, TL_UNLOCK */ +#include "sql_array.h" /* YACC and LEX Definitions */ @@ -602,6 +603,7 @@ public: }; typedef class st_select_lex_unit SELECT_LEX_UNIT; +typedef Bounds_checked_array Ref_ptr_array; /* SELECT_LEX - store information of parsed SELECT statment @@ -655,8 +657,9 @@ public: SQL_I_List order_list; /* ORDER clause */ SQL_I_List *gorder_list; Item *select_limit, *offset_limit; /* LIMIT clause parameters */ - // Arrays of pointers to top elements of all_fields list - Item **ref_pointer_array; + + // Array of pointers to top elements of all_fields list + Ref_ptr_array ref_pointer_array; /* number of items in select_list and HAVING clause used to get number @@ -666,7 +669,7 @@ public: uint select_n_having_items; uint cond_count; /* number of arguments of and/or/xor in where/having/on */ uint between_count; /* number of between predicates in where/having/on */ - uint max_equal_elems; /* maximal number of elements in multiple equalities */ + uint max_equal_elems; /* maximal number of elements in multiple equalities */ /* Number of fields used in select list or where clause of current select and all inner subselects. === modified file 'sql/sql_load.cc' --- a/sql/sql_load.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_load.cc 2011-05-30 10:44:01 +0000 @@ -268,15 +268,18 @@ int mysql_load(THD *thd,sql_exchange *ex Let us also prepare SET clause, altough it is probably empty in this case. */ - if (setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) || - setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), + set_fields, MARK_COLUMNS_WRITE, 0, 0) || + setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0)) DBUG_RETURN(TRUE); } else { // Part field list /* TODO: use this conds for 'WITH CHECK OPTIONS' */ - if (setup_fields(thd, 0, fields_vars, MARK_COLUMNS_WRITE, 0, 0) || - setup_fields(thd, 0, set_fields, MARK_COLUMNS_WRITE, 0, 0) || + if (setup_fields(thd, Ref_ptr_array(), + fields_vars, MARK_COLUMNS_WRITE, 0, 0) || + setup_fields(thd, Ref_ptr_array(), + set_fields, MARK_COLUMNS_WRITE, 0, 0) || check_that_all_fields_are_given_values(thd, table, table_list)) DBUG_RETURN(TRUE); /* @@ -295,7 +298,7 @@ int mysql_load(THD *thd,sql_exchange *ex } } /* Fix the expressions in SET clause */ - if (setup_fields(thd, 0, set_values, MARK_COLUMNS_READ, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), set_values, MARK_COLUMNS_READ, 0, 0)) DBUG_RETURN(TRUE); } === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_prepare.cc 2011-05-30 10:44:01 +0000 @@ -1294,7 +1294,7 @@ static bool mysql_test_insert(Prepared_s my_error(ER_WRONG_VALUE_COUNT_ON_ROW, MYF(0), counter); goto error; } - if (setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), *values, MARK_COLUMNS_NONE, 0, 0)) goto error; } } @@ -1373,7 +1373,8 @@ static int mysql_test_update(Prepared_st table_list->register_want_access(want_privilege); #endif thd->lex->select_lex.no_wrap_view_item= TRUE; - res= setup_fields(thd, 0, select->item_list, MARK_COLUMNS_READ, 0, 0); + res= setup_fields(thd, Ref_ptr_array(), + select->item_list, MARK_COLUMNS_READ, 0, 0); thd->lex->select_lex.no_wrap_view_item= FALSE; if (res) goto error; @@ -1384,7 +1385,8 @@ static int mysql_test_update(Prepared_st (SELECT_ACL & ~table_list->table->grant.privilege); table_list->register_want_access(SELECT_ACL); #endif - if (setup_fields(thd, 0, stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), + stmt->lex->value_list, MARK_COLUMNS_NONE, 0, 0)) goto error; /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); @@ -1530,7 +1532,8 @@ static bool mysql_test_do_fields(Prepare if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL)) DBUG_RETURN(TRUE); - DBUG_RETURN(setup_fields(thd, 0, *values, MARK_COLUMNS_NONE, 0, 0)); + DBUG_RETURN(setup_fields(thd, Ref_ptr_array(), + *values, MARK_COLUMNS_NONE, 0, 0)); } === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_select.cc 2011-05-30 10:44:01 +0000 @@ -203,7 +203,7 @@ static int remove_dup_with_hash_index(TH static bool cmp_buffer_with_ref(THD *thd, TABLE *table, TABLE_REF *tab_ref); static bool setup_new_fields(THD *thd, List &fields, List &all_fields, ORDER *new_order); -static ORDER *create_distinct_group(THD *thd, Item **ref_pointer_array, +static ORDER *create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array, ORDER *order, List &fields, List &all_fields, bool *all_order_by_fields_used); @@ -213,12 +213,12 @@ static void calc_group_buffer(JOIN *join static bool make_group_fields(JOIN *main_join, JOIN *curr_join); static bool alloc_group_fields(JOIN *join,ORDER *group); // Create list for using with tempory table -static bool change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, +static bool change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &new_list1, List &new_list2, uint elements, List &items); // Create list for using with tempory table -static bool change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, +static bool change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &new_list1, List &new_list2, uint elements, List &items); @@ -460,7 +460,7 @@ bool handle_select(THD *thd, LEX *lex, s bool fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, - Item **ref_pointer_array, ORDER *group_list) + Ref_ptr_array ref_pointer_array, ORDER *group_list) { Item_outer_ref *ref; @@ -487,7 +487,7 @@ fix_inner_refs(THD *thd, List &all If it's needed reset each Item_ref item that refers this field with a new reference taken from ref_pointer_array. */ - item_ref= ref_pointer_array + el; + item_ref= &ref_pointer_array[el]; } if (ref->in_sum_func) @@ -546,7 +546,7 @@ fix_inner_refs(THD *thd, List &all /** Function to setup clauses without sum functions. */ -inline int setup_without_group(THD *thd, Item **ref_pointer_array, +inline int setup_without_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, TABLE_LIST *leaves, List &fields, @@ -600,7 +600,7 @@ inline int setup_without_group(THD *thd, 0 on success */ int -JOIN::prepare(Item ***rref_pointer_array, +JOIN::prepare(Ref_ptr_array *rref_pointer_array, TABLE_LIST *tables_init, uint wild_num, Item *conds_init, uint og_num, ORDER *order_init, ORDER *group_init, @@ -647,15 +647,27 @@ JOIN::prepare(Item ***rref_pointer_array table_ptr= table_ptr->next_leaf) tables++; - if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num) || - select_lex->setup_ref_array(thd, og_num) || - setup_fields(thd, (*rref_pointer_array), fields_list, MARK_COLUMNS_READ, - &all_fields, 1) || - setup_without_group(thd, (*rref_pointer_array), tables_list, + if (setup_wild(thd, tables_list, fields_list, &all_fields, wild_num)) + DBUG_RETURN(-1); + // find_order_in_list() may need some extra space, so multiply og_num by two. + if (select_lex->setup_ref_array(thd, og_num * 2)) + DBUG_RETURN(-1); + /* + Item and Item_field CTORs will both increment some counters + in current_select, based on the current parsing context. + We are not parsing anymore: any new Items created now are due to + query rewriting, so stop incrementing counters. + */ + select_lex->parsing_place= NO_MATTER; + + if (setup_fields(thd, *rref_pointer_array, fields_list, MARK_COLUMNS_READ, + &all_fields, 1)) + DBUG_RETURN(-1); + if (setup_without_group(thd, (*rref_pointer_array), tables_list, select_lex->leaf_tables, fields_list, all_fields, &conds, order, group_list, &hidden_group_fields)) - DBUG_RETURN(-1); /* purecov: inspected */ + DBUG_RETURN(-1); ref_pointer_array= *rref_pointer_array; @@ -712,14 +724,14 @@ JOIN::prepare(Item ***rref_pointer_array real_order= TRUE; if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM) - item->split_sum_func(thd, ref_pointer_array, all_fields); + item->split_sum_func(thd, ref_pointer_array.array(), all_fields); } if (!real_order) order= NULL; } if (having && having->with_sum_func) - having->split_sum_func2(thd, ref_pointer_array, all_fields, + having->split_sum_func2(thd, ref_pointer_array.array(), all_fields, &having, TRUE); if (select_lex->inner_sum_func_list) { @@ -728,7 +740,7 @@ JOIN::prepare(Item ***rref_pointer_array do { item_sum= item_sum->next; - item_sum->split_sum_func2(thd, ref_pointer_array, + item_sum->split_sum_func2(thd, ref_pointer_array.array(), all_fields, item_sum->ref_by, FALSE); } while (item_sum != end); } @@ -755,7 +767,7 @@ JOIN::prepare(Item ***rref_pointer_array int el= all_fields.elements; ref_pointer_array[el]= field; all_fields.push_front(field); - ord->item= ref_pointer_array + el; + ord->item= &ref_pointer_array[el]; } } } @@ -824,7 +836,6 @@ JOIN::prepare(Item ***rref_pointer_array /* Init join struct */ count_field_types(select_lex, &tmp_table_param, all_fields, 0); - ref_pointer_array_size= all_fields.elements*sizeof(Item*); this->group= group_list != 0; unit= unit_arg; @@ -3040,7 +3051,8 @@ JOIN::exec() curr_join->all_fields= *curr_all_fields; if (!items1) { - items1= items0 + all_fields.elements; + items1= Ref_ptr_array(&ref_pointer_array[2 * all_fields.elements], + all_fields.elements); if (sort_and_group || curr_tmp_table->group || tmp_table_param.precomputed_group_by) { @@ -3205,7 +3217,8 @@ JOIN::exec() // No sum funcs anymore if (!items2) { - items2= items1 + all_fields.elements; + items2= Ref_ptr_array(&ref_pointer_array[3 * all_fields.elements], + all_fields.elements); if (change_to_use_tmp_fields(thd, items2, tmp_fields_list2, tmp_all_fields2, fields_list.elements, tmp_all_fields1)) @@ -3262,7 +3275,8 @@ JOIN::exec() { if (!items0) init_items_ref_array(); - items3= ref_pointer_array + (all_fields.elements*4); + items3= Ref_ptr_array(&ref_pointer_array[4 * all_fields.elements], + all_fields.elements); setup_copy_fields(thd, &curr_join->tmp_table_param, items3, tmp_fields_list3, tmp_all_fields3, curr_fields_list->elements, *curr_all_fields); @@ -3615,7 +3629,7 @@ void JOIN::cleanup_item_list(List */ bool -mysql_select(THD *thd, Item ***rref_pointer_array, +mysql_select(THD *thd, Ref_ptr_array *rref_pointer_array, TABLE_LIST *tables, uint wild_num, List &fields, Item *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulonglong select_options, @@ -21122,7 +21136,7 @@ cp_buffer_from_ref(THD *thd, TABLE *tabl */ static bool -find_order_in_list(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +find_order_in_list(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, ORDER *order, List &fields, List &all_fields, bool is_group_field) { @@ -21146,7 +21160,7 @@ find_order_in_list(THD *thd, Item **ref_ order_item->full_name(), thd->where); return TRUE; } - order->item= ref_pointer_array + count - 1; + order->item= &ref_pointer_array[count - 1]; order->in_field_list= 1; order->counter= count; order->counter_used= 1; @@ -21207,7 +21221,7 @@ find_order_in_list(THD *thd, Item **ref_ 'shadowed' a table field with the same name, the table field will be chosen over the derived field. */ - order->item= ref_pointer_array + counter; + order->item= &ref_pointer_array[counter]; order->in_field_list=1; return FALSE; } @@ -21265,7 +21279,7 @@ find_order_in_list(THD *thd, Item **ref_ uint el= all_fields.elements; all_fields.push_front(order_item); /* Add new field to field list. */ ref_pointer_array[el]= order_item; - order->item= ref_pointer_array + el; + order->item= &ref_pointer_array[el]; return FALSE; } @@ -21277,7 +21291,7 @@ find_order_in_list(THD *thd, Item **ref_ the field list. */ -int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order) { thd->where="order clause"; @@ -21318,7 +21332,7 @@ int setup_order(THD *thd, Item **ref_poi */ int -setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool *hidden_group_fields) { @@ -21449,13 +21463,14 @@ setup_new_fields(THD *thd, List &f */ ORDER * -create_distinct_group(THD *thd, Item **ref_pointer_array, +create_distinct_group(THD *thd, Ref_ptr_array ref_pointer_array, ORDER *order_list, List &fields, List &all_fields, bool *all_order_by_fields_used) { List_iterator li(fields); - Item *item, **orig_ref_pointer_array= ref_pointer_array; + Item *item; + Ref_ptr_array orig_ref_pointer_array= ref_pointer_array; ORDER *order,*group,**prev; *all_order_by_fields_used= 1; @@ -21509,7 +21524,7 @@ create_distinct_group(THD *thd, Item **r int el= all_fields.elements; orig_ref_pointer_array[el]= new_item; all_fields.push_front(new_item); - ord->item= orig_ref_pointer_array + el; + ord->item= &orig_ref_pointer_array[el]; } else { @@ -21518,14 +21533,14 @@ create_distinct_group(THD *thd, Item **r simple indexing of ref_pointer_array (order in the array and in the list are same) */ - ord->item= ref_pointer_array; + ord->item= &ref_pointer_array[0]; } ord->direction= ORDER::ORDER_ASC; *prev=ord; prev= &ord->next; } next_item: - ref_pointer_array++; + ref_pointer_array.pop_front(); } *prev=0; return group; @@ -21840,7 +21855,7 @@ int test_if_item_cache_changed(List &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) { @@ -22121,7 +22136,7 @@ bool JOIN::make_sum_func_list(List */ static bool -change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array, +change_to_use_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) @@ -22212,7 +22227,7 @@ change_to_use_tmp_fields(THD *thd, Item */ static bool -change_refs_to_tmp_fields(THD *thd, Item **ref_pointer_array, +change_refs_to_tmp_fields(THD *thd, Ref_ptr_array ref_pointer_array, List &res_selected_fields, List &res_all_fields, uint elements, List &all_fields) @@ -22587,15 +22602,20 @@ bool JOIN::rollup_init() */ tmp_table_param.group_parts= send_group_parts; - if (!(rollup.null_items= (Item_null_result**) thd->alloc((sizeof(Item*) + - sizeof(Item**) + - sizeof(List) + - ref_pointer_array_size) - * send_group_parts ))) - return 1; - - rollup.fields= (List*) (rollup.null_items + send_group_parts); - rollup.ref_pointer_arrays= (Item***) (rollup.fields + send_group_parts); + Item_null_result **null_items= + static_cast(thd->alloc(sizeof(Item*)*send_group_parts)); + + rollup.null_items=Item_null_array(null_items, send_group_parts); + rollup.ref_pointer_arrays= + static_cast + (thd->alloc((sizeof(Ref_ptr_array) + + all_fields.elements * sizeof(Item*)) * send_group_parts)); + rollup.fields= + static_cast*>(thd->alloc(sizeof(List) * send_group_parts)); + + if (!rollup.null_items || !rollup.ref_pointer_arrays || !rollup.fields) + return true; + ref_array= (Item**) (rollup.ref_pointer_arrays+send_group_parts); /* @@ -22607,7 +22627,7 @@ bool JOIN::rollup_init() rollup.null_items[i]= new (thd->mem_root) Item_null_result(); List *rollup_fields= &rollup.fields[i]; rollup_fields->empty(); - rollup.ref_pointer_arrays[i]= ref_array; + rollup.ref_pointer_arrays[i]= Ref_ptr_array(ref_array, all_fields.elements); ref_array+= all_fields.elements; } for (i= 0 ; i < send_group_parts; i++) @@ -22753,11 +22773,11 @@ bool JOIN::rollup_make_fields(List bool real_fields= 0; Item *item; List_iterator new_it(rollup.fields[pos]); - Item **ref_array_start= rollup.ref_pointer_arrays[pos]; + Ref_ptr_array ref_array_start= rollup.ref_pointer_arrays[pos]; ORDER *start_group; /* Point to first hidden field */ - Item **ref_array= ref_array_start + fields_arg.elements-1; + Item **ref_array= &ref_array_start[fields_arg.elements-1]; /* Remember where the sum functions ends for the previous level */ sum_funcs_end[pos+1]= *func; @@ -22774,7 +22794,7 @@ bool JOIN::rollup_make_fields(List if (item == first_field) { real_fields= 1; // End of hidden fields - ref_array= ref_array_start; + ref_array= &ref_array_start[0]; } if (item->type() == Item::SUM_FUNC_ITEM && !item->const_item() && @@ -22858,9 +22878,7 @@ int JOIN::rollup_send_data(uint idx) for (i= send_group_parts ; i-- > idx ; ) { /* Get reference pointers to sum functions in place */ - memcpy((char*) ref_pointer_array, - (char*) rollup.ref_pointer_arrays[i], - ref_pointer_array_size); + copy_ref_ptr_array(ref_pointer_array, rollup.ref_pointer_arrays[i]); if ((!having || having->val_int())) { if (send_records < unit->select_limit_cnt && do_send_rows && @@ -22900,9 +22918,7 @@ int JOIN::rollup_write_data(uint idx, TA for (i= send_group_parts ; i-- > idx ; ) { /* Get reference pointers to sum functions in place */ - memcpy((char*) ref_pointer_array, - (char*) rollup.ref_pointer_arrays[i], - ref_pointer_array_size); + copy_ref_ptr_array(ref_pointer_array, rollup.ref_pointer_arrays[i]); if ((!having || having->val_int())) { int write_error; === modified file 'sql/sql_select.h' --- a/sql/sql_select.h 2011-05-26 15:20:09 +0000 +++ b/sql/sql_select.h 2011-05-30 10:44:01 +0000 @@ -1598,12 +1598,14 @@ typedef struct st_position : public Sql_ } POSITION; +typedef Bounds_checked_array Item_null_array; + typedef struct st_rollup { enum State { STATE_NONE, STATE_INITED, STATE_READY }; State state; - Item_null_result **null_items; - Item ***ref_pointer_arrays; + Item_null_array null_items; + Ref_ptr_array *ref_pointer_arrays; List *fields; } ROLLUP; @@ -1879,10 +1881,19 @@ public: FirstMatch strategy. */ JOIN_TAB *return_tab; - Item **ref_pointer_array; /// &all_fields, List &send_fields, bool before_group_by, bool recompute= FALSE); - inline void set_items_ref_array(Item **ptr) + void copy_ref_ptr_array(Ref_ptr_array dst_arr, Ref_ptr_array src_arr) + { + DBUG_ASSERT(dst_arr.size() >= src_arr.size()); + void *dest= dst_arr.array(); + const void *src= src_arr.array(); + memcpy(dest, src, src_arr.size() * src_arr.element_size()); + } + void set_items_ref_array(Ref_ptr_array ptr) { - memcpy((char*) ref_pointer_array, (char*) ptr, ref_pointer_array_size); + copy_ref_ptr_array(ref_pointer_array, ptr); current_ref_pointer_array= ptr; } - inline void init_items_ref_array() + void init_items_ref_array() { - items0= ref_pointer_array + all_fields.elements; - memcpy(items0, ref_pointer_array, ref_pointer_array_size); + items0= Ref_ptr_array(&ref_pointer_array[all_fields.elements], + all_fields.elements); + copy_ref_ptr_array(items0, Ref_ptr_array(&ref_pointer_array[0], + all_fields.elements)); current_ref_pointer_array= items0; } @@ -2074,7 +2098,7 @@ void free_tmp_table(THD *thd, TABLE *ent void count_field_types(SELECT_LEX *select_lex, TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param, - Item **ref_pointer_array, + Ref_ptr_array ref_pointer_array, List &new_list1, List &new_list2, uint elements, List &fields); void copy_fields(TMP_TABLE_PARAM *param); @@ -2263,17 +2287,17 @@ Item *remove_eq_conds(THD *thd, Item *co int get_quick_record(SQL_SELECT *select); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length, SORT_FIELD *sortorder); -int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +int setup_order(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order); -int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, +int setup_group(THD *thd, Ref_ptr_array ref_pointer_array, TABLE_LIST *tables, List &fields, List &all_fields, ORDER *order, bool *hidden_group_fields); bool fix_inner_refs(THD *thd, List &all_fields, SELECT_LEX *select, - Item **ref_pointer_array, ORDER *group_list= NULL); + Ref_ptr_array ref_pointer_array, ORDER *group_list= NULL); bool handle_select(THD *thd, LEX *lex, select_result *result, ulong setup_tables_done_option); -bool mysql_select(THD *thd, Item ***rref_pointer_array, +bool mysql_select(THD *thd, Ref_ptr_array *rref_pointer_array, TABLE_LIST *tables, uint wild_num, List &list, Item *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, ulonglong select_type, === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2011-05-26 15:20:09 +0000 +++ b/sql/sql_update.cc 2011-05-30 10:44:01 +0000 @@ -328,7 +328,8 @@ int mysql_update(THD *thd, table_list->grant.want_privilege= table->grant.want_privilege= want_privilege; table_list->register_want_access(want_privilege); #endif - if (setup_fields_with_no_wrap(thd, 0, fields, MARK_COLUMNS_WRITE, 0, 0)) + if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), + fields, MARK_COLUMNS_WRITE, 0, 0)) DBUG_RETURN(1); /* purecov: inspected */ if (table_list->view && check_fields(thd, fields)) { @@ -359,7 +360,7 @@ int mysql_update(THD *thd, table_list->grant.want_privilege= table->grant.want_privilege= (SELECT_ACL & ~table->grant.privilege); #endif - if (setup_fields(thd, 0, values, MARK_COLUMNS_READ, 0, 0)) + if (setup_fields(thd, Ref_ptr_array(), values, MARK_COLUMNS_READ, 0, 0)) { free_underlaid_joins(thd, select_lex); DBUG_RETURN(1); /* purecov: inspected */ @@ -1148,7 +1149,8 @@ int mysql_multi_update_prepare(THD *thd) UPDATE_ACL, SELECT_ACL)) DBUG_RETURN(TRUE); - if (setup_fields_with_no_wrap(thd, 0, *fields, MARK_COLUMNS_WRITE, 0, 0)) + if (setup_fields_with_no_wrap(thd, Ref_ptr_array(), + *fields, MARK_COLUMNS_WRITE, 0, 0)) DBUG_RETURN(TRUE); for (tl= table_list; tl ; tl= tl->next_local) @@ -1422,7 +1424,8 @@ int multi_update::prepare(List &no reference tables */ - int error= setup_fields(thd, 0, *values, MARK_COLUMNS_READ, 0, 0); + int error= setup_fields(thd, Ref_ptr_array(), + *values, MARK_COLUMNS_READ, 0, 0); for (table_ref= leaves; table_ref; table_ref= table_ref->next_leaf) { === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-05-18 08:29:46 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-05-30 10:44:01 +0000 @@ -205,6 +205,7 @@ ENDIF() # Add tests (link them with gunit library) SET(TESTS bounded_queue + bounds_checked_array dbug dynarray mdl === added file 'unittest/gunit/bounds_checked_array-t.cc' --- a/unittest/gunit/bounds_checked_array-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/bounds_checked_array-t.cc 2011-05-30 10:44:01 +0000 @@ -0,0 +1,117 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include "sql_array.h" + +namespace { + +typedef Bounds_checked_array Int_array; + +class BoundsCheckedArray : public ::testing::Test +{ +public: + BoundsCheckedArray() : some_integer(0) {} + + virtual void SetUp() + { + for (int ix= 0; ix < c_array_size; ++ix) + c_array[ix]= ix; + } + + static const int c_array_size= 5; + int c_array[c_array_size]; + + int some_integer; + Int_array int_array; +}; + +TEST_F(BoundsCheckedArray, Empty) +{ + EXPECT_EQ(sizeof(int), int_array.element_size()); + EXPECT_EQ(0U, int_array.size()); + if (int_array) ADD_FAILURE() << "operator bool() should have returned false"; + int *pi= NULL; + EXPECT_EQ(pi, int_array.array()); +} + +#if !defined(DBUG_OFF) + +// Google Test recommends DeathTest suffix for classes used in death tests. +typedef BoundsCheckedArray BoundsCheckedArrayDeathTest; + +TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckRead) +{ + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + int_array= Int_array(c_array, 2); + EXPECT_DEATH_IF_SUPPORTED(some_integer= int_array[5], + ".*Assertion .*n < m_size.*"); +} + +TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckAssign) +{ + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + int_array= Int_array(c_array, 2); + EXPECT_DEATH_IF_SUPPORTED(int_array[5]= some_integer, + ".*Assertion .*n < m_size.*"); +} + +TEST_F(BoundsCheckedArrayDeathTest, BoundsCheckPopFront) +{ + ::testing::FLAGS_gtest_death_test_style = "threadsafe"; + int_array= Int_array(c_array, 1); + int_array.pop_front(); + EXPECT_DEATH_IF_SUPPORTED(int_array.pop_front(), + ".*Assertion .*m_size > 0.*"); +} + +#endif // !defined(DBUG_OFF) + +TEST_F(BoundsCheckedArray, Indexing) +{ + int_array= Int_array(c_array, c_array_size); + EXPECT_EQ(0, int_array[0]); + int_array[0]= 42; + EXPECT_EQ(42, int_array[0]); +} + + +TEST_F(BoundsCheckedArray, Reset) +{ + int_array= Int_array(c_array, c_array_size); + EXPECT_EQ(c_array, int_array.array()); + if (!int_array) ADD_FAILURE() << "operator bool() should have returned true"; + int_array.reset(); + int *pi= NULL; + EXPECT_EQ(pi, int_array.array()); + if (int_array) ADD_FAILURE() << "operator bool() should have returned false"; +} + + +TEST_F(BoundsCheckedArray, PopFront) +{ + int_array= Int_array(c_array, c_array_size); + for (int ix= 0; ix < c_array_size; ++ix) + { + EXPECT_EQ(ix, int_array[0]); + int_array.pop_front(); + } +} + +} // namespace --===============2896752961140822213== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # hogb7z5uw44k55y0 # target_branch: file:///export/home/didrik/repo/trunk-bug11765255-\ # arraycheck/ # testament_sha1: bb56897c760f0675a702a74c7d2016f5fa3f6400 # timestamp: 2011-05-30 12:44:10 +0200 # base_revision_id: alexander.nozdrin@stripped\ # hg5jaxisod09ltjh # # Begin bundle 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 --===============2896752961140822213==--