andrey Thu, 29 Apr 2010 15:49:51 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=298781
Log: Handle OOM cases, in case of persistent connections this is real and the Zend MM won't help. Changed paths: U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd.c U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_priv.h U php/php-src/trunk/ext/mysqlnd/mysqlnd.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_priv.h
Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd.c 2010-04-29 15:47:41 UTC (rev 298780) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd.c 2010-04-29 15:49:51 UTC (rev 298781) @@ -61,6 +61,7 @@ PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away"; PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now"; +PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory"; PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL; static zend_bool mysqlnd_library_initted = FALSE; @@ -524,16 +525,25 @@ transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port); } + if (!transport) { + goto err; /* OOM */ + } DBG_INF_FMT("transport=%s", transport); conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent); conn->scheme_len = transport_len; efree(transport); /* allocated by spprintf */ transport = NULL; + if (!conn->scheme) { + goto err; /* OOM */ + } } greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE TSRMLS_CC); auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); + if (!greet_packet || !auth_packet || !ok_packet) { + goto err; /* OOM */ + } if (FAIL == conn->net->m.connect(conn->net, conn->scheme, conn->scheme_len, conn->persistent, &errstr, &errcode TSRMLS_CC)) { goto err; @@ -602,6 +612,9 @@ auth_packet->client_flags= mysql_flags; conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent); + if (!conn->scramble) { + goto err; /* OOM */ + } memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH); if (!PACKET_WRITE(auth_packet, conn)) { @@ -668,20 +681,35 @@ conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); conn->connect_or_select_db_len = db_len; + if (!conn->user || !conn->passwd || !conn->connect_or_select_db) { + goto err; /* OOM */ + } + if (!unix_socket) { - conn->host = mnd_pestrdup(host, conn->persistent); + if (!conn->host) { + goto err; /* OOM */ + } conn->host_len = strlen(conn->host); { char *p; spprintf(&p, 0, "%s via TCP/IP", conn->host); + if (!p) { + goto err; /* OOM */ + } conn->host_info = mnd_pestrdup(p, conn->persistent); efree(p); /* allocated by spprintf */ + if (!conn->host_info) { + goto err; /* OOM */ + } } } else { conn->unix_socket = mnd_pestrdup(socket, conn->persistent); + conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); + if (!conn->unix_socket || !conn->host_info) { + goto err; /* OOM */ + } conn->unix_socket_len = strlen(conn->unix_socket); - conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); } conn->client_flag = auth_packet->client_flags; conn->max_packet_size = auth_packet->max_packet_size; @@ -720,15 +748,17 @@ unsigned int current_command = 0; for (; current_command < conn->options.num_commands; ++current_command) { const char * const command = conn->options.init_commands[current_command]; - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT); - if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) { - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT); - goto err; + if (command) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT); + if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT); + goto err; + } + if (conn->last_query_type == QUERY_SELECT) { + MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC); + result->m.free_result(result, TRUE TSRMLS_CC); + } } - if (conn->last_query_type == QUERY_SELECT) { - MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC); - result->m.free_result(result, TRUE TSRMLS_CC); - } } } @@ -782,6 +812,7 @@ if (!conn) { self_alloced = TRUE; if (!(conn = mysqlnd_init(FALSE))) { + /* OOM */ DBG_RETURN(NULL); } } @@ -1110,7 +1141,8 @@ result->m.fetch_row = result->m.fetch_row_normal_unbuffered; result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED)); if (!result->unbuf) { - DBG_ERR("OOM"); + /* OOM */ + SET_OOM_ERROR(conn->error_info); result->m.free_result(result, TRUE TSRMLS_CC); DBG_RETURN(NULL); } @@ -1252,6 +1284,11 @@ } conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); conn->connect_or_select_db_len = db_len; + if (!conn->connect_or_select_db) { + /* OOM */ + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + } } DBG_RETURN(ret); } @@ -1860,10 +1897,16 @@ } } if (ret == PASS) { - mnd_pefree(conn->user, conn->persistent); + if (conn->user) { + mnd_pefree(conn->user, conn->persistent); + } conn->user = mnd_pestrndup(user, user_len, conn->persistent); - mnd_pefree(conn->passwd, conn->persistent); + + if (conn->passwd) { + mnd_pefree(conn->passwd, conn->persistent); + } conn->passwd = mnd_pestrdup(passwd, conn->persistent); + if (conn->last_message) { mnd_pefree(conn->last_message, conn->persistent); conn->last_message = NULL; @@ -1896,6 +1939,7 @@ const char * const value TSRMLS_DC) { + enum_func_status ret = PASS; DBG_ENTER("mysqlnd_conn::set_client_option"); DBG_INF_FMT("conn=%llu option=%d", conn->thread_id, option); switch (option) { @@ -1915,7 +1959,7 @@ case MYSQL_OPT_CONNECT_TIMEOUT: case MYSQLND_OPT_NET_CMD_BUFFER_SIZE: case MYSQLND_OPT_NET_READ_BUFFER_SIZE: - conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); + ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); break; #if PHP_MAJOR_VERSION >= 6 case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE: @@ -1943,11 +1987,11 @@ conn->options.init_commands = mnd_perealloc(conn->options.init_commands, sizeof(char *) * (conn->options.num_commands + 1), conn->persistent); if (!conn->options.init_commands) { - DBG_RETURN(FAIL); + goto oom; } conn->options.init_commands[conn->options.num_commands] = mnd_pestrdup(value, conn->persistent); if (!conn->options.init_commands[conn->options.num_commands]) { - DBG_RETURN(FAIL); + goto oom; } ++conn->options.num_commands; break; @@ -1966,6 +2010,9 @@ conn->options.charset_name = NULL; } conn->options.charset_name = mnd_pestrdup(value, conn->persistent); + if (!conn->options.charset_name) { + goto oom; + } DBG_INF_FMT("charset=%s", conn->options.charset_name); break; #ifdef WHEN_SUPPORTED_BY_MYSQLI @@ -1990,9 +2037,12 @@ /* not sure, todo ? */ #endif default: - DBG_RETURN(FAIL); + ret = FAIL; } - DBG_RETURN(PASS); + DBG_RETURN(ret); +oom: + SET_OOM_ERROR(conn->error_info); + DBG_RETURN(FAIL); } /* }}} */ @@ -2176,6 +2226,9 @@ DBG_ENTER("mysqlnd_init"); DBG_INF_FMT("persistent=%d", persistent); + if (!ret) { + DBG_RETURN(NULL); + } ret->persistent = persistent; ret->m = mysqlnd_conn_methods; Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_priv.h =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_priv.h 2010-04-29 15:47:41 UTC (rev 298780) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_priv.h 2010-04-29 15:49:51 UTC (rev 298781) @@ -127,6 +127,9 @@ strlcpy(error_info.error, (c), sizeof(error_info.error)); \ } +#define SET_OOM_ERROR(error_info) SET_CLIENT_ERROR(error_info, CR_OUT_OF_MEMORY, UNKNOWN_SQLSTATE, mysqlnd_out_of_memory) + + #define SET_STMT_ERROR(stmt, a, b, c) SET_CLIENT_ERROR(stmt->error_info, a, b, c) @@ -157,6 +160,7 @@ PHPAPI extern const char * const mysqlnd_old_passwd; PHPAPI extern const char * const mysqlnd_out_of_sync; PHPAPI extern const char * const mysqlnd_server_gone; +PHPAPI extern const char * const mysqlnd_out_of_memory; enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC); Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd.c 2010-04-29 15:47:41 UTC (rev 298780) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd.c 2010-04-29 15:49:51 UTC (rev 298781) @@ -61,6 +61,7 @@ PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away"; PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now"; +PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory"; PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL; static zend_bool mysqlnd_library_initted = FALSE; @@ -524,16 +525,25 @@ transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port); } + if (!transport) { + goto err; /* OOM */ + } DBG_INF_FMT("transport=%s", transport); conn->scheme = mnd_pestrndup(transport, transport_len, conn->persistent); conn->scheme_len = transport_len; efree(transport); /* allocated by spprintf */ transport = NULL; + if (!conn->scheme) { + goto err; /* OOM */ + } } greet_packet = conn->protocol->m.get_greet_packet(conn->protocol, FALSE TSRMLS_CC); auth_packet = conn->protocol->m.get_auth_packet(conn->protocol, FALSE TSRMLS_CC); ok_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); + if (!greet_packet || !auth_packet || !ok_packet) { + goto err; /* OOM */ + } if (FAIL == conn->net->m.connect(conn->net, conn->scheme, conn->scheme_len, conn->persistent, &errstr, &errcode TSRMLS_CC)) { goto err; @@ -602,6 +612,9 @@ auth_packet->client_flags= mysql_flags; conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent); + if (!conn->scramble) { + goto err; /* OOM */ + } memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH); if (!PACKET_WRITE(auth_packet, conn)) { @@ -668,20 +681,35 @@ conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); conn->connect_or_select_db_len = db_len; + if (!conn->user || !conn->passwd || !conn->connect_or_select_db) { + goto err; /* OOM */ + } + if (!unix_socket) { - conn->host = mnd_pestrdup(host, conn->persistent); + if (!conn->host) { + goto err; /* OOM */ + } conn->host_len = strlen(conn->host); { char *p; spprintf(&p, 0, "%s via TCP/IP", conn->host); + if (!p) { + goto err; /* OOM */ + } conn->host_info = mnd_pestrdup(p, conn->persistent); efree(p); /* allocated by spprintf */ + if (!conn->host_info) { + goto err; /* OOM */ + } } } else { conn->unix_socket = mnd_pestrdup(socket, conn->persistent); + conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); + if (!conn->unix_socket || !conn->host_info) { + goto err; /* OOM */ + } conn->unix_socket_len = strlen(conn->unix_socket); - conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); } conn->client_flag = auth_packet->client_flags; conn->max_packet_size = auth_packet->max_packet_size; @@ -720,15 +748,17 @@ unsigned int current_command = 0; for (; current_command < conn->options.num_commands; ++current_command) { const char * const command = conn->options.init_commands[current_command]; - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT); - if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) { - MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT); - goto err; + if (command) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_EXECUTED_COUNT); + if (PASS != conn->m->query(conn, command, strlen(command) TSRMLS_CC)) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_INIT_COMMAND_FAILED_COUNT); + goto err; + } + if (conn->last_query_type == QUERY_SELECT) { + MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC); + result->m.free_result(result, TRUE TSRMLS_CC); + } } - if (conn->last_query_type == QUERY_SELECT) { - MYSQLND_RES * result = conn->m->use_result(conn TSRMLS_CC); - result->m.free_result(result, TRUE TSRMLS_CC); - } } } @@ -782,6 +812,7 @@ if (!conn) { self_alloced = TRUE; if (!(conn = mysqlnd_init(FALSE))) { + /* OOM */ DBG_RETURN(NULL); } } @@ -1110,7 +1141,8 @@ result->m.fetch_row = result->m.fetch_row_normal_unbuffered; result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED)); if (!result->unbuf) { - DBG_ERR("OOM"); + /* OOM */ + SET_OOM_ERROR(conn->error_info); result->m.free_result(result, TRUE TSRMLS_CC); DBG_RETURN(NULL); } @@ -1252,6 +1284,11 @@ } conn->connect_or_select_db = mnd_pestrndup(db, db_len, conn->persistent); conn->connect_or_select_db_len = db_len; + if (!conn->connect_or_select_db) { + /* OOM */ + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + } } DBG_RETURN(ret); } @@ -1860,10 +1897,16 @@ } } if (ret == PASS) { - mnd_pefree(conn->user, conn->persistent); + if (conn->user) { + mnd_pefree(conn->user, conn->persistent); + } conn->user = mnd_pestrndup(user, user_len, conn->persistent); - mnd_pefree(conn->passwd, conn->persistent); + + if (conn->passwd) { + mnd_pefree(conn->passwd, conn->persistent); + } conn->passwd = mnd_pestrdup(passwd, conn->persistent); + if (conn->last_message) { mnd_pefree(conn->last_message, conn->persistent); conn->last_message = NULL; @@ -1896,6 +1939,7 @@ const char * const value TSRMLS_DC) { + enum_func_status ret = PASS; DBG_ENTER("mysqlnd_conn::set_client_option"); DBG_INF_FMT("conn=%llu option=%d", conn->thread_id, option); switch (option) { @@ -1915,7 +1959,7 @@ case MYSQL_OPT_CONNECT_TIMEOUT: case MYSQLND_OPT_NET_CMD_BUFFER_SIZE: case MYSQLND_OPT_NET_READ_BUFFER_SIZE: - conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); + ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); break; #if PHP_MAJOR_VERSION >= 6 case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE: @@ -1943,11 +1987,11 @@ conn->options.init_commands = mnd_perealloc(conn->options.init_commands, sizeof(char *) * (conn->options.num_commands + 1), conn->persistent); if (!conn->options.init_commands) { - DBG_RETURN(FAIL); + goto oom; } conn->options.init_commands[conn->options.num_commands] = mnd_pestrdup(value, conn->persistent); if (!conn->options.init_commands[conn->options.num_commands]) { - DBG_RETURN(FAIL); + goto oom; } ++conn->options.num_commands; break; @@ -1966,6 +2010,9 @@ conn->options.charset_name = NULL; } conn->options.charset_name = mnd_pestrdup(value, conn->persistent); + if (!conn->options.charset_name) { + goto oom; + } DBG_INF_FMT("charset=%s", conn->options.charset_name); break; #ifdef WHEN_SUPPORTED_BY_MYSQLI @@ -1990,9 +2037,12 @@ /* not sure, todo ? */ #endif default: - DBG_RETURN(FAIL); + ret = FAIL; } - DBG_RETURN(PASS); + DBG_RETURN(ret); +oom: + SET_OOM_ERROR(conn->error_info); + DBG_RETURN(FAIL); } /* }}} */ @@ -2176,6 +2226,9 @@ DBG_ENTER("mysqlnd_init"); DBG_INF_FMT("persistent=%d", persistent); + if (!ret) { + DBG_RETURN(NULL); + } ret->persistent = persistent; ret->m = mysqlnd_conn_methods; Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_priv.h =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_priv.h 2010-04-29 15:47:41 UTC (rev 298780) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_priv.h 2010-04-29 15:49:51 UTC (rev 298781) @@ -127,6 +127,9 @@ strlcpy(error_info.error, (c), sizeof(error_info.error)); \ } +#define SET_OOM_ERROR(error_info) SET_CLIENT_ERROR(error_info, CR_OUT_OF_MEMORY, UNKNOWN_SQLSTATE, mysqlnd_out_of_memory) + + #define SET_STMT_ERROR(stmt, a, b, c) SET_CLIENT_ERROR(stmt->error_info, a, b, c) @@ -157,6 +160,7 @@ PHPAPI extern const char * const mysqlnd_old_passwd; PHPAPI extern const char * const mysqlnd_out_of_sync; PHPAPI extern const char * const mysqlnd_server_gone; +PHPAPI extern const char * const mysqlnd_out_of_memory; enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC);
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php