@@ -3697,11 +3697,26 @@ PHP_FUNCTION(mb_convert_kana)
36973697 RETVAL_STR (jp_kana_convert (str , enc , opt ));
36983698}
36993699
3700+ static zend_always_inline bool mb_check_stack_limit (void )
3701+ {
3702+ #ifdef ZEND_CHECK_STACK_LIMIT
3703+ if (UNEXPECTED (zend_call_stack_overflowed (EG (stack_limit )))) {
3704+ zend_call_stack_size_error ();
3705+ return true;
3706+ }
3707+ #endif
3708+ return false;
3709+ }
3710+
37003711static unsigned int mb_recursive_count_strings (zval * var )
37013712{
37023713 unsigned int count = 0 ;
37033714 ZVAL_DEREF (var );
37043715
3716+ if (mb_check_stack_limit ()) {
3717+ return 0 ;
3718+ }
3719+
37053720 if (Z_TYPE_P (var ) == IS_STRING ) {
37063721 count ++ ;
37073722 } else if (Z_TYPE_P (var ) == IS_ARRAY || Z_TYPE_P (var ) == IS_OBJECT ) {
@@ -3732,6 +3747,10 @@ static bool mb_recursive_find_strings(zval *var, const unsigned char **val_list,
37323747{
37333748 ZVAL_DEREF (var );
37343749
3750+ if (mb_check_stack_limit ()) {
3751+ return true;
3752+ }
3753+
37353754 if (Z_TYPE_P (var ) == IS_STRING ) {
37363755 val_list [* count ] = (const unsigned char * )Z_STRVAL_P (var );
37373756 len_list [* count ] = Z_STRLEN_P (var );
@@ -3769,6 +3788,10 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
37693788{
37703789 zval * entry , * orig_var ;
37713790
3791+ if (mb_check_stack_limit ()) {
3792+ return true;
3793+ }
3794+
37723795 orig_var = var ;
37733796 ZVAL_DEREF (var );
37743797
@@ -3777,17 +3800,25 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
37773800 zval_ptr_dtor (orig_var );
37783801 ZVAL_STR (orig_var , ret );
37793802 } else if (Z_TYPE_P (var ) == IS_ARRAY || Z_TYPE_P (var ) == IS_OBJECT ) {
3780- if ( Z_TYPE_P ( var ) == IS_ARRAY ) {
3781- SEPARATE_ARRAY ( var ) ;
3782- }
3783- if (Z_REFCOUNTED_P ( var ) ) {
3784- if (Z_IS_RECURSIVE_P ( var )) {
3803+ HashTable * ht = HASH_OF ( var );
3804+ HashTable * orig_ht = ht ;
3805+
3806+ if (ht ) {
3807+ if (GC_IS_RECURSIVE ( ht )) {
37853808 return true;
37863809 }
3787- Z_PROTECT_RECURSION_P (var );
3810+
3811+ GC_TRY_PROTECT_RECURSION (ht );
37883812 }
37893813
3790- HashTable * ht = HASH_OF (var );
3814+ if (Z_TYPE_P (var ) == IS_ARRAY ) {
3815+ SEPARATE_ARRAY (var );
3816+ ht = Z_ARRVAL_P (var );
3817+
3818+ if (ht && ht != orig_ht && !GC_IS_RECURSIVE (ht )) {
3819+ GC_TRY_PROTECT_RECURSION (ht );
3820+ }
3821+ }
37913822 if (ht != NULL ) {
37923823 ZEND_HASH_FOREACH_VAL (ht , entry ) {
37933824 /* Can be a typed property declaration, in which case we need to remove the reference from the source list.
@@ -3806,16 +3837,22 @@ static bool mb_recursive_convert_variable(zval *var, const mbfl_encoding* from_e
38063837 }
38073838
38083839 if (mb_recursive_convert_variable (entry , from_encoding , to_encoding )) {
3809- if (Z_REFCOUNTED_P (var )) {
3810- Z_UNPROTECT_RECURSION_P (var );
3840+ if (ht && ht != orig_ht ) {
3841+ GC_TRY_UNPROTECT_RECURSION (ht );
3842+ }
3843+ if (orig_ht ) {
3844+ GC_TRY_UNPROTECT_RECURSION (orig_ht );
38113845 }
38123846 return true;
38133847 }
38143848 } ZEND_HASH_FOREACH_END ();
38153849 }
38163850
3817- if (Z_REFCOUNTED_P (var )) {
3818- Z_UNPROTECT_RECURSION_P (var );
3851+ if (ht && ht != orig_ht ) {
3852+ GC_TRY_UNPROTECT_RECURSION (ht );
3853+ }
3854+ if (orig_ht ) {
3855+ GC_TRY_UNPROTECT_RECURSION (orig_ht );
38193856 }
38203857 }
38213858
@@ -3889,7 +3926,9 @@ PHP_FUNCTION(mb_convert_variables)
38893926 efree (ZEND_VOIDP (elist ));
38903927 efree (ZEND_VOIDP (val_list ));
38913928 efree (len_list );
3892- php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3929+ if (!EG (exception )) {
3930+ php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3931+ }
38933932 RETURN_FALSE ;
38943933 }
38953934 }
@@ -3911,7 +3950,9 @@ PHP_FUNCTION(mb_convert_variables)
39113950 zval * zv = & args [n ];
39123951 ZVAL_DEREF (zv );
39133952 if (mb_recursive_convert_variable (zv , from_encoding , to_encoding )) {
3914- php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3953+ if (!EG (exception )) {
3954+ php_error_docref (NULL , E_WARNING , "Cannot handle recursive references" );
3955+ }
39153956 RETURN_FALSE ;
39163957 }
39173958 }
0 commit comments