@@ -1247,6 +1247,7 @@ PHP_METHOD(PDOStatement, fetchAll)
12471247 zval * arg2 = NULL ;
12481248 zend_class_entry * old_ce ;
12491249 zval old_ctor_args , * ctor_args = NULL ;
1250+ HashTable * current_ctor = NULL ;
12501251 bool error = false;
12511252 int flags , old_arg_count ;
12521253
@@ -1264,6 +1265,10 @@ PHP_METHOD(PDOStatement, fetchAll)
12641265
12651266 old_ce = stmt -> fetch .cls .ce ;
12661267 ZVAL_COPY_VALUE (& old_ctor_args , & stmt -> fetch .cls .ctor_args );
1268+ if (Z_TYPE (old_ctor_args ) == IS_ARRAY ) {
1269+ /* Protect against destruction by marking this as immutable: we consider this non-owned temporarily */
1270+ Z_TYPE_INFO (stmt -> fetch .cls .ctor_args ) = IS_ARRAY ;
1271+ }
12671272 old_arg_count = stmt -> fetch .cls .fci .param_count ;
12681273
12691274 do_fetch_opt_finish (stmt , 0 );
@@ -1288,7 +1293,13 @@ PHP_METHOD(PDOStatement, fetchAll)
12881293 }
12891294
12901295 if (ctor_args && zend_hash_num_elements (Z_ARRVAL_P (ctor_args )) > 0 ) {
1291- ZVAL_COPY_VALUE (& stmt -> fetch .cls .ctor_args , ctor_args ); /* we're not going to free these */
1296+ /* We increase the refcount and store it in case usercode has been messing around with the ctor args.
1297+ * We need to store current_ctor separately as usercode may change the ctor_args which will cause a leak. */
1298+ current_ctor = Z_ARRVAL_P (ctor_args );
1299+ ZVAL_COPY (& stmt -> fetch .cls .ctor_args , ctor_args );
1300+ /* Protect against destruction by marking this as immutable: we consider this non-owned
1301+ * as destruction is handled via current_ctor. */
1302+ Z_TYPE_INFO (stmt -> fetch .cls .ctor_args ) = IS_ARRAY ;
12921303 } else {
12931304 ZVAL_UNDEF (& stmt -> fetch .cls .ctor_args );
12941305 }
@@ -1360,6 +1371,7 @@ PHP_METHOD(PDOStatement, fetchAll)
13601371 }
13611372
13621373 PDO_STMT_CLEAR_ERR ();
1374+
13631375 if ((how & PDO_FETCH_GROUP ) || how == PDO_FETCH_KEY_PAIR ||
13641376 (how == PDO_FETCH_USE_DEFAULT && stmt -> default_fetch_type == PDO_FETCH_KEY_PAIR )
13651377 ) {
@@ -1384,9 +1396,15 @@ PHP_METHOD(PDOStatement, fetchAll)
13841396 }
13851397
13861398 do_fetch_opt_finish (stmt , 0 );
1399+ if (current_ctor ) {
1400+ zend_array_release (current_ctor );
1401+ }
13871402
13881403 /* Restore defaults which were changed by PDO_FETCH_CLASS mode */
13891404 stmt -> fetch .cls .ce = old_ce ;
1405+ /* ctor_args may have been changed to an owned object in the meantime, so destroy it.
1406+ * If it was not, then the type flags update will have protected us against destruction. */
1407+ zval_ptr_dtor (& stmt -> fetch .cls .ctor_args );
13901408 ZVAL_COPY_VALUE (& stmt -> fetch .cls .ctor_args , & old_ctor_args );
13911409 stmt -> fetch .cls .fci .param_count = old_arg_count ;
13921410
0 commit comments