Commit 8c78c97f196 for php

commit 8c78c97f1960438d2c7e586139a9f33762fac68c
Merge: f2469f6684f 357fcf12f4e
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Wed Sep 30 13:56:03 2026 -0400

    Merge branch 'PHP-8.4' into PHP-8.5

    * PHP-8.4:
      ext/pdo: Make PDOStatement::setFetchMode() updates atomic

diff --cc ext/pdo/pdo_stmt.c
index d0bb89ea6a2,b5b74351419..8a33cb74ddb
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@@ -1678,14 -1772,20 +1678,17 @@@ bool pdo_stmt_setup_fetch_mode(pdo_stmt
  	uint32_t arg1_arg_num = mode_arg_num + 1;
  	uint32_t constructor_arg_num = mode_arg_num + 2;
  	uint32_t total_num_args = mode_arg_num + variadic_num_args;
-
- 	pdo_stmt_free_default_fetch_mode(stmt);
-
- 	stmt->default_fetch_type = stmt->dbh->default_fetch_type;
+ 	zend_long fetch_type = mode & ~PDO_FETCH_FLAGS;
+ 	zend_long fetch_column = 0;
+ 	zend_class_entry *fetch_class = NULL;
 -	zend_array *fetch_ctor_args = NULL;
++	HashTable *fetch_ctor_args = NULL;
+ 	zend_object *fetch_into = NULL;
 -	zval old_ctor_args;
 -	zval old_into;
 -
 -	ZVAL_UNDEF(&old_ctor_args);
 -	ZVAL_UNDEF(&old_into);
++	zend_object *old_into = NULL;
++	HashTable *old_ctor_args = NULL;

  	flags = mode & PDO_FETCH_FLAGS;

- 	if (!pdo_verify_fetch_mode(stmt->default_fetch_type, mode, mode_arg_num, false)) {
 -	if (!pdo_stmt_verify_mode(stmt, mode, mode_arg_num, false)) {
++	if (!pdo_verify_fetch_mode(stmt->dbh->default_fetch_type, mode, mode_arg_num, false)) {
  		return false;
  	}

@@@ -1774,15 -1873,19 +1775,14 @@@
  						return false;
  					}
  					if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
 -						constructor_args = Z_ARRVAL(args[1]);
 +						if (cep->constructor == NULL) {
 +							zend_argument_value_error(3, "must be empty when class provided in argument #2 ($class) does not have a constructor");
 +							return false;
 +						}
- 						GC_TRY_ADDREF(Z_ARRVAL(args[1]));
- 						stmt->fetch.cls.ctor_args = Z_ARRVAL(args[1]);
++						fetch_ctor_args = Z_ARRVAL(args[1]);
  					}
  				}
- 				stmt->fetch.cls.ce = cep;
+ 				fetch_class = cep;
 -
 -				/* If constructor arguments are present and not empty */
 -				if (constructor_args) {
 -					if (!cep->constructor) {
 -						zend_throw_error(NULL, "User-supplied statement does not accept constructor arguments");
 -						return false;
 -					}
 -					fetch_ctor_args = zend_array_dup(constructor_args);
 -				}
  			}
  			break;
  		}
@@@ -1807,10 -1909,50 +1806,45 @@@
  			return false;
  	}

- 	if (!use_default) {
+ 	if ((stmt->default_fetch_type & ~PDO_FETCH_FLAGS) == PDO_FETCH_INTO) {
 -		ZVAL_COPY_VALUE(&old_into, &stmt->fetch.into);
 -		ZVAL_UNDEF(&stmt->fetch.into);
++		old_into = stmt->fetch.into;
+ 	} else if ((stmt->default_fetch_type & ~PDO_FETCH_FLAGS) == PDO_FETCH_CLASS) {
 -		do_fetch_opt_finish(stmt, 0);
 -		ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
 -		ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
 -	} else {
 -		do_fetch_opt_finish(stmt, 1);
++		old_ctor_args = stmt->fetch.cls.ctor_args;
+ 	}
++	memset(&stmt->fetch, 0, sizeof(stmt->fetch));
+
+ 	switch (fetch_type) {
+ 		case PDO_FETCH_COLUMN:
+ 			stmt->fetch.column = fetch_column;
+ 			break;
+ 		case PDO_FETCH_CLASS:
+ 			stmt->fetch.cls.ce = fetch_class;
+ 			if (fetch_ctor_args) {
 -				ZVAL_ARR(&stmt->fetch.cls.ctor_args, fetch_ctor_args);
 -			} else {
 -				ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
++				GC_TRY_ADDREF(fetch_ctor_args);
++				stmt->fetch.cls.ctor_args = fetch_ctor_args;
+ 			}
 -			do_fetch_class_prepare(stmt);
+ 			break;
+ 		case PDO_FETCH_INTO:
 -			ZVAL_OBJ_COPY(&stmt->fetch.into, fetch_into);
++			GC_ADDREF(fetch_into);
++			stmt->fetch.into = fetch_into;
+ 			break;
+ 		default:
+ 			break;
+ 	}
+
+ 	if (fetch_type == PDO_FETCH_USE_DEFAULT) {
+ 		stmt->default_fetch_type = stmt->dbh->default_fetch_type;
+ 	} else {
  		stmt->default_fetch_type = mode;
  	}

 -	if (!Z_ISUNDEF(old_into)) {
 -		zval_ptr_dtor(&old_into);
++	if (old_into) {
++		OBJ_RELEASE(old_into);
+ 	}
 -	if (!Z_ISUNDEF(old_ctor_args)) {
 -		zval_ptr_dtor(&old_ctor_args);
++	if (old_ctor_args) {
++		zend_array_release(old_ctor_args);
+ 	}
+
  	return true;
  }