andrey Tue, 25 May 2010 19:19:29 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=299752
Log: Handle OOM in the code that generates PS Execute requests to the server. Fixes crashes in case of OOM. Changed paths: U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps.c U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_result.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_ps.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c U php/php-src/trunk/ext/mysqlnd/mysqlnd_result.c
Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -39,8 +39,7 @@ static struct st_mysqlnd_stmt_methods *mysqlnd_stmt_methods; /* Exported by mysqlnd_ps_codec.c */ -zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len, - zend_bool *free_buffer TSRMLS_DC); +enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC); @@ -523,8 +522,8 @@ { MYSQLND_STMT_DATA * stmt = s->data; enum_func_status ret; - MYSQLND *conn = stmt->conn; - zend_uchar *request; + MYSQLND * conn = stmt->conn; + zend_uchar *request = NULL; size_t request_len; zend_bool free_request; @@ -628,14 +627,16 @@ DBG_RETURN(FAIL); } } - request = mysqlnd_stmt_execute_generate_request(s, &request_len, &free_request TSRMLS_CC); - - /* support for buffer types should be added here ! */ + ret = mysqlnd_stmt_execute_generate_request(s, &request, &request_len, &free_request TSRMLS_CC); + if (ret == PASS) { + /* support for buffer types should be added here ! */ + ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len, + PROT_LAST /* we will handle the response packet*/, + FALSE, FALSE TSRMLS_CC); + } else { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM."); + } - ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len, - PROT_LAST /* we will handle the response packet*/, - FALSE, FALSE TSRMLS_CC); - if (free_request) { mnd_efree(request); } Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -578,22 +578,26 @@ /* {{{ mysqlnd_stmt_copy_it */ -static void +static enum_func_status mysqlnd_stmt_copy_it(zval *** copies, zval *original, unsigned int param_count, unsigned int current TSRMLS_DC) { if (!*copies) { *copies = mnd_ecalloc(param_count, sizeof(zval *)); } - MAKE_STD_ZVAL((*copies)[current]); - *(*copies)[current] = *original; - Z_SET_REFCOUNT_P((*copies)[current], 1); - zval_copy_ctor((*copies)[current]); + if (*copies) { + MAKE_STD_ZVAL((*copies)[current]); + *(*copies)[current] = *original; + Z_SET_REFCOUNT_P((*copies)[current], 1); + zval_copy_ctor((*copies)[current]); + return PASS; + } + return FAIL; } /* }}} */ /* {{{ mysqlnd_stmt_execute_store_params */ -static void +static enum_func_status mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC) { @@ -603,7 +607,10 @@ size_t left = (*buf_len - (*p - *buf)); size_t data_size = 0; zval **copies = NULL;/* if there are different types */ + enum_func_status ret = FAIL; + DBG_ENTER("mysqlnd_stmt_execute_store_params"); + /* 1. Store type information */ if (stmt->send_types_to_server) { @@ -613,6 +620,10 @@ zend_uchar *tmp_buf; *buf_len = offset + stmt->param_count * 2 + 20; tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } memcpy(tmp_buf, *buf, offset); *buf = tmp_buf; @@ -643,7 +654,10 @@ for (j = i + 1; j < stmt->param_count; j++) { if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } break; } } @@ -653,7 +667,10 @@ data_size += 8; if (Z_TYPE_P(the_var) != IS_DOUBLE) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } } break; @@ -668,7 +685,10 @@ #endif if (Z_TYPE_P(the_var) != IS_LONG) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } } break; @@ -691,7 +711,10 @@ #endif { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } the_var = copies[i]; #if PHP_MAJOR_VERSION >= 6 @@ -714,6 +737,10 @@ zend_uchar *tmp_buf; *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */ tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } memcpy(tmp_buf, *buf, offset); /* When too many columns the buffer provided to the function might not be sufficient. @@ -779,6 +806,8 @@ } } } + ret = PASS; +end: if (copies) { for (i = 0; i < stmt->param_count; i++) { if (copies[i]) { @@ -787,13 +816,16 @@ } mnd_efree(copies); } + + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); + DBG_RETURN(ret); } /* }}} */ /* {{{ mysqlnd_stmt_execute_generate_request */ -zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, size_t *request_len, - zend_bool * free_buffer TSRMLS_DC) +enum_func_status +mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s->data; zend_uchar *p = stmt->execute_cmd_buffer.buffer, @@ -801,7 +833,10 @@ size_t cmd_buffer_length = stmt->execute_cmd_buffer.length; unsigned int null_byte_offset, null_count= (stmt->param_count + 7) / 8; + enum_func_status ret; + DBG_ENTER("mysqlnd_stmt_execute_generate_request"); + int4store(p, stmt->stmt_id); p += 4; @@ -824,11 +859,13 @@ int1store(p, stmt->send_types_to_server); p++; - mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); + ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer); *request_len = (p - cmd_buffer); - return cmd_buffer; + *request = cmd_buffer; + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); + DBG_RETURN(ret); } /* }}} */ Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_result.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_result.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_result.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -394,6 +394,7 @@ */ conn->error_info = rset_header->error_info; ret = FAIL; + DBG_ERR_FMT("error=%s", rset_header->error_info.error); /* Return back from CONN_QUERY_SENT */ CONN_SET_STATE(conn, CONN_READY); break; Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_ps.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_ps.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_ps.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -39,8 +39,7 @@ static struct st_mysqlnd_stmt_methods *mysqlnd_stmt_methods; /* Exported by mysqlnd_ps_codec.c */ -zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len, - zend_bool *free_buffer TSRMLS_DC); +enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC); @@ -523,8 +522,8 @@ { MYSQLND_STMT_DATA * stmt = s->data; enum_func_status ret; - MYSQLND *conn = stmt->conn; - zend_uchar *request; + MYSQLND * conn = stmt->conn; + zend_uchar *request = NULL; size_t request_len; zend_bool free_request; @@ -628,14 +627,16 @@ DBG_RETURN(FAIL); } } - request = mysqlnd_stmt_execute_generate_request(s, &request_len, &free_request TSRMLS_CC); - - /* support for buffer types should be added here ! */ + ret = mysqlnd_stmt_execute_generate_request(s, &request, &request_len, &free_request TSRMLS_CC); + if (ret == PASS) { + /* support for buffer types should be added here ! */ + ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len, + PROT_LAST /* we will handle the response packet*/, + FALSE, FALSE TSRMLS_CC); + } else { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM."); + } - ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request, request_len, - PROT_LAST /* we will handle the response packet*/, - FALSE, FALSE TSRMLS_CC); - if (free_request) { mnd_efree(request); } Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -578,22 +578,26 @@ /* {{{ mysqlnd_stmt_copy_it */ -static void +static enum_func_status mysqlnd_stmt_copy_it(zval *** copies, zval *original, unsigned int param_count, unsigned int current TSRMLS_DC) { if (!*copies) { *copies = mnd_ecalloc(param_count, sizeof(zval *)); } - MAKE_STD_ZVAL((*copies)[current]); - *(*copies)[current] = *original; - Z_SET_REFCOUNT_P((*copies)[current], 1); - zval_copy_ctor((*copies)[current]); + if (*copies) { + MAKE_STD_ZVAL((*copies)[current]); + *(*copies)[current] = *original; + Z_SET_REFCOUNT_P((*copies)[current], 1); + zval_copy_ctor((*copies)[current]); + return PASS; + } + return FAIL; } /* }}} */ /* {{{ mysqlnd_stmt_execute_store_params */ -static void +static enum_func_status mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC) { @@ -603,7 +607,10 @@ size_t left = (*buf_len - (*p - *buf)); size_t data_size = 0; zval **copies = NULL;/* if there are different types */ + enum_func_status ret = FAIL; + DBG_ENTER("mysqlnd_stmt_execute_store_params"); + /* 1. Store type information */ if (stmt->send_types_to_server) { @@ -613,6 +620,10 @@ zend_uchar *tmp_buf; *buf_len = offset + stmt->param_count * 2 + 20; tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } memcpy(tmp_buf, *buf, offset); *buf = tmp_buf; @@ -643,7 +654,10 @@ for (j = i + 1; j < stmt->param_count; j++) { if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } break; } } @@ -653,7 +667,10 @@ data_size += 8; if (Z_TYPE_P(the_var) != IS_DOUBLE) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } } break; @@ -668,7 +685,10 @@ #endif if (Z_TYPE_P(the_var) != IS_LONG) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } } break; @@ -691,7 +711,10 @@ #endif { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC); + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } } the_var = copies[i]; #if PHP_MAJOR_VERSION >= 6 @@ -714,6 +737,10 @@ zend_uchar *tmp_buf; *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */ tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "OOM"); + goto end; + } memcpy(tmp_buf, *buf, offset); /* When too many columns the buffer provided to the function might not be sufficient. @@ -779,6 +806,8 @@ } } } + ret = PASS; +end: if (copies) { for (i = 0; i < stmt->param_count; i++) { if (copies[i]) { @@ -787,13 +816,16 @@ } mnd_efree(copies); } + + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); + DBG_RETURN(ret); } /* }}} */ /* {{{ mysqlnd_stmt_execute_generate_request */ -zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, size_t *request_len, - zend_bool * free_buffer TSRMLS_DC) +enum_func_status +mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s->data; zend_uchar *p = stmt->execute_cmd_buffer.buffer, @@ -801,7 +833,10 @@ size_t cmd_buffer_length = stmt->execute_cmd_buffer.length; unsigned int null_byte_offset, null_count= (stmt->param_count + 7) / 8; + enum_func_status ret; + DBG_ENTER("mysqlnd_stmt_execute_generate_request"); + int4store(p, stmt->stmt_id); p += 4; @@ -824,11 +859,13 @@ int1store(p, stmt->send_types_to_server); p++; - mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); + ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer); *request_len = (p - cmd_buffer); - return cmd_buffer; + *request = cmd_buffer; + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); + DBG_RETURN(ret); } /* }}} */ Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_result.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_result.c 2010-05-25 18:58:30 UTC (rev 299751) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_result.c 2010-05-25 19:19:29 UTC (rev 299752) @@ -394,6 +394,7 @@ */ conn->error_info = rset_header->error_info; ret = FAIL; + DBG_ERR_FMT("error=%s", rset_header->error_info.error); /* Return back from CONN_QUERY_SENT */ CONN_SET_STATE(conn, CONN_READY); break;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php