Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ PHP NEWS
. Fixed PDOStatement::getColumnMeta() reading out of bounds for an invalid
column index. (Ilia Alshanetsky)

- PDO_DBLIB:
. Fixed bug GH-23741 (segfault after a failed query inside a PDO
transaction). Errors raised by beginTransaction(), commit(), rollBack()
and lastInsertId() are now reported instead of being dropped.
(Ilia Alshanetsky)

- Sockets:
. Fixed socket_select() silently truncating sets larger than FD_SETSIZE on
Windows. (David Carlier)
Expand Down
7 changes: 6 additions & 1 deletion ext/pdo_dblib/dblib_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ static void dblib_handle_closer(pdo_dbh_t *dbh)
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;

if (H) {
pdo_dblib_err_dtor(&H->err);
if (H->link) {
dbsetuserdata(H->link, (BYTE*) &H->err);
dbclose(H->link);
H->link = NULL;
}
pdo_dblib_err_dtor(&H->err);
if (H->login) {
dbfreelogin(H->login);
H->login = NULL;
Expand Down Expand Up @@ -202,6 +203,8 @@ static bool pdo_dblib_transaction_cmd(const char *cmd, pdo_dbh_t *dbh)
{
pdo_dblib_db_handle *H = (pdo_dblib_db_handle *)dbh->driver_data;

dbsetuserdata(H->link, (BYTE*) &H->err);

if (FAIL == dbcmd(H->link, cmd)) {
return false;
}
Expand Down Expand Up @@ -241,6 +244,8 @@ zend_string *dblib_handle_last_id(pdo_dbh_t *dbh, const zend_string *name)
* Would use scope_identity() but it's not implemented on Sybase
*/

dbsetuserdata(H->link, (BYTE*) &H->err);

if (FAIL == dbcmd(H->link, "SELECT @@IDENTITY")) {
return NULL;
}
Expand Down
14 changes: 13 additions & 1 deletion ext/pdo_dblib/dblib_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ static int pdo_dblib_stmt_cursor_closer(pdo_stmt_t *stmt)
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;

dbsetuserdata(H->link, (BYTE*) &S->err);

/* Cancel any pending results */
dbcancel(H->link);

Expand Down Expand Up @@ -152,6 +154,8 @@ static int pdo_dblib_stmt_next_rowset(pdo_stmt_t *stmt)
pdo_dblib_db_handle *H = S->H;
RETCODE ret = SUCCESS;

dbsetuserdata(H->link, (BYTE*) &S->err);

/* Ideally use dbcanquery here, but there is a bug in FreeTDS's implementation of dbcanquery
* It has been resolved but is currently only available in nightly builds
*/
Expand Down Expand Up @@ -201,6 +205,8 @@ static int pdo_dblib_stmt_fetch(pdo_stmt_t *stmt,
pdo_dblib_stmt *S = (pdo_dblib_stmt*)stmt->driver_data;
pdo_dblib_db_handle *H = S->H;

dbsetuserdata(H->link, (BYTE*) &S->err);

ret = dbnextrow(H->link);

if (FAIL == ret) {
Expand All @@ -226,6 +232,8 @@ static int pdo_dblib_stmt_describe(pdo_stmt_t *stmt, int colno)
return FAILURE;
}

dbsetuserdata(H->link, (BYTE*) &S->err);

if (colno == 0) {
S->computed_column_name_count = 0;
}
Expand Down Expand Up @@ -350,6 +358,8 @@ static int pdo_dblib_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *zv, enum pd
DBCHAR *tmp_data;
DBINT data_len, tmp_data_len;

dbsetuserdata(H->link, (BYTE*) &S->err);

coltype = dbcoltype(H->link, colno+1);
data = dbdata(H->link, colno+1);
data_len = dbdatlen(H->link, colno+1);
Expand Down Expand Up @@ -472,14 +482,16 @@ static int pdo_dblib_stmt_get_column_meta(pdo_stmt_t *stmt, zend_long colno, zva
return FAILURE;
}

array_init(return_value);
dbsetuserdata(H->link, (BYTE*) &S->err);

dbtypeinfo = dbcoltypeinfo(H->link, colno+1);

if(!dbtypeinfo) return FAILURE;

coltype = dbcoltype(H->link, colno+1);

array_init(return_value);

add_assoc_long(return_value, "max_length", dbcollen(H->link, colno+1) );
add_assoc_long(return_value, "precision", (int) dbtypeinfo->precision );
add_assoc_long(return_value, "scale", (int) dbtypeinfo->scale );
Expand Down
40 changes: 40 additions & 0 deletions ext/pdo_dblib/tests/gh23741.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
--TEST--
GH-23741 (pdo_dblib: segfault after a failed query inside a PDO transaction)
--EXTENSIONS--
pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';

$db = getDbConnection(PDO::class, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]);

$db->query('DROP VIEW IF EXISTS gh23741');
$db->query('DROP TABLE IF EXISTS gh23741');
$db->query('CREATE TABLE gh23741 (id int)');

$db->beginTransaction();
echo 'failing query inside the transaction: ';
var_dump($db->query('CREATE VIEW gh23741 AS SELECT 1 AS x'));
$db->rollBack();

echo 'query after the failure: ';
var_dump($db->query('DROP TABLE IF EXISTS gh23741') instanceof PDOStatement);

echo "survived connection teardown\n";
?>
--CLEAN--
<?php
require __DIR__ . '/config.inc';
$db = getDbConnection();
$db->exec('DROP VIEW IF EXISTS gh23741');
$db->exec('DROP TABLE IF EXISTS gh23741');
?>
--EXPECT--
failing query inside the transaction: bool(false)
query after the failure: bool(true)
survived connection teardown
27 changes: 27 additions & 0 deletions ext/pdo_dblib/tests/gh23741_2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
GH-23741 (pdo_dblib: crash reading metadata after a sibling statement is freed)
--EXTENSIONS--
pdo_dblib
--SKIPIF--
<?php
require __DIR__ . '/config.inc';
getDbConnection();
?>
--FILE--
<?php
require __DIR__ . '/config.inc';

$db = getDbConnection(PDO::class, [PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT]);

$wide = $db->query('SELECT 1 AS a, 2 AS b, 3 AS c');
$narrow = $db->query('SELECT 9 AS z');
unset($narrow);

echo 'metadata for a column the connection no longer has: ';
var_dump($wide->getColumnMeta(2));

echo "survived the out-of-range column\n";
?>
--EXPECT--
metadata for a column the connection no longer has: bool(false)
survived the out-of-range column
Loading