Merge branch 'PHP-8.3' into PHP-8.4

* PHP-8.3:
  Add NEWS entries
  Fix crash in firebird statement dtor
  ext/pdo: Fix memory leak if GC needs to free PDO Statement
  Fix GHA config yml error
This commit is contained in:
Gina Peter Banyard 2025-01-24 20:20:01 +00:00
commit eda8ce728a
No known key found for this signature in database
GPG key ID: F30F8C1ACF51943F
5 changed files with 165 additions and 13 deletions

View file

@ -427,7 +427,7 @@ jobs:
-d zend_extension=opcache.so -d zend_extension=opcache.so
-d opcache.enable_cli=1 -d opcache.enable_cli=1
- uses: codecov/codecov-action@v4 - uses: codecov/codecov-action@v4
if: !cancelled() if: ${{ !cancelled() }}
with: with:
fail_ci_if_error: true fail_ci_if_error: true
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
@ -500,7 +500,7 @@ jobs:
echo opcache.jit_hot_side_exit=1 >> /etc/php.d/opcache.ini echo opcache.jit_hot_side_exit=1 >> /etc/php.d/opcache.ini
php -v php -v
- name: Test AMPHP - name: Test AMPHP
if: !cancelled() if: ${{ !cancelled() }}
run: | run: |
repositories="amp cache dns file http parallel parser pipeline process serialization socket sync websocket-client websocket-server" repositories="amp cache dns file http parallel parser pipeline process serialization socket sync websocket-client websocket-server"
X=0 X=0
@ -518,7 +518,7 @@ jobs:
done done
exit $X exit $X
- name: Test Laravel - name: Test Laravel
if: !cancelled() if: ${{ !cancelled() }}
run: | run: |
git clone https://github.com/laravel/framework.git --branch=master --depth=1 git clone https://github.com/laravel/framework.git --branch=master --depth=1
cd framework cd framework
@ -531,7 +531,7 @@ jobs:
exit 1 exit 1
fi fi
- name: Test ReactPHP - name: Test ReactPHP
if: !cancelled() if: ${{ !cancelled() }}
run: | run: |
repositories="async cache child-process datagram dns event-loop promise promise-stream promise-timer stream" repositories="async cache child-process datagram dns event-loop promise promise-stream promise-timer stream"
X=0 X=0
@ -549,7 +549,7 @@ jobs:
done done
exit $X exit $X
- name: Test Revolt PHP - name: Test Revolt PHP
if: !cancelled() if: ${{ !cancelled() }}
run: | run: |
git clone https://github.com/revoltphp/event-loop.git --depth=1 git clone https://github.com/revoltphp/event-loop.git --depth=1
cd event-loop cd event-loop
@ -560,7 +560,7 @@ jobs:
exit 1 exit 1
fi fi
- name: Test Symfony - name: Test Symfony
if: !cancelled() && !inputs.skip_symfony if: ${{ !cancelled() && !inputs.skip_symfony }}
run: | run: |
git clone https://github.com/symfony/symfony.git --depth=1 git clone https://github.com/symfony/symfony.git --depth=1
cd symfony cd symfony
@ -581,7 +581,7 @@ jobs:
done done
exit $X exit $X
- name: Test PHPUnit - name: Test PHPUnit
if: !cancelled() if: ${{ !cancelled() }}
run: | run: |
git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1 git clone https://github.com/sebastianbergmann/phpunit.git --branch=main --depth=1
cd phpunit cd phpunit
@ -592,7 +592,7 @@ jobs:
exit 1 exit 1
fi fi
- name: 'Symfony Preloading' - name: 'Symfony Preloading'
if: !cancelled() && !inputs.skip_symfony if: ${{ !cancelled() && !inputs.skip_symfony }}
run: | run: |
php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-reqs php /usr/bin/composer create-project symfony/symfony-demo symfony_demo --no-progress --ignore-platform-reqs
cd symfony_demo cd symfony_demo
@ -600,7 +600,7 @@ jobs:
sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php sed -i 's/PHP_SAPI/"cli-server"/g' var/cache/dev/App_KernelDevDebugContainer.preload.php
php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php php -d opcache.preload=var/cache/dev/App_KernelDevDebugContainer.preload.php public/index.php
- name: Test Wordpress - name: Test Wordpress
if: !cancelled() && !inputs.skip_wordpress if: ${{ !cancelled() && !inputs.skip_wordpress }}
run: | run: |
git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1 git clone https://github.com/WordPress/wordpress-develop.git wordpress --depth=1
cd wordpress cd wordpress

4
NEWS
View file

@ -65,6 +65,10 @@ PHP NEWS
the cpu mask argument with entries type different than int/string. the cpu mask argument with entries type different than int/string.
(David Carlier) (David Carlier)
- PDO:
. Fixed a memory leak when the GC is used to free a PDOStatment. (Girgias)
. Fixed a crash in the PDO Firebird Statement destructor. (nielsdos)
- PgSql: - PgSql:
. Fixed build failure when the constant PGRES_TUPLES_CHUNK is not present . Fixed build failure when the constant PGRES_TUPLES_CHUNK is not present
in the system. (chschneider) in the system. (chschneider)

View file

@ -2074,8 +2074,11 @@ out:
static HashTable *dbstmt_get_gc(zend_object *object, zval **gc_data, int *gc_count) static HashTable *dbstmt_get_gc(zend_object *object, zval **gc_data, int *gc_count)
{ {
pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object); pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
*gc_data = &stmt->fetch.into;
*gc_count = 1; zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
zend_get_gc_buffer_add_zval(gc_buffer, &stmt->database_object_handle);
zend_get_gc_buffer_add_zval(gc_buffer, &stmt->fetch.into);
zend_get_gc_buffer_use(gc_buffer, gc_data, gc_count);
/** /**
* If there are no dynamic properties and the default property is 1 (that is, there is only one property * If there are no dynamic properties and the default property is 1 (that is, there is only one property

View file

@ -0,0 +1,138 @@
--TEST--
PDO Common: Cyclic PDOStatement child class
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
class Ref {
public CyclicStatement $stmt;
}
class CyclicStatement extends PDOStatement {
protected function __construct(public Ref $ref) {}
}
class TestRow {
public $id;
public $val;
public $val2;
public function __construct(public string $arg) {}
}
$db = PDOTest::factory();
$db->exec('CREATE TABLE pdo_stmt_cyclic_ref(id INT NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_stmt_cyclic_ref VALUES(1, 'A', 'AA')");
$db->exec("INSERT INTO pdo_stmt_cyclic_ref VALUES(2, 'B', 'BB')");
$db->exec("INSERT INTO pdo_stmt_cyclic_ref VALUES(3, 'C', 'CC')");
$db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['CyclicStatement', [new Ref]]);
echo "Column fetch:\n";
$stmt = $db->query('SELECT id, val2, val FROM pdo_stmt_cyclic_ref');
$stmt->ref->stmt = $stmt;
$stmt->setFetchMode(PDO::FETCH_COLUMN, 2);
foreach($stmt as $obj) {
var_dump($obj);
}
echo "Class fetch:\n";
$stmt = $db->query('SELECT id, val2, val FROM pdo_stmt_cyclic_ref');
$stmt->ref->stmt = $stmt;
$stmt->setFetchMode(PDO::FETCH_CLASS, 'TestRow', ['Hello world']);
foreach($stmt as $obj) {
var_dump($obj);
}
echo "Fetch into:\n";
$stmt = $db->query('SELECT id, val2, val FROM pdo_stmt_cyclic_ref');
$stmt->ref->stmt = $stmt;
$stmt->setFetchMode(PDO::FETCH_INTO, new TestRow('I am being fetch into'));
foreach($stmt as $obj) {
var_dump($obj);
}
?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_stmt_cyclic_ref");
?>
--EXPECTF--
Column fetch:
string(1) "A"
string(1) "B"
string(1) "C"
Class fetch:
object(TestRow)#%d (4) {
["id"]=>
string(1) "1"
["val"]=>
string(1) "A"
["val2"]=>
string(2) "AA"
["arg"]=>
string(11) "Hello world"
}
object(TestRow)#%d (4) {
["id"]=>
string(1) "2"
["val"]=>
string(1) "B"
["val2"]=>
string(2) "BB"
["arg"]=>
string(11) "Hello world"
}
object(TestRow)#%d (4) {
["id"]=>
string(1) "3"
["val"]=>
string(1) "C"
["val2"]=>
string(2) "CC"
["arg"]=>
string(11) "Hello world"
}
Fetch into:
object(TestRow)#4 (4) {
["id"]=>
string(1) "1"
["val"]=>
string(1) "A"
["val2"]=>
string(2) "AA"
["arg"]=>
string(21) "I am being fetch into"
}
object(TestRow)#4 (4) {
["id"]=>
string(1) "2"
["val"]=>
string(1) "B"
["val2"]=>
string(2) "BB"
["arg"]=>
string(21) "I am being fetch into"
}
object(TestRow)#4 (4) {
["id"]=>
string(1) "3"
["val"]=>
string(1) "C"
["val2"]=>
string(2) "CC"
["arg"]=>
string(21) "I am being fetch into"
}

View file

@ -158,8 +158,15 @@ static int pdo_firebird_stmt_dtor(pdo_stmt_t *stmt) /* {{{ */
pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data; pdo_firebird_stmt *S = (pdo_firebird_stmt*)stmt->driver_data;
int result = 1; int result = 1;
/* release the statement */ /* TODO: for master, move this check to a separate function shared between pdo drivers.
if (isc_dsql_free_statement(S->H->isc_status, &S->stmt, DSQL_drop)) { * pdo_pgsql and pdo_mysql do this exact same thing */
bool server_obj_usable = !Z_ISUNDEF(stmt->database_object_handle)
&& IS_OBJ_VALID(EG(objects_store).object_buckets[Z_OBJ_HANDLE(stmt->database_object_handle)])
&& !(OBJ_FLAGS(Z_OBJ(stmt->database_object_handle)) & IS_OBJ_FREE_CALLED);
/* release the statement.
* Note: if the server object is already gone then the statement was closed already as well. */
if (server_obj_usable && isc_dsql_free_statement(S->H->isc_status, &S->stmt, DSQL_drop)) {
php_firebird_error_stmt(stmt); php_firebird_error_stmt(stmt);
result = 0; result = 0;
} }