]> granicus.if.org Git - php/commitdiff
Handle gracefully OOM in mysqlnd_mempool_create and up the stack
authorAndrey Hristov <andrey@php.net>
Mon, 3 May 2010 17:07:18 +0000 (17:07 +0000)
committerAndrey Hristov <andrey@php.net>
Mon, 3 May 2010 17:07:18 +0000 (17:07 +0000)
ext/mysqlnd/mysqlnd.c
ext/mysqlnd/mysqlnd_block_alloc.c
ext/mysqlnd/mysqlnd_result.c

index 414d6f2b5a9c84c7d31afa450eb2666f7542e5ab..f67c468c83b6c1251be9f127565cda06e5f42655 100644 (file)
@@ -2060,7 +2060,7 @@ oom:
 static MYSQLND_RES *
 MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
 {
-       MYSQLND_RES *result;
+       MYSQLND_RES * result;
 
        DBG_ENTER("mysqlnd_conn::use_result");
        DBG_INF_FMT("conn=%llu", conn->thread_id);
@@ -2079,11 +2079,14 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
 
        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_UNBUFFERED_SETS);
 
-       result = conn->current_result;
-       conn->current_result = NULL;
-       result->conn = conn->m->get_reference(conn TSRMLS_CC);
+       conn->current_result->conn = conn->m->get_reference(conn TSRMLS_CC);
+       result = conn->current_result->m.use_result(conn->current_result, FALSE TSRMLS_CC);
 
-       result = result->m.use_result(result, FALSE TSRMLS_CC);
+       if (!result) {
+               conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);
+       }
+       conn->current_result = NULL;
+       
        DBG_RETURN(result);
 }
 /* }}} */
@@ -2112,10 +2115,11 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
 
        MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
 
-       result = conn->current_result;
+       result = conn->current_result->m.store_result(conn->current_result, conn, FALSE TSRMLS_CC);
+       if (!result) {
+               conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC);      
+       }
        conn->current_result = NULL;
-
-       result = result->m.store_result(result, conn, FALSE TSRMLS_CC);
        DBG_RETURN(result);
 }
 /* }}} */
index 5d618d145ed816716ff74b1e3cb075ac0115c493..8bcfffa951c56bb2404766b7d684df8d0eeb2280 100644 (file)
@@ -156,13 +156,17 @@ mysqlnd_mempool_create(size_t arena_size TSRMLS_DC)
        /* We calloc, because we free(). We don't mnd_calloc()  for a reason. */
        MYSQLND_MEMORY_POOL * ret = mnd_calloc(1, sizeof(MYSQLND_MEMORY_POOL));
        DBG_ENTER("mysqlnd_mempool_create");
-
-       ret->free_size = ret->arena_size = arena_size ? arena_size : 0;
-       ret->refcount = 0;
-       /* OOM ? */
-       ret->arena = mnd_malloc(ret->arena_size);
-       ret->get_chunk = mysqlnd_mempool_get_chunk;
-
+       if (ret) {
+               ret->get_chunk = mysqlnd_mempool_get_chunk;
+               ret->free_size = ret->arena_size = arena_size ? arena_size : 0;
+               ret->refcount = 0;
+               /* OOM ? */
+               ret->arena = mnd_malloc(ret->arena_size);
+               if (!ret->arena) {
+                       mysqlnd_mempool_destroy(ret TSRMLS_CC);
+                       ret = NULL;
+               }
+       }
        DBG_RETURN(ret);
 }
 /* }}} */
index 657fa406991d274a36206a1782bb511dd886b17a..5d5ad5012e57545e590b96c5915e37f75cdc9828 100644 (file)
@@ -841,22 +841,28 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
 
        SET_EMPTY_ERROR(result->conn->error_info);
 
+       result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
+       result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+       if (!result->result_set_memory_pool || !result->unbuf) {
+               goto oom;
+       }
+
        if (ps == FALSE) {
                result->type                    = MYSQLND_RES_NORMAL;
                result->m.fetch_row             = result->m.fetch_row_normal_unbuffered;
                result->m.fetch_lengths = mysqlnd_fetch_lengths_unbuffered;
-               result->lengths                 = mnd_ecalloc(result->field_count, sizeof(unsigned long));
                result->m.row_decoder   = php_mysqlnd_rowp_read_text_protocol;
+               result->lengths                 = mnd_ecalloc(result->field_count, sizeof(unsigned long));
+               if (!result->lengths) {
+                       goto oom;
+               }
        } else {
                result->type                    = MYSQLND_RES_PS_UNBUF;
                /* result->m.fetch_row() will be set in mysqlnd_ps.c */
                result->m.fetch_lengths = NULL; /* makes no sense */
-               result->lengths                 = NULL;
                result->m.row_decoder   = php_mysqlnd_rowp_read_binary_protocol;
+               result->lengths                 = NULL;
        }
-       result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
-
-       result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
 
        /*
          Will be freed in the mysqlnd_internal_free_result_contents() called
@@ -865,6 +871,9 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
        */
        /* FALSE = non-persistent */
        result->row_packet = result->conn->protocol->m.get_row_packet(result->conn->protocol, FALSE TSRMLS_CC);
+       if (!result->row_packet) {
+               goto oom;
+       }
        result->row_packet->result_set_memory_pool = result->result_set_memory_pool;
        result->row_packet->field_count = result->field_count;
        result->row_packet->binary_protocol = ps;
@@ -873,6 +882,9 @@ MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
        result->row_packet->bit_fields_total_len = result->meta->bit_fields_total_len;
 
        DBG_RETURN(result);
+oom:
+       SET_OOM_ERROR(result->conn->error_info);
+       DBG_RETURN(NULL);
 }
 /* }}} */
 
@@ -1163,6 +1175,13 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
        DBG_ENTER("mysqlnd_res::store_result");
        DBG_INF_FMT("conn=%d ps_protocol=%d", conn->thread_id, ps_protocol);
 
+       result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
+       result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
+       if (!result->result_set_memory_pool || !result->lengths) {
+               SET_OOM_ERROR(conn->error_info);
+               DBG_RETURN(NULL);
+       }
+
        /* We need the conn because we are doing lazy zval initialization in buffered_fetch_row */
        result->conn                    = conn->m->get_reference(conn TSRMLS_CC);
        result->type                    = MYSQLND_RES_NORMAL;
@@ -1171,18 +1190,13 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
 
        CONN_SET_STATE(conn, CONN_FETCHING_DATA);
 
-       result->result_set_memory_pool = mysqlnd_mempool_create(MYSQLND_G(mempool_default_size) TSRMLS_CC);
-       result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
-
        ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol, to_cache TSRMLS_CC);
-       if (PASS == ret) {
-               /* libmysql's documentation says it should be so for SELECT statements */
-               conn->upsert_status.affected_rows = result->stored_data->row_count;
-       } else {
+       if (FAIL == ret) {
                conn->error_info = result->stored_data->error_info;
-               result->m.free_result_internal(result TSRMLS_CC);
-               result = NULL;
+               DBG_RETURN(NULL);
        }
+       /* libmysql's documentation says it should be so for SELECT statements */
+       conn->upsert_status.affected_rows = result->stored_data->row_count;
 
        DBG_RETURN(result);
 }