Skip to content

Commit 2a3080d

Browse files
committed
ext/pdo: Do not register a bindColumn() binding after an exception
Under ERRMODE_EXCEPTION, really_register_bound_param() raised the implementation error for an unknown column name and then registered the binding anyway, so repeated failing bindColumn() calls with distinct names grew bound_columns without bound. Abort registration once an exception is pending; bindValue() and bindParam() take the is_param path and are unaffected.
1 parent 9c2acc3 commit 2a3080d

3 files changed

Lines changed: 40 additions & 0 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ PHP NEWS
4343
- PDO:
4444
. Fixed PDOStatement::getColumnMeta() reading out of bounds for an invalid
4545
column index. (Ilia Alshanetsky)
46+
. Fixed bindColumn() registering a binding for an unknown column name after
47+
an exception was thrown. (Ilia Alshanetsky)
4648

4749
- Readline:
4850
. Fixed a heap over-read in the interactive shell prompt when cli.prompt is

ext/pdo/pdo_stmt.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_
311311
spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
312312
pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
313313
efree(tmp);
314+
if (EG(exception)) {
315+
return 0;
316+
}
314317
}
315318
}
316319

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
PDO: bindColumn() must not register the binding when an exception is thrown for an unknown column name
3+
--EXTENSIONS--
4+
pdo
5+
pdo_sqlite
6+
--FILE--
7+
<?php
8+
$db = new PDO('sqlite::memory:');
9+
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
10+
$stmt = $db->prepare('SELECT 1 AS foo');
11+
$stmt->execute();
12+
$var = null;
13+
$n = 200000;
14+
for ($i = 0; $i < $n; $i++) {
15+
try {
16+
$stmt->bindColumn("bogus$i", $var);
17+
} catch (PDOException $e) {
18+
}
19+
}
20+
$before = memory_get_usage();
21+
for ($i = 0; $i < $n; $i++) {
22+
try {
23+
$stmt->bindColumn("bogus$i", $var);
24+
} catch (PDOException $e) {
25+
}
26+
}
27+
$diff = memory_get_usage() - $before;
28+
if ($diff > 1000) {
29+
echo "LEAK\n";
30+
} else {
31+
echo "OK\n";
32+
}
33+
?>
34+
--EXPECT--
35+
OK

0 commit comments

Comments
 (0)