diff options
author | Andrey Hristov <andrey@php.net> | 2010-05-25 23:18:13 +0000 |
---|---|---|
committer | Andrey Hristov <andrey@php.net> | 2010-05-25 23:18:13 +0000 |
commit | 58f13c3c9f25b36cedcdf48c15dd8cabec7985b0 (patch) | |
tree | 24f32259122fcceb818ea9cc00e3a02d0bede5e8 /ext/mysqlnd | |
parent | bccf2cea5dc8084119382bd5f1ec0abfad223551 (diff) | |
download | php-git-58f13c3c9f25b36cedcdf48c15dd8cabec7985b0.tar.gz |
Handle the situation when MYSQLND_PROTOCOL's methods return NULL.
mysqlnd should not crash but gracefully return with an error.
Diffstat (limited to 'ext/mysqlnd')
-rw-r--r-- | ext/mysqlnd/mysqlnd.c | 54 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_ps.c | 44 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_result.c | 5 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_result_meta.c | 1 |
4 files changed, 77 insertions, 27 deletions
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index a9356dafc5..37b7c1bf42 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -225,7 +225,7 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu zend_bool silent, enum php_mysqlnd_server_command command, zend_bool ignore_upsert_status TSRMLS_DC) { - enum_func_status ret; + enum_func_status ret = FAIL; DBG_ENTER("mysqlnd_conn::simple_command_handle_response"); DBG_INF_FMT("silent=%d packet=%d command=%s", silent, ok_packet, mysqlnd_command_to_text[command]); @@ -233,6 +233,10 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu switch (ok_packet) { case PROT_OK_PACKET:{ MYSQLND_PACKET_OK * ok_response = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); + if (!ok_response) { + SET_OOM_ERROR(conn->error_info); + break; + } if (FAIL == (ret = PACKET_READ(ok_response, conn))) { if (!silent) { DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]); @@ -274,6 +278,10 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu } case PROT_EOF_PACKET:{ MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC); + if (!ok_response) { + SET_OOM_ERROR(conn->error_info); + break; + } if (FAIL == (ret = PACKET_READ(ok_response, conn))) { SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet"); @@ -300,7 +308,6 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu break; } default: - ret = FAIL; SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet"); php_error_docref(NULL TSRMLS_CC, E_ERROR, "Wrong response packet %d passed to the function", ok_packet); break; @@ -344,6 +351,11 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command)(MYSQLND * conn, enum php_mysqlnd_se SET_EMPTY_ERROR(conn->error_info); cmd_packet = conn->protocol->m.get_command_packet(conn->protocol, FALSE TSRMLS_CC); + if (!cmd_packet) { + SET_OOM_ERROR(conn->error_info); + DBG_RETURN(FAIL); + } + cmd_packet->command = command; if (arg && arg_len) { cmd_packet->argument = arg; @@ -526,6 +538,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port); } if (!transport) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } DBG_INF_FMT("transport=%s", transport); @@ -542,6 +555,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, 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) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } @@ -613,6 +627,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent); if (!conn->scramble) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH); @@ -682,12 +697,14 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, conn->connect_or_select_db_len = db_len; if (!conn->user || !conn->passwd || !conn->connect_or_select_db) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } if (!unix_socket) { conn->host = mnd_pestrdup(host, conn->persistent); if (!conn->host) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } conn->host_len = strlen(conn->host); @@ -695,11 +712,13 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, char *p; spprintf(&p, 0, "%s via TCP/IP", conn->host); if (!p) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } conn->host_info = mnd_pestrdup(p, conn->persistent); efree(p); /* allocated by spprintf */ if (!conn->host_info) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } } @@ -707,6 +726,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, 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) { + SET_OOM_ERROR(conn->error_info); goto err; /* OOM */ } conn->unix_socket_len = strlen(conn->unix_socket); @@ -1333,6 +1353,11 @@ MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND * conn, char **message, unsigned int DBG_RETURN(FAIL); } stats_header = conn->protocol->m.get_stats_packet(conn->protocol, FALSE TSRMLS_CC); + if (!stats_header) { + SET_OOM_ERROR(conn->error_info); + DBG_RETURN(FAIL); + } + if (FAIL == (ret = PACKET_READ(stats_header, conn))) { DBG_RETURN(FAIL); } @@ -1829,7 +1854,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, buffer overflows. */ size_t user_len; - enum_func_status ret; + enum_func_status ret = FAIL; MYSQLND_PACKET_CHG_USER_RESPONSE * chg_user_resp; char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1]; char *p = buffer; @@ -1838,6 +1863,8 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s silent=%d", conn->thread_id, user?user:"", passwd?"***":"null", db?db:"", (silent == TRUE)?1:0 ); + SET_ERROR_AFF_ROWS(conn); + if (!user) { user = ""; } @@ -1878,6 +1905,10 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, } chg_user_resp = conn->protocol->m.get_change_user_response_packet(conn->protocol, FALSE TSRMLS_CC); + if (!chg_user_resp) { + SET_OOM_ERROR(conn->error_info); + goto end; + } ret = PACKET_READ(chg_user_resp, conn); conn->error_info = chg_user_resp->error_info; @@ -1888,13 +1919,15 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, bug#25371 mysql_change_user() triggers "packets out of sync" When it gets fixed, there should be one more check here */ - if (mysqlnd_get_server_version(conn) > 50113L && - mysqlnd_get_server_version(conn) < 50118L) - { + if (mysqlnd_get_server_version(conn) > 50113L && mysqlnd_get_server_version(conn) < 50118L) { MYSQLND_PACKET_OK * redundant_error_packet = conn->protocol->m.get_ok_packet(conn->protocol, FALSE TSRMLS_CC); - PACKET_READ(redundant_error_packet, conn); - PACKET_FREE(redundant_error_packet); - DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn)); + if (redundant_error_packet) { + PACKET_READ(redundant_error_packet, conn); + PACKET_FREE(redundant_error_packet); + DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn)); + } else { + SET_OOM_ERROR(conn->error_info); + } } } if (ret == PASS) { @@ -1919,10 +1952,9 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, DBG_ERR(mysqlnd_old_passwd); SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); } +end: PACKET_FREE(chg_user_resp); - SET_ERROR_AFF_ROWS(conn); - /* Here we should close all statements. Unbuffered queries should not be a problem as we won't allow sending COM_CHANGE_USER. diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 41ec5e646d..d1ceba60ae 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -243,7 +243,10 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC) DBG_INF_FMT("stmt=%lu", stmt->stmt_id); field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC); - if (field_packet) { + if (!field_packet) { + SET_OOM_ERROR(stmt->error_info); + SET_OOM_ERROR(stmt->conn->error_info); + } else { ret = PASS; field_packet->skip_parsing = TRUE; for (;i < stmt->param_count; i++) { @@ -266,23 +269,27 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s->data; MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp; - enum_func_status ret = PASS; + enum_func_status ret = FAIL; DBG_ENTER("mysqlnd_stmt_read_prepare_response"); DBG_INF_FMT("stmt=%lu", stmt->stmt_id); prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC); + if (!prepare_resp) { + SET_OOM_ERROR(stmt->error_info); + SET_OOM_ERROR(stmt->conn->error_info); + goto done; + } + if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) { - ret = FAIL; goto done; } if (0xFF == prepare_resp->error_code) { stmt->error_info = stmt->conn->error_info = prepare_resp->error_info; - ret = FAIL; goto done; } - + ret = PASS; stmt->stmt_id = prepare_resp->stmt_id; stmt->warning_count = stmt->conn->upsert_status.warning_count = prepare_resp->warning_count; stmt->field_count = stmt->conn->field_count = prepare_resp->field_count; @@ -307,19 +314,24 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC) DBG_INF_FMT("stmt=%lu", stmt->stmt_id); fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC); - if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) { - if (stmt->result) { - stmt->result->m.free_result_contents(stmt->result TSRMLS_CC); - mnd_efree(stmt->result); - memset(stmt, 0, sizeof(MYSQLND_STMT_DATA)); - stmt->state = MYSQLND_STMT_INITTED; - } + if (!fields_eof) { + SET_OOM_ERROR(stmt->error_info); + SET_OOM_ERROR(stmt->conn->error_info); } else { - stmt->upsert_status.server_status = fields_eof->server_status; - stmt->upsert_status.warning_count = fields_eof->warning_count; - stmt->state = MYSQLND_STMT_PREPARED; + if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) { + if (stmt->result) { + stmt->result->m.free_result_contents(stmt->result TSRMLS_CC); + mnd_efree(stmt->result); + memset(stmt, 0, sizeof(MYSQLND_STMT_DATA)); + stmt->state = MYSQLND_STMT_INITTED; + } + } else { + stmt->upsert_status.server_status = fields_eof->server_status; + stmt->upsert_status.warning_count = fields_eof->warning_count; + stmt->state = MYSQLND_STMT_PREPARED; + } + PACKET_FREE(fields_eof); } - PACKET_FREE(fields_eof); DBG_RETURN(ret); } diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 00368aaa0f..5590375763 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -493,6 +493,11 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) /* Check for SERVER_STATUS_MORE_RESULTS if needed */ fields_eof = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC); + if (!fields_eof) { + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + break; + } if (FAIL == (ret = PACKET_READ(fields_eof, conn))) { DBG_ERR("Error ocurred while reading the EOF packet"); result->m.free_result_contents(result TSRMLS_CC); diff --git a/ext/mysqlnd/mysqlnd_result_meta.c b/ext/mysqlnd/mysqlnd_result_meta.c index 5c30aafead..9f4220bb25 100644 --- a/ext/mysqlnd/mysqlnd_result_meta.c +++ b/ext/mysqlnd/mysqlnd_result_meta.c @@ -151,6 +151,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met field_packet = conn->protocol->m.get_result_field_packet(conn->protocol, FALSE TSRMLS_CC); if (!field_packet) { + SET_OOM_ERROR(conn->error_info); DBG_RETURN(FAIL); } field_packet->persistent_alloc = meta->persistent; |