@@ -3691,11 +3691,26 @@ PHP_FUNCTION(mb_convert_kana)
36913691 RETVAL_STR (jp_kana_convert (str , enc , opt ));
36923692}
36933693
3694+ static zend_always_inline bool mb_check_stack_limit (void )
3695+ {
3696+ #ifdef ZEND_CHECK_STACK_LIMIT
3697+ if (UNEXPECTED (zend_call_stack_overflowed (EG (stack_limit )))) {
3698+ zend_call_stack_size_error ();
3699+ return true;
3700+ }
3701+ #endif
3702+ return false;
3703+ }
3704+
36943705static unsigned int mb_recursive_count_strings (zval * var )
36953706{
36963707 unsigned int count = 0 ;
36973708 ZVAL_DEREF (var );
36983709
3710+ if (mb_check_stack_limit ()) {
3711+ return 0 ;
3712+ }
3713+
36993714 if (Z_TYPE_P (var ) == IS_STRING ) {
37003715 count ++ ;
37013716 } else if (Z_TYPE_P (var ) == IS_ARRAY || Z_TYPE_P (var ) == IS_OBJECT ) {
@@ -3726,6 +3741,10 @@ static bool mb_recursive_find_strings(zval *var, const unsigned char **val_list,
37263741{
37273742 ZVAL_DEREF (var );
37283743
3744+ if (mb_check_stack_limit ()) {
3745+ return true;
3746+ }
3747+
37293748 if (Z_TYPE_P (var ) == IS_STRING ) {
37303749 val_list [* count ] = (const unsigned char * )Z_STRVAL_P (var );
37313750 len_list [* count ] = Z_STRLEN_P (var );
@@ -3763,6 +3782,10 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
37633782{
37643783 zval * entry , * orig_var ;
37653784
3785+ if (mb_check_stack_limit ()) {
3786+ return true;
3787+ }
3788+
37663789 orig_var = var ;
37673790 ZVAL_DEREF (var );
37683791
@@ -3771,17 +3794,25 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
37713794 zval_ptr_dtor (orig_var );
37723795 ZVAL_STR (orig_var , ret );
37733796 } else if (Z_TYPE_P (var ) == IS_ARRAY || Z_TYPE_P (var ) == IS_OBJECT ) {
3774- if ( Z_TYPE_P ( var ) == IS_ARRAY ) {
3775- SEPARATE_ARRAY ( var ) ;
3776- }
3777- if (Z_REFCOUNTED_P ( var ) ) {
3778- if (Z_IS_RECURSIVE_P ( var )) {
3797+ HashTable * ht = HASH_OF ( var );
3798+ HashTable * orig_ht = ht ;
3799+
3800+ if (ht ) {
3801+ if (GC_IS_RECURSIVE ( ht )) {
37793802 return true;
37803803 }
3781- Z_PROTECT_RECURSION_P (var );
3804+
3805+ GC_TRY_PROTECT_RECURSION (ht );
37823806 }
37833807
3784- HashTable * ht = HASH_OF (var );
3808+ if (Z_TYPE_P (var ) == IS_ARRAY ) {
3809+ SEPARATE_ARRAY (var );
3810+ ht = Z_ARRVAL_P (var );
3811+
3812+ if (ht && ht != orig_ht && !GC_IS_RECURSIVE (ht )) {
3813+ GC_TRY_PROTECT_RECURSION (ht );
3814+ }
3815+ }
37853816 if (ht != NULL ) {
37863817 ZEND_HASH_FOREACH_VAL (ht , entry ) {
37873818 /* Can be a typed property declaration, in which case we need to remove the reference from the source list.
@@ -3800,16 +3831,22 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
38003831 }
38013832
38023833 if (mb_recursive_convert_variable (entry , from_encoding , to_encoding )) {
3803- if (Z_REFCOUNTED_P (var )) {
3804- Z_UNPROTECT_RECURSION_P (var );
3834+ if (ht && ht != orig_ht ) {
3835+ GC_TRY_UNPROTECT_RECURSION (ht );
3836+ }
3837+ if (orig_ht ) {
3838+ GC_TRY_UNPROTECT_RECURSION (orig_ht );
38053839 }
38063840 return true;
38073841 }
38083842 } ZEND_HASH_FOREACH_END ();
38093843 }
38103844
3811- if (Z_REFCOUNTED_P (var )) {
3812- Z_UNPROTECT_RECURSION_P (var );
3845+ if (ht && ht != orig_ht ) {
3846+ GC_TRY_UNPROTECT_RECURSION (ht );
3847+ }
3848+ if (orig_ht ) {
3849+ GC_TRY_UNPROTECT_RECURSION (orig_ht );
38133850 }
38143851 }
38153852
@@ -3883,7 +3920,9 @@ PHP_FUNCTION(mb_convert_variables)
38833920 efree (ZEND_VOIDP (elist ));
38843921 efree (ZEND_VOIDP (val_list ));
38853922 efree (len_list );
3886- php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3923+ if (!EG (exception )) {
3924+ php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3925+ }
38873926 RETURN_FALSE ;
38883927 }
38893928 }
@@ -3905,7 +3944,9 @@ PHP_FUNCTION(mb_convert_variables)
39053944 zval * zv = & args [n ];
39063945 ZVAL_DEREF (zv );
39073946 if (mb_recursive_convert_variable (zv , from_encoding , to_encoding )) {
3908- php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3947+ if (!EG (exception )) {
3948+ php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3949+ }
39093950 RETURN_FALSE ;
39103951 }
39113952 }
0 commit comments