From: Alexander Nozdrin Date: April 25 2011 2:12pm Subject: bzr commit into mysql-5.5 branch (alexander.nozdrin:3458) Bug#12374486 List-Archive: http://lists.mysql.com/commits/136011 X-Bug: 12374486 Message-Id: <201104251412.p3PECetO024228@acsmt357.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1585536764418109859==" --===============1585536764418109859== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/alik/MySQL/bzr/00/bug12374486/mysql-5.5-bug12374486/ based on revid:jon.hauglid@stripped 3458 Alexander Nozdrin 2011-04-25 Patch for Bug#12374486 - SEVERE MEMORY LEAK IN PREPARED STATEMENTS THAT CALL STORED PROCEDURES. The bug was introduced by WL#4435. The problem was that if a stored procedure generated a few result sets with different set of columns, a new memory would be allocated after every EXECUTE for every result set. The fix is to introduce a new memory root in scope of MYSQL_STMT, and to store result-set metadata in that memory root. modified: include/mysql.h include/mysql.h.pp libmysql/libmysql.c === modified file 'include/mysql.h' --- a/include/mysql.h 2010-11-20 22:56:09 +0000 +++ b/include/mysql.h 2011-04-25 14:12:29 +0000 @@ -573,6 +573,8 @@ typedef struct st_mysql_bind } MYSQL_BIND; +struct st_mysql_stmt_extension; + /* statement handler */ typedef struct st_mysql_stmt { @@ -618,7 +620,7 @@ typedef struct st_mysql_stmt metadata fields when doing mysql_stmt_store_result. */ my_bool update_max_length; - void *extension; + struct st_mysql_stmt_extension *extension; } MYSQL_STMT; enum enum_stmt_attr_type === modified file 'include/mysql.h.pp' --- a/include/mysql.h.pp 2011-02-11 14:00:09 +0000 +++ b/include/mysql.h.pp 2011-04-25 14:12:29 +0000 @@ -512,6 +512,7 @@ typedef struct st_mysql_bind my_bool is_null_value; void *extension; } MYSQL_BIND; +struct st_mysql_stmt_extension; typedef struct st_mysql_stmt { MEM_ROOT mem_root; @@ -541,7 +542,7 @@ typedef struct st_mysql_stmt unsigned char bind_result_done; my_bool unbuffered_fetch_cancelled; my_bool update_max_length; - void *extension; + struct st_mysql_stmt_extension *extension; } MYSQL_STMT; enum enum_stmt_attr_type { === modified file 'libmysql/libmysql.c' --- a/libmysql/libmysql.c 2011-03-08 17:39:25 +0000 +++ b/libmysql/libmysql.c 2011-04-25 14:12:29 +0000 @@ -94,6 +94,18 @@ sig_handler my_pipe_sig_handler(int sig) static my_bool mysql_client_init= 0; static my_bool org_my_init_done= 0; +typedef struct st_mysql_stmt_extension +{ + my_bool fields_mem_root_initialized; + MEM_ROOT fields_mem_root; +} MYSQL_STMT_EXT; + + +static inline MYSQL_STMT_EXT *get_stmt_exension(MYSQL_STMT *stmt) +{ + return (MYSQL_STMT_EXT *) stmt->extension; +} + /* Initialize the MySQL client library @@ -1478,6 +1490,7 @@ MYSQL_STMT * STDCALL mysql_stmt_init(MYSQL *mysql) { MYSQL_STMT *stmt; + MYSQL_STMT_EXT *stmt_ext; DBUG_ENTER("mysql_stmt_init"); if (!(stmt= (MYSQL_STMT *) my_malloc(sizeof(MYSQL_STMT), @@ -1497,6 +1510,11 @@ mysql_stmt_init(MYSQL *mysql) stmt->read_row_func= stmt_read_row_no_result_set; stmt->prefetch_rows= DEFAULT_PREFETCH_ROWS; strmov(stmt->sqlstate, not_error_sqlstate); + + stmt_ext= alloc_root(&stmt->mem_root, sizeof (MYSQL_STMT_EXT)); + stmt_ext->fields_mem_root_initialized= FALSE; + + stmt->extension= stmt_ext; /* The rest of statement members was bzeroed inside malloc */ DBUG_RETURN(stmt); @@ -1541,6 +1559,8 @@ int STDCALL mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, ulong length) { MYSQL *mysql= stmt->mysql; + MYSQL_STMT_EXT *stmt_ext= get_stmt_exension(stmt); + DBUG_ENTER("mysql_stmt_prepare"); if (!mysql) @@ -1571,6 +1591,11 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, con stmt->bind_param_done= stmt->bind_result_done= FALSE; stmt->param_count= stmt->field_count= 0; free_root(&stmt->mem_root, MYF(MY_KEEP_PREALLOC)); + if (stmt_ext->fields_mem_root_initialized) + { + free_root(&stmt_ext->fields_mem_root, MYF(MY_KEEP_PREALLOC)); + stmt_ext->fields_mem_root_initialized= FALSE; + } int4store(buff, stmt->stmt_id); @@ -1631,12 +1656,17 @@ mysql_stmt_prepare(MYSQL_STMT *stmt, con static void alloc_stmt_fields(MYSQL_STMT *stmt) { MYSQL_FIELD *fields, *field, *end; - MEM_ROOT *alloc= &stmt->mem_root; + MYSQL_STMT_EXT *stmt_ext= get_stmt_exension(stmt); + MEM_ROOT *alloc= &stmt_ext->fields_mem_root; MYSQL *mysql= stmt->mysql; - DBUG_ASSERT(mysql->field_count); + DBUG_ASSERT(stmt->field_count); - stmt->field_count= mysql->field_count; + if (stmt_ext->fields_mem_root_initialized) + free_root(&stmt_ext->fields_mem_root, MYF(0)); + + init_alloc_root(&stmt_ext->fields_mem_root, 2048, 2048); + stmt_ext->fields_mem_root_initialized= TRUE; /* Get the field information for non-select statements @@ -2387,6 +2417,9 @@ static void reinit_result_set_metadata(M prepared statements can't send result set metadata for these queries on prepare stage. Read it now. */ + + stmt->field_count= stmt->mysql->field_count; + alloc_stmt_fields(stmt); } else @@ -2404,7 +2437,7 @@ static void reinit_result_set_metadata(M previous branch always works. TODO: send metadata only when it's really necessary and add a warning 'Metadata changed' when it's sent twice. - */ + */ update_stmt_fields(stmt); } } @@ -4600,12 +4633,19 @@ my_bool STDCALL mysql_stmt_free_result(M my_bool STDCALL mysql_stmt_close(MYSQL_STMT *stmt) { MYSQL *mysql= stmt->mysql; + MYSQL_STMT_EXT *stmt_ext= get_stmt_exension(stmt); int rc= 0; DBUG_ENTER("mysql_stmt_close"); free_root(&stmt->result.alloc, MYF(0)); free_root(&stmt->mem_root, MYF(0)); + if (stmt_ext->fields_mem_root_initialized) + { + free_root(&stmt_ext->fields_mem_root, MYF(0)); + stmt_ext->fields_mem_root_initialized= FALSE; + } + if (mysql) { mysql->stmts= list_delete(mysql->stmts, &stmt->list); @@ -4805,16 +4845,13 @@ int STDCALL mysql_stmt_next_result(MYSQL stmt->state= MYSQL_STMT_EXECUTE_DONE; stmt->bind_result_done= FALSE; + stmt->field_count= mysql->field_count; if (mysql->field_count) { alloc_stmt_fields(stmt); prepare_to_fetch_result(stmt); } - else - { - stmt->field_count= mysql->field_count; - } DBUG_RETURN(0); } --===============1585536764418109859== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/alexander.nozdrin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alexander.nozdrin@stripped\ # z5txne0w12a6jwk4 # target_branch: file:///home/alik/MySQL/bzr/00/bug12374486/mysql-5.5-\ # bug12374486/ # testament_sha1: 93317b0f1b811aef12c1aa552715988696f7bdb8 # timestamp: 2011-04-25 18:12:32 +0400 # base_revision_id: jon.hauglid@stripped\ # wqkqx1u7jjw06jrh # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWXQYlF8ABADfgFAQWXf//3/v /+C////6YAic6TPjpdh0DgT3MBQp00yAJJTKninhPU1T9KPaaZTyk9Q/SnlNAABtJoABoDSiZDJo aBkZNAA0aZGhkDQAAADRT0ZJlNDU09TTI0BoANAGhoAaADQJEQmiqf6NJhFP0o/VG1PSaAaaGgGQ GnqNB6R+qHAMIwmmIYBAMgBhGmTJhGAhoJJAQCYIDSaMU9BJ6ptPRT1PUGgGjQA2pIjic23ua4bD ju38rGeMEcIhqkOI7vR39Ziddo6ueymVHR8mWwbtydh0qRBhOqcGzGs+XA5DSWTQlYSrJaB2lcxp ovmU3wM27cjI6g/axSLoIiUEKjIsMwJeLD9cmrEjFr8C/RdCaE2m03XuQd9McKcKLp6Y7G2TO+lb Kz4kK3Hqr616FjHGCSxBleIuQpNntI3K6KxeKPqmq5UXN4cbxllm40A1pdXLgPpo27F+VaZ6TGae shjrhQHWfeLoko05HOmpu/eTfYzWfYKcSfZcSMbIFJdItTI3xk7DNmo0OJhQmar8fp2aQ2ZZd7Rt /d1sm1st6cT6ROYSq5fQjPrRwNLiJoluiVi68fqgcJHmDMM0qPoyDSUJIh7Gw2m47gCB1O4oTDAG 89s35rmFcYeEzWmBfnhGEHfG6xWoCbhWh5JFi35KF1C718Tpc6YG1kQi4A695JPhtDqa3sDpgwgb g/Fl1zVgZMSgoZj91ZS1WmRQw4l61wKiYS5p8iZ/tSJytrgWYCKfhZeA9lJmuj52I++0cl/ByFRo XcpJKppQjJ9oiP3+/Mprjrfg2OwRK/Ix1Uby/WlAi63wRpgu3fFWFXi0TY7D5uyvRt4hOkvRcNFf FApQDAV2JUqgQzjKKjPuHXKBGRE0A1s7bQfwTrBIoYimGcVREV5GsnVgWzhVQIzpgAd5gRsKziYm oZe4styolTZIenYsMEq9RbUbKHNJxNOao+FWPdwfQSpphLnpx3H5TNCFFeGT3xSZzWsTelgwihk5 RYRlS8nodDZGNG06WD1KUioeFhhmOncNELgvnepxmUwU5FXIdUC4dh/SBRCds0TnOu0WYvlHiNg6 ikdScdsYHuQ1DDxlrhA2UhKRuHWaNYfl6c+e+00PqItLmzyfsOxGN2wxdnziZDzWUF5WQZU0s51h 5QsGpcV4bbkUKF8tChXCNVb2vc7uHFQUed5jfS+l5iqZFb5SIPaZYaEDURxxRKBqOxipq61mi1rJ 40zwHl8HWmtw8NZApGeYtPVXfeY15zrabq9Vo+8JCKC3IrIyNdd8CykpYplhaQCgqJUkwxIzJy25 NbTSxoMi2pYDUXzjZXCJCICtpQ4dAwFbB+Tt5eOT6qJxFFEvRqJpu8wbMAoKr3rQlUiVAvB+S7fC hFz47LFI1eV/Sv65+nf8GxbmxtvzY8P7bhQ++/2+pnnplzg6PRf1BTL/spee0DuULXjHfXTnShLX MRKzMBEL822htyc3OGpW03ls8COrYIjjbXGx3K5WcZq+XQIyi4h34N6mFdcS76q+vKRf04AQH0e3 DffFkEZiX1xAwygZCOf9OaHJC597kwwDC/ESchvQevFJdoiPijFzbG+75foJgT5vPpIdBA0PRyPE oaTQeOW8gAnEEmYcCedGIAwk/sBAdEL5mtU20W9AL5FdaD4uOklvG1bJ8X04yKEu/A5476jkLz6d HS45xiU5ceK7Vrf9cQwdHPkRYpIj418IGksY99hmDYbTz/D8BiO3lWailmQDj3Y4IDX6bUWI8Su9 bWK2WS4ct9fUxoRBDfYFKICKkaGeHA5moxL7iu0FTpkGzd/U9QWAljoq/AtkWu3dqU3lc52sgCJi Ibs9Z+OJ4ypu6ah50nFeaksm8HXqwTlqOVtekTKk1FoGbseklxC2xrb8rTZydyaf/HHckGyvaINu tcQYWCOCZG2r7DCTAnEH4Y9d9RfcWKKuB7n8xhUlOAL3CRYkyPUzKulqZmy4hUZ9TyHnPZweHg2d R3FKICHsmYOZZJwWVGBY8MrT7nV3H7VuM70pbmXjzmrsqqTyPY6b/RMypHGsCBBfNZlTdp+BbvSD xq7m6FxiPArrBzvXj+bzSkndEgnw72PFGlXmTQXUE7WGSKj/ArMo3AMv59t8eKQRw2iz9WAx65UK 4Bm2uNx0PgdyvW+CimEci4RyNgqzsrq3s9C7wzChEDkXTF70gnVCAYUOFaQ6/xMYqziQXMFeoGTV mORc4AbsPPE9IxSVnVVrcHvYRzXdm5uZ4V42KqgOAkHld9xtLdJ3veuHAb5tki/NjMGAh7GglIeK pxrusQxME9BGG65TNiKm1IzkJUswMKKZGwcrDdsPtfoDBO07DuZP2MMkgsA7JkizdYkiLXH1QFQD lRU/FMViXyZB2pkcMEiVS50q8GTI2Dwm8DTktqt4+3NuKyhcxieHEtWAg0kpl8mahgBySNHanlaf FBdqWpzgxN6lz8QVSrapazRVTEMyQ+iUUOHCkcob6hKN+V9OmVeVLzWKVBiYQq9JiGTudq8Lb2iD O6Hu8njVBv5ecawhFFPz1izGrI2ilFzFTvODPM/I6oijoQYchkegJh8ZR5kJD3M4HFHGHClIUU8D RExUhQzx3ODhkHfpgK6xxKp4DvLAdWJBI5OAuEyLpvRQ/qIz+R5HzXRUovIdvo167Fx9uezFVb4I fbtq9cJ1rMiwrT4cnpvRUCPbQyMB0RFI6w96zLNCpYlwJpjgkYiGHCA3FzCjiSoHiCsRjrBWnG5C iWZ6i/3cRzOb/4u5IpwoSDoMSi+A --===============1585536764418109859==--