]> granicus.if.org Git - php/commitdiff
Handle OOM in the code that generates PS Execute requests
authorAndrey Hristov <andrey@php.net>
Tue, 25 May 2010 19:19:29 +0000 (19:19 +0000)
committerAndrey Hristov <andrey@php.net>
Tue, 25 May 2010 19:19:29 +0000 (19:19 +0000)
to the server. Fixes crashes in case of OOM.

ext/mysqlnd/mysqlnd_ps.c
ext/mysqlnd/mysqlnd_ps_codec.c
ext/mysqlnd/mysqlnd_result.c

index 9fab366a93537fae6399e1d7d6067b517a6e3a71..db50bbce6419917396ea26f47d187ac29c5e0d02 100644 (file)
@@ -39,8 +39,7 @@ const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
 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_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
 {
        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,13 +627,15 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
                        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 = 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);
+       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.");
+       }
 
        if (free_request) {
                mnd_efree(request);
index d66e90c039e7ef8f7931e11148c8f34c4660b041..24559070ec6e9d2f15c16fd9fd18f4e8327cd42b 100644 (file)
@@ -578,22 +578,26 @@ void _mysqlnd_init_ps_fetch_subsystem()
 
 
 /* {{{ 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,6 +607,9 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
        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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                        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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                                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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
 #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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
 #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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                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 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                        }
                }
        }
+       ret = PASS;
+end:
        if (copies) {
                for (i = 0; i < stmt->param_count; i++) {
                        if (copies[i]) {
@@ -787,13 +816,16 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
                }
                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,6 +833,9 @@ zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, size_t *requ
        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 @@ zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * s, size_t *requ
        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);
 }
 /* }}} */
 
index 136ab190b45a3827335368557ec12b15cda8a2b3..00368aaa0fa647827ba01b0cc4bd88045469d8be 100644 (file)
@@ -394,6 +394,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC)
                        */
                        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;