summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent <vquatrevieux@b2pweb.com>2019-06-26 11:37:08 +0200
committerChristoph M. Becker <cmbecker69@gmx.de>2019-06-28 12:36:02 +0200
commit05c00a832c7b395398ef8e60edd8a7ec25439861 (patch)
treec370019ae42a557af143f55c3d49610b1ab2736f
parent7d28a24c6602a0cf66def582c82712408254f81d (diff)
downloadphp-git-05c00a832c7b395398ef8e60edd8a7ec25439861.tar.gz
Fix bug #78192 PDO SQLite SegFault when reuse statement after schema has changed
Reset stmt->columns when column count changed on new execution of prepared statement
-rw-r--r--NEWS4
-rw-r--r--ext/pdo_sqlite/sqlite_statement.c44
-rw-r--r--ext/pdo_sqlite/tests/bug78192.phpt46
3 files changed, 92 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index 14b7b612c7..8c2a6c2d22 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2019, PHP 7.2.21
+- PDO_Sqlite:
+ . Fixed #78192 (SegFault when reuse statement after schema has changed).
+ (Vincent Quatrevieux)
+
- XMLRPC:
. Fixed #78173 (XML-RPC mutates immutable objects during encoding). (Asher
Baker)
diff --git a/ext/pdo_sqlite/sqlite_statement.c b/ext/pdo_sqlite/sqlite_statement.c
index 4437bbbde0..58811aee58 100644
--- a/ext/pdo_sqlite/sqlite_statement.c
+++ b/ext/pdo_sqlite/sqlite_statement.c
@@ -43,6 +43,46 @@ static int pdo_sqlite_stmt_dtor(pdo_stmt_t *stmt)
return 1;
}
+/**
+ * Change the column count on the statement.
+ *
+ * Since PHP 7.2 sqlite3_prepare_v2 is used which auto recompile prepared statement on schema change.
+ * Instead of raise an error on schema change, the result set will change, and the statement's columns must be updated.
+ *
+ * See bug #78192
+ */
+static void pdo_sqlite_stmt_set_column_count(pdo_stmt_t *stmt, int new_count)
+{
+ /* Columns not yet "described" */
+ if (!stmt->columns) {
+ stmt->column_count = new_count;
+
+ return;
+ }
+
+ /*
+ * The column count has not changed : no need to reload columns description
+ * Note: Do not handle attribute name change, without column count change
+ */
+ if (new_count == stmt->column_count) {
+ return;
+ }
+
+ /* Free previous columns to force reload description */
+ int i;
+
+ for (i = 0; i < stmt->column_count; i++) {
+ if (stmt->columns[i].name) {
+ zend_string_release(stmt->columns[i].name);
+ stmt->columns[i].name = NULL;
+ }
+ }
+
+ efree(stmt->columns);
+ stmt->columns = NULL;
+ stmt->column_count = new_count;
+}
+
static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
{
pdo_sqlite_stmt *S = (pdo_sqlite_stmt*)stmt->driver_data;
@@ -55,11 +95,11 @@ static int pdo_sqlite_stmt_execute(pdo_stmt_t *stmt)
switch (sqlite3_step(S->stmt)) {
case SQLITE_ROW:
S->pre_fetched = 1;
- stmt->column_count = sqlite3_data_count(S->stmt);
+ pdo_sqlite_stmt_set_column_count(stmt, sqlite3_data_count(S->stmt));
return 1;
case SQLITE_DONE:
- stmt->column_count = sqlite3_column_count(S->stmt);
+ pdo_sqlite_stmt_set_column_count(stmt, sqlite3_column_count(S->stmt));
stmt->row_count = sqlite3_changes(S->H->db);
sqlite3_reset(S->stmt);
S->done = 1;
diff --git a/ext/pdo_sqlite/tests/bug78192.phpt b/ext/pdo_sqlite/tests/bug78192.phpt
new file mode 100644
index 0000000000..dcf4b749be
--- /dev/null
+++ b/ext/pdo_sqlite/tests/bug78192.phpt
@@ -0,0 +1,46 @@
+--TEST--
+PDO SQLite Bug #78192 SegFault when reuse statement after schema change
+--SKIPIF--
+<?php
+if (!extension_loaded('pdo_sqlite')) print 'skip not loaded';
+?>
+--FILE--
+<?php
+$connection = new \PDO('sqlite::memory:');
+$connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
+$connection->query('CREATE TABLE user (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR(255) NOT NULL)');
+
+$stmt = $connection->prepare('INSERT INTO user (id, name) VALUES(:id, :name)');
+$stmt->execute([
+ 'id' => 10,
+ 'name' => 'test',
+]);
+
+$stmt = $connection->prepare('SELECT * FROM user WHERE id = :id');
+$stmt->execute(['id' => 10]);
+var_dump($stmt->fetchAll(\PDO::FETCH_ASSOC));
+
+$connection->query('ALTER TABLE user ADD new_col VARCHAR(255)');
+$stmt->execute(['id' => 10]);
+var_dump($stmt->fetchAll(\PDO::FETCH_ASSOC));
+--EXPECT--
+array(1) {
+ [0]=>
+ array(2) {
+ ["id"]=>
+ string(2) "10"
+ ["name"]=>
+ string(4) "test"
+ }
+}
+array(1) {
+ [0]=>
+ array(3) {
+ ["id"]=>
+ string(2) "10"
+ ["name"]=>
+ string(4) "test"
+ ["new_col"]=>
+ NULL
+ }
+}