Skip to content

Commit 29a03cf

Browse files
authored
Merge pull request #83 from datastax/101
101 - Fix: Potential leak when paging results
2 parents c3f9122 + 41f10b4 commit 29a03cf

File tree

6 files changed

+404
-139
lines changed

6 files changed

+404
-139
lines changed

ext/php_cassandra_types.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,15 +271,17 @@ PHP_CASSANDRA_BEGIN_OBJECT_TYPE(rows)
271271
cassandra_ref *statement;
272272
php5to7_zval session;
273273
php5to7_zval rows;
274-
const CassResult *result;
275-
php5to7_zval next_page;
274+
php5to7_zval next_rows;
275+
cassandra_ref *result;
276+
cassandra_ref *next_result;
276277
php5to7_zval future_next_page;
277278
PHP_CASSANDRA_END_OBJECT_TYPE(rows)
278279

279280
PHP_CASSANDRA_BEGIN_OBJECT_TYPE(future_rows)
280281
cassandra_ref *statement;
281282
php5to7_zval session;
282283
php5to7_zval rows;
284+
cassandra_ref *result;
283285
CassFuture *future;
284286
PHP_CASSANDRA_END_OBJECT_TYPE(future_rows)
285287

ext/src/Cassandra/DefaultSession.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ zend_class_entry *cassandra_default_session_ce = NULL;
3030
return SUCCESS; \
3131
}
3232

33+
static void
34+
free_result(void *result)
35+
{
36+
cass_result_free((CassResult *) result);
37+
}
38+
3339
static int
3440
bind_argument_by_index(CassStatement *statement, size_t index, zval *value TSRMLS_DC)
3541
{
@@ -624,8 +630,8 @@ PHP_METHOD(DefaultSession, execute)
624630

625631
if (single && cass_result_has_more_pages(result)) {
626632
rows->statement = php_cassandra_new_ref(single, free_statement);
633+
rows->result = php_cassandra_new_ref((void *)result, free_result);
627634
PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(rows->session), getThis());
628-
rows->result = result;
629635
return;
630636
}
631637

ext/src/Cassandra/FutureRows.c

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -24,75 +24,73 @@ zend_class_entry *cassandra_future_rows_ce = NULL;
2424
ZEND_EXTERN_MODULE_GLOBALS(cassandra)
2525

2626
static void
27-
php_cassandra_future_clear(cassandra_future_rows *self)
27+
free_result(void *result)
2828
{
29-
if (self->statement) {
30-
php_cassandra_del_ref(&self->statement);
31-
self->statement = NULL;
32-
}
29+
cass_result_free((CassResult *) result);
30+
}
3331

34-
PHP5TO7_ZVAL_MAYBE_DESTROY(self->session);
35-
if (self->future) {
36-
cass_future_free(self->future);
37-
self->future = NULL;
32+
int
33+
php_cassandra_future_rows_get_result(cassandra_future_rows *future_rows, zval *timeout TSRMLS_DC)
34+
{
35+
if (!future_rows->result) {
36+
const CassResult *result = NULL;
37+
38+
if (php_cassandra_future_wait_timed(future_rows->future, timeout TSRMLS_CC) == FAILURE) {
39+
return FAILURE;
40+
}
41+
42+
if (php_cassandra_future_is_error(future_rows->future TSRMLS_CC) == FAILURE) {
43+
return FAILURE;
44+
}
45+
46+
result = cass_future_get_result(future_rows->future);
47+
if (!result) {
48+
zend_throw_exception_ex(cassandra_runtime_exception_ce, 0 TSRMLS_CC,
49+
"Future doesn't contain a result.");
50+
return FAILURE;
51+
}
52+
53+
future_rows->result = php_cassandra_new_ref((void *)result, free_result);
3854
}
55+
56+
return SUCCESS;
3957
}
4058

4159
PHP_METHOD(FutureRows, get)
4260
{
4361
zval *timeout = NULL;
4462
cassandra_rows *rows = NULL;
45-
const CassResult *result = NULL;
4663

4764
cassandra_future_rows *self = PHP_CASSANDRA_GET_FUTURE_ROWS(getThis());
4865

49-
if (!PHP5TO7_ZVAL_IS_UNDEF(self->rows)) {
50-
RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(self->rows), 1, 0);
51-
}
52-
5366
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &timeout) == FAILURE) {
5467
return;
5568
}
5669

57-
if (php_cassandra_future_wait_timed(self->future, timeout TSRMLS_CC) == FAILURE) {
70+
if (php_cassandra_future_rows_get_result(self, timeout TSRMLS_CC) == FAILURE) {
5871
return;
5972
}
6073

61-
if (php_cassandra_future_is_error(self->future TSRMLS_CC) == FAILURE) {
62-
return;
74+
if (PHP5TO7_ZVAL_IS_UNDEF(self->rows)) {
75+
if (php_cassandra_get_result((const CassResult *) self->result->data,
76+
&self->rows TSRMLS_CC) == FAILURE) {
77+
PHP5TO7_ZVAL_MAYBE_DESTROY(self->rows);
78+
return;
79+
}
6380
}
6481

65-
result = cass_future_get_result(self->future);
66-
67-
if (!result) {
68-
zend_throw_exception_ex(cassandra_runtime_exception_ce, 0 TSRMLS_CC,
69-
"Future doesn't contain a result.");
70-
return;
71-
}
82+
object_init_ex(return_value, cassandra_rows_ce);
83+
rows = PHP_CASSANDRA_GET_ROWS(return_value);
7284

73-
PHP5TO7_ZVAL_MAYBE_MAKE(self->rows);
74-
object_init_ex(PHP5TO7_ZVAL_MAYBE_P(self->rows), cassandra_rows_ce);
75-
rows = PHP_CASSANDRA_GET_ROWS(PHP5TO7_ZVAL_MAYBE_P(self->rows));
85+
PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(rows->rows),
86+
PHP5TO7_ZVAL_MAYBE_P(self->rows));
7687

77-
if (php_cassandra_get_result(result, &rows->rows TSRMLS_CC) == FAILURE) {
78-
cass_result_free(result);
79-
zval_ptr_dtor(&self->rows);
80-
PHP5TO7_ZVAL_UNDEF(self->rows);
81-
return;
82-
}
83-
84-
if (cass_result_has_more_pages(result)) {
88+
if (cass_result_has_more_pages((const CassResult *)self->result->data)) {
8589
PHP5TO7_ZVAL_COPY(PHP5TO7_ZVAL_MAYBE_P(rows->session),
8690
PHP5TO7_ZVAL_MAYBE_P(self->session));
8791
rows->statement = php_cassandra_add_ref(self->statement);
88-
rows->result = result;
89-
} else {
90-
cass_result_free(result);
92+
rows->result = php_cassandra_add_ref(self->result);
9193
}
92-
93-
php_cassandra_future_clear(self);
94-
95-
RETURN_ZVAL(PHP5TO7_ZVAL_MAYBE_P(self->rows), 1, 0);
9694
}
9795

9896
ZEND_BEGIN_ARG_INFO_EX(arginfo_timeout, 0, ZEND_RETURN_VALUE, 0)
@@ -129,8 +127,12 @@ php_cassandra_future_rows_free(php5to7_zend_object_free *object TSRMLS_DC)
129127
cassandra_future_rows *self = PHP5TO7_ZEND_OBJECT_GET(future_rows, object);
130128

131129
PHP5TO7_ZVAL_MAYBE_DESTROY(self->rows);
130+
PHP5TO7_ZVAL_MAYBE_DESTROY(self->session);
131+
132+
php_cassandra_del_ref(&self->statement);
133+
php_cassandra_del_ref(&self->result);
132134

133-
php_cassandra_future_clear(self);
135+
cass_future_free(self->future);
134136

135137
zend_object_std_dtor(&self->zval TSRMLS_CC);
136138
PHP5TO7_MAYBE_EFREE(self);
@@ -144,6 +146,7 @@ php_cassandra_future_rows_new(zend_class_entry *ce TSRMLS_DC)
144146

145147
self->future = NULL;
146148
self->statement = NULL;
149+
self->result = NULL;
147150
PHP5TO7_ZVAL_UNDEF(self->rows);
148151
PHP5TO7_ZVAL_UNDEF(self->session);
149152

ext/src/Cassandra/FutureRows.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* Copyright 2015-2016 DataStax, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef PHP_CASSANDRA_FUTURE_ROWS_H
18+
#define PHP_CASSANDRA_FUTURE_ROWS_H
19+
20+
int
21+
php_cassandra_future_rows_get_result(cassandra_future_rows *future_rows, zval *timeout TSRMLS_DC);
22+
23+
#endif /* PHP_CASSANDRA_FUTURE_ROWS_H */

0 commit comments

Comments
 (0)