@@ -384,6 +384,11 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_
384
384
zend_string * op1_str = Z_STR_P (op1 );
385
385
zend_string * op2_str = Z_STR_P (op2 );
386
386
zend_string * str ;
387
+ uint32_t flags = 0 ;
388
+
389
+ if (ZSTR_IS_VALID_UTF8 (op1_str ) && ZSTR_IS_VALID_UTF8 (op2_str )) {
390
+ flags = IS_STR_VALID_UTF8 ;
391
+ }
387
392
388
393
if (OP1_TYPE != IS_CONST && UNEXPECTED (ZSTR_LEN (op1_str ) == 0 )) {
389
394
if (OP2_TYPE == IS_CONST || OP2_TYPE == IS_CV ) {
@@ -412,6 +417,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_
412
417
}
413
418
str = zend_string_extend (op1_str , len + ZSTR_LEN (op2_str ), 0 );
414
419
memcpy (ZSTR_VAL (str ) + len , ZSTR_VAL (op2_str ), ZSTR_LEN (op2_str )+ 1 );
420
+ GC_ADD_FLAGS (str , flags );
415
421
ZVAL_NEW_STR (EX_VAR (opline -> result .var ), str );
416
422
if (OP2_TYPE & (IS_TMP_VAR |IS_VAR )) {
417
423
zend_string_release_ex (op2_str , 0 );
@@ -420,6 +426,7 @@ ZEND_VM_HANDLER(8, ZEND_CONCAT, CONST|TMPVAR|CV, CONST|TMPVAR|CV, SPEC(NO_CONST_
420
426
str = zend_string_alloc (ZSTR_LEN (op1_str ) + ZSTR_LEN (op2_str ), 0 );
421
427
memcpy (ZSTR_VAL (str ), ZSTR_VAL (op1_str ), ZSTR_LEN (op1_str ));
422
428
memcpy (ZSTR_VAL (str ) + ZSTR_LEN (op1_str ), ZSTR_VAL (op2_str ), ZSTR_LEN (op2_str )+ 1 );
429
+ GC_ADD_FLAGS (str , flags );
423
430
ZVAL_NEW_STR (EX_VAR (opline -> result .var ), str );
424
431
if (OP1_TYPE & (IS_TMP_VAR |IS_VAR )) {
425
432
zend_string_release_ex (op1_str , 0 );
@@ -3140,6 +3147,11 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP
3140
3147
zend_string * op1_str = Z_STR_P (op1 );
3141
3148
zend_string * op2_str = Z_STR_P (op2 );
3142
3149
zend_string * str ;
3150
+ uint32_t flags = 0 ;
3151
+
3152
+ if (ZSTR_IS_VALID_UTF8 (op1_str ) && ZSTR_IS_VALID_UTF8 (op2_str )) {
3153
+ flags = IS_STR_VALID_UTF8 ;
3154
+ }
3143
3155
3144
3156
if (OP1_TYPE != IS_CONST && UNEXPECTED (ZSTR_LEN (op1_str ) == 0 )) {
3145
3157
if (OP2_TYPE == IS_CONST || OP2_TYPE == IS_CV ) {
@@ -3165,6 +3177,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP
3165
3177
3166
3178
str = zend_string_extend (op1_str , len + ZSTR_LEN (op2_str ), 0 );
3167
3179
memcpy (ZSTR_VAL (str ) + len , ZSTR_VAL (op2_str ), ZSTR_LEN (op2_str )+ 1 );
3180
+ GC_ADD_FLAGS (str , flags );
3168
3181
ZVAL_NEW_STR (EX_VAR (opline -> result .var ), str );
3169
3182
if (OP2_TYPE & (IS_TMP_VAR |IS_VAR )) {
3170
3183
zend_string_release_ex (op2_str , 0 );
@@ -3173,6 +3186,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP
3173
3186
str = zend_string_alloc (ZSTR_LEN (op1_str ) + ZSTR_LEN (op2_str ), 0 );
3174
3187
memcpy (ZSTR_VAL (str ), ZSTR_VAL (op1_str ), ZSTR_LEN (op1_str ));
3175
3188
memcpy (ZSTR_VAL (str ) + ZSTR_LEN (op1_str ), ZSTR_VAL (op2_str ), ZSTR_LEN (op2_str )+ 1 );
3189
+ GC_ADD_FLAGS (str , flags );
3176
3190
ZVAL_NEW_STR (EX_VAR (opline -> result .var ), str );
3177
3191
if (OP1_TYPE & (IS_TMP_VAR |IS_VAR )) {
3178
3192
zend_string_release_ex (op1_str , 0 );
@@ -3233,6 +3247,10 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(53, ZEND_FAST_CONCAT, CONST|TMPVAR|CV, CONST|TMP
3233
3247
str = zend_string_alloc (ZSTR_LEN (op1_str ) + ZSTR_LEN (op2_str ), 0 );
3234
3248
memcpy (ZSTR_VAL (str ), ZSTR_VAL (op1_str ), ZSTR_LEN (op1_str ));
3235
3249
memcpy (ZSTR_VAL (str ) + ZSTR_LEN (op1_str ), ZSTR_VAL (op2_str ), ZSTR_LEN (op2_str )+ 1 );
3250
+
3251
+ if (ZSTR_IS_VALID_UTF8 (op1_str ) && ZSTR_IS_VALID_UTF8 (op2_str )) {
3252
+ GC_ADD_FLAGS (str , IS_STR_VALID_UTF8 );
3253
+ }
3236
3254
ZVAL_NEW_STR (EX_VAR (opline -> result .var ), str );
3237
3255
if (OP1_TYPE != IS_CONST ) {
3238
3256
zend_string_release_ex (op1_str , 0 );
0 commit comments