[MDEV-24777] ASAN memcpy-param-overlap in copy_if_not_alloced upon SELECT with a mix of functions Created: 2021-02-03  Updated: 2023-04-27

Status: Open
Project: MariaDB Server
Component/s: Server
Affects Version/s: 10.2, 10.3, 10.4, 10.5, 10.6
Fix Version/s: 10.4, 10.5

Type: Bug Priority: Major
Reporter: Elena Stepanova Assignee: Oleksandr Byelkin
Resolution: Unresolved Votes: 0
Labels: None


 Description   

CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (0),(4);
SELECT DECODE(RIGHT(CONVERT(-2817, CHAR), a), 1) AS f FROM t1;
 
# Cleanup
DROP TABLE t1;

10.2 6ede84f4

==3793785==ERROR: AddressSanitizer: memcpy-param-overlap: memory ranges [0x7fa731de65e0,0x7fa731de65e4) and [0x7fa731de65e1, 0x7fa731de65e5) overlap
    #0 0x7fa73d03f19e  (/lib/x86_64-linux-gnu/libasan.so.5+0x9b19e)
    #1 0x5557637bdf3a in copy_if_not_alloced(String*, String*, unsigned int) /data/src/10.2/sql/sql_string.cc:972
    #2 0x555763db87dd in Item_func_encode::val_str(String*) /data/src/10.2/sql/item_strfunc.cc:2289
    #3 0x555763c679cc in Item::send(Protocol*, String*) /data/src/10.2/sql/item.cc:6898
    #4 0x5557633a030f in Protocol::send_result_set_row(List<Item>*) /data/src/10.2/sql/protocol.cc:992
    #5 0x555763507b3a in select_send::send_data(List<Item>&) /data/src/10.2/sql/sql_class.cc:2734
    #6 0x5557636f07be in end_send /data/src/10.2/sql/sql_select.cc:20031
    #7 0x5557636e92d8 in evaluate_join_record /data/src/10.2/sql/sql_select.cc:19079
    #8 0x5557636e82db in sub_select(JOIN*, st_join_table*, bool) /data/src/10.2/sql/sql_select.cc:18898
    #9 0x5557636e5d33 in do_select /data/src/10.2/sql/sql_select.cc:18403
    #10 0x55576367fec6 in JOIN::exec_inner() /data/src/10.2/sql/sql_select.cc:3642
    #11 0x55576367d9dd in JOIN::exec() /data/src/10.2/sql/sql_select.cc:3437
    #12 0x5557636811e5 in mysql_select(THD*, TABLE_LIST*, unsigned int, List<Item>&, Item*, unsigned int, st_order*, st_order*, Item*, st_order*, unsigned long long, select_result*, st_select_lex_unit*, st_select_lex*) /data/src/10.2/sql/sql_select.cc:3837
    #13 0x55576365dc87 in handle_select(THD*, LEX*, select_result*, unsigned long) /data/src/10.2/sql/sql_select.cc:361
    #14 0x5557635d4b72 in execute_sqlcom_select /data/src/10.2/sql/sql_parse.cc:6248
    #15 0x5557635c1b17 in mysql_execute_command(THD*) /data/src/10.2/sql/sql_parse.cc:3559
    #16 0x5557635de0ef in mysql_parse(THD*, char*, unsigned int, Parser_state*, bool, bool) /data/src/10.2/sql/sql_parse.cc:7763
    #17 0x5557635b7134 in dispatch_command(enum_server_command, THD*, char*, unsigned int, bool, bool) /data/src/10.2/sql/sql_parse.cc:1827
    #18 0x5557635b3ef3 in do_command(THD*) /data/src/10.2/sql/sql_parse.cc:1381
    #19 0x55576393c774 in do_handle_one_connection(CONNECT*) /data/src/10.2/sql/sql_connect.cc:1336
    #20 0x55576393c037 in handle_one_connection /data/src/10.2/sql/sql_connect.cc:1241
    #21 0x555764cd84b7 in pfs_spawn_thread /data/src/10.2/storage/perfschema/pfs.cc:1869
    #22 0x7fa73cb4a608 in start_thread /build/glibc-ZN95T4/glibc-2.31/nptl/pthread_create.c:477
    #23 0x7fa73c724292 in __clone (/lib/x86_64-linux-gnu/libc.so.6+0x122292)
 
Address 0x7fa731de65e0 is located in stack of thread T5 at offset 224 in frame
    #0 0x5557633a0129 in Protocol::send_result_set_row(List<Item>*) /data/src/10.2/sql/protocol.cc:983
 
  This frame has 4 object(s):
    [32, 64) 'str_buffer' (line 985)
    [96, 128) 'it' (line 986)
    [160, 192) '_db_stack_frame_' (line 988)
    [224, 990) 'buffer' (line 984) <== Memory access at offset 224 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
Thread T5 created by T0 here:
    #0 0x7fa73cfde805 in pthread_create (/lib/x86_64-linux-gnu/libasan.so.5+0x3a805)
    #1 0x555764cd88a8 in spawn_thread_v1 /data/src/10.2/storage/perfschema/pfs.cc:1919
    #2 0x555763359083 in inline_mysql_thread_create /data/src/10.2/include/mysql/psi/mysql_thread.h:1246
    #3 0x555763370c54 in create_thread_to_handle_connection(CONNECT*) /data/src/10.2/sql/mysqld.cc:6573
    #4 0x5557633713ef in create_new_thread /data/src/10.2/sql/mysqld.cc:6643
    #5 0x555763372581 in handle_connections_sockets() /data/src/10.2/sql/mysqld.cc:6901
    #6 0x55576336ffa5 in mysqld_main(int, char**) /data/src/10.2/sql/mysqld.cc:6192
    #7 0x55576335793c in main /data/src/10.2/sql/main.cc:25
    #8 0x7fa73c6290b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
 
Address 0x7fa731de65e1 is located in stack of thread T5 at offset 225 in frame
    #0 0x5557633a0129 in Protocol::send_result_set_row(List<Item>*) /data/src/10.2/sql/protocol.cc:983
 
  This frame has 4 object(s):
    [32, 64) 'str_buffer' (line 985)
    [96, 128) 'it' (line 986)
    [160, 192) '_db_stack_frame_' (line 988)
    [224, 990) 'buffer' (line 984) <== Memory access at offset 225 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: memcpy-param-overlap (/lib/x86_64-linux-gnu/libasan.so.5+0x9b19e) 
==3793785==ABORTING

Reproducible on 10.1+.
No obvious immediate effect on a non-ASAN build (although it's hard to say for sure whether SELECT returns a correct result, due to the nature of the SELECT).

Note this output at the end of ASAN report:

  This frame has 4 object(s):
    [32, 64) 'str_buffer' (line 985)
    [96, 128) 'it' (line 986)
    [160, 192) '_db_stack_frame_' (line 988)
    [224, 990) 'buffer' (line 984) <== Memory access at offset 225 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)

I can't say whether the disclaimer about possible false positiveness applies to this case.



 Comments   
Comment by Marko Mäkelä [ 2021-02-03 ]

As far as I can tell, the error is being flagged for the following code:

  if ((to->str_length=MY_MIN(from->str_length,from_length)))
    memcpy(to->Ptr,from->Ptr,to->str_length);

The comment before the declaration of copy_if_not_alloced() seems to suggest that the from_length bytes starting at from->Ptr are supposed to be read but not written (except on a successful from->realloc()).

If the intention is to copy possibly overlapping bytes, then the correct function to call should be memmove().

Generated at Thu Feb 08 09:32:35 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.