diff --git a/NEWS b/NEWS index 70dd9bce1c48..bb852dd7a233 100644 --- a/NEWS +++ b/NEWS @@ -55,6 +55,7 @@ PHP NEWS longer than the declared maxlen). (iliaal) . Fixed bug GH-22665 (Out-of-bounds write when the ODBC driver reports a diagnostic message length beyond the error buffer). (iliaal) + . Fixed memory leak of the buffer bound for an output parameter. (iliaal) - Phar: . Fixed inconsistent handling of the magic ".phar" directory. Paths such as diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index 8940143da09c..1477c007b8a2 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -133,6 +133,11 @@ static void free_cols(pdo_stmt_t *stmt, pdo_odbc_stmt *S) } } +static void odbc_free_out_buffer(zval *el) +{ + efree(Z_PTR_P(el)); +} + static int odbc_stmt_dtor(pdo_stmt_t *stmt) { pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; @@ -153,6 +158,10 @@ static int odbc_stmt_dtor(pdo_stmt_t *stmt) if (S->convbuf) { efree(S->convbuf); } + if (S->out_buffers) { + zend_hash_destroy(S->out_buffers); + FREE_HASHTABLE(S->out_buffers); + } efree(S); return 1; @@ -386,6 +395,11 @@ static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *p } P->outbuf = emalloc(P->len + (P->is_unicode ? 2:1)); P->outbuflen = P->len; + if (!S->out_buffers) { + ALLOC_HASHTABLE(S->out_buffers); + zend_hash_init(S->out_buffers, 8, NULL, odbc_free_out_buffer, 0); + } + zend_hash_next_index_insert_ptr(S->out_buffers, P->outbuf); } } diff --git a/ext/pdo_odbc/php_pdo_odbc_int.h b/ext/pdo_odbc/php_pdo_odbc_int.h index ea93c58b2b60..96c936c2ab3a 100644 --- a/ext/pdo_odbc/php_pdo_odbc_int.h +++ b/ext/pdo_odbc/php_pdo_odbc_int.h @@ -145,6 +145,7 @@ typedef struct { pdo_odbc_errinfo einfo; char *convbuf; zend_ulong convbufsize; + HashTable *out_buffers; unsigned going_long:1; unsigned assume_utf8:1; signed col_count:16; diff --git a/ext/pdo_odbc/tests/output_param_leak.phpt b/ext/pdo_odbc/tests/output_param_leak.phpt new file mode 100644 index 000000000000..f6d4aad5a8c6 --- /dev/null +++ b/ext/pdo_odbc/tests/output_param_leak.phpt @@ -0,0 +1,29 @@ +--TEST-- +pdo_odbc: bound output parameter buffer is released (no leak) +--EXTENSIONS-- +pdo_odbc +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); + +$stmt = $pdo->prepare('SELECT ? AS v'); +$var = 'seed'; +$stmt->bindParam(1, $var, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 256); +$stmt->execute(); +$row = $stmt->fetch(PDO::FETCH_ASSOC); + +var_dump($row['v']); +?> +--EXPECT-- +string(4) "seed"