]> granicus.if.org Git - php/commitdiff
Handle the situation when MYSQLND_PROTOCOL's methods return NULL.
authorAndrey Hristov <andrey@php.net>
Tue, 25 May 2010 23:18:13 +0000 (23:18 +0000)
committerAndrey Hristov <andrey@php.net>
Tue, 25 May 2010 23:18:13 +0000 (23:18 +0000)
mysqlnd should not crash but gracefully return with an error.

ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd_ps.c
ext/mysqlnd/mysqlnd_result.c
ext/mysqlnd/mysqlnd_result_meta.c

index a9356dafc5ff3b022ca064f1fbdac07e173739a6..37b7c1bf4203c87e21229a7fc21a912f931544e8 100644 (file)
@@ -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.
index 41ec5e646d93c9c43dbee0da9936f2562b3b5bcf..d1ceba60aeb3ec0f958f8490dd97720ea7be6301 100644 (file)
@@ -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);
 }
index 00368aaa0fa647827ba01b0cc4bd88045469d8be..5590375763dc01958cf4821d3cf6af079d41411c 100644 (file)
@@ -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);
index 5c30aafead423e79ccc753fba7ab75b3e113ecbd..9f4220bb25ce221d52ec7625e868c869ef34ff87 100644 (file)
@@ -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;