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

Reading from freed memory when running main.view with --ps-protocol

Details

    Description

      test case from main.view +ps-protocol

       
      create table t1 (s1 int);
      prepare stmt from "create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;";
      execute stmt;
      prepare stmt from "select * from v1;";
      execute stmt;
      

      10.3 08b0b70daa43a539d91

      Version: '10.3.28-MariaDB-debug-log'  socket: '/git/10.3/mysql-test/var/tmp/mysqld.1.sock'  port: 16000  Source distribution
      =================================================================
      ==56422==ERROR: AddressSanitizer: use-after-poison on address 0x62b000000b98 at pc 0x7fd1bfe6d550 bp 0x7fd1b54b73f0 sp 0x7fd1b54b6ba0
      READ of size 10 at 0x62b000000b98 thread T5
          #0 0x7fd1bfe6d54f  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa854f)
          #1 0x561328021f6c in Item_basic_constant::cleanup() /git/10.3/sql/item.h:2493
          #2 0x5613281dbd9b in Item::delete_self() /git/10.3/sql/item.h:2008
          #3 0x5613281c1ef6 in Query_arena::free_items() /git/10.3/sql/sql_class.cc:3724
          #4 0x56132832ae6d in Prepared_statement::~Prepared_statement() /git/10.3/sql/sql_prepare.cc:4038
          #5 0x56132832b1ed in Prepared_statement::~Prepared_statement() /git/10.3/sql/sql_prepare.cc:4047
          #6 0x5613281c3500 in delete_statement_as_hash_key /git/10.3/sql/sql_class.cc:3864
          #7 0x561329f8640e in my_hash_delete /git/10.3/mysys/hash.c:632
          #8 0x5613281c3ad6 in Statement_map::erase(Statement*) /git/10.3/sql/sql_class.cc:3979
          #9 0x561328333e5f in Prepared_statement::deallocate() /git/10.3/sql/sql_prepare.cc:5146
          #10 0x5613283242f0 in mysql_sql_stmt_prepare(THD*) /git/10.3/sql/sql_prepare.cc:2867
          #11 0x5613282c2792 in mysql_execute_command(THD*) /git/10.3/sql/sql_parse.cc:3858
          #12 0x5613282ded30 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /git/10.3/sql/sql_parse.cc:7839
          #13 0x5613282b53cf in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /git/10.3/sql/sql_parse.cc:1852
          #14 0x5613282b1b0a in do_command(THD*) /git/10.3/sql/sql_parse.cc:1398
          #15 0x5613286a1c6c in do_handle_one_connection(CONNECT*) /git/10.3/sql/sql_connect.cc:1403
          #16 0x5613286a1524 in handle_one_connection /git/10.3/sql/sql_connect.cc:1308
          #17 0x561329e03f92 in pfs_spawn_thread /git/10.3/storage/perfschema/pfs.cc:1869
          #18 0x7fd1bfdabfa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
          #19 0x7fd1bf72f4ce in clone (/lib/x86_64-linux-gnu/libc.so.6+0xf94ce)
       
      0x62b000000b98 is located 2456 bytes inside of 24716-byte region [0x62b000000200,0x62b00000628c)
      allocated by thread T5 here:
          #0 0x7fd1bfeae330 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
          #1 0x56132a018396 in sf_malloc /git/10.3/mysys/safemalloc.c:118
          #2 0x561329fe78d0 in my_malloc /git/10.3/mysys/my_malloc.c:101
          #3 0x561329fc3e56 in reset_root_defaults /git/10.3/mysys/my_alloc.c:152
          #4 0x5613281ad619 in THD::init_for_queries() /git/10.3/sql/sql_class.cc:1340
          #5 0x5613286a0e5d in prepare_new_connection_state(THD*) /git/10.3/sql/sql_connect.cc:1239
          #6 0x5613286a156a in thd_prepare_connection(THD*) /git/10.3/sql/sql_connect.cc:1323
          #7 0x5613286a1b97 in do_handle_one_connection(CONNECT*) /git/10.3/sql/sql_connect.cc:1393
          #8 0x5613286a1524 in handle_one_connection /git/10.3/sql/sql_connect.cc:1308
          #9 0x561329e03f92 in pfs_spawn_thread /git/10.3/storage/perfschema/pfs.cc:1869
          #10 0x7fd1bfdabfa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
       
      Thread T5 created by T0 here:
          #0 0x7fd1bfe15db0 in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x50db0)
          #1 0x561329e043ce in spawn_thread_v1 /git/10.3/storage/perfschema/pfs.cc:1919
          #2 0x561327fc56f4 in inline_mysql_thread_create /git/10.3/include/mysql/psi/mysql_thread.h:1275
          #3 0x561327fdeba8 in create_thread_to_handle_connection(CONNECT*) /git/10.3/sql/mysqld.cc:6658
          #4 0x561327fdf2fd in create_new_thread /git/10.3/sql/mysqld.cc:6728
          #5 0x561327fe047e in handle_connections_sockets() /git/10.3/sql/mysqld.cc:6986
          #6 0x561327fddf1c in mysqld_main(int, char**) /git/10.3/sql/mysqld.cc:6280
          #7 0x561327fc3df4 in main /git/10.3/sql/main.cc:25
          #8 0x7fd1bf65a09a in __libc_start_main ../csu/libc-start.c:308
       
      SUMMARY: AddressSanitizer: use-after-poison (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa854f) 
      Shadow bytes around the buggy address:
        0x0c567fff8120: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8130: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8140: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8150: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8160: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
      =>0x0c567fff8170: f7 f7 f7[f7]f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8180: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff8190: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff81a0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff81b0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c567fff81c0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
      Shadow byte legend (one shadow byte represents 8 application bytes):
        Addressable:           00
        Partially addressable: 01 02 03 04 05 06 07 
        Heap left redzone:       fa
        Freed heap region:       fd
        Stack left redzone:      f1
        Stack mid redzone:       f2
        Stack right redzone:     f3
        Stack after return:      f5
        Stack use after scope:   f8
        Global redzone:          f9
        Global init order:       f6
        Poisoned by user:        f7
        Container overflow:      fc
        Array cookie:            ac
        Intra object redzone:    bb
        ASan internal:           fe
        Left alloca redzone:     ca
        Right alloca redzone:    cb
      ==56422==ABORTING
      ----------SERVER LOG END-------------
      

      10.4 7effcb8ed6a9fd75452

      Version: '10.4.18-MariaDB-debug-log'  socket: '/git/10.4/mysql-test/var/tmp/mysqld.1.sock'  port: 16000  Source distribution
      =================================================================
      ==58044==ERROR: AddressSanitizer: use-after-poison on address 0x62b000062b88 at pc 0x7f1151601550 bp 0x7f1147ac4500 sp 0x7f1147ac3cb0
      READ of size 10 at 0x62b000062b88 thread T5
          #0 0x7f115160154f  (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa854f)
          #1 0x5633a668cf3c in Item::cleanup() /git/10.4/sql/item.cc:548
          #2 0x5633a5d7f381 in Item::delete_self() /git/10.4/sql/item.h:2214
          #3 0x5633a5d647f8 in Query_arena::free_items() /git/10.4/sql/sql_class.cc:3793
          #4 0x5633a5ed50e9 in Prepared_statement::~Prepared_statement() /git/10.4/sql/sql_prepare.cc:4061
          #5 0x5633a5ed5469 in Prepared_statement::~Prepared_statement() /git/10.4/sql/sql_prepare.cc:4070
          #6 0x5633a5d65e02 in delete_statement_as_hash_key /git/10.4/sql/sql_class.cc:3933
          #7 0x5633a792e302 in my_hash_delete /git/10.4/mysys/hash.c:632
          #8 0x5633a5d663d8 in Statement_map::erase(Statement*) /git/10.4/sql/sql_class.cc:4048
          #9 0x5633a5edd9e5 in Prepared_statement::deallocate() /git/10.4/sql/sql_prepare.cc:5119
          #10 0x5633a5ece7f5 in mysql_sql_stmt_prepare(THD*) /git/10.4/sql/sql_prepare.cc:2886
          #11 0x5633a5e6fd8e in mysql_execute_command(THD*) /git/10.4/sql/sql_parse.cc:3936
          #12 0x5633a5e8b5a0 in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /git/10.4/sql/sql_parse.cc:7938
          #13 0x5633a5e62812 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /git/10.4/sql/sql_parse.cc:1839
          #14 0x5633a5e5f291 in do_command(THD*) /git/10.4/sql/sql_parse.cc:1357
          #15 0x5633a623e32a in do_handle_one_connection(CONNECT*) /git/10.4/sql/sql_connect.cc:1412
          #16 0x5633a623dbcc in handle_one_connection /git/10.4/sql/sql_connect.cc:1316
          #17 0x5633a787a4d0 in pfs_spawn_thread /git/10.4/storage/perfschema/pfs.cc:1869
          #18 0x7f115153ffa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
          #19 0x7f1150b464ce in clone (/lib/x86_64-linux-gnu/libc.so.6+0xf94ce)
       
      0x62b000062b88 is located 2440 bytes inside of 24716-byte region [0x62b000062200,0x62b00006828c)
      allocated by thread T5 here:
          #0 0x7f1151642330 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xe9330)
          #1 0x5633a79c0ac4 in sf_malloc /git/10.4/mysys/safemalloc.c:118
          #2 0x5633a798ffd6 in my_malloc /git/10.4/mysys/my_malloc.c:101
          #3 0x5633a796bfd7 in reset_root_defaults /git/10.4/mysys/my_alloc.c:152
          #4 0x5633a5d4fdb9 in THD::init_for_queries() /git/10.4/sql/sql_class.cc:1392
          #5 0x5633a623d56c in prepare_new_connection_state(THD*) /git/10.4/sql/sql_connect.cc:1247
          #6 0x5633a623dc12 in thd_prepare_connection(THD*) /git/10.4/sql/sql_connect.cc:1331
          #7 0x5633a623e255 in do_handle_one_connection(CONNECT*) /git/10.4/sql/sql_connect.cc:1402
          #8 0x5633a623dbcc in handle_one_connection /git/10.4/sql/sql_connect.cc:1316
          #9 0x5633a787a4d0 in pfs_spawn_thread /git/10.4/storage/perfschema/pfs.cc:1869
          #10 0x7f115153ffa2 in start_thread /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
       
      Thread T5 created by T0 here:
          #0 0x7f11515a9db0 in __interceptor_pthread_create (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x50db0)
          #1 0x5633a787a8bd in spawn_thread_v1 /git/10.4/storage/perfschema/pfs.cc:1919
          #2 0x5633a5b7c7b5 in inline_mysql_thread_create /git/10.4/include/mysql/psi/mysql_thread.h:1275
          #3 0x5633a5b93b10 in create_thread_to_handle_connection(CONNECT*) /git/10.4/sql/mysqld.cc:6259
          #4 0x5633a5b94265 in create_new_thread(CONNECT*) /git/10.4/sql/mysqld.cc:6329
          #5 0x5633a5b9473f in handle_accepted_socket(st_mysql_socket, st_mysql_socket) /git/10.4/sql/mysqld.cc:6427
          #6 0x5633a5b955ec in handle_connections_sockets() /git/10.4/sql/mysqld.cc:6585
          #7 0x5633a5b93274 in mysqld_main(int, char**) /git/10.4/sql/mysqld.cc:5917
          #8 0x5633a5b7a684 in main /git/10.4/sql/main.cc:25
          #9 0x7f1150a7109a in __libc_start_main ../csu/libc-start.c:308
       
      SUMMARY: AddressSanitizer: use-after-poison (/usr/lib/x86_64-linux-gnu/libasan.so.5+0xa854f) 
      Shadow bytes around the buggy address:
        0x0c5680004520: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004530: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004540: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004550: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004560: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
      =>0x0c5680004570: f7[f7]f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004580: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c5680004590: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c56800045a0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c56800045b0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
        0x0c56800045c0: f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7 f7
      Shadow byte legend (one shadow byte represents 8 application bytes):
        Addressable:           00
        Partially addressable: 01 02 03 04 05 06 07 
        Heap left redzone:       fa
        Freed heap region:       fd
        Stack left redzone:      f1
        Stack mid redzone:       f2
        Stack right redzone:     f3
        Stack after return:      f5
        Stack use after scope:   f8
        Global redzone:          f9
        Global init order:       f6
        Poisoned by user:        f7
        Container overflow:      fc
        Array cookie:            ac
        Intra object redzone:    bb
        ASan internal:           fe
        Left alloca redzone:     ca
        Right alloca redzone:    cb
      ==58044==ABORTING
      ----------SERVER LOG END-------------
      
      

      Attachments

        Activity

          igor Igor Babaev (Inactive) added a comment - - edited

          Let's consider the test case

          create table t1 (s1 int);
          prepare stmt from "
          create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
          ";
          execute stmt;
          deallocate prepare stmt;
          

          and see how we come to the reported problem when the server executes the statement

          deallocate prepare stmt;
          

          1. When the server executes the statement

          prepare stmt from "
          create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
          ";
          

          it parses the command

          create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
          

          Doing so it calls the function st_select_lex::add_item_to_list() for all 3 elements of the select list
          's1', s1, 1.
          As a result the pointers to the items' trees are pushed into the list lex->current_select->item_list.
          For the first item we have:

          (gdb) p dbug_print_item(item)
          $4 = 0x55555757cca0 <dbug_item_print_buf> "'s1'"
          (gdb) p item->orig_name
          $5 = 0x0
          (gdb) p item->name
          $6 = {str = 0x7fffd4124b70 "s1", length = 2}
          

          For the second item we have:

          (gdb) p dbug_print_item(item)
          $7 = 0x55555757cca0 <dbug_item_print_buf> "s1"
          (gdb) p item->orig_name
          $8 = 0x0
          (gdb) p item->name
          $9 = {str = 0x7fffd4186bf0 "s1", length = 2}
          

          For the third item we have:

          (gdb) p dbug_print_item(item)
          $10 = 0x55555757cca0 <dbug_item_print_buf> "1"
          (gdb) p item->orig_name
          $11 = 0x0
          (gdb) p item->name
          $12 = {str = 0x7fffd4073840 "1", length = 1}
          

          Yet for the third item we additionally call Item::set_name() that changes item->name

          (gdb) p name
          $13 = {str = 0x7fffd4076e90 "My_exp_s1", length = 9}
          

          All these items and names are allocated in lex->thd->mem_root used for the query

          (gdb) p thd->query()
          $14 = 0x7fffd4067a20 "create view v1 as select 's1', s1, 1 as My_exp_s1 from t1"
          

          In my case the address of this mem_root was:

          (gdb) p thd->mem_root
          $16 = (MEM_ROOT *) 0x7fffd413b5b0
          

          igor Igor Babaev (Inactive) added a comment - - edited Let's consider the test case create table t1 (s1 int ); prepare stmt from " create view v1 as select 's1', s1, 1 as My_exp_s1 from t1; " ; execute stmt; deallocate prepare stmt; and see how we come to the reported problem when the server executes the statement deallocate prepare stmt; 1. When the server executes the statement prepare stmt from " create view v1 as select 's1', s1, 1 as My_exp_s1 from t1; " ; it parses the command create view v1 as select 's1' , s1, 1 as My_exp_s1 from t1; Doing so it calls the function st_select_lex::add_item_to_list() for all 3 elements of the select list 's1', s1, 1. As a result the pointers to the items' trees are pushed into the list lex->current_select->item_list. For the first item we have: (gdb) p dbug_print_item(item) $4 = 0x55555757cca0 <dbug_item_print_buf> "'s1'" (gdb) p item->orig_name $5 = 0x0 (gdb) p item->name $6 = {str = 0x7fffd4124b70 "s1", length = 2} For the second item we have: (gdb) p dbug_print_item(item) $7 = 0x55555757cca0 <dbug_item_print_buf> "s1" (gdb) p item->orig_name $8 = 0x0 (gdb) p item->name $9 = {str = 0x7fffd4186bf0 "s1", length = 2} For the third item we have: (gdb) p dbug_print_item(item) $10 = 0x55555757cca0 <dbug_item_print_buf> "1" (gdb) p item->orig_name $11 = 0x0 (gdb) p item->name $12 = {str = 0x7fffd4073840 "1", length = 1} Yet for the third item we additionally call Item::set_name() that changes item->name (gdb) p name $13 = {str = 0x7fffd4076e90 "My_exp_s1", length = 9} All these items and names are allocated in lex->thd->mem_root used for the query (gdb) p thd->query() $14 = 0x7fffd4067a20 "create view v1 as select 's1', s1, 1 as My_exp_s1 from t1" In my case the address of this mem_root was: (gdb) p thd->mem_root $16 = (MEM_ROOT *) 0x7fffd413b5b0
          igor Igor Babaev (Inactive) added a comment - - edited

          2. We come to execution of the statement:

          execute stmt;
          

          that brings us to a call of the function Prepared_statement::execute(). The latter brings us to a call of mysql_create_view(). This function calls check_duplicate_names() for the specification of the view:

          $23 = 0x55555757cca0 <dbug_item_print_buf> "select 's1' AS s1,t1.s1 AS s1,1 AS My_exp_s1 from test.t1"
          

          Here the function sees that the name for the first item is the name for the second item and it generates the new name for the first item as 'My_exp_s1'. At the same time the orig_name for the first item is set to 's1'. Then the function notices that the new name for the first item coincides with the name for the third item and it renames the first item for 'My_exp_1_s1' setting orig_name for the first to ''My_exp_s1'.
          Bare in mind that allocation of these generated names is done in thd->mem_root used 'execute stmt'.
          in my case it was

          (gdb) p thd->mem_root
          $14 = (MEM_ROOT *) 0x7fffd4006168
          

          At the end of the above mentioned invocation of Prepared_statement::execute() the function Prepared_statement::cleanup_stmt() is called that brings us to the statement

            cleanup_items(free_list);
          

          First it cleans up the item

          (gdb) p dbug_print_item(item)
          $1 = 0x55555757cca0 <dbug_item_print_buf> "1"
          (gdb) p item->orig_name
          $2 = 0x0
          (gdb) p item->name
          $3 = {str = 0x7fffd4075d90 "My_exp_s1", length = 9}
          

          Here nothing is actually done as item->orig_name == 0.
          For the second item

          (gdb) p dbug_print_item(item)
          $4 = 0x55555757cca0 <dbug_item_print_buf> "t1.s1"
          (gdb) p item->orig_name
          $5 = 0x0
          (gdb) p item->name
          $6 = {str = 0x7fffd4029d00 "s1", length = 2}
          

          the function Item_field::cleanup() is called.
          For the third item

          (gdb) p dbug_print_item(item)
          $7 = 0x55555757cca0 <dbug_item_print_buf> "'s1'"
          (gdb) p item->orig_name
          $8 = 0x7fffd417d3e0 "My_exp_s1"
          (gdb) p item->name
          $9 = {str = 0x7fffd4139be0 "My_exp_1_s1", length = 11}
          

          Item_basic_constant::cleanup() is called that sets item->name to item->orig_name.
          Note that item->name and item->orig_name belong to different mem_roots and this is not good.

          igor Igor Babaev (Inactive) added a comment - - edited 2. We come to execution of the statement: execute stmt; that brings us to a call of the function Prepared_statement::execute(). The latter brings us to a call of mysql_create_view(). This function calls check_duplicate_names() for the specification of the view: $23 = 0x55555757cca0 <dbug_item_print_buf> "select 's1' AS s1,t1.s1 AS s1,1 AS My_exp_s1 from test.t1" Here the function sees that the name for the first item is the name for the second item and it generates the new name for the first item as 'My_exp_s1'. At the same time the orig_name for the first item is set to 's1'. Then the function notices that the new name for the first item coincides with the name for the third item and it renames the first item for 'My_exp_1_s1' setting orig_name for the first to ''My_exp_s1'. Bare in mind that allocation of these generated names is done in thd->mem_root used 'execute stmt'. in my case it was (gdb) p thd->mem_root $14 = (MEM_ROOT *) 0x7fffd4006168 At the end of the above mentioned invocation of Prepared_statement::execute() the function Prepared_statement::cleanup_stmt() is called that brings us to the statement cleanup_items(free_list); First it cleans up the item (gdb) p dbug_print_item(item) $1 = 0x55555757cca0 <dbug_item_print_buf> "1" (gdb) p item->orig_name $2 = 0x0 (gdb) p item->name $3 = {str = 0x7fffd4075d90 "My_exp_s1", length = 9} Here nothing is actually done as item->orig_name == 0. For the second item (gdb) p dbug_print_item(item) $4 = 0x55555757cca0 <dbug_item_print_buf> "t1.s1" (gdb) p item->orig_name $5 = 0x0 (gdb) p item->name $6 = {str = 0x7fffd4029d00 "s1", length = 2} the function Item_field::cleanup() is called. For the third item (gdb) p dbug_print_item(item) $7 = 0x55555757cca0 <dbug_item_print_buf> "'s1'" (gdb) p item->orig_name $8 = 0x7fffd417d3e0 "My_exp_s1" (gdb) p item->name $9 = {str = 0x7fffd4139be0 "My_exp_1_s1", length = 11} Item_basic_constant::cleanup() is called that sets item->name to item->orig_name. Note that item->name and item->orig_name belong to different mem_roots and this is not good.

          3. At the end of execution of the command

          execute stmt;
          

          the mem_root used for this execution is freed. This is the root

          (gdb) p root
          $4 = (MEM_ROOT *) 0x7fffd4006168
          

          After we have done with the execution of the statement

          execute stmt;
          

          we move to the execution of the statement

          deallocate prepare stmt;
          

          The function Prepared_statement::deallocate() is called that calls Statement_map::erase() that calls indirectly Prepared_statement::~Prepared_statement(). The latter calls the function Query_arena::free_items() that frees the item allocated when the CREATE VIEW statement was parsed.
          The first item in the free_list is

          (gdb) p dbug_print_item(free_list)
          $3 = 0x55555757cca0 <dbug_item_print_buf> "1"
          

          Item_basic_constant::cleanup() is called. As orig_name is 0 for it we do nothing.
          The second item in the free_list is

          (gdb) p dbug_print_item(free_list)
          $4 = 0x55555757cca0 <dbug_item_print_buf> "s1"
          

          Item_field::cleanup() works fine for it.
          The third item in the free_list is

          (gdb) p dbug_print_item(free_list)
          $5 = 0x55555757cca0 <dbug_item_print_buf> "'s1'"
          

          Item_basic_constant::cleanup() is called. As orig_name is

          (gdb) p orig_name
          $6 = 0x7fffd417d3e0 "My_exp_s1"
          

          the code

          if (orig_name)
          {
            name.str=    orig_name;
            name.length= strlen(orig_name);
          }
          

          is executed. Yet the value of the orig_name was allocated in the mem_root that has been already freed.

          igor Igor Babaev (Inactive) added a comment - 3. At the end of execution of the command execute stmt; the mem_root used for this execution is freed. This is the root (gdb) p root $4 = (MEM_ROOT *) 0x7fffd4006168 After we have done with the execution of the statement execute stmt; we move to the execution of the statement deallocate prepare stmt; The function Prepared_statement::deallocate() is called that calls Statement_map::erase() that calls indirectly Prepared_statement::~Prepared_statement(). The latter calls the function Query_arena::free_items() that frees the item allocated when the CREATE VIEW statement was parsed. The first item in the free_list is (gdb) p dbug_print_item(free_list) $3 = 0x55555757cca0 <dbug_item_print_buf> "1" Item_basic_constant::cleanup() is called. As orig_name is 0 for it we do nothing. The second item in the free_list is (gdb) p dbug_print_item(free_list) $4 = 0x55555757cca0 <dbug_item_print_buf> "s1" Item_field::cleanup() works fine for it. The third item in the free_list is (gdb) p dbug_print_item(free_list) $5 = 0x55555757cca0 <dbug_item_print_buf> "'s1'" Item_basic_constant::cleanup() is called. As orig_name is (gdb) p orig_name $6 = 0x7fffd417d3e0 "My_exp_s1" the code if (orig_name) { name.str= orig_name; name.length= strlen(orig_name); } is executed. Yet the value of the orig_name was allocated in the mem_root that has been already freed.
          igor Igor Babaev (Inactive) added a comment - - edited

          A fix would be not to reset the value of orig_name in the function make_unique_view_field_name()

          -  target->orig_name= target->name.str;
          +  if (!target->orig_name)
          +    target->orig_name= target->name.str;
          

          In this case we know that orig_name was set only once and it set to the value of name_str that is allocated in the mem_root used for the prepared statement.
          With this change we see that for our test case that when the item

          (gdb) p dbug_print_item(free_list)
          $1 = 0x55555757cca0 <dbug_item_print_buf> "'s1'"
          

          is freed in the destructor of the prepared statement the value of the orig_name is

          (gdb) p orig_name
          $2 = 0x7fffd4186660 "s1"
          

          and this value is allocated in the mem_root that is used when CREATE VIEW is parsed.

          igor Igor Babaev (Inactive) added a comment - - edited A fix would be not to reset the value of orig_name in the function make_unique_view_field_name() - target->orig_name= target->name.str; + if (!target->orig_name) + target->orig_name= target->name.str; In this case we know that orig_name was set only once and it set to the value of name_str that is allocated in the mem_root used for the prepared statement. With this change we see that for our test case that when the item (gdb) p dbug_print_item(free_list) $1 = 0x55555757cca0 <dbug_item_print_buf> "'s1'" is freed in the destructor of the prepared statement the value of the orig_name is (gdb) p orig_name $2 = 0x7fffd4186660 "s1" and this value is allocated in the mem_root that is used when CREATE VIEW is parsed.

          If I add another another 'execute stmt' to the test case:

          create table t1 (s1 int);
          prepare stmt from "
          create view v1 as select 's1', s1, 1 as My_exp_s1 from t1;
          ";
          execute stmt;
          --error ER_TABLE_EXISTS_ERROR
          execute stmt;
          deallocate prepare stmt;
          show create view v1;
          select * from v1;
          drop view v1;
          drop table t1;
          

          then I have additionally problems of reading from freed memory when executing this second 'execute stmt'. For example I have additionally this invalid reading:

          ==22339== Invalid read of size 1
          ==22339==    at 0x95F8FD: check_column_name(char const*) (table.cc:4333)
          ==22339==    by 0x94A5B0: make_valid_column_names(THD*, List<Item>&) (sql_view.cc:184)
          ==22339==    by 0x94B4D9: mysql_create_view(THD*, TABLE_LIST*, enum_view_create_mode) (sql_view.cc:577)
          ==22339==    by 0x83F3AF: mysql_execute_command(THD*) (sql_parse.cc:5898)
          ==22339==    by 0x864F1B: Prepared_statement::execute(String*, bool) (sql_prepare.cc:5027)
          ==22339==    by 0x8631C7: Prepared_statement::execute_loop(String*, bool, unsigned char*, unsigned char*) (sql_prepare.cc:4455)
          ==22339==    by 0x860BAD: mysql_sql_stmt_execute(THD*) (sql_prepare.cc:3545)
          ==22339==    by 0x8379E3: mysql_execute_command(THD*) (sql_parse.cc:3886)
          ==22339==    by 0x8451BE: mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) (sql_parse.cc:7870)
          

          igor Igor Babaev (Inactive) added a comment - If I add another another 'execute stmt' to the test case: create table t1 (s1 int ); prepare stmt from " create view v1 as select 's1', s1, 1 as My_exp_s1 from t1; " ; execute stmt; --error ER_TABLE_EXISTS_ERROR execute stmt; deallocate prepare stmt; show create view v1; select * from v1; drop view v1; drop table t1; then I have additionally problems of reading from freed memory when executing this second 'execute stmt'. For example I have additionally this invalid reading: ==22339== Invalid read of size 1 ==22339== at 0x95F8FD: check_column_name(char const*) (table.cc:4333) ==22339== by 0x94A5B0: make_valid_column_names(THD*, List<Item>&) (sql_view.cc:184) ==22339== by 0x94B4D9: mysql_create_view(THD*, TABLE_LIST*, enum_view_create_mode) (sql_view.cc:577) ==22339== by 0x83F3AF: mysql_execute_command(THD*) (sql_parse.cc:5898) ==22339== by 0x864F1B: Prepared_statement::execute(String*, bool) (sql_prepare.cc:5027) ==22339== by 0x8631C7: Prepared_statement::execute_loop(String*, bool, unsigned char*, unsigned char*) (sql_prepare.cc:4455) ==22339== by 0x860BAD: mysql_sql_stmt_execute(THD*) (sql_prepare.cc:3545) ==22339== by 0x8379E3: mysql_execute_command(THD*) (sql_parse.cc:3886) ==22339== by 0x8451BE: mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) (sql_parse.cc:7870)

          OK to push

          sanja Oleksandr Byelkin added a comment - OK to push

          Let's figure out whether we need a similar change in the following code of make_valid_column_names()

            for (uint column_no= 1; (item= it++); column_no++)
            {
              if (!item->is_autogenerated_name || !check_column_name(item->name.str))
                continue;
              name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no);
              item->orig_name= item->name.str;
              item->set_name(thd, buff, name_len, system_charset_info);
            }
          

          Consider the following test case:

          create table t1 (s1 int);
          prepare stmt from "
          create view v1 as 
          select 
          's0123456789012345678901234567890123456789012345678901234567890123456789',
           s1,
           1 as My_exp_s1 from t1;
          ";
          execute stmt;
          deallocate prepare stmt;
          drop view v1;
          drop table t1;
          

          See what happens the item

          (gdb) p dbug_print_item(item)
          $3 = 0x55555757cca0 <dbug_item_print_buf> "'s0123456789012345678901234567890123456789012345678901234567890123456789'"
          (gdb) p item->name
          $1 = {str = 0x7fffd4071770 "s0123456789012345678901234567890123456789012345678901234567890123456789", length = 71}
          

          is processed in make_valid_column_names().
          As length > NAME_CHAR_LEN item->orig_name is set to item->name.str. Once item->orig_name is set to a value not equal to 0 it will never be reset in when the CREATE VIEW command is executed due to the suggested fix.

          igor Igor Babaev (Inactive) added a comment - Let's figure out whether we need a similar change in the following code of make_valid_column_names() for (uint column_no= 1; (item= it++); column_no++) { if (!item->is_autogenerated_name || !check_column_name(item->name.str)) continue; name_len= my_snprintf(buff, NAME_LEN, "Name_exp_%u", column_no); item->orig_name= item->name.str; item->set_name(thd, buff, name_len, system_charset_info); } Consider the following test case: create table t1 (s1 int ); prepare stmt from " create view v1 as select 's0123456789012345678901234567890123456789012345678901234567890123456789', s1, 1 as My_exp_s1 from t1; " ; execute stmt; deallocate prepare stmt; drop view v1; drop table t1; See what happens the item (gdb) p dbug_print_item(item) $3 = 0x55555757cca0 <dbug_item_print_buf> "'s0123456789012345678901234567890123456789012345678901234567890123456789'" (gdb) p item->name $1 = {str = 0x7fffd4071770 "s0123456789012345678901234567890123456789012345678901234567890123456789", length = 71} is processed in make_valid_column_names(). As length > NAME_CHAR_LEN item->orig_name is set to item->name.str. Once item->orig_name is set to a value not equal to 0 it will never be reset in when the CREATE VIEW command is executed due to the suggested fix.

          A fix for this bug was pushed into 10.3

          igor Igor Babaev (Inactive) added a comment - A fix for this bug was pushed into 10.3

          People

            igor Igor Babaev (Inactive)
            alice Alice Sherepa
            Votes:
            0 Vote for this issue
            Watchers:
            5 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.