Bug #69752 [Com]: PDOStatement::execute() leaks memory with DML Statements when closeCuror() is u
| From: | phofstetter at sensational dot ch | Date: | Fri, 05 Jun 2015 07:02:27 +0000 |
| Subject: | Bug #69752 [Com]: PDOStatement::execute() leaks memory with DML Statements when closeCuror() is u | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-193132@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69752&edit=1
ID: 69752
Comment by: phofstetter at sensational dot ch
Reported by: phofstetter at sensational dot ch
Summary: PDOStatement::execute() leaks memory with DML
Statements when closeCuror() is u
Status: Open
Type: Bug
Package: PDO PgSQL
Operating System: MacOS X and Linux
PHP Version: 5.6.9
Block user comment: N
Private report: N
New Comment:
With the attached pull request, all tests (including the new one that checks for the leak) pass now.
Is there anything else you need from me?
Previous Comments:
------------------------------------------------------------------------
[2015-06-03 13:05:09] phofstetter at sensational dot ch
Based on the previous analysis, I came up with
https://github.com/pilif/php-src/commit/c34f70dd0dc42c007352940a7af562d89bddc6bf
which fixes the leak. I'll add tests and then create an official pull request.
Just giving a heads-up here so nobody starts working on this :-)
------------------------------------------------------------------------
[2015-06-03 12:43:19] phofstetter at sensational dot ch
I'm not 100% sure and I'd like confirmation by somebody familiar with PDO, but I think
this is what happens:
Once you call closeCursor(), PDOStatement will first call the driver specific closing function
(which in case of postgres is a noop). Then, the parent implementation will set the executed member
to 0. Here: https://github.com/php/php-src/blob/master/ext/pdo/pdo_stmt.c#L2098
The postgres PDO driver calls ecealloc() depending on the state of that executed flag though. Like
here:
https://github.com/php/php-src/blob/master/ext/pdo_pgsql/pgsql_statement.c#L227
But that memory is never freed if the
executed member gets reset outside.
I'll try to find a clean solution and propose a pull request (with tests, of course)
------------------------------------------------------------------------
[2015-06-03 11:59:33] phofstetter at sensational dot ch
Description:
------------
using PDO PGSql, when calling closeCursor() on a statement before re-using it in a future execute(),
some amount of memory is leaked every time the statement is executed.
This only happens on DML statements (insert or update) and it only happens when closeCursor() is
being called.
Test script:
---------------
<?php
printf("I'm pid %d\n", getmypid());
$pdo = new PDO('pgsql:dbname=somedb;user=someuser;host=127.0.0.1');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
$pdo->exec('discard all');
$pdo->exec("set client_encoding to 'utf-8'");
$pdo->beginTransaction();
$pdo->exec("
create table foo (
id bigserial not null primary key,
field1 text not null,
field2 text not null,
field3 text not null,
field4 int4 not null
)
");
// leaks
$stmt = $pdo->prepare("insert into foo (field1, field2, field3, field4) values (:field1,
:field2, :field3, :field4)");
// also leaks
//$stmt = $pdo->prepare("update foo set field1 = :field1, field2 = :field2, field3 = :field3
where field4 = :field4");
// doesn't leak
//$stmt = $pdo->prepare("select * from foo where field1 = :field1 and field2 = :field2 and
field3 = :field3 and field4 = :field4");
$max = 10000;
for($i = 0; $i < $max; $i++) {
$data = array(
'field1' => "field1: $i",
'field2' => "field2: $i",
'field3' => "field3: $i",
'field4' => $i
);
$stmt->execute($data);
$stmt->closeCursor(); // leak goes away if closeCursor() is removed
printf("\r%d", memory_get_usage(true)/1024);
}
$pdo->rollBack();
Expected result:
----------------
printed memory usage should stay constant.
Actual result:
--------------
printed memory usage is continuously increasing.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=69752&edit=1