From aa7280264e9b42a287cf38c68a019ca516db01dd Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Dec 2021 11:30:03 +0300 Subject: [PATCH 01/75] Fix refcount inferemce ($a += $a returns old array with RCN) Fixes oss-fuzz #41670 --- ext/opcache/Optimizer/zend_inference.c | 2 +- ext/opcache/tests/jit/assign_op_008.phpt | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/jit/assign_op_008.phpt diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index f7e28643f448a..92ae858b707bc 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -2570,7 +2570,7 @@ static zend_always_inline int _zend_update_type_info( ssa, opline->extended_value, t1, t2, opline->opcode == ZEND_ASSIGN_OP ? ssa_op->op1_def : -1, optimization_level); if (tmp & (MAY_BE_STRING|MAY_BE_ARRAY)) { - tmp |= MAY_BE_RC1; + tmp |= MAY_BE_RC1 | MAY_BE_RCN; } if (tmp & (MAY_BE_OBJECT|MAY_BE_RESOURCE)) { tmp |= MAY_BE_RC1 | MAY_BE_RCN; diff --git a/ext/opcache/tests/jit/assign_op_008.phpt b/ext/opcache/tests/jit/assign_op_008.phpt new file mode 100644 index 0000000000000..efd9418741fc0 --- /dev/null +++ b/ext/opcache/tests/jit/assign_op_008.phpt @@ -0,0 +1,22 @@ +--TEST-- +JIT ASSIGN_OP: 008 Arrays merging with itself +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- + +DONE +--EXPECTF-- +Warning: Undefined array key "b" in %sassign_op_008.php on line 6 +DONE From 5459ed4c2fbc25560da3808e823c0503704a8f31 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Dec 2021 13:08:27 +0300 Subject: [PATCH 02/75] Fix use after free because of data clobbering by user error handler Fixes oss-fuzz #41692 --- Zend/tests/falsetoarray_002.phpt | 15 + Zend/zend_execute.c | 19 +- Zend/zend_vm_def.h | 31 +- Zend/zend_vm_execute.h | 656 +++++++++++++++++++++-------- ext/opcache/jit/zend_jit_helpers.c | 36 +- 5 files changed, 561 insertions(+), 196 deletions(-) create mode 100644 Zend/tests/falsetoarray_002.phpt diff --git a/Zend/tests/falsetoarray_002.phpt b/Zend/tests/falsetoarray_002.phpt new file mode 100644 index 0000000000000..c01b799545965 --- /dev/null +++ b/Zend/tests/falsetoarray_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +Autovivification of false to array with data clobbering by error handler +--FILE-- + +--EXPECT-- +Err: Automatic conversion of false to array is deprecated +string(0) "" diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 02eda69787a15..aa0a2e39ec438 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2508,13 +2508,24 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * if (type != BP_VAR_W && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { - zend_false_to_array_deprecated(); - } if (type != BP_VAR_UNSET) { - array_init(container); + HashTable *ht = zend_new_array(0); + zend_uchar old_type = Z_TYPE_P(container); + + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto return_null; + } + } goto fetch_from_array; } else { + if (UNEXPECTED(Z_TYPE_P(container) == IS_FALSE)) { + zend_false_to_array_deprecated(); + } return_null: /* for read-mode only */ if (ZEND_CONST_COND(dim_type == IS_CV, dim != NULL) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index df0f853fba067..335c4f7a7ab71 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1217,13 +1217,23 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + ZEND_VM_C_GOTO(assign_dim_op_ret_null); + } } - ZVAL_ARR(container, zend_new_array(8)); ZEND_VM_C_GOTO(assign_dim_op_new_array); } else { dim = GET_OP2_ZVAL_PTR(BP_VAR_R); @@ -2626,10 +2636,6 @@ ZEND_VM_C_LABEL(try_assign_dim_array): FREE_OP_DATA(); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -2637,7 +2643,18 @@ ZEND_VM_C_LABEL(try_assign_dim_array): FREE_OP_DATA(); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + ZEND_VM_C_GOTO(assign_dim_error); + } + } ZEND_VM_C_GOTO(try_assign_dim_array); } } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 89f0cab5e20a1..2596d5261a41a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -22459,13 +22459,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = RT_CONSTANT(opline, opline->op2); @@ -23431,10 +23441,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -23442,7 +23448,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -23568,10 +23585,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -23579,7 +23592,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -23705,10 +23729,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -23716,7 +23736,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -23841,10 +23872,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -23852,7 +23879,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -25100,13 +25138,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -26077,10 +26125,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -26088,7 +26132,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -26214,10 +26269,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -26225,7 +26276,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -26351,10 +26413,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -26362,7 +26420,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -26487,10 +26556,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -26498,7 +26563,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -27379,13 +27455,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = NULL; @@ -27555,10 +27641,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -27566,7 +27648,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -27692,10 +27785,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -27703,7 +27792,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -27829,10 +27929,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -27840,7 +27936,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -27965,10 +28072,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -27976,7 +28079,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -29206,13 +29320,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); @@ -30178,10 +30302,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -30189,7 +30309,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -30315,10 +30446,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -30326,7 +30453,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -30452,10 +30590,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -30463,7 +30597,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -30588,10 +30733,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -30599,7 +30740,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -39900,13 +40052,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = RT_CONSTANT(opline, opline->op2); @@ -41135,10 +41297,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -41146,7 +41304,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -41272,10 +41441,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -41283,7 +41448,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -41409,10 +41585,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -41420,7 +41592,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -41545,10 +41728,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -41556,7 +41735,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -43620,13 +43810,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -44854,10 +45054,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -44865,7 +45061,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -44991,10 +45198,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -45002,7 +45205,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -45128,10 +45342,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -45139,7 +45349,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -45264,10 +45485,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -45275,7 +45492,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -46475,13 +46703,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = NULL; @@ -46779,10 +47017,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -46790,7 +47024,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -46916,10 +47161,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -46927,7 +47168,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -47053,10 +47305,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -47064,7 +47312,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -47189,10 +47448,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -47200,7 +47455,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -48833,13 +49099,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL } zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { + HashTable *ht; + zend_uchar old_type; + if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); } - if (Z_TYPE_P(container) == IS_FALSE) { + ht = zend_new_array(8); + old_type = Z_TYPE_P(container); + ZVAL_ARR(container, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_op_ret_null; + } } - ZVAL_ARR(container, zend_new_array(8)); goto assign_dim_op_new_array; } else { dim = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); @@ -50063,10 +50339,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -50074,7 +50346,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -50200,10 +50483,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -50211,7 +50490,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -50337,10 +50627,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -50348,7 +50634,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { @@ -50473,10 +50770,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } else if (EXPECTED(Z_TYPE_P(object_ptr) <= IS_FALSE)) { - if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); - } - if (Z_ISREF_P(orig_object_ptr) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(orig_object_ptr)) && !zend_verify_ref_array_assignable(Z_REF_P(orig_object_ptr))) { @@ -50484,7 +50777,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ UNDEF_RESULT(); } else { - ZVAL_ARR(object_ptr, zend_new_array(8)); + HashTable *ht = zend_new_array(8); + zend_uchar old_type = Z_TYPE_P(object_ptr); + + ZVAL_ARR(object_ptr, ht); + if (UNEXPECTED(old_type == IS_FALSE)) { + GC_ADDREF(ht); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(ht) == 0)) { + zend_array_destroy(ht); + goto assign_dim_error; + } + } goto try_assign_dim_array; } } else { diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 2779636831420..2aeb68cbf8305 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1152,9 +1152,15 @@ static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval } ZVAL_UNDEF(result); } else if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); zend_array *arr = zend_new_array(0); ZVAL_ARR(object_ptr, arr); + GC_ADDREF(arr); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(arr) == 0)) { + zend_array_destroy(arr); + ZVAL_NULL(result); + return; + } zval *var; if (dim) { if (type == BP_VAR_W) { @@ -1247,12 +1253,6 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim return; } - if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { - const zend_op *opline = EG(current_execute_data)->opline; - zend_jit_undefined_op_helper(opline->op2.var); - dim = &EG(uninitialized_zval); - } - if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { const zend_op *op_data = EG(current_execute_data)->opline + 1; ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV); @@ -1266,9 +1266,17 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim ZVAL_UNDEF(result); } } else if (Z_TYPE_P(object_ptr) == IS_FALSE) { - zend_false_to_array_deprecated(); zend_array *arr = zend_new_array(0); ZVAL_ARR(object_ptr, arr); + GC_ADDREF(arr); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(arr) == 0)) { + zend_array_destroy(arr); + if (result) { + ZVAL_NULL(result); + } + return; + } zval *var = dim ? zend_jit_fetch_dim_w_helper(arr, dim) : zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval)); @@ -1284,6 +1292,11 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim ZVAL_COPY(result, var); } } else { + if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { + const zend_op *opline = EG(current_execute_data)->opline; + zend_jit_undefined_op_helper(opline->op2.var); + dim = &EG(uninitialized_zval); + } zend_throw_error(NULL, "Cannot use a scalar value as an array"); if (result) { ZVAL_UNDEF(result); @@ -1335,9 +1348,14 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d zend_wrong_string_offset_error(); } } else if (Z_TYPE_P(container) == IS_FALSE) { - zend_false_to_array_deprecated(); zend_array *arr = zend_new_array(0); ZVAL_ARR(container, arr); + GC_ADDREF(arr); + zend_false_to_array_deprecated(); + if (UNEXPECTED(GC_DELREF(arr) == 0)) { + zend_array_destroy(arr); + return; + } zval *var = dim ? zend_jit_fetch_dim_rw_helper(arr, dim) : zend_hash_next_index_insert_new(arr, &EG(uninitialized_zval)); From c29f6baaee5e4d1bc826a7c1414f912b21c3e8f8 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Dec 2021 14:22:07 +0300 Subject: [PATCH 03/75] JIT: Fix incorrect elimination of type store Fixes oss-fuzz #41995 --- ext/opcache/jit/zend_jit.c | 12 +++++++++--- ext/opcache/tests/jit/mul_008.phpt | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/jit/mul_008.phpt diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index c4d2fdc4ce2a1..48d3d55d32e0a 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2341,7 +2341,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (opline->result_type != IS_UNUSED) { res_use_info = -1; - if (opline->result_type == IS_CV) { + if (opline->result_type == IS_CV + && ssa_op->result_use >= 0 + && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); if (Z_MODE(res_use_addr) != IS_REG @@ -2403,7 +2405,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } else { res_use_info = -1; - if (opline->result_type == IS_CV) { + if (opline->result_type == IS_CV + && ssa_op->result_use >= 0 + && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); if (Z_MODE(res_use_addr) != IS_REG @@ -2458,7 +2462,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } else { res_use_info = -1; - if (opline->result_type == IS_CV) { + if (opline->result_type == IS_CV + && ssa_op->result_use >= 0 + && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); if (Z_MODE(res_use_addr) != IS_REG diff --git a/ext/opcache/tests/jit/mul_008.phpt b/ext/opcache/tests/jit/mul_008.phpt new file mode 100644 index 0000000000000..d890a86c8f485 --- /dev/null +++ b/ext/opcache/tests/jit/mul_008.phpt @@ -0,0 +1,26 @@ +--TEST-- +JIT MUL: 008 incorrect elimination of type store +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %smul_008.php:6 +Stack trace: +#0 %smul_008.php(8): foo(%d) +#1 {main} + thrown in %smul_008.php on line 6 From 7b629afe4e9411c8fb5a68a2641d33027a9784e6 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 6 Dec 2021 15:59:30 +0300 Subject: [PATCH 04/75] Fixed incorrect DCE of a constructor call Fixez oss-fuzz #42049 --- ext/opcache/Optimizer/dce.c | 5 ++++- ext/opcache/tests/opt/dce_012.phpt | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/opt/dce_012.phpt diff --git a/ext/opcache/Optimizer/dce.c b/ext/opcache/Optimizer/dce.c index f0f67055dfa7e..47f5f271062e2 100644 --- a/ext/opcache/Optimizer/dce.c +++ b/ext/opcache/Optimizer/dce.c @@ -592,7 +592,10 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, zend_bool reor while ((i = zend_bitset_pop_first(ctx.instr_worklist, ctx.instr_worklist_len)) >= 0) { zend_bitset_excl(ctx.instr_dead, i); add_operands_to_worklists(&ctx, &op_array->opcodes[i], &ssa->ops[i], ssa, 1); - if (i < op_array->last && op_array->opcodes[i+1].opcode == ZEND_OP_DATA) { + if (i < op_array->last + && (op_array->opcodes[i+1].opcode == ZEND_OP_DATA + || (op_array->opcodes[i].opcode == ZEND_NEW + && op_array->opcodes[i+1].opcode == ZEND_DO_FCALL))) { zend_bitset_excl(ctx.instr_dead, i+1); add_operands_to_worklists(&ctx, &op_array->opcodes[i+1], &ssa->ops[i+1], ssa, 1); } diff --git a/ext/opcache/tests/opt/dce_012.phpt b/ext/opcache/tests/opt/dce_012.phpt new file mode 100644 index 0000000000000..49cde14b33c33 --- /dev/null +++ b/ext/opcache/tests/opt/dce_012.phpt @@ -0,0 +1,26 @@ +--TEST-- +Incorrect DCE of constructor DO_FCALL +--FILE-- +orop1 = 'abc'; + } + + foreach (range(0, 6) as $levels) { + print "$levels level" . ($levels == C ? "" : "s") . "aaa"; + } + + $obj->prop1 = null; +} +test(); +?> +--EXPECTF-- +Fatal error: Uncaught Error: Undefined constant "C" in %sdce_012.php:11 +Stack trace: +#0 %sdce_012.php(16): test() +#1 {main} + thrown in %sdce_012.php on line 11 From daf79e2d91dc4dd47f516229ebc5922ad35f27ab Mon Sep 17 00:00:00 2001 From: Aliaksandr Bystry Date: Tue, 30 Nov 2021 14:23:50 +0100 Subject: [PATCH 05/75] Fix #75917: SplFileObject::seek broken with CSV flags Closes GH-7697. --- NEWS | 4 ++++ ext/spl/spl_directory.c | 2 ++ ext/spl/tests/bug75917.phpt | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 ext/spl/tests/bug75917.phpt diff --git a/NEWS b/NEWS index 49a6c06732253..767b2978d4fb2 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,10 @@ PHP NEWS - Core: . Fixed bug #81656 (GCC-11 silently ignores -R). (Michael Wallner) +- Spl: + . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr + Bystry) + 16 Dec 2021, PHP 8.0.14 - Core: diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index c7dd8b472173f..045aad5bc1b02 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1939,6 +1939,8 @@ static int spl_filesystem_file_read_line_ex(zval * this_ptr, spl_filesystem_obje /* 1) use fgetcsv? 2) overloaded call the function, 3) do it directly */ if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_CSV) || intern->u.file.func_getCurr->common.scope != spl_ce_SplFileObject) { + spl_filesystem_file_free_line(intern); + if (php_stream_eof(intern->u.file.stream)) { if (!silent) { zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Cannot read from file %s", intern->file_name); diff --git a/ext/spl/tests/bug75917.phpt b/ext/spl/tests/bug75917.phpt new file mode 100644 index 0000000000000..c9bc02869c2d1 --- /dev/null +++ b/ext/spl/tests/bug75917.phpt @@ -0,0 +1,24 @@ +--TEST-- +Bug #75917 (SplFileObject::seek broken with CSV flags) +--FILE-- +fputcsv($row); +} +$tmp->setFlags(0); +$tmp->seek(23); +var_dump($tmp->current()); + +$tmp->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY); +$tmp->seek(23); +var_dump($tmp->current()); +?> +--EXPECT-- +bool(false) +bool(false) From cf377eefa66d76a83cf71dca9166015ccb97bb27 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Mon, 6 Dec 2021 21:56:04 +0100 Subject: [PATCH 06/75] Don't convert assign op operand types in opcache This is the same change as 56b18d478ed9e40afd66860e82017d5c2017eac1 but for ASSIGN_OP. Changing the operand type may change the error message and can result in different behavior with operator overloading. As with the other patch, if there is strong interest this could be added to the DFA pass instead, with an appropriate type check. --- Zend/Optimizer/pass1.c | 30 ++------------- Zend/tests/assign_op_type_error.phpt | 57 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 27 deletions(-) create mode 100644 Zend/tests/assign_op_type_error.phpt diff --git a/Zend/Optimizer/pass1.c b/Zend/Optimizer/pass1.c index 110babf3e95d4..695348a389179 100644 --- a/Zend/Optimizer/pass1.c +++ b/Zend/Optimizer/pass1.c @@ -104,33 +104,9 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx) break; case ZEND_ASSIGN_OP: - if (opline->op2_type == IS_CONST) { - if (opline->extended_value == ZEND_ADD - || opline->extended_value == ZEND_SUB - || opline->extended_value == ZEND_MUL - || opline->extended_value == ZEND_DIV - || opline->extended_value == ZEND_POW) { - if (Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING) { - /* don't optimize if it should produce a runtime numeric string error */ - if (is_numeric_string(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), NULL, NULL, 0)) { - convert_scalar_to_number(&ZEND_OP2_LITERAL(opline)); - } - } - } else if (opline->extended_value == ZEND_MOD - || opline->extended_value == ZEND_SL - || opline->extended_value == ZEND_SR) { - zval *op2 = &ZEND_OP2_LITERAL(opline); - if (Z_TYPE_P(op2) != IS_LONG) { - if (!zend_is_op_long_compatible(op2)) { - break; - } - convert_to_long(op2); - } - } else if (opline->extended_value == ZEND_CONCAT) { - if (Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) { - convert_to_string(&ZEND_OP2_LITERAL(opline)); - } - } + if (opline->extended_value == ZEND_CONCAT && opline->op2_type == IS_CONST + && Z_TYPE(ZEND_OP2_LITERAL(opline)) != IS_STRING) { + convert_to_string(&ZEND_OP2_LITERAL(opline)); } break; diff --git a/Zend/tests/assign_op_type_error.phpt b/Zend/tests/assign_op_type_error.phpt new file mode 100644 index 0000000000000..5f175613e20b8 --- /dev/null +++ b/Zend/tests/assign_op_type_error.phpt @@ -0,0 +1,57 @@ +--TEST-- +TypeError for compound assignment operations +--FILE-- +getMessage(), "\n"; +} +try { + $x -= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x *= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x /= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x **= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x %= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x <<= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} +try { + $x >>= "1"; +} catch (TypeError $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECT-- +Unsupported operand types: array + string +Unsupported operand types: array - string +Unsupported operand types: array * string +Unsupported operand types: array / string +Unsupported operand types: array ** string +Unsupported operand types: array % string +Unsupported operand types: array << string +Unsupported operand types: array >> string From 08f1d470fb6cc418264884dc291e7d9b428bde5e Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 7 Dec 2021 11:46:32 +0300 Subject: [PATCH 07/75] Separate "cold" code --- Zend/zend_execute.c | 6 +-- Zend/zend_vm_def.h | 33 +++++++++--- Zend/zend_vm_execute.h | 117 +++++++++++++++++++---------------------- 3 files changed, 81 insertions(+), 75 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index aa0a2e39ec438..084eb34a1b016 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1425,17 +1425,17 @@ static zend_always_inline int zend_binary_op(zval *ret, zval *op1, zval *op2 OPL return zend_binary_ops[opcode - ZEND_ADD](ret, op1, op2); } -static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zval *property OPLINE_DC EXECUTE_DATA_DC) { zval *value; zval *z; zval rv, res; value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); - if ((z = Z_OBJ_HT_P(object)->read_dimension(Z_OBJ_P(object), property, BP_VAR_R, &rv)) != NULL) { + if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) { if (zend_binary_op(&res, z, value OPLINE_CC) == SUCCESS) { - Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), property, &res); + obj->handlers->write_dimension(obj, property, &res); } if (z == &rv) { zval_ptr_dtor(&rv); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 335c4f7a7ab71..5632931cf2150 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1145,6 +1145,27 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP) ZEND_VM_NEXT_OPCODE_EX(1, 2); } +ZEND_VM_COLD_HELPER(zend_assign_dim_op_obj_undef_helper, ANY, ANY, zend_object *obj) +{ + USE_OPLINE + zval *dim; + + GC_ADDREF(obj); + dim = ZVAL_UNDEFINED_OP2(); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + FREE_OP_DATA(); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + } + FREE_OP2(); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + ZEND_VM_HANDLER(27, ZEND_ASSIGN_DIM_OP, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, OP) { USE_OPLINE @@ -1203,19 +1224,15 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZEND_VM_C_GOTO(assign_dim_op_ret_null); - } + ZEND_VM_DISPATCH_TO_HELPER(zend_assign_dim_op_obj_undef_helper, obj, obj); } else if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 2596d5261a41a..96e21e38241d3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -799,6 +799,27 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_OP_SPEC_HAN ZEND_VM_NEXT_OPCODE_EX(1, 2); } +static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_assign_dim_op_obj_undef_helper_SPEC(zend_object *obj ZEND_OPCODE_HANDLER_ARGS_DC) +{ + USE_OPLINE + zval *dim; + + GC_ADDREF(obj); + dim = ZVAL_UNDEFINED_OP2(); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + } + FREE_OP(opline->op2_type, opline->op2.var); + FREE_OP(opline->op1_type, opline->op1.var); + ZEND_VM_NEXT_OPCODE_EX(1, 2); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_STATIC_PROP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -22445,19 +22466,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -25124,19 +25141,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -27441,19 +27454,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -29306,19 +29315,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -40038,19 +40043,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -43796,19 +43797,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -46689,19 +46686,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; @@ -49085,19 +49078,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); - dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } + ZEND_VM_TAIL_CALL(zend_assign_dim_op_obj_undef_helper_SPEC(obj ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { HashTable *ht; zend_uchar old_type; From efb901ebedf941039241c6194c452f8a16d807aa Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Tue, 7 Dec 2021 18:26:18 +0100 Subject: [PATCH 08/75] Skip bug_36798.phpt for PDO_DBLIB MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some reason, this test fails now with "Incorrect syntax near ''. [SELECT '�' as test FROM test WHERE id = '1']", so we skip it. --- ext/pdo/tests/bug_36798.phpt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ext/pdo/tests/bug_36798.phpt b/ext/pdo/tests/bug_36798.phpt index 1ce192acc9286..3deeaa9a198dd 100644 --- a/ext/pdo/tests/bug_36798.phpt +++ b/ext/pdo/tests/bug_36798.phpt @@ -10,7 +10,8 @@ PDOTest::skip(); if (!strncasecmp(getenv('PDOTEST_DSN'), 'oci', strlen('oci'))){ if (!strpos(strtolower(getenv('PDOTEST_DSN')), 'charset=we8mswin1252')) die('skip expected output valid for Oracle with WE8MSWIN1252 character set'); - +} elseif (!strncasecmp(getenv('PDOTEST_DSN'), 'dblib', strlen('dblib'))) { + die('skip not for pdo_dblib'); } ?> From 7e080183f48b8da54038ecaedd1534cd49cf56b0 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 9 Dec 2021 18:15:47 +0300 Subject: [PATCH 09/75] Fix crush after compilation of nullsafe operator introduced in 307e476e86e19135976ba7e686558de68dbb9b29 Now we flush only delayed opcodes realted to this nullsafe operator. Fixes oss-fuzz #42152 --- Zend/tests/bug81216_2.phpt | 15 +++++++++++++++ Zend/zend_compile.c | 35 +++++++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/bug81216_2.phpt diff --git a/Zend/tests/bug81216_2.phpt b/Zend/tests/bug81216_2.phpt new file mode 100644 index 0000000000000..8bf347a80e57c --- /dev/null +++ b/Zend/tests/bug81216_2.phpt @@ -0,0 +1,15 @@ +--TEST-- +Bug #81216_2: Nullsafe operator leaks dynamic property name +--FILE-- +x; +var_dump($a); +?> +--EXPECT-- +array(2) { + [0]=> + NULL + [1]=> + NULL +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 0b025939ec457..7a338775174e0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2258,9 +2258,11 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ ZEND_ASSERT(count >= offset); for (i = offset; i < count; ++i) { - if (oplines[i].opcode != ZEND_NOP) { + if (EXPECTED(oplines[i].opcode != ZEND_NOP)) { opline = get_next_op(); memcpy(opline, &oplines[i], sizeof(zend_op)); + } else { + opline = CG(active_op_array)->opcodes + oplines[i].extended_value; } } @@ -2888,15 +2890,28 @@ static zend_op *zend_delayed_compile_prop(znode *result, zend_ast *ast, uint32_t opline = zend_delayed_compile_var(&obj_node, obj_ast, type, 0); zend_separate_if_call_and_write(&obj_node, obj_ast, type); if (nullsafe) { - /* Flush delayed oplines */ - zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack)); - uint32_t i, count = zend_stack_count(&CG(delayed_oplines_stack)); - - for (i = 0; i < count; ++i) { - if (oplines[i].opcode != ZEND_NOP) { - opline = get_next_op(); - memcpy(opline, &oplines[i], sizeof(zend_op)); - oplines[i].opcode = ZEND_NOP; + if (obj_node.op_type == IS_TMP_VAR) { + /* Flush delayed oplines */ + zend_op *opline = NULL, *oplines = zend_stack_base(&CG(delayed_oplines_stack)); + uint32_t var = obj_node.u.op.var; + uint32_t count = zend_stack_count(&CG(delayed_oplines_stack)); + uint32_t i = count; + + while (i > 0 && oplines[i-1].result_type == IS_TMP_VAR && oplines[i-1].result.var == var) { + i--; + if (oplines[i].op1_type == IS_TMP_VAR) { + var = oplines[i].op1.var; + } else { + break; + } + } + for (; i < count; ++i) { + if (oplines[i].opcode != ZEND_NOP) { + opline = get_next_op(); + memcpy(opline, &oplines[i], sizeof(zend_op)); + oplines[i].opcode = ZEND_NOP; + oplines[i].extended_value = opline - CG(active_op_array)->opcodes; + } } } zend_emit_jmp_null(&obj_node); From da684582d74a2c4016f5d9ccad78ce587fcd0b83 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Thu, 9 Dec 2021 17:15:59 +0000 Subject: [PATCH 10/75] ZEND_INIT_FCALL is only produced when function exists at compile time (#7728) --- UPGRADING.INTERNALS | 13 +++++++++++++ Zend/zend_vm_def.h | 4 +--- Zend/zend_vm_execute.h | 4 +--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 7feaee74ef705..7175f0b54b4db 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -6,6 +6,8 @@ PHP 8.2 INTERNALS UPGRADE NOTES 3. Module changes +4. OpCode changes + ======================== 1. Internal API changes ======================== @@ -24,3 +26,14 @@ PHP 8.2 INTERNALS UPGRADE NOTES 3. Module changes ======================== +======================== +4. OpCode changes +======================== + +* The ZEND_INIT_FCALL opcode now asserts that the function exists in the symbol + table as the function's existence is checked at compile time. + For extensions modifying the function symbol table, setting + CG(compiler_options) |= ZEND_COMPILE_IGNORE_USER_FUNCTIONS | ZEND_COMPILE_IGNORE_INTERNAL_FUNCTIONS; + will produce ZEND_INIT_FCALL_BY_NAME opcodes instead which check for the + existence of the function at runtime. + diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 68e08162ca6d1..934860c33012e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3930,9 +3930,7 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) if (UNEXPECTED(fbc == NULL)) { fname = (zval*)RT_CONSTANT(opline, opline->op2); func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname)); - if (UNEXPECTED(func == NULL)) { - ZEND_VM_DISPATCH_TO_HELPER(zend_undefined_function_helper); - } + ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time"); fbc = Z_FUNC_P(func); if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 32b9232d90bf8..37c2d1ee653e2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3693,9 +3693,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_SPEC_CO if (UNEXPECTED(fbc == NULL)) { fname = (zval*)RT_CONSTANT(opline, opline->op2); func = zend_hash_find_known_hash(EG(function_table), Z_STR_P(fname)); - if (UNEXPECTED(func == NULL)) { - ZEND_VM_TAIL_CALL(zend_undefined_function_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); - } + ZEND_ASSERT(func != NULL && "Function existence must be checked at compile time"); fbc = Z_FUNC_P(func); if (EXPECTED(fbc->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&fbc->op_array))) { init_func_run_time_cache(&fbc->op_array); From 0ac3d78d7d05e254680f58d072e36b3b6779ee78 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 10 Dec 2021 01:39:28 +0300 Subject: [PATCH 11/75] Fix incorrect JMP optimization Fixes oss-fuzz #42155 --- ext/opcache/Optimizer/dfa_pass.c | 12 ++++++++---- ext/opcache/tests/opt/jmp_002.phpt | 13 +++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 ext/opcache/tests/opt/jmp_002.phpt diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 7a03c8ba02a56..823eccdb4f23f 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -730,9 +730,13 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) uint32_t op_num; zend_op *opline; zend_ssa_op *ssa_op; + zend_bool can_follow = 1; while (next_block_num < ssa->cfg.blocks_count && !(ssa->cfg.blocks[next_block_num].flags & ZEND_BB_REACHABLE)) { + if (ssa->cfg.blocks[next_block_num].flags & ZEND_BB_UNREACHABLE_FREE) { + can_follow = 0; + } next_block_num++; } @@ -744,7 +748,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) switch (opline->opcode) { case ZEND_JMP: optimize_jmp: - if (block->successors[0] == next_block_num) { + if (block->successors[0] == next_block_num && can_follow) { MAKE_NOP(opline); removed_ops++; goto optimize_nop; @@ -765,7 +769,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) goto optimize_jmp; } } else { - if (block->successors[0] == next_block_num) { + if (block->successors[0] == next_block_num && can_follow) { take_successor_0(ssa, block_num, block); if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_UNDEF)) { opline->opcode = ZEND_CHECK_VAR; @@ -796,7 +800,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) goto optimize_nop; } } else if (block->successors_count == 2) { - if (block->successors[0] == next_block_num) { + if (block->successors[0] == next_block_num && can_follow) { take_successor_0(ssa, block_num, block); if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_UNDEF)) { opline->opcode = ZEND_CHECK_VAR; @@ -830,7 +834,7 @@ static int zend_dfa_optimize_jmps(zend_op_array *op_array, zend_ssa *ssa) } else if (block->successors_count == 2) { if (block->successors[0] == block->successors[1]) { take_successor_0(ssa, block_num, block); - if (block->successors[0] == next_block_num) { + if (block->successors[0] == next_block_num && can_follow) { if (opline->op1_type == IS_CV && (OP1_INFO() & MAY_BE_UNDEF)) { opline->opcode = ZEND_CHECK_VAR; opline->op2.num = 0; diff --git a/ext/opcache/tests/opt/jmp_002.phpt b/ext/opcache/tests/opt/jmp_002.phpt new file mode 100644 index 0000000000000..cd7f05b225dac --- /dev/null +++ b/ext/opcache/tests/opt/jmp_002.phpt @@ -0,0 +1,13 @@ +--TEST-- +JMP 002: JMP around unreachable FREE +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +DONE +--EXPECT-- +DONE From 5675ebe649352ffa89754defd87019223b88b4e5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 9 Dec 2021 15:36:26 +0100 Subject: [PATCH 12/75] Fix #81585: cached_chunks are not counted to real_size on shutdown The amount of allocated system memory is kept in `real_size`, including the allocated `cached_chunks`. Thus, we need to keep the proper count at the end of the shutdown. Closes GH-7745. --- NEWS | 2 ++ Zend/zend_alloc.c | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 767b2978d4fb2..9207f3cc6d5c8 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Fixed bug #81656 (GCC-11 silently ignores -R). (Michael Wallner) + . Fixed bug #81585 (cached_chunks are not counted to real_size on shutdown). + (cmb) - Spl: . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 0d3e41776d732..5738c030a5822 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -2303,10 +2303,10 @@ void zend_mm_shutdown(zend_mm_heap *heap, bool full, bool silent) #endif memset(heap->free_slot, 0, sizeof(heap->free_slot)); #if ZEND_MM_STAT || ZEND_MM_LIMIT - heap->real_size = ZEND_MM_CHUNK_SIZE; + heap->real_size = (heap->cached_chunks_count + 1) * ZEND_MM_CHUNK_SIZE; #endif #if ZEND_MM_STAT - heap->real_peak = ZEND_MM_CHUNK_SIZE; + heap->real_peak = (heap->cached_chunks_count + 1) * ZEND_MM_CHUNK_SIZE; #endif heap->chunks_count = 1; heap->peak_chunks_count = 1; From 6f42c073cf80f699b754274d2f163f3b6f7e4966 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 10 Dec 2021 14:32:47 +0300 Subject: [PATCH 13/75] Remove range inference for booleans. Range inference for bolleans and longs comparison was incorrect. Fizes oss-fuzz #fuzz-42161.php --- ext/opcache/Optimizer/zend_inference.c | 157 +------------------------ ext/opcache/Optimizer/zend_ssa.c | 8 -- ext/opcache/tests/jit/cmp_008.phpt | 26 ++++ 3 files changed, 28 insertions(+), 163 deletions(-) create mode 100644 ext/opcache/tests/jit/cmp_008.phpt diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 92ae858b707bc..e4bb7ec3454a9 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -996,8 +996,6 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, zend_ssa_op* ssa_op, int var, zend_ssa_range *tmp) { - zend_long op1_min, op2_min, op1_max, op2_max; - tmp->underflow = 0; tmp->overflow = 0; switch (opline->opcode) { @@ -1025,8 +1023,8 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, tmp->min = ZEND_LONG_MIN; tmp->max = ZEND_LONG_MAX; } else { - op1_min = OP1_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); + zend_long op1_min = OP1_MIN_RANGE(); + zend_long op1_max = OP1_MAX_RANGE(); tmp->min = ~op1_max; tmp->max = ~op1_min; } @@ -1059,144 +1057,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, } } break; - case ZEND_BOOL: - case ZEND_JMPZ_EX: - case ZEND_JMPNZ_EX: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - tmp->min = (op1_min > 0 || op1_max < 0); - tmp->max = (op1_min != 0 || op1_max != 0); - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_BOOL_NOT: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - tmp->min = (op1_min == 0 && op1_max == 0); - tmp->max = (op1_min <= 0 && op1_max >= 0); - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_BOOL_XOR: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op2_min = OP2_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - op2_max = OP2_MAX_RANGE(); - op1_min = (op1_min > 0 || op1_max < 0); - op1_max = (op1_min != 0 || op1_max != 0); - op2_min = (op2_min > 0 || op2_max < 0); - op2_max = (op2_min != 0 || op2_max != 0); - tmp->min = 0; - tmp->max = 1; - if (op1_min == op1_max && op2_min == op2_max) { - if (op1_min == op2_min) { - tmp->max = 0; - } else { - tmp->min = 1; - } - } - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_IS_IDENTICAL: - case ZEND_IS_EQUAL: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op2_min = OP2_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - op2_max = OP2_MAX_RANGE(); - - tmp->min = (op1_min == op1_max && - op2_min == op2_max && - op1_min == op2_max); - tmp->max = (op1_min <= op2_max && op1_max >= op2_min); - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_IS_NOT_IDENTICAL: - case ZEND_IS_NOT_EQUAL: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op2_min = OP2_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - op2_max = OP2_MAX_RANGE(); - - tmp->min = (op1_min > op2_max || op1_max < op2_min); - tmp->max = (op1_min != op1_max || - op2_min != op2_max || - op1_min != op2_max); - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_IS_SMALLER: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op2_min = OP2_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - op2_max = OP2_MAX_RANGE(); - - tmp->min = op1_max < op2_min; - tmp->max = op1_min < op2_max; - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (ssa_op->result_def == var) { - if (OP1_HAS_RANGE() && OP2_HAS_RANGE()) { - op1_min = OP1_MIN_RANGE(); - op2_min = OP2_MIN_RANGE(); - op1_max = OP1_MAX_RANGE(); - op2_max = OP2_MAX_RANGE(); - - tmp->min = op1_max <= op2_min; - tmp->max = op1_min <= op2_max; - return 1; - } else { - tmp->min = 0; - tmp->max = 1; - return 1; - } - } - break; case ZEND_QM_ASSIGN: case ZEND_JMP_SET: case ZEND_COALESCE: @@ -1222,13 +1082,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, } } break; - case ZEND_ASSERT_CHECK: - if (ssa_op->result_def == var) { - tmp->min = 0; - tmp->max = 1; - return 1; - } - break; case ZEND_SEND_VAR: if (ssa_op->op1_def == var) { if (ssa_op->op1_def >= 0) { @@ -1409,12 +1262,6 @@ int zend_inference_propagate_range(const zend_op_array *op_array, zend_ssa *ssa, tmp->max = ZEND_LONG_MAX; tmp->overflow = 0; return 1; - } else if (mask == MAY_BE_BOOL) { - tmp->underflow = 0; - tmp->min = 0; - tmp->max = 1; - tmp->overflow = 0; - return 1; } } } diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 23b78222839de..26d0b8b385f4c 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -335,10 +335,6 @@ static void place_essa_pis( if (Z_TYPE_P(zv) == IS_LONG) { add_val2 = Z_LVAL_P(zv); - } else if (Z_TYPE_P(zv) == IS_FALSE) { - add_val2 = 0; - } else if (Z_TYPE_P(zv) == IS_TRUE) { - add_val2 = 1; } else { var1 = -1; } @@ -356,10 +352,6 @@ static void place_essa_pis( zval *zv = CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1); if (Z_TYPE_P(zv) == IS_LONG) { add_val1 = Z_LVAL_P(CRT_CONSTANT_EX(op_array, (opline-1), (opline-1)->op1)); - } else if (Z_TYPE_P(zv) == IS_FALSE) { - add_val1 = 0; - } else if (Z_TYPE_P(zv) == IS_TRUE) { - add_val1 = 1; } else { var2 = -1; } diff --git a/ext/opcache/tests/jit/cmp_008.phpt b/ext/opcache/tests/jit/cmp_008.phpt new file mode 100644 index 0000000000000..6216de5527726 --- /dev/null +++ b/ext/opcache/tests/jit/cmp_008.phpt @@ -0,0 +1,26 @@ +--TEST-- +JIT CMP: 008 Wrong range inference for comparison between IS_LONG and IS_FALSE/IS_TRUE +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $a in %scmp_008.php on line 3 + +Warning: Undefined variable $a in %scmp_008.php on line 3 + +Fatal error: Uncaught DivisionByZeroError: Modulo by zero in %scmp_008.php:3 +Stack trace: +#0 %scmp_008.php(6): test() +#1 {main} + thrown in %scmp_008.php on line 3 From 25bb229f573b8fb5386cef6f293c855a9abea7a9 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Fri, 10 Dec 2021 09:19:16 -0500 Subject: [PATCH 14/75] Allocate less memory for EG(errors) when recording errors for opcache (#7744) errors is an array of pointers, not an array of values. Low importance since this is freed after opcache compiles a file and there are typically no or very few errors. --- Zend/zend.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index e42fc648a4dc7..c37cd9ed97453 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1331,7 +1331,7 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( /* This is very inefficient for a large number of errors. * Use pow2 realloc if it becomes a problem. */ EG(num_errors)++; - EG(errors) = erealloc(EG(errors), sizeof(zend_error_info) * EG(num_errors)); + EG(errors) = erealloc(EG(errors), sizeof(zend_error_info*) * EG(num_errors)); EG(errors)[EG(num_errors)-1] = info; } @@ -1575,7 +1575,7 @@ ZEND_API ZEND_COLD void zend_error_zstr(int type, zend_string *message) { ZEND_API void zend_begin_record_errors(void) { - ZEND_ASSERT(!EG(record_errors) && "Error recoreding already enabled"); + ZEND_ASSERT(!EG(record_errors) && "Error recording already enabled"); EG(record_errors) = true; EG(num_errors) = 0; EG(errors) = NULL; From 7daf01258df783f63d6b960767122001fd3885a3 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 10 Dec 2021 17:29:44 +0100 Subject: [PATCH 15/75] Fix GH-7748: gethostbyaddr outputs binary string `getnameinfo(3)` returns zero on success; all other values need to be regarded as failure. --- NEWS | 3 +++ ext/standard/dns.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index daaa3611eeec5..80f56d484fe18 100644 --- a/NEWS +++ b/NEWS @@ -31,6 +31,9 @@ PHP NEWS . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr Bystry) +- Standard: + . Fixed bug GH-7748 (gethostbyaddr outputs binary string). (cmb) + 02 Dec 2021, PHP 8.1.1 - IMAP: diff --git a/ext/standard/dns.c b/ext/standard/dns.c index e88e5a79db114..6d22e644a8eff 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -182,14 +182,14 @@ static zend_string *php_gethostbyaddr(char *ip) if (inet_pton(AF_INET6, ip, &sa6.sin6_addr)) { sa6.sin6_family = AF_INET6; - if (getnameinfo((struct sockaddr *)&sa6, sizeof(sa6), out, sizeof(out), NULL, 0, NI_NAMEREQD) < 0) { + if (getnameinfo((struct sockaddr *)&sa6, sizeof(sa6), out, sizeof(out), NULL, 0, NI_NAMEREQD) != 0) { return zend_string_init(ip, strlen(ip), 0); } return zend_string_init(out, strlen(out), 0); } else if (inet_pton(AF_INET, ip, &sa4.sin_addr)) { sa4.sin_family = AF_INET; - if (getnameinfo((struct sockaddr *)&sa4, sizeof(sa4), out, sizeof(out), NULL, 0, NI_NAMEREQD) < 0) { + if (getnameinfo((struct sockaddr *)&sa4, sizeof(sa4), out, sizeof(out), NULL, 0, NI_NAMEREQD) != 0) { return zend_string_init(ip, strlen(ip), 0); } return zend_string_init(out, strlen(out), 0); From ac91b83ceb71a2f90af6e772ab313417af05943e Mon Sep 17 00:00:00 2001 From: Christopher Jones Date: Sun, 28 Nov 2021 12:06:25 +1100 Subject: [PATCH 16/75] Add oci_set_prefetch_lob() --- UPGRADING | 7 +- ext/oci8/config.m4 | 8 +- ext/oci8/oci8.c | 9 +- ext/oci8/oci8.stub.php | 3 + ext/oci8/oci8_arginfo.h | 9 +- ext/oci8/oci8_interface.c | 24 ++++ ext/oci8/oci8_statement.c | 37 ++++-- ext/oci8/package.xml | 14 ++- ext/oci8/php_oci8_int.h | 3 +- ext/oci8/tests/lob_prefetch.phpt | 77 +++++++------ ext/oci8/tests/lob_prefetch_ini.phpt | 165 +++++++++++++++++++++++++++ php.ini-production | 2 +- 12 files changed, 298 insertions(+), 60 deletions(-) create mode 100755 ext/oci8/tests/lob_prefetch_ini.phpt diff --git a/UPGRADING b/UPGRADING index 3b02ec4bf3f2b..0e4dfc42b690a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -28,9 +28,10 @@ PHP 8.2 UPGRADE NOTES HTTP method in curl_getinfo() return value. - OCI8: - . Added an oci8.prefetch_lob_size directive to tune LOB query performance - by reducing the number of round-trips between PHP and Oracle Database when - fetching LOBS. This is usable with Oracle Database 12.2 or later. + . Added an oci8.prefetch_lob_size directive and oci_set_prefetch_lob() + function to tune LOB query performance by reducing the number of + round-trips between PHP and Oracle Database when fetching LOBS. This is + usable with Oracle Database 12.2 or later. - PCRE: . Added support for the "n" (NO_AUTO_CAPTURE) modifier, which makes simple diff --git a/ext/oci8/config.m4 b/ext/oci8/config.m4 index 89da625e27b0e..09eae79692cbe 100644 --- a/ext/oci8/config.m4 +++ b/ext/oci8/config.m4 @@ -211,7 +211,13 @@ if test "$PHP_OCI8" != "no"; then oci8_php_version=`expr [$]1 \* 1000000 + [$]2 \* 1000 + [$]3` if test "$oci8_php_version" -lt "5002000"; then - AC_MSG_ERROR([You need at least PHP 5.2.0 to be able to use this version of OCI8. PHP $php_version found]) + AC_MSG_ERROR([You need at least PHP 8.1.0 to be able to use this version of OCI8. Use OCI8 1.4 for PHP $php_version]) + elif test "$oci8_php_version" -lt "7000000"; then + AC_MSG_ERROR([You need at least PHP 8.1.0 to be able to use this version of OCI8. Use OCI8 2.0 for PHP $php_version]) + elif test "$oci8_php_version" -lt "8000000"; then + AC_MSG_ERROR([You need at least PHP 8.1.0 to be able to use this version of OCI8. Use OCI8 2.2 for PHP $php_version]) + elif test "$oci8_php_version" -lt "8001000"; then + AC_MSG_ERROR([You need at least PHP 8.1.0 to be able to use this version of OCI8. Use OCI8 3.0 for PHP $php_version]) else AC_MSG_RESULT([$php_version, ok]) fi diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index 8efb04ea0f629..38dcfc42f35df 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -35,6 +35,9 @@ #ifdef HAVE_OCI8 +/* Note to maintainers: config.m4 should/does check the minimum PHP version so + * the below checks are obsolete - but are kept 'just in case' */ + /* PHP 5.2 is the minimum supported version for OCI8 2.0 */ #if PHP_MAJOR_VERSION < 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1) #error Use PHP OCI8 1.4 for your version of PHP @@ -42,8 +45,10 @@ /* PHP 7 is the minimum supported version for OCI8 2.1 */ #error Use PHP OCI8 2.0 for your version of PHP #elif PHP_MAJOR_VERSION < 8 -/* PHP 8 is the minimum supported version for OCI8 3.0 */ +/* PHP 8 is the minimum supported version for OCI8 3 */ #error Use PHP OCI8 2.2 for your version of PHP +#elif PHP_MAJOR_VERSION == 8 && PHP_MINOR_VERSION < 1 +#error Use PHP OCI8 3.0 for your version of PHP #endif #include "php_oci8.h" @@ -174,7 +179,7 @@ PHP_INI_BEGIN() #if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) STD_PHP_INI_BOOLEAN("oci8.events", "0", PHP_INI_SYSTEM, OnUpdateBool, events, zend_oci_globals, oci_globals) #endif - STD_PHP_INI_ENTRY( "oci8.prefetch_lob_size", "0", PHP_INI_ALL, OnUpdateLong, prefetch_lob_size, zend_oci_globals, oci_globals) + STD_PHP_INI_ENTRY( "oci8.prefetch_lob_size", "0", PHP_INI_SYSTEM, OnUpdateLong, prefetch_lob_size, zend_oci_globals, oci_globals) PHP_INI_END() /* }}} */ diff --git a/ext/oci8/oci8.stub.php b/ext/oci8/oci8.stub.php index cf24b20a74a5e..efedc3eb9063c 100644 --- a/ext/oci8/oci8.stub.php +++ b/ext/oci8/oci8.stub.php @@ -381,6 +381,9 @@ function oci_set_prefetch($statement, int $rows): bool {} */ function ocisetprefetch($statement, int $rows): bool {} +/** @param resource $statement */ +function oci_set_prefetch_lob($statement, int $prefetch_lob_size): bool {} + /** @param resource $connection */ function oci_set_client_identifier($connection, string $client_id): bool {} diff --git a/ext/oci8/oci8_arginfo.h b/ext/oci8/oci8_arginfo.h index 26bc20bcc70fe..b6916e49c37c5 100644 --- a/ext/oci8/oci8_arginfo.h +++ b/ext/oci8/oci8_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 46ee8ce62b36639636b4f5126e20a4b4e1df2e25 */ + * Stub hash: 9db587b5d431b9dfe7178fd843ae8907db737a04 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_oci_define_by_name, 0, 3, _IS_BOOL, 0) ZEND_ARG_INFO(0, statement) @@ -299,6 +299,11 @@ ZEND_END_ARG_INFO() #define arginfo_ocisetprefetch arginfo_oci_set_prefetch +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_oci_set_prefetch_lob, 0, 2, _IS_BOOL, 0) + ZEND_ARG_INFO(0, statement) + ZEND_ARG_TYPE_INFO(0, prefetch_lob_size, IS_LONG, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_oci_set_client_identifier, 0, 2, _IS_BOOL, 0) ZEND_ARG_INFO(0, connection) ZEND_ARG_TYPE_INFO(0, client_id, IS_STRING, 0) @@ -596,6 +601,7 @@ ZEND_FUNCTION(oci_num_fields); ZEND_FUNCTION(oci_parse); ZEND_FUNCTION(oci_get_implicit_resultset); ZEND_FUNCTION(oci_set_prefetch); +ZEND_FUNCTION(oci_set_prefetch_lob); ZEND_FUNCTION(oci_set_client_identifier); ZEND_FUNCTION(oci_set_edition); ZEND_FUNCTION(oci_set_module_name); @@ -710,6 +716,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(oci_get_implicit_resultset, arginfo_oci_get_implicit_resultset) ZEND_FE(oci_set_prefetch, arginfo_oci_set_prefetch) ZEND_DEP_FALIAS(ocisetprefetch, oci_set_prefetch, arginfo_ocisetprefetch) + ZEND_FE(oci_set_prefetch_lob, arginfo_oci_set_prefetch_lob) ZEND_FE(oci_set_client_identifier, arginfo_oci_set_client_identifier) ZEND_FE(oci_set_edition, arginfo_oci_set_edition) ZEND_FE(oci_set_module_name, arginfo_oci_set_module_name) diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index 7668e102ba5a8..d277e0441d346 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -1633,6 +1633,30 @@ PHP_FUNCTION(oci_set_prefetch) } /* }}} */ +/* {{{ Sets the amount of LOB data to be prefetched when OCI LOB locators are fetched */ +PHP_FUNCTION(oci_set_prefetch_lob) +{ + zval *z_statement; + php_oci_statement *statement; + zend_long prefetch_lob_size; + + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_RESOURCE(z_statement) + Z_PARAM_LONG(prefetch_lob_size) + ZEND_PARSE_PARAMETERS_END(); + + PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement); + + if (prefetch_lob_size < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); + } + + statement->prefetch_lob_size = (ub4) prefetch_lob_size; + RETURN_TRUE; +} +/* }}} */ + /* {{{ Sets the client identifier attribute on the connection */ PHP_FUNCTION(oci_set_client_identifier) { diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c index 5ee04a6168e9e..4db6337dbcd79 100644 --- a/ext/oci8/oci8_statement.c +++ b/ext/oci8/oci8_statement.c @@ -117,6 +117,12 @@ php_oci_statement *php_oci_statement_create(php_oci_connection *connection, char php_oci_statement_set_prefetch(statement, (ub4)100); /* semi-arbitrary, "sensible default" */ } + if (OCI_G(prefetch_lob_size) > 0) { + statement->prefetch_lob_size = (ub4)OCI_G(prefetch_lob_size); + } else { + statement->prefetch_lob_size = 0; + } + PHP_OCI_REGISTER_RESOURCE(statement, le_statement); OCI_G(num_statements)++; @@ -173,6 +179,7 @@ php_oci_statement *php_oci_get_implicit_resultset(php_oci_statement *statement) GC_ADDREF(statement2->connection->id); php_oci_statement_set_prefetch(statement2, statement->prefetch_count); + statement2->prefetch_lob_size = statement->prefetch_lob_size; PHP_OCI_REGISTER_RESOURCE(statement2, le_statement); @@ -186,7 +193,7 @@ php_oci_statement *php_oci_get_implicit_resultset(php_oci_statement *statement) /* {{{ php_oci_statement_set_prefetch() Set prefetch buffer size for the statement */ -int php_oci_statement_set_prefetch(php_oci_statement *statement, ub4 prefetch ) +int php_oci_statement_set_prefetch(php_oci_statement *statement, ub4 prefetch) { sword errstatus; @@ -820,18 +827,30 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode) return 1; } + /* Enable LOB data prefetching */ + if ((outcol->data_type == SQLT_CLOB || outcol->data_type == SQLT_BLOB) && statement->prefetch_lob_size > 0) { + int get_lob_len = 1; /* == true */ + + PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &get_lob_len, 0, OCI_ATTR_LOBPREFETCH_LENGTH, statement->err)); + if (errstatus != OCI_SUCCESS) { + statement->errcode = php_oci_error(statement->err, errstatus); + PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode); + return 1; + } + + PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &(statement->prefetch_lob_size), 0, OCI_ATTR_LOBPREFETCH_SIZE, statement->err)); + if (errstatus != OCI_SUCCESS) { + statement->errcode = php_oci_error(statement->err, errstatus); + PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode); + return 1; + } + } + /* additional define setup */ switch (outcol->data_type) { + case SQLT_RSET: case SQLT_BLOB: case SQLT_CLOB: - if (OCI_G(prefetch_lob_size) > 0) { - int get_lob_len = 1; /* == true */ - ub4 prefetch_size = OCI_G(prefetch_lob_size); - PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &get_lob_len, 0, OCI_ATTR_LOBPREFETCH_LENGTH, statement->err)); - PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (outcol->oci_define, OCI_HTYPE_DEFINE, &prefetch_size, 0, OCI_ATTR_LOBPREFETCH_SIZE, statement->err)); - } - ZEND_FALLTHROUGH; - case SQLT_RSET: case SQLT_RDD: case SQLT_BFILE: PHP_OCI_CALL_RETURN(errstatus, diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml index 25de0a9867d40..61bb1ad76416c 100644 --- a/ext/oci8/package.xml +++ b/ext/oci8/package.xml @@ -10,7 +10,9 @@ http://pear.php.net/dtd/package-2.0.xsd"> The OCI8 extension lets you access Oracle Database. -Use 'pecl install oci8' to install for PHP 8. +Use 'pecl install oci8' to install for PHP 8.1. + +Use 'pecl install oci8-3.0.1' to install for PHP 8.0. Use 'pecl install oci8-2.2.0' to install for PHP 7. @@ -53,7 +55,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin no - 2021-11-15 + 2021-12-11 @@ -66,9 +68,9 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin PHP - This version is for PHP 8 only. + This version is for PHP 8.1 only. - Added oci8.prefetch_lob_size directive to improve LOB query performance. + Added oci8.prefetch_lob_size directive and oci_set_prefetch_lob() function to improve LOB query performance. @@ -373,6 +375,8 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin + + @@ -435,7 +439,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - 8.0.0 + 8.1.0 1.4.0b1 diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index b2e5f88c26b87..dec9172f5c5e4 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -235,7 +235,8 @@ typedef struct { unsigned has_data:1; /* statement has more data flag */ unsigned has_descr:1; /* statement has at least one descriptor or cursor column */ ub2 stmttype; /* statement type */ - ub4 prefetch_count; /* current prefetch count */ + ub4 prefetch_count; /* row prefetch count */ + ub4 prefetch_lob_size; /* LOB prefetch size */ } php_oci_statement; /* }}} */ diff --git a/ext/oci8/tests/lob_prefetch.phpt b/ext/oci8/tests/lob_prefetch.phpt index 0fbdb1603300a..94a85585a8e8a 100755 --- a/ext/oci8/tests/lob_prefetch.phpt +++ b/ext/oci8/tests/lob_prefetch.phpt @@ -13,14 +13,14 @@ require(__DIR__.'/skipif.inc'); require __DIR__.'/connect.inc'; require __DIR__.'/create_table.inc'; -define("NUMROWS", 500); +define("NUMROWS", 200); define("LOBSIZE", 64000); $ora_sql = "declare c clob; b blob; - numrows number := 500; + numrows number := " . NUMROWS . "; dest_offset integer := 1; src_offset integer := 1; warn integer; @@ -44,8 +44,10 @@ $statement = oci_parse($c,$ora_sql); oci_execute($statement); -function get_clob_loc($c, $sql) { +function get_clob_loc($c, $sql, $pfl) { $stid = oci_parse($c, $sql); + if ($pfl >= 0) + oci_set_prefetch_lob($stid, $pfl); oci_execute($stid); $l = []; while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) { @@ -56,8 +58,10 @@ function get_clob_loc($c, $sql) { return($l); } -function get_clob_inline($c, $sql) { +function get_clob_inline($c, $sql, $pfl) { $stid = oci_parse($c, $sql); + if ($pfl >= 0) + oci_set_prefetch_lob($stid, $pfl); oci_execute($stid); $l = []; while (($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_LOBS)) != false) { @@ -81,8 +85,10 @@ function check_clobs($locarr, $inlinearr) { } } -function get_blob_loc($c, $sql) { +function get_blob_loc($c, $sql, $pfl) { $stid = oci_parse($c, $sql); + if ($pfl >= 0) + oci_set_prefetch_lob($stid, $pfl); oci_execute($stid); $l = []; while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) { @@ -94,22 +100,28 @@ function get_blob_loc($c, $sql) { } -print("Test 1\n"); +print("Test 1 - Default prefetch_lob_size\n"); -$ig = ini_get("oci8.prefetch_lob_size"); -var_dump($ig); +$r = ini_get("oci8.prefetch_lob_size"); +var_dump($r); -$ig = ini_set("oci8.prefetch_lob_size", "100000"); -var_dump($ig); +print("Test 2\n"); -$ig = ini_get("oci8.prefetch_lob_size"); -var_dump($ig); +$s = oci_parse($c, 'select * from dual'); +$r = oci_set_prefetch_lob($s, 0); +var_dump($r); -print("Test 2 - CLOB prefetch_lob_size 100000\n"); +try { + oci_set_prefetch_lob($s, -1); +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +print("Test 3 - CLOB prefetch_lob_size 100000\n"); $sql = "select clob from ${schema}${table_name}" . " order by id"; -$locarr = get_clob_loc($c, $sql); -$inlinearr = get_clob_inline($c, $sql); +$locarr = get_clob_loc($c, $sql, 100000); +$inlinearr = get_clob_inline($c, $sql, 100000); print(count($locarr) . "\n"); print(count($inlinearr) . "\n"); @@ -117,12 +129,8 @@ check_clobs($locarr, $inlinearr); print("Test 3 - CLOB prefetch_lob_size 100\n"); -ini_set("oci8.prefetch_lob_size", "100"); -$ig = ini_get("oci8.prefetch_lob_size"); -var_dump($ig); - -$locarr = get_clob_loc($c, $sql); -$inlinearr = get_clob_inline($c, $sql); +$locarr = get_clob_loc($c, $sql, 100); +$inlinearr = get_clob_inline($c, $sql, 100); print(count($locarr) . "\n"); print(count($inlinearr) . "\n"); @@ -130,12 +138,8 @@ check_clobs($locarr, $inlinearr); print("Test 4 - BLOB prefetch_lob_size 100000\n"); -ini_set("oci8.prefetch_lob_size", "100000"); -$ig = ini_get("oci8.prefetch_lob_size"); -var_dump($ig); - $sql = "select blob from ${schema}${table_name}" . " order by id"; -$locarr = get_blob_loc($c, $sql); +$locarr = get_blob_loc($c, $sql, 100000); print(count($locarr) . "\n"); @@ -144,20 +148,19 @@ require __DIR__.'/drop_table.inc'; ?> DONE --EXPECTF-- -Test 1 -string(1) "0" +Test 1 - Default prefetch_lob_size string(1) "0" -string(6) "100000" -Test 2 - CLOB prefetch_lob_size 100000 -500 -500 +Test 2 +bool(true) +oci_set_prefetch_lob(): Argument #2 ($prefetch_lob_size) must be greater than or equal to 0 +Test 3 - CLOB prefetch_lob_size 100000 +200 +200 Comparing CLOBS Test 3 - CLOB prefetch_lob_size 100 -string(3) "100" -500 -500 +200 +200 Comparing CLOBS Test 4 - BLOB prefetch_lob_size 100000 -string(6) "100000" -500 +200 DONE diff --git a/ext/oci8/tests/lob_prefetch_ini.phpt b/ext/oci8/tests/lob_prefetch_ini.phpt new file mode 100755 index 0000000000000..2142a8e0ece01 --- /dev/null +++ b/ext/oci8/tests/lob_prefetch_ini.phpt @@ -0,0 +1,165 @@ +--TEST-- +LOB prefetching with oci8. +--EXTENSIONS-- +oci8 +--SKIPIF-- + true, 'timesten' => false); // test runs on these DBs +require(__DIR__.'/skipif.inc'); +?> +--INI-- +oci8.prefetch_lob_size=100000 +--FILE-- += 0) + oci_set_prefetch_lob($stid, $pfl); + oci_execute($stid); + $l = []; + while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) { + $l[] = $row['CLOB']->load(); + $row['CLOB']->free(); + if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; } + } + return($l); +} + +function get_clob_inline($c, $sql, $pfl) { + $stid = oci_parse($c, $sql); + if ($pfl >= 0) + oci_set_prefetch_lob($stid, $pfl); + oci_execute($stid); + $l = []; + while (($row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_LOBS)) != false) { + $l[] = $row['CLOB']; + if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; } + } + return($l); +} + +function check_clobs($locarr, $inlinearr) { + print("Comparing CLOBS\n"); + for ($i = 0; $i < NUMROWS; ++$i) { + if (strlen($locarr[$i]) != LOBSIZE) { + trigger_error("size mismatch at $i " . strlen($locarr[$i]), E_USER_ERROR); + exit; + } + if (strcmp($locarr[$i], $inlinearr[$i])) { + trigger_error("data mismatch at $i " . strlen($locarr[$i]) . " " . strlen($inlinearr[$i]), E_USER_ERROR); + exit; + } + } +} + +function get_blob_loc($c, $sql, $pfl) { + $stid = oci_parse($c, $sql); + if ($pfl >= 0) + oci_set_prefetch_lob($stid, $pfl); + oci_execute($stid); + $l = []; + while (($row = oci_fetch_array($stid, OCI_ASSOC)) != false) { + $l[] = $row['BLOB']->load(); + $row['BLOB']->free(); + if (strlen($l[0]) != LOBSIZE) { print("strlen(l) failure" . strlen($l)); exit; } + } + return($l); +} + + +print("Test 1 - prefetch_lob_size\n"); + +$r = ini_get("oci8.prefetch_lob_size"); +var_dump($r); + +print("Test 2 - CLOB with current oci8.prefetch_lob_size\n"); + +$sql = "select clob from ${schema}${table_name}" . " order by id"; +$locarr = get_clob_loc($c, $sql, -1); +$inlinearr = get_clob_inline($c, $sql, -1); + +print(count($locarr) . "\n"); +print(count($inlinearr) . "\n"); +check_clobs($locarr, $inlinearr); + +print("Test 3 - CLOB override prefetch_lob_size 0\n"); + +$locarr = get_clob_loc($c, $sql, 0); +$inlinearr = get_clob_inline($c, $sql, 0); + +print(count($locarr) . "\n"); +print(count($inlinearr) . "\n"); +check_clobs($locarr, $inlinearr); + +print("Test 4 - CLOB override prefetch_lob_size 1000\n"); + +$locarr = get_clob_loc($c, $sql, 1000); +$inlinearr = get_clob_inline($c, $sql, 1000); + +print(count($locarr) . "\n"); +print(count($inlinearr) . "\n"); +check_clobs($locarr, $inlinearr); + +print("Test 5 - BLOB with current ocig8.prefetch_lob_size \n"); + +$sql = "select blob from ${schema}${table_name}" . " order by id"; +$locarr = get_blob_loc($c, $sql, -1); + +print(count($locarr) . "\n"); + +require __DIR__.'/drop_table.inc'; + +?> +DONE +--EXPECTF-- +Test 1 - prefetch_lob_size +string(6) "100000" +Test 2 - CLOB with current oci8.prefetch_lob_size +200 +200 +Comparing CLOBS +Test 3 - CLOB override prefetch_lob_size 0 +200 +200 +Comparing CLOBS +Test 4 - CLOB override prefetch_lob_size 1000 +200 +200 +Comparing CLOBS +Test 5 - BLOB with current ocig8.prefetch_lob_size +200 +DONE diff --git a/php.ini-production b/php.ini-production index e25092e688f59..89a198db395a6 100644 --- a/php.ini-production +++ b/php.ini-production @@ -1273,7 +1273,7 @@ mysqlnd.collect_memory_statistics = Off ; https://php.net/oci8.statement-cache-size ;oci8.statement_cache_size = 20 -; Tuning: Enables statement prefetching and sets the default number of +; Tuning: Enables row prefetching and sets the default number of ; rows that will be fetched automatically after statement execution. ; https://php.net/oci8.default-prefetch ;oci8.default_prefetch = 100 From e7f3bc95068996dd7f8e7af8a9992f01e321b66a Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 11 Dec 2021 20:49:31 +0000 Subject: [PATCH 17/75] Fix pcntl_forkx condition in stub (#7755) --- ext/pcntl/pcntl.stub.php | 4 ++-- ext/pcntl/pcntl_arginfo.h | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ext/pcntl/pcntl.stub.php b/ext/pcntl/pcntl.stub.php index d668b4d06627a..d89854256e1b6 100644 --- a/ext/pcntl/pcntl.stub.php +++ b/ext/pcntl/pcntl.stub.php @@ -83,7 +83,7 @@ function pcntl_unshare(int $flags): bool {} #ifdef HAVE_RFORK function pcntl_rfork(int $flags, int $signal = 0): int{} #endif -# -#ifdef HAVE_RFORK + +#ifdef HAVE_FORKX function pcntl_forkx(int $flags): int{} #endif diff --git a/ext/pcntl/pcntl_arginfo.h b/ext/pcntl/pcntl_arginfo.h index 4caaff2bcffcb..91147e70ea9da 100644 --- a/ext/pcntl/pcntl_arginfo.h +++ b/ext/pcntl/pcntl_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: fb7d243e0a1b5e85e0bfc0b2add5145cee134b25 */ + * Stub hash: e9f831c37e960f9b0db7561faefe61d49dd7df21 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_fork, 0, 0, IS_LONG, 0) ZEND_END_ARG_INFO() @@ -125,9 +125,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_rfork, 0, 1, IS_LONG, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, signal, IS_LONG, 0, "0") ZEND_END_ARG_INFO() #endif - + #if defined(HAVE_FORKX) -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_forkx, 0, 0, IS_LONG, 0) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_pcntl_forkx, 0, 1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, flags, IS_LONG, 0) ZEND_END_ARG_INFO() #endif @@ -174,6 +174,9 @@ ZEND_FUNCTION(pcntl_unshare); #if defined(HAVE_RFORK) ZEND_FUNCTION(pcntl_rfork); #endif +#if defined(HAVE_FORKX) +ZEND_FUNCTION(pcntl_forkx); +#endif static const zend_function_entry ext_functions[] = { @@ -218,6 +221,9 @@ static const zend_function_entry ext_functions[] = { #endif #if defined(HAVE_RFORK) ZEND_FE(pcntl_rfork, arginfo_pcntl_rfork) +#endif +#if defined(HAVE_FORKX) + ZEND_FE(pcntl_forkx, arginfo_pcntl_forkx) #endif ZEND_FE_END }; From 93f6af691348fbc0486c05666dfe08de93455e70 Mon Sep 17 00:00:00 2001 From: Christopher Jones Date: Sun, 12 Dec 2021 13:32:34 +1100 Subject: [PATCH 18/75] It's past time to drop linking support for Oracle Client 10g --- UPGRADING | 3 ++ ext/oci8/config.m4 | 9 +++- ext/oci8/oci8.c | 86 +++------------------------------ ext/oci8/oci8_interface.c | 34 ++++--------- ext/oci8/oci8_statement.c | 15 ++---- ext/oci8/package.xml | 69 ++++++++++++++++---------- ext/oci8/php_oci8.h | 3 +- ext/oci8/php_oci8_int.h | 4 ++ ext/oci8/tests/driver_name.phpt | 6 +-- 9 files changed, 83 insertions(+), 146 deletions(-) diff --git a/UPGRADING b/UPGRADING index 0e4dfc42b690a..8b016ba30255b 100644 --- a/UPGRADING +++ b/UPGRADING @@ -118,6 +118,9 @@ PHP 8.2 UPGRADE NOTES 9. Other Changes to Extensions ======================================== +- OCI8: + . The minimum Oracle Client library version required is now 11.2. + - Zip: . extension updated to 1.20.0 with new methods: ZipArchive::clearError, getStreamName and getStreamIndex diff --git a/ext/oci8/config.m4 b/ext/oci8/config.m4 index 09eae79692cbe..714c655be439d 100644 --- a/ext/oci8/config.m4 +++ b/ext/oci8/config.m4 @@ -340,8 +340,8 @@ if test "$PHP_OCI8" != "no"; then AC_OCI8_ORACLE_VERSION($OCI8_DIR) case $OCI8_ORACLE_VERSION in - 7.3|8.0|8.1|9.0) - AC_MSG_ERROR([Oracle client libraries < 10 are not supported]) + 7.3|8.0|8.1|9.0|10.1) + AC_MSG_ERROR([Oracle Client libraries < 11.2 are not supported]) ;; esac @@ -413,6 +413,11 @@ if test "$PHP_OCI8" != "no"; then fi AC_OCI8IC_VERSION($PHP_OCI8_INSTANT_CLIENT) + case $OCI8_ORACLE_VERSION in + 10.1) + AC_MSG_ERROR([Oracle Client libraries < 11.2 are not supported]) + ;; + esac PHP_ADD_LIBRARY(clntsh, 1, OCI8_SHARED_LIBADD) PHP_ADD_LIBPATH($PHP_OCI8_INSTANT_CLIENT, OCI8_SHARED_LIBADD) diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index 38dcfc42f35df..b574138c28bab 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -36,7 +36,8 @@ #ifdef HAVE_OCI8 /* Note to maintainers: config.m4 should/does check the minimum PHP version so - * the below checks are obsolete - but are kept 'just in case' */ + * the below checks are obsolete - but are kept 'just in case'. Also bump the + * minimum version in package.xml, as appropriate. */ /* PHP 5.2 is the minimum supported version for OCI8 2.0 */ #if PHP_MAJOR_VERSION < 5 || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION <= 1) @@ -173,12 +174,8 @@ PHP_INI_BEGIN() STD_PHP_INI_ENTRY( "oci8.statement_cache_size", "20", PHP_INI_SYSTEM, OnUpdateLong, statement_cache_size, zend_oci_globals, oci_globals) STD_PHP_INI_ENTRY( "oci8.default_prefetch", "100", PHP_INI_SYSTEM, OnUpdateLong, default_prefetch, zend_oci_globals, oci_globals) STD_PHP_INI_BOOLEAN("oci8.old_oci_close_semantics", "0", PHP_INI_SYSTEM, OnUpdateOldCloseSemantics, old_oci_close_semantics,zend_oci_globals, oci_globals) -#if (OCI_MAJOR_VERSION >= 11) STD_PHP_INI_ENTRY( "oci8.connection_class", "", PHP_INI_ALL, OnUpdateString, connection_class, zend_oci_globals, oci_globals) -#endif -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) STD_PHP_INI_BOOLEAN("oci8.events", "0", PHP_INI_SYSTEM, OnUpdateBool, events, zend_oci_globals, oci_globals) -#endif STD_PHP_INI_ENTRY( "oci8.prefetch_lob_size", "0", PHP_INI_SYSTEM, OnUpdateLong, prefetch_lob_size, zend_oci_globals, oci_globals) PHP_INI_END() /* }}} */ @@ -216,23 +213,7 @@ static void php_oci_init_global_handles(void) errstatus = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL); - if (errstatus == OCI_SUCCESS) { -#if !defined(OCI_MAJOR_VERSION) || (OCI_MAJOR_VERSION < 11) - /* This fixes PECL bug 15988 (sqlnet.ora not being read). The - * root cause was fixed in Oracle 10.2.0.4 but there is no - * compile time method to check for that precise patch level, - * nor can it be guaranteed that runtime will use the same - * patch level the code was compiled with. So, we do this - * code for all non 11g versions. - */ - OCICPool *cpoolh; - ub4 cpoolmode = 0x80000000; /* Pass invalid mode to OCIConnectionPoolCreate */ - PHP_OCI_CALL(OCIHandleAlloc, (OCI_G(env), (dvoid **) &cpoolh, OCI_HTYPE_CPOOL, (size_t) 0, (dvoid **) 0)); - PHP_OCI_CALL(OCIConnectionPoolCreate, (OCI_G(env), OCI_G(err), cpoolh, NULL, 0, NULL, 0, 0, 0, 0, NULL, 0, NULL, 0, cpoolmode)); - PHP_OCI_CALL(OCIConnectionPoolDestroy, (cpoolh, OCI_G(err), OCI_DEFAULT)); - PHP_OCI_CALL(OCIHandleFree, (cpoolh, OCI_HTYPE_CPOOL)); -#endif - } else { + if (errstatus != OCI_SUCCESS) { OCIErrorGet(OCI_G(env), (ub4)1, NULL, &ora_error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR); if (ora_error_code) { @@ -348,11 +329,9 @@ PHP_MINIT_FUNCTION(oci) REGISTER_LONG_CONSTANT("SQLT_LBI",SQLT_LBI, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_ODT",SQLT_ODT, CONST_CS | CONST_PERSISTENT); -#if defined(HAVE_OCI_INSTANT_CLIENT) || (defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 10) REGISTER_LONG_CONSTANT("SQLT_BDOUBLE",SQLT_BDOUBLE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("SQLT_BFLOAT",SQLT_BFLOAT, CONST_CS | CONST_PERSISTENT); -#endif -#if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12 +#if OCI_MAJOR_VERSION >= 12 REGISTER_LONG_CONSTANT("SQLT_BOL",SQLT_BOL, CONST_CS | CONST_PERSISTENT); #endif @@ -369,7 +348,7 @@ PHP_MINIT_FUNCTION(oci) REGISTER_LONG_CONSTANT("OCI_B_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_B_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("OCI_B_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT); -#if defined(OCI_MAJOR_VERSION) && OCI_MAJOR_VERSION >= 12 +#if OCI_MAJOR_VERSION >= 12 REGISTER_LONG_CONSTANT("OCI_B_BOL",SQLT_BOL, CONST_CS | CONST_PERSISTENT); #endif @@ -450,9 +429,7 @@ PHP_RSHUTDOWN_FUNCTION(oci) PHP_MINFO_FUNCTION(oci) { char buf[32]; -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) char ver[256]; -#endif php_info_print_table_start(); php_info_print_table_row(2, "OCI8 Support", "enabled"); @@ -463,19 +440,9 @@ PHP_MINFO_FUNCTION(oci) #endif php_info_print_table_row(2, "OCI8 Version", PHP_OCI8_VERSION); -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) php_oci_client_get_version(ver, sizeof(ver)); php_info_print_table_row(2, "Oracle Run-time Client Library Version", ver); -#else - php_info_print_table_row(2, "Oracle Run-time Client Library Version", "Unknown"); -#endif -#if defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION); -#elif defined(PHP_OCI8_ORACLE_VERSION) - snprintf(buf, sizeof(buf), "%s", PHP_OCI8_ORACLE_VERSION); -#else - snprintf(buf, sizeof(buf), "Unknown"); -#endif #if defined(HAVE_OCI_INSTANT_CLIENT) php_info_print_table_row(2, "Oracle Compile-time Instant Client Version", buf); #else @@ -1342,23 +1309,14 @@ php_oci_connection *php_oci_do_connect_ex(char *username, int username_len, char static int php_oci_connection_ping(php_oci_connection *connection) { sword errstatus; -#if (!((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2)))) - char version[256]; -#endif OCI_G(errcode) = 0; /* assume ping is successful */ - /* Use OCIPing instead of OCIServerVersion. If OCIPing returns ORA-1010 (invalid OCI operation) - * such as from Pre-10.1 servers, the error is still from the server and we would have - * successfully performed a roundtrip and validated the connection. Use OCIServerVersion for - * Pre-10.2 clients + /* If OCIPing returns ORA-1010 (invalid OCI operation) such as from + * pre-10.1 servers, the error is still from the server and we would have + * successfully performed a roundtrip and validated the connection. */ -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) /* OCIPing available 10.2 onwards */ PHP_OCI_CALL_RETURN(errstatus, OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT)); -#else - /* use good old OCIServerVersion() */ - PHP_OCI_CALL_RETURN(errstatus, OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX)); -#endif if (errstatus == OCI_SUCCESS) { return 1; @@ -1583,16 +1541,6 @@ int php_oci_connection_release(php_oci_connection *connection) rlsMode |= OCI_SESSRLS_DROPSESS; } - /* Sessions for non-persistent connections should be dropped. For 11 and above, the session - * pool has its own mechanism for doing so for purity NEW connections. We need to do so - * explicitly for 10.2 and earlier. - */ -#if (!(OCI_MAJOR_VERSION >= 11)) - if (!connection->is_persistent) { - rlsMode |= OCI_SESSRLS_DROPSESS; - } -#endif - if (connection->svc) { PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL, 0, rlsMode)); @@ -1654,7 +1602,6 @@ int php_oci_password_change(php_oci_connection *connection, char *user, int user */ void php_oci_client_get_version(char *version, size_t version_size) { -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) /* OCIClientVersion only available 10.2 onwards */ sword major_version = 0; sword minor_version = 0; sword update_num = 0; @@ -1663,9 +1610,6 @@ void php_oci_client_get_version(char *version, size_t version_size) PHP_OCI_CALL(OCIClientVersion, (&major_version, &minor_version, &update_num, &patch_num, &port_update_num)); snprintf(version, version_size, "%d.%d.%d.%d.%d", major_version, minor_version, update_num, patch_num, port_update_num); -#else - memcpy(version, "Unknown", sizeof("Unknown")); -#endif } /* }}} */ @@ -2050,13 +1994,8 @@ static php_oci_spool *php_oci_create_spool(char *username, int username_len, cha } /* Disable RLB as we mostly have single-connection pools */ -#if (OCI_MAJOR_VERSION > 10) poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS; -#else - poolmode = OCI_SPC_HOMOGENEOUS; -#endif -#if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2))) /* {{{ Allocate auth handle for session pool */ PHP_OCI_CALL_RETURN(errstatus, OCIHandleAlloc, (session_pool->env, (dvoid **)&(spoolAuth), OCI_HTYPE_AUTHINFO, 0, NULL)); @@ -2098,7 +2037,6 @@ static php_oci_spool *php_oci_create_spool(char *username, int username_len, cha goto exit_create_spool; } /* }}} */ -#endif /* Create the homogeneous session pool - We have different session pools for every different * username, password, charset and dbname. @@ -2327,7 +2265,6 @@ static int php_oci_old_create_session(php_oci_connection *connection, char *dbna /* }}} */ /* {{{ Set the edition attribute on the session handle */ -#if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2))) if (OCI_G(edition)) { PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(edition), (ub4) (strlen(OCI_G(edition))), (ub4) OCI_ATTR_EDITION, OCI_G(err))); @@ -2336,18 +2273,15 @@ static int php_oci_old_create_session(php_oci_connection *connection, char *dbna return 1; } } -#endif /* }}} */ /* {{{ Set the driver name attribute on the session handle */ -#if (OCI_MAJOR_VERSION >= 11) PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) PHP_OCI8_DRIVER_NAME, (ub4) sizeof(PHP_OCI8_DRIVER_NAME)-1, (ub4) OCI_ATTR_DRIVER_NAME, OCI_G(err))); if (OCI_G(errcode) != OCI_SUCCESS) { php_oci_error(OCI_G(err), OCI_G(errcode)); return 1; } -#endif /* }}} */ /* {{{ Set the server handle in the service handle */ @@ -2435,9 +2369,7 @@ static int php_oci_old_create_session(php_oci_connection *connection, char *dbna static int php_oci_create_session(php_oci_connection *connection, php_oci_spool *session_pool, char *dbname, int dbname_len, char *username, int username_len, char *password, int password_len, char *new_password, int new_password_len, int session_mode) { php_oci_spool *actual_spool = NULL; -#if (OCI_MAJOR_VERSION > 10) ub4 purity = -2; /* Illegal value to initialize */ -#endif time_t timestamp = time(NULL); ub4 statement_cache_size = 0; @@ -2493,7 +2425,6 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool } /* Set the Connection class and purity if OCI client version >= 11g */ -#if (OCI_MAJOR_VERSION > 10) PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(connection_class), (ub4)(strlen(OCI_G(connection_class))), (ub4)OCI_ATTR_CONNECTION_CLASS, OCI_G(err))); if (OCI_G(errcode) != OCI_SUCCESS) { @@ -2512,7 +2443,6 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool php_oci_error(OCI_G(err), OCI_G(errcode)); return 1; } -#endif } /* }}} */ diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index d277e0441d346..2b1117dd6515f 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -1637,14 +1637,17 @@ PHP_FUNCTION(oci_set_prefetch) PHP_FUNCTION(oci_set_prefetch_lob) { zval *z_statement; - php_oci_statement *statement; zend_long prefetch_lob_size; +#if (OCI_MAJOR_VERSION > 12 || (OCI_MAJOR_VERSION == 12 && OCI_MINOR_VERSION >= 2)) + php_oci_statement *statement; +#endif ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_RESOURCE(z_statement) Z_PARAM_LONG(prefetch_lob_size) ZEND_PARSE_PARAMETERS_END(); +#if (OCI_MAJOR_VERSION > 12 || (OCI_MAJOR_VERSION == 12 && OCI_MINOR_VERSION >= 2)) PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement); if (prefetch_lob_size < 0) { @@ -1654,6 +1657,12 @@ PHP_FUNCTION(oci_set_prefetch_lob) statement->prefetch_lob_size = (ub4) prefetch_lob_size; RETURN_TRUE; +#else + /* Although the LOB prefetch feature was available in some earlier Oracle + * version, I don't consider it stable until 12.2 */ + php_error_docref(NULL, E_NOTICE, "Unsupported with this version of Oracle Client"); + RETURN_FALSE; +#endif } /* }}} */ @@ -1718,7 +1727,6 @@ PHP_FUNCTION(oci_set_edition) Z_PARAM_STRING(edition, edition_len) ZEND_PARSE_PARAMETERS_END(); -#if ((OCI_MAJOR_VERSION > 11) || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION >= 2))) if (OCI_G(edition)) { efree(OCI_G(edition)); } @@ -1732,10 +1740,6 @@ PHP_FUNCTION(oci_set_edition) } RETURN_TRUE; -#else - php_error_docref(NULL, E_NOTICE, "Unsupported attribute type"); - RETURN_FALSE; -#endif } /* }}} */ @@ -1751,8 +1755,6 @@ PHP_FUNCTION(oci_set_module_name) Z_PARAM_STRING(module, module_len) ZEND_PARSE_PARAMETERS_END(); -#if (OCI_MAJOR_VERSION >= 10) - php_oci_connection *connection; sword errstatus; @@ -1766,10 +1768,6 @@ PHP_FUNCTION(oci_set_module_name) } RETURN_TRUE; -#else - php_error_docref(NULL, E_NOTICE, "Unsupported attribute type"); - RETURN_FALSE; -#endif } /* }}} */ @@ -1785,8 +1783,6 @@ PHP_FUNCTION(oci_set_action) Z_PARAM_STRING(action, action_len) ZEND_PARSE_PARAMETERS_END(); -#if (OCI_MAJOR_VERSION >= 10) - php_oci_connection *connection; sword errstatus; @@ -1800,10 +1796,6 @@ PHP_FUNCTION(oci_set_action) } RETURN_TRUE; -#else - php_error_docref(NULL, E_NOTICE, "Unsupported attribute type"); - RETURN_FALSE; -#endif } /* }}} */ @@ -1819,8 +1811,6 @@ PHP_FUNCTION(oci_set_client_info) Z_PARAM_STRING(client_info, client_info_len) ZEND_PARSE_PARAMETERS_END(); -#if (OCI_MAJOR_VERSION >= 10) - php_oci_connection *connection; sword errstatus; @@ -1834,10 +1824,6 @@ PHP_FUNCTION(oci_set_client_info) } RETURN_TRUE; -#else - php_error_docref(NULL, E_NOTICE, "Unsupported attribute type"); - RETURN_FALSE; -#endif } /* }}} */ diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c index 4db6337dbcd79..ca7ef1c8cd50f 100644 --- a/ext/oci8/oci8_statement.c +++ b/ext/oci8/oci8_statement.c @@ -36,8 +36,7 @@ #include "php_oci8.h" #include "php_oci8_int.h" -#if defined(OCI_MAJOR_VERSION) && (OCI_MAJOR_VERSION > 10) && \ - (defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64)) +#if defined(__x86_64__) || defined(__LP64__) || defined(_LP64) || defined(_WIN64) typedef ub8 oci_phpsized_int; #else typedef ub4 oci_phpsized_int; @@ -267,11 +266,7 @@ int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows) zend_hash_apply(statement->columns, php_oci_cleanup_pre_fetch); } -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch2, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, 0, OCI_DEFAULT)); -#else - PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT)); -#endif if (errstatus == OCI_NO_DATA || nrows == 0) { if (statement->last_query == NULL) { @@ -347,11 +342,7 @@ int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows) } } -#if ((OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION >= 2))) PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch2, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, 0, OCI_DEFAULT)); -#else - PHP_OCI_CALL_RETURN(errstatus, OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT)); -#endif if (piecewisecols) { for (i = 0; i < statement->ncolumns; i++) { @@ -827,7 +818,8 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode) return 1; } - /* Enable LOB data prefetching */ + /* Enable LOB data prefetching. */ +#if (OCI_MAJOR_VERSION > 12 || (OCI_MAJOR_VERSION == 12 && OCI_MINOR_VERSION >= 2)) if ((outcol->data_type == SQLT_CLOB || outcol->data_type == SQLT_BLOB) && statement->prefetch_lob_size > 0) { int get_lob_len = 1; /* == true */ @@ -845,6 +837,7 @@ int php_oci_statement_execute(php_oci_statement *statement, ub4 mode) return 1; } } +#endif /* additional define setup */ switch (outcol->data_type) { diff --git a/ext/oci8/package.xml b/ext/oci8/package.xml index 61bb1ad76416c..f5ba6005b61c3 100644 --- a/ext/oci8/package.xml +++ b/ext/oci8/package.xml @@ -20,9 +20,9 @@ Use 'pecl install oci8-2.0.12' to install for PHP 5.2 - PHP 5.6. Use 'pecl install oci8-1.4.10' to install for PHP 4.3.9 - PHP 5.1. -The OCI8 extension can be linked with Oracle client libraries from Oracle Database 10.2 or later. These libraries are found in your database installation, or in the free Oracle Instant Client from https://www.oracle.com/database/technologies/instant-client.html. +The current OCI8 extension can be linked with Oracle Client libraries from Oracle Database 11.2 or later. (OCI8 3.0 and earlier can be linked with 10g or later). The Oracle Client libraries are in the free Oracle Instant Client from https://www.oracle.com/database/technologies/instant-client.html. They are also included in your database installation. -Oracle's standard cross-version connectivity applies. For example, PHP OCI8 linked with Instant Client 19c can connect to Oracle Database 11.2 onward. See Oracle's note "Oracle Client / Server Interoperability Support" (ID 207303.1) for details. +Oracle's standard cross-version connectivity applies. For example, PHP OCI8 linked with Oracle Client 19c can connect to Oracle Database 11.2 onward. See Oracle's note "Oracle Client / Server Interoperability Support" (ID 207303.1) for details. Christopher Jones @@ -55,12 +55,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin no - 2021-12-11 + 2021-12-12 - 3.2.0 - 3.2.0 + 3.2.1 + 3.2.1 stable @@ -70,7 +70,7 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin This version is for PHP 8.1 only. - Added oci8.prefetch_lob_size directive and oci_set_prefetch_lob() function to improve LOB query performance. + Requires Oracle Client libraries from 11.2 or later. @@ -454,8 +454,8 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin - 3.1.0 - 3.1.0 + 3.2.0 + 3.2.0 stable @@ -463,16 +463,16 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin PHP - This version is for PHP 8 only. + This version is for PHP 8.1 only. - Deprecated directive oci8.old_oci_close_semantics + Added oci8.prefetch_lob_size directive and oci_set_prefetch_lob() function to improve LOB query performance. - + - 3.0.1 - 3.0.1 + 3.1.0 + 3.1.0 stable @@ -480,16 +480,16 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin PHP - This version is for PHP 8 only. + This version is for PHP 8.0 only. - Updated Windows build environment to build with newer Oracle Client libraries. (cmb) + Deprecated directive oci8.old_oci_close_semantics - + - 2.2.0 - 2.2.0 + 3.0.1 + 3.0.1 stable @@ -497,15 +497,12 @@ Oracle's standard cross-version connectivity applies. For example, PHP OCI8 lin PHP -This version is for PHP 7 only. -Added oci_set_call_timeout() for call timeouts. (Requires Oracle client libraries 18c or later) -Added oci_set_db_operation() for the Oracle Database 'DBOP' end-to-end-tracing attribute. (Requires Oracle 12.2 or later) -Fixed bug #76804 (oci_pconnect with OCI_CRED_EXT not working). (KoenigsKind) -Fixed installation on PHP 7.3. -Internal change: Convert some parameter parsing to the Fast Parameter Parsing API. + This version is for PHP 8.0 only. + + Updated Windows build environment to build with newer Oracle Client libraries. (cmb) - + 3.0.0 @@ -517,7 +514,7 @@ Internal change: Convert some parameter parsing to the Fast Parameter Parsing AP PHP - This version is for PHP 8 only. + This version is for PHP 8.0 only. Deprecated old OCI8 function aliases. (Jens de Nies) @@ -531,6 +528,26 @@ Internal change: Convert some parameter parsing to the Fast Parameter Parsing AP + + + 2.2.0 + 2.2.0 + + + stable + stable + + PHP + +This version is for PHP 7 only. +Added oci_set_call_timeout() for call timeouts. (Requires Oracle client libraries 18c or later) +Added oci_set_db_operation() for the Oracle Database 'DBOP' end-to-end-tracing attribute. (Requires Oracle 12.2 or later) +Fixed bug #76804 (oci_pconnect with OCI_CRED_EXT not working). (KoenigsKind) +Fixed installation on PHP 7.3. +Internal change: Convert some parameter parsing to the Fast Parameter Parsing API. + + + 2.1.8 diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h index e447600441655..5ed8c7bbe72c5 100644 --- a/ext/oci8/php_oci8.h +++ b/ext/oci8/php_oci8.h @@ -31,7 +31,6 @@ # include "TSRM.h" #endif - /* * The version of the OCI8 extension. */ @@ -41,7 +40,7 @@ */ #undef PHP_OCI8_VERSION #endif -#define PHP_OCI8_VERSION "3.2.0" +#define PHP_OCI8_VERSION "3.2.1" extern zend_module_entry oci8_module_entry; #define phpext_oci8_ptr &oci8_module_entry diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index dec9172f5c5e4..9b34fc922cbb9 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -55,6 +55,10 @@ #include "ext/standard/php_string.h" #include +#if !defined(OCI_MAJOR_VERSION) || OCI_MAJOR_VERSION < 11 || ((OCI_MAJOR_VERSION == 11) && (OCI_MINOR_VERSION < 2)) +#error This version of PHP OCI8 requires Oracle Client libraries from 11.2 or later. +#endif + extern int le_connection; extern int le_pconnection; extern int le_statement; diff --git a/ext/oci8/tests/driver_name.phpt b/ext/oci8/tests/driver_name.phpt index 0b32c4bd1f6be..80b4740bc140b 100644 --- a/ext/oci8/tests/driver_name.phpt +++ b/ext/oci8/tests/driver_name.phpt @@ -57,11 +57,11 @@ function get_attr($conn) ?> --EXPECT-- **Test 1.1 - Default values for the attribute ************** -The value of DRIVER_NAME is PHP OCI8 : 3.2.0 +The value of DRIVER_NAME is PHP OCI8 : 3.2.1 ***Test 1.2 - Get the values from different connections ************** Testing with oci_pconnect() -The value of DRIVER_NAME is PHP OCI8 : 3.2.0 +The value of DRIVER_NAME is PHP OCI8 : 3.2.1 Testing with oci_new_connect() -The value of DRIVER_NAME is PHP OCI8 : 3.2.0 +The value of DRIVER_NAME is PHP OCI8 : 3.2.1 Done From 98175fc7f1623873ceb2e9a017a319d19bfb3912 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 13:41:37 +0100 Subject: [PATCH 19/75] Fix openssl_x509_checkpurpose_basic.phpt This test fails because san-cert.pem and san-ca.pem have expired. We fix that by using the CertificateGenerator to generate temporary certs during the test run. Since san-cert.pem and san-ca.pem have been identical, we only generate one certificate. Closes GH-7763. --- .../openssl_x509_checkpurpose_basic.phpt | 10 +++++- ext/openssl/tests/san-ca.pem | 15 --------- ext/openssl/tests/san-cert.pem | 31 ------------------- 3 files changed, 9 insertions(+), 47 deletions(-) delete mode 100644 ext/openssl/tests/san-ca.pem delete mode 100644 ext/openssl/tests/san-cert.pem diff --git a/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt b/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt index 99b4f0bdff312..35629bd936266 100644 --- a/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt +++ b/ext/openssl/tests/openssl_x509_checkpurpose_basic.phpt @@ -8,10 +8,14 @@ if (OPENSSL_VERSION_NUMBER < 0x10000000) die("skip Output requires OpenSSL 1.0") ?> --FILE-- saveCaCert(__DIR__ . "/san-cert.pem"); + $cert = "file://" . __DIR__ . "/cert.crt"; $bert = "file://" . __DIR__ . "/bug41033.pem"; $sert = "file://" . __DIR__ . "/san-cert.pem"; -$cpca = __DIR__ . "/san-ca.pem"; +$cpca = __DIR__ . "/san-cert.pem"; $utfl = __DIR__ . "/sni_server_uk.pem"; $rcrt = openssl_x509_read($cert); @@ -84,6 +88,10 @@ var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_SMIME_ENCRYPT, array($cpc var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_CRL_SIGN, array($cpca), $utfl)); var_dump(openssl_x509_checkpurpose($sert, X509_PURPOSE_ANY, array($cpca), $utfl)); ?> +--CLEAN-- + --EXPECT-- bool(false) bool(false) diff --git a/ext/openssl/tests/san-ca.pem b/ext/openssl/tests/san-ca.pem deleted file mode 100644 index 88682ba2dcf65..0000000000000 --- a/ext/openssl/tests/san-ca.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICYTCCAcqgAwIBAgIJAIaqxtY5dwjtMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UEBxMLTWlubmVhcG9saXMxITAfBgNV -BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDAeFw0xMzA5MjQwODA1NTFaFw0y -MTEyMTEwODA1NTFaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UE -BxMLTWlubmVhcG9saXMxITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRl -ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsFGqfbU/8D+KjroQl4XMyt9m -dcSP7iZtqphOu9nVZxYAAqfaqj8FnC/pwYV3TU6ZHndLTQAllwYT3sQBQPPGmZQ9 -clSIMEL003t3pi4ZVXkttG6Vvr+Z9PBcHhlKLQ7WMHnn4qctllWXTSoyTQpkETF3 -Fc3mrG5G37BhoUno7NECAwEAAaM9MDswOQYDVR0RBDIwMIILZXhhbXBsZS5vcmeC -D3d3dy5leGFtcGxlLm9yZ4IQdGVzdC5leGFtcGxlLm9yZzANBgkqhkiG9w0BAQUF -AAOBgQBf/FZhzheIcQJ+dyTk8xQ/nJLvpmBhbd1LNtfwk/MsC9UHsz4QXs9sBw1k -rH0FjoqgM6avj7zKHJFTj6q7Rd+OX5V4HynYPhX67sWbN3KWEHffL98nGGd/bo3X -pSjNk5vnyKYiwdUUe11Ac9csh0HcSBbhOYjy0T/i9AlQcKbuCg== ------END CERTIFICATE----- diff --git a/ext/openssl/tests/san-cert.pem b/ext/openssl/tests/san-cert.pem deleted file mode 100644 index 923d490e72fd3..0000000000000 --- a/ext/openssl/tests/san-cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICYTCCAcqgAwIBAgIJAIaqxtY5dwjtMA0GCSqGSIb3DQEBBQUAMFMxCzAJBgNV -BAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UEBxMLTWlubmVhcG9saXMxITAfBgNV -BAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRlZDAeFw0xMzA5MjQwODA1NTFaFw0y -MTEyMTEwODA1NTFaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJNTjEUMBIGA1UE -BxMLTWlubmVhcG9saXMxITAfBgNVBAsTGERvbWFpbiBDb250cm9sIFZhbGlkYXRl -ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsFGqfbU/8D+KjroQl4XMyt9m -dcSP7iZtqphOu9nVZxYAAqfaqj8FnC/pwYV3TU6ZHndLTQAllwYT3sQBQPPGmZQ9 -clSIMEL003t3pi4ZVXkttG6Vvr+Z9PBcHhlKLQ7WMHnn4qctllWXTSoyTQpkETF3 -Fc3mrG5G37BhoUno7NECAwEAAaM9MDswOQYDVR0RBDIwMIILZXhhbXBsZS5vcmeC -D3d3dy5leGFtcGxlLm9yZ4IQdGVzdC5leGFtcGxlLm9yZzANBgkqhkiG9w0BAQUF -AAOBgQBf/FZhzheIcQJ+dyTk8xQ/nJLvpmBhbd1LNtfwk/MsC9UHsz4QXs9sBw1k -rH0FjoqgM6avj7zKHJFTj6q7Rd+OX5V4HynYPhX67sWbN3KWEHffL98nGGd/bo3X -pSjNk5vnyKYiwdUUe11Ac9csh0HcSBbhOYjy0T/i9AlQcKbuCg== ------END CERTIFICATE----- ------BEGIN PRIVATE KEY----- -MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALBRqn21P/A/io66 -EJeFzMrfZnXEj+4mbaqYTrvZ1WcWAAKn2qo/BZwv6cGFd01OmR53S00AJZcGE97E -AUDzxpmUPXJUiDBC9NN7d6YuGVV5LbRulb6/mfTwXB4ZSi0O1jB55+KnLZZVl00q -Mk0KZBExdxXN5qxuRt+wYaFJ6OzRAgMBAAECgYB11e5iWvqjPmQEZRdnnJU0VD8u -n7ItT+Nk6qtb4gY8Abj6DWIW+01th5vqqJ8FvGyartFVYa69kuM+srG/zevAZWeu -fGZtwiwZR4DRSyRcPp4rnNiksK3dkAZA6UewmRDPv8uyHJlXc5i+Ft1ILJ5Q5jgn -UkC4z3EJP5Se9KZywQJBAOO4lRq42wLsYr2SDrQDSs4leie3FKc2bgvjF7Djosh1 -ZYbf55F5b9w1zgnccmni2HkqOnyFu4SKarmXyCsYxrkCQQDGNvnUh7/zZswrdWZ/ -PMp9zVDTh/5Oc2B4ByNLw1ERDwYhjchKgPRlQvn4cp3Pwf3UYPQ/8XGXzzEJey3A -r0rZAkBf/tDEOgcBPXsGZQrTscuYCU5sbY5ESvqrAilbhSp7DJom+D5bIfEYyIm5 -uHd20Yzlzvpmwc1huyPwZt6X5FLpAkATDReoGMAXSesXxjnqwtIHk2NQYYLM0YQV -JUJ8NrKk/Bevw+vbVVeoH+7ctU97t36JGiR/vNoZKD3jVmaIXZDJAkEA4wJbwzIo -L32mu9VmZa7wjmfkraQEmXTPaA5D9lNC0AwRTgkj+x2Qe1vawNblNK9PPLBDdplQ -L//53ADq/wv5rA== ------END PRIVATE KEY----- From 778513f60512f85dd4e10a848e0a4f4f4ef3b9d1 Mon Sep 17 00:00:00 2001 From: SATO Kentaro Date: Mon, 6 Dec 2021 06:59:52 +0900 Subject: [PATCH 20/75] Fix error message allocation of PDO PgSQL Closes GH-7723. --- NEWS | 3 +++ ext/pdo_pgsql/pgsql_driver.c | 2 +- ext/pdo_pgsql/tests/gh7723.phpt | 30 ++++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 ext/pdo_pgsql/tests/gh7723.phpt diff --git a/NEWS b/NEWS index 9207f3cc6d5c8..18a8b747a0b1e 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ PHP NEWS . Fixed bug #81585 (cached_chunks are not counted to real_size on shutdown). (cmb) +- PDO_PGSQL: + . Fixed error message allocation of PDO PgSQL. (SATO Kentaro) + - Spl: . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr Bystry) diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index a5b0a22f2057b..b6449095ca0cb 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -87,7 +87,7 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char * } if (msg) { - einfo->errmsg = estrdup(msg); + einfo->errmsg = pestrdup(msg, dbh->is_persistent); } else if (errmsg) { einfo->errmsg = _pdo_pgsql_trim_message(errmsg, dbh->is_persistent); diff --git a/ext/pdo_pgsql/tests/gh7723.phpt b/ext/pdo_pgsql/tests/gh7723.phpt new file mode 100644 index 0000000000000..bbbf5fd5bc21c --- /dev/null +++ b/ext/pdo_pgsql/tests/gh7723.phpt @@ -0,0 +1,30 @@ +--TEST-- +GitHub #7723 (Fix error message allocation of PDO PgSQL) +--SKIPIF-- + +--FILE-- +setAttribute(PDO::ATTR_PERSISTENT, true); +$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + +$st = $db->prepare('select 1'); +for ($i = 0; ++$i <= 2;) { + try { + $st->bindValue(':invalid', $i); + } catch (PDOException $e) { + echo $e->getMessage() . "\n"; + } +} +?> +--EXPECT-- +SQLSTATE[HY093]: Invalid parameter number: :invalid +SQLSTATE[HY093]: Invalid parameter number: :invalid From 0b3a9376701c3e8095d4fdaa2c363b26df8d20f9 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sat, 11 Dec 2021 22:16:00 +0100 Subject: [PATCH 21/75] Fix GH-7759: Incorrect return types for hash() and hash_hmac() `hash()` and `hash_hmac()` never return `false`; only `hash_file()` and `hash_hmac_file()` return `false` in case the data cannot be read. Closes GH-7760. --- NEWS | 4 ++++ ext/hash/hash.stub.php | 4 ++-- ext/hash/hash_arginfo.h | 13 +++++++++---- ext/opcache/Optimizer/zend_func_info.c | 4 ++-- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 18a8b747a0b1e..020add82e597e 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,10 @@ PHP NEWS . Fixed bug #81585 (cached_chunks are not counted to real_size on shutdown). (cmb) +- Hash: + . Fixed bug GH-7759 (Incorrect return types for hash() and hash_hmac()). + (cmb) + - PDO_PGSQL: . Fixed error message allocation of PDO PgSQL. (SATO Kentaro) diff --git a/ext/hash/hash.stub.php b/ext/hash/hash.stub.php index c0d4cbca7c3d5..250fb68ee4e9f 100644 --- a/ext/hash/hash.stub.php +++ b/ext/hash/hash.stub.php @@ -2,11 +2,11 @@ /** @generate-function-entries */ -function hash(string $algo, string $data, bool $binary = false): string|false {} +function hash(string $algo, string $data, bool $binary = false): string {} function hash_file(string $algo, string $filename, bool $binary = false): string|false {} -function hash_hmac(string $algo, string $data, string $key, bool $binary = false): string|false {} +function hash_hmac(string $algo, string $data, string $key, bool $binary = false): string {} function hash_hmac_file(string $algo, string $data, string $key, bool $binary = false): string|false {} diff --git a/ext/hash/hash_arginfo.h b/ext/hash/hash_arginfo.h index db043da97b477..5aef2c11d1d61 100644 --- a/ext/hash/hash_arginfo.h +++ b/ext/hash/hash_arginfo.h @@ -1,7 +1,7 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 9352e0ac98e2ac53dc15d5024f9ef0c8092c4e9c */ + * Stub hash: f73c6fa1a4ac1ca93f87775bbe69fbdb2deb5746 */ -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash, 0, 2, MAY_BE_STRING|MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_hash, 0, 2, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false") @@ -13,14 +13,19 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash_file, 0, 2, MAY_BE_STRING|M ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash_hmac, 0, 3, MAY_BE_STRING|MAY_BE_FALSE) +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_hash_hmac, 0, 3, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() -#define arginfo_hash_hmac_file arginfo_hash_hmac +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_hash_hmac_file, 0, 3, MAY_BE_STRING|MAY_BE_FALSE) + ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, data, IS_STRING, 0) + ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, binary, _IS_BOOL, 0, "false") +ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_hash_init, 0, 1, HashContext, 0) ZEND_ARG_TYPE_INFO(0, algo, IS_STRING, 0) diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c index 3589aa1b3c2ef..84c9d20966cae 100644 --- a/ext/opcache/Optimizer/zend_func_info.c +++ b/ext/opcache/Optimizer/zend_func_info.c @@ -581,9 +581,9 @@ static const func_info_t func_infos[] = { F1("ob_gzhandler", MAY_BE_FALSE | MAY_BE_STRING), /* ext/hash */ - F1("hash", MAY_BE_FALSE | MAY_BE_STRING), + F1("hash", MAY_BE_STRING), F1("hash_file", MAY_BE_FALSE | MAY_BE_STRING), - F1("hash_hmac", MAY_BE_FALSE | MAY_BE_STRING), + F1("hash_hmac", MAY_BE_STRING), F1("hash_hmac_algos", MAY_BE_ARRAY | MAY_BE_ARRAY_KEY_LONG | MAY_BE_ARRAY_OF_STRING), F1("hash_hmac_file", MAY_BE_FALSE | MAY_BE_STRING), F1("hash_hkdf", MAY_BE_STRING), From 6d5f2ba78d85f24e69eee5c7c3948171b9fc3b05 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 16:57:57 +0100 Subject: [PATCH 22/75] macOS 10.14 runners are no longer available via Azure Pipeline These images have already been deprecated for two months[1]. Thus, we upgrade to macOS 10.15. Since clang 12 is picky about `int-in-bool-context` warning, we disable `-Werror`. [1] --- azure/macos/job.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure/macos/job.yml b/azure/macos/job.yml index 4b979d41a8672..a27a16fb336cd 100644 --- a/azure/macos/job.yml +++ b/azure/macos/job.yml @@ -5,7 +5,7 @@ parameters: jobs: - job: ${{ parameters.configurationName }} pool: - vmImage: 'macOS-10.14' + vmImage: 'macOS-10.15' steps: - template: brew.yml - script: | @@ -66,7 +66,6 @@ jobs: --enable-intl \ --with-mhash \ --with-sodium \ - --enable-werror \ --with-config-file-path=/etc \ --with-config-file-scan-dir=/etc/php.d displayName: 'Configure Build' From 206c521a1f980c1c422543f3a17fca619e9ec5ee Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 19:53:02 +0100 Subject: [PATCH 23/75] Fix GH-7757: Multi-inherited final constant causes fatal error "Diamond" inheritance of final constants is supposed to be supported. Closes GH-7767. --- NEWS | 2 ++ .../final_constants/final_const13.phpt | 18 ++++++++++++++++++ Zend/zend_inheritance.c | 2 +- 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/constants/final_constants/final_const13.phpt diff --git a/NEWS b/NEWS index 28575db948d25..c6ae9489f96f4 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ PHP NEWS on final or abstract interface methods). (ilutov) . Fixed bug #81585 (cached_chunks are not counted to real_size on shutdown). (cmb) + . Fixed bug GH-7757 (Multi-inherited final constant causes fatal error). + (cmb) - Hash: . Fixed bug GH-7759 (Incorrect return types for hash() and hash_hmac()). diff --git a/Zend/tests/constants/final_constants/final_const13.phpt b/Zend/tests/constants/final_constants/final_const13.phpt new file mode 100644 index 0000000000000..5e19e8a212695 --- /dev/null +++ b/Zend/tests/constants/final_constants/final_const13.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug GH-7757 (Multi-inherited final constant causes fatal error) +--FILE-- + +--EXPECT-- diff --git a/Zend/zend_inheritance.c b/Zend/zend_inheritance.c index 4903ef4b3828b..020c5e6553920 100644 --- a/Zend/zend_inheritance.c +++ b/Zend/zend_inheritance.c @@ -1605,7 +1605,7 @@ static bool do_inherit_constant_check( } zend_class_constant *old_constant = Z_PTR_P(zv); - if ((ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) { + if (parent_constant->ce != old_constant->ce && (ZEND_CLASS_CONST_FLAGS(parent_constant) & ZEND_ACC_FINAL)) { zend_error_noreturn(E_COMPILE_ERROR, "%s::%s cannot override final constant %s::%s", ZSTR_VAL(old_constant->ce->name), ZSTR_VAL(name), ZSTR_VAL(parent_constant->ce->name), ZSTR_VAL(name) From c435e67746ab8d9c9e3946395f57bde6a6f51b89 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 18:37:15 +0100 Subject: [PATCH 24/75] Fix GH-7765: php_oci_cleanup_global_handles segfaults at second call We must not use the TSRM accessor macros in GINIT and GSHUTDOWN, but rather use the passed pointers directly. For simplicity, we inline `php_oci_cleanup_global_handles()`, and also the `PHP_OCI_CALL()` macros; the latter are unlikely to be needed here, but don't hurt. Closes GH-7766. --- NEWS | 4 ++++ ext/oci8/oci8.c | 33 ++++++++++++++------------------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/NEWS b/NEWS index 020add82e597e..6f1a19ddd8a76 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ PHP NEWS . Fixed bug GH-7759 (Incorrect return types for hash() and hash_hmac()). (cmb) +- OCI8: + . Fixed bug GH-7765 (php_oci_cleanup_global_handles segfaults at second + call). (cmb) + - PDO_PGSQL: . Fixed error message allocation of PDO PgSQL. (SATO Kentaro) diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index ad9b23a9c40ac..a7abc6be859ac 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -239,24 +239,6 @@ static void php_oci_init_global_handles(void) } /* }}} */ -/* {{{ php_oci_cleanup_global_handles() - * - * Free global handles (if they were initialized before) - */ -static void php_oci_cleanup_global_handles(void) -{ - if (OCI_G(err)) { - PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR)); - OCI_G(err) = NULL; - } - - if (OCI_G(env)) { - PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV)); - OCI_G(env) = NULL; - } -} -/* }}} */ - /* {{{ PHP_GINIT_FUNCTION * * Zerofill globals during module init @@ -270,10 +252,23 @@ static PHP_GINIT_FUNCTION(oci) /* {{{ PHP_GSHUTDOWN_FUNCTION * * Called for thread shutdown in ZTS, after module shutdown for non-ZTS + * Free global handles (if they were initialized before) */ static PHP_GSHUTDOWN_FUNCTION(oci) { - php_oci_cleanup_global_handles(); + if (oci_globals->err) { + oci_globals->in_call = 1; + OCIHandleFree((dvoid *) oci_globals->err, OCI_HTYPE_ERROR); + oci_globals->in_call = 0; + oci_globals->err = NULL; + } + + if (oci_globals->env) { + oci_globals->in_call = 1; + OCIHandleFree((dvoid *) oci_globals->env, OCI_HTYPE_ENV); + oci_globals->in_call = 0; + oci_globals->env = NULL; + } } /* }}} */ From 1d54097435bc09a287cb50b6e166eccba19f2925 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 22:45:46 +0100 Subject: [PATCH 25/75] Fix oci8 Oracle Client paths on Windows This is a copy & paste relict, but we don't fix it for the stable branches, since some may rely on these paths now (unlikely, but still possible). --- ext/oci8/config.w32 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/oci8/config.w32 b/ext/oci8/config.w32 index 5f0da8f33d2d8..1c94c1578995c 100644 --- a/ext/oci8/config.w32 +++ b/ext/oci8/config.w32 @@ -164,8 +164,8 @@ if (PHP_OCI8_19 != "no") { oci8_19_inc_paths += oci8_19_dirs[i] + "\\include;"; } - oci8_19_inc_paths += PHP_PHP_BUILD + "\\include\\instantclient_12;" - oci8_19_lib_paths += PHP_PHP_BUILD + "\\lib\\instantclient_12;"; + oci8_19_inc_paths += PHP_PHP_BUILD + "\\include\\instantclient_19;" + oci8_19_lib_paths += PHP_PHP_BUILD + "\\lib\\instantclient_19;"; if (CHECK_HEADER_ADD_INCLUDE("oci.h", "CFLAGS_OCI8_19", oci8_19_inc_paths) && CHECK_LIB("oci.lib", "oci8_19", oci8_19_lib_paths)) From e79dbe1124bc5e556ab87ce6a4bfa3826108a2fa Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Dec 2021 11:49:51 +0300 Subject: [PATCH 26/75] JIT: Fix crash during compilation of function with incompletely constructed SSA Fixes oss-fuzz #42200 --- ext/opcache/jit/zend_jit.c | 5 ++++- ext/opcache/tests/jit/mod_006.phpt | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/jit/mod_006.phpt diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 48d3d55d32e0a..bbe879b9fddd2 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2311,7 +2311,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } end = ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1; for (i = ssa->cfg.blocks[b].start; i <= end; i++) { - zend_ssa_op *ssa_op = &ssa->ops[i]; + zend_ssa_op *ssa_op = ssa->ops ? &ssa->ops[i] : NULL; opline = op_array->opcodes + i; switch (opline->opcode) { case ZEND_INIT_FCALL: @@ -2342,6 +2342,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op res_use_info = -1; if (opline->result_type == IS_CV + && ssa->vars && ssa_op->result_use >= 0 && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); @@ -2406,6 +2407,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op res_use_info = -1; if (opline->result_type == IS_CV + && ssa->vars && ssa_op->result_use >= 0 && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); @@ -2463,6 +2465,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op res_use_info = -1; if (opline->result_type == IS_CV + && ssa->vars && ssa_op->result_use >= 0 && !ssa->vars[ssa_op->result_use].no_val) { zend_jit_addr res_use_addr = RES_USE_REG_ADDR(); diff --git a/ext/opcache/tests/jit/mod_006.phpt b/ext/opcache/tests/jit/mod_006.phpt new file mode 100644 index 0000000000000..b13ef68a8e1ba --- /dev/null +++ b/ext/opcache/tests/jit/mod_006.phpt @@ -0,0 +1,19 @@ +--TEST-- +JIT MOD: 005 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +--FILE-- + +DONE +--EXPECT-- +DONE \ No newline at end of file From 230de7721f17ca0aeb85d819f1d4001a6be56d22 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Dec 2021 13:08:05 +0300 Subject: [PATCH 27/75] Fix incorrect optimization that leads to memory leak Fixes oss-fuzz #42221 --- ext/opcache/Optimizer/sccp.c | 4 +++- ext/opcache/tests/opt/sccp_034.phpt | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/opt/sccp_034.phpt diff --git a/ext/opcache/Optimizer/sccp.c b/ext/opcache/Optimizer/sccp.c index 7792311637632..bdeb883aa562a 100644 --- a/ext/opcache/Optimizer/sccp.c +++ b/ext/opcache/Optimizer/sccp.c @@ -2279,7 +2279,9 @@ static int try_remove_definition(sccp_ctx *ctx, int var_num, zend_ssa_var *var, removed_ops = remove_call(ctx, opline, ssa_op); } else if (opline->opcode == ZEND_TYPE_CHECK && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && !value_known(&ctx->values[ssa_op->op1_use])) { + && (!value_known(&ctx->values[ssa_op->op1_use]) + || IS_PARTIAL_ARRAY(&ctx->values[ssa_op->op1_use]) + || IS_PARTIAL_OBJECT(&ctx->values[ssa_op->op1_use]))) { /* For TYPE_CHECK we may compute the result value without knowing the * operand, based on type inference information. Make sure the operand is * freed and leave further cleanup to DCE. */ diff --git a/ext/opcache/tests/opt/sccp_034.phpt b/ext/opcache/tests/opt/sccp_034.phpt new file mode 100644 index 0000000000000..8fafc89178a64 --- /dev/null +++ b/ext/opcache/tests/opt/sccp_034.phpt @@ -0,0 +1,16 @@ +--TEST-- +SCCP 034: memory leak +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +DONE +--EXPECTF-- +Warning: Undefined variable $y in %ssccp_034.php on line 2 + +Warning: Undefined variable $y in %ssccp_034.php on line 2 +DONE From cbc0b1afeb97044f7a813e8678736649c15f3974 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Dec 2021 14:59:30 +0300 Subject: [PATCH 28/75] Fix array clobering by user error handler Fixes oss-fuzz #42234 --- Zend/tests/objects_034.phpt | 10 +- Zend/tests/objects_035.phpt | 25 ++ Zend/zend_execute.c | 39 +- Zend/zend_vm_def.h | 20 +- Zend/zend_vm_execute.h | 640 ++++++++++------------------- ext/opcache/jit/zend_jit_helpers.c | 61 ++- 6 files changed, 317 insertions(+), 478 deletions(-) create mode 100644 Zend/tests/objects_035.phpt diff --git a/Zend/tests/objects_034.phpt b/Zend/tests/objects_034.phpt index ddb11a13fea28..e7cc5f9e90cff 100644 --- a/Zend/tests/objects_034.phpt +++ b/Zend/tests/objects_034.phpt @@ -2,7 +2,15 @@ Array object clobbering by user error handler --FILE-- +DONE +--EXPECT-- +DONE diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index d9f7789847c99..a8f5c27071662 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1264,9 +1264,9 @@ static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_string_offset zend_type_error("Cannot access offset of type %s on string", zend_zval_type_name(offset)); } -static zend_never_inline void zend_assign_to_object_dim(zval *object, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_assign_to_object_dim(zend_object *obj, zval *dim, zval *value OPLINE_DC EXECUTE_DATA_DC) { - Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), dim, value); + obj->handlers->write_dimension(obj, dim, value); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); @@ -1300,12 +1300,14 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval * zval *value; zval *z; zval rv, res; + zend_object *obj = Z_OBJ_P(object); + GC_ADDREF(obj); value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); - if ((z = Z_OBJ_HT_P(object)->read_dimension(Z_OBJ_P(object), property, BP_VAR_R, &rv)) != NULL) { + if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) { if (zend_binary_op(&res, z, value OPLINE_CC) == SUCCESS) { - Z_OBJ_HT_P(object)->write_dimension(Z_OBJ_P(object), property, &res); + obj->handlers->write_dimension(obj, property, &res); } if (z == &rv) { zval_ptr_dtor(&rv); @@ -1321,6 +1323,9 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval * } } FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC) @@ -2317,22 +2322,17 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * } ZVAL_UNDEF(result); } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + GC_ADDREF(obj); if (ZEND_CONST_COND(dim_type == IS_CV, dim != NULL) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZVAL_NULL(result); - return; - } } else if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, type, result); + retval = obj->handlers->read_dimension(obj, dim, type, result); if (UNEXPECTED(retval == &EG(uninitialized_zval))) { - zend_class_entry *ce = Z_OBJCE_P(container); + zend_class_entry *ce = obj->ce; ZVAL_NULL(result); zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name)); @@ -2343,7 +2343,7 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * retval = result; } if (Z_TYPE_P(retval) != IS_OBJECT) { - zend_class_entry *ce = Z_OBJCE_P(container); + zend_class_entry *ce = obj->ce; zend_error(E_NOTICE, "Indirect modification of overloaded element of %s has no effect", ZSTR_VAL(ce->name)); } } else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) { @@ -2356,6 +2356,9 @@ static zend_always_inline void zend_fetch_dimension_address(zval *result, zval * ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception"); ZVAL_UNDEF(result); } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else { if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (type != BP_VAR_W && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { @@ -2508,13 +2511,16 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z ZVAL_CHAR(result, c); } } else if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); if (ZEND_CONST_COND(dim_type == IS_CV, 1) && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { dim = ZVAL_UNDEFINED_OP2(); } if (dim_type == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, type, result); + retval = obj->handlers->read_dimension(obj, dim, type, result); ZEND_ASSERT(result != NULL); if (retval) { @@ -2526,6 +2532,9 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z } else { ZVAL_NULL(result); } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else { if (type != BP_VAR_IS && UNEXPECTED(Z_TYPE_P(container) == IS_UNDEF)) { container = ZVAL_UNDEFINED_OP1(); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 80db78b36adfc..0648ddac77055 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2583,35 +2583,29 @@ ZEND_VM_C_LABEL(try_assign_dim_array): } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZEND_VM_C_GOTO(assign_dim_error); - } } else if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = GET_OP_DATA_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP_DATA_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZEND_VM_C_GOTO(assign_dim_error); - } } else if (OP_DATA_TYPE & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); FREE_OP_DATA(); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (OP2_TYPE == IS_UNUSED) { zend_use_new_element_for_string(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d74e40a0427b8..a5300d9099b01 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -23243,34 +23243,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -23375,35 +23369,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -23508,35 +23496,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -23641,34 +23623,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -25843,34 +25819,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -25975,35 +25945,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -26108,35 +26072,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -26241,34 +26199,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -27299,34 +27251,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -27431,35 +27377,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -27564,35 +27504,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -27697,34 +27631,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -29914,34 +29842,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -30046,35 +29968,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -30179,35 +30095,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -30312,34 +30222,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -40853,34 +40757,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -40985,35 +40883,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -41118,35 +41010,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -41251,34 +41137,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CONST == IS_UNUSED) { zend_use_new_element_for_string(); @@ -44527,34 +44407,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -44659,35 +44533,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -44792,35 +44660,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -44925,34 +44787,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { zend_use_new_element_for_string(); @@ -46429,34 +46285,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -46561,35 +46411,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -46694,35 +46538,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -46827,34 +46665,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_UNUSED == IS_UNUSED) { zend_use_new_element_for_string(); @@ -49712,34 +49544,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = RT_CONSTANT((opline+1), (opline+1)->op1); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CONST & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -49844,35 +49670,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_TMP_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_TMP_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -49977,35 +49797,29 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (IS_VAR == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_VAR & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); @@ -50110,34 +49924,28 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ } } if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(object_ptr); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } value = EX_VAR((opline+1)->op1.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(value))) { - zend_object *obj = Z_OBJ_P(object_ptr); - GC_ADDREF(obj); value = zval_undefined_cv((opline+1)->op1.var EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_error; - } } else if (IS_CV & (IS_CV|IS_VAR)) { ZVAL_DEREF(value); } - zend_assign_to_object_dim(object_ptr, dim, value OPLINE_CC EXECUTE_DATA_CC); + zend_assign_to_object_dim(obj, dim, value OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (IS_CV == IS_UNUSED) { zend_use_new_element_for_string(); diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 31d48709fc93f..4595afdc17873 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -992,13 +992,15 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_str_is_helper(zend_string *str, zva static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval *dim, zval *result) { zval *retval; + zend_object *obj = Z_OBJ_P(container); + GC_ADDREF(obj); if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var); dim = &EG(uninitialized_zval); } - retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_R, result); + retval = obj->handlers->read_dimension(obj, dim, BP_VAR_R, result); if (retval) { if (result != retval) { @@ -1009,18 +1011,23 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_r_helper(zval *container, zval } else { ZVAL_NULL(result); } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval *dim, zval *result) { zval *retval; + zend_object *obj = Z_OBJ_P(container); + GC_ADDREF(obj); if (UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { zend_jit_undefined_op_helper(EG(current_execute_data)->opline->op2.var); dim = &EG(uninitialized_zval); } - retval = Z_OBJ_HT_P(container)->read_dimension(Z_OBJ_P(container), dim, BP_VAR_IS, result); + retval = obj->handlers->read_dimension(obj, dim, BP_VAR_IS, result); if (retval) { if (result != retval) { @@ -1031,6 +1038,9 @@ static void ZEND_FASTCALL zend_jit_fetch_dim_obj_is_helper(zval *container, zval } else { ZVAL_NULL(result); } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } static zend_never_inline ZEND_COLD void zend_wrong_string_offset(void) @@ -1292,16 +1302,11 @@ static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(object_ptr); + GC_ADDREF(obj); if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) { const zend_op *opline = EG(current_execute_data)->opline; - GC_ADDREF(obj); zend_jit_undefined_op_helper(opline->op2.var); dim = &EG(uninitialized_zval); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZVAL_NULL(result); - return; - } } retval = obj->handlers->read_dimension(obj, dim, type, result); @@ -1330,6 +1335,9 @@ static zend_always_inline void ZEND_FASTCALL zend_jit_fetch_dim_obj_helper(zval ZEND_ASSERT(EG(exception) && "read_dimension() returned NULL without exception"); ZVAL_UNDEF(result); } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING)) { if (!dim) { zend_throw_error(NULL, "[] operator not supported for strings"); @@ -1373,38 +1381,23 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim if (EXPECTED(Z_TYPE_P(object_ptr) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(object_ptr); + GC_ADDREF(obj); if (dim && UNEXPECTED(Z_TYPE_P(dim) == IS_UNDEF)) { const zend_op *opline = EG(current_execute_data)->opline; - GC_ADDREF(obj); zend_jit_undefined_op_helper(opline->op2.var); dim = &EG(uninitialized_zval); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - if (result) { - ZVAL_NULL(result); - } - return; - } } if (UNEXPECTED(Z_TYPE_P(value) == IS_UNDEF)) { const zend_op *op_data = EG(current_execute_data)->opline + 1; ZEND_ASSERT(op_data->opcode == ZEND_OP_DATA && op_data->op1_type == IS_CV); - GC_ADDREF(obj); zend_jit_undefined_op_helper(op_data->op1.var); value = &EG(uninitialized_zval); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - if (result) { - ZVAL_NULL(result); - } - return; - } } else { ZVAL_DEREF(value); } - Z_OBJ_HT_P(object_ptr)->write_dimension(obj, dim, value); + obj->handlers->write_dimension(obj, dim, value); if (result) { if (EXPECTED(!EG(exception))) { ZVAL_COPY(result, value); @@ -1412,6 +1405,9 @@ static void ZEND_FASTCALL zend_jit_assign_dim_helper(zval *object_ptr, zval *dim ZVAL_UNDEF(result); } } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } return; } else if (EXPECTED(Z_TYPE_P(object_ptr) == IS_STRING) && EXPECTED(dim != NULL)) { zend_assign_to_string_offset(object_ptr, dim, value, result); @@ -1451,18 +1447,11 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d zval *z; zval rv, res; + GC_ADDREF(obj); if (dim && UNEXPECTED(Z_ISUNDEF_P(dim))) { const zend_op *opline = EG(current_execute_data)->opline; - GC_ADDREF(obj); zend_jit_undefined_op_helper(opline->op2.var); dim = &EG(uninitialized_zval); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); -//??? if (retval) { -//??? ZVAL_NULL(retval); -//??? } - return; - } } z = obj->handlers->read_dimension(obj, dim, BP_VAR_R, &rv); @@ -1484,6 +1473,12 @@ static void ZEND_FASTCALL zend_jit_assign_dim_op_helper(zval *container, zval *d //??? ZVAL_NULL(retval); //??? } } + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); +//??? if (retval) { +//??? ZVAL_NULL(retval); +//??? } + } } else { if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { if (!dim) { From fe320e83aee316de07305f7808bdb158ba8b3fea Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Dec 2021 16:28:45 +0300 Subject: [PATCH 29/75] Tracing JIT: Fix reference counting Fixes oss-fuzz #42225 --- ext/opcache/jit/zend_jit_x86.dasc | 9 ++++--- ext/opcache/tests/jit/fetch_obj_008.phpt | 31 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 ext/opcache/tests/jit/fetch_obj_008.phpt diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 5f4e914a6cea2..cb41c6a2656e9 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -11865,7 +11865,7 @@ static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, ze return 1; } -static zend_bool zend_jit_may_avoid_refcounting(const zend_op *opline) +static zend_bool zend_jit_may_avoid_refcounting(const zend_op *opline, uint32_t op1_info) { switch (opline->opcode) { case ZEND_FETCH_OBJ_FUNC_ARG: @@ -11877,7 +11877,8 @@ static zend_bool zend_jit_may_avoid_refcounting(const zend_op *opline) /* break missing intentionally */ case ZEND_FETCH_OBJ_R: case ZEND_FETCH_OBJ_IS: - if (opline->op2_type == IS_CONST + if ((op1_info & MAY_BE_OBJECT) + && opline->op2_type == IS_CONST && Z_TYPE_P(RT_CONSTANT(opline, opline->op2)) == IS_STRING && Z_STRVAL_P(RT_CONSTANT(opline, opline->op2))[0] != '\0') { return 1; @@ -11956,7 +11957,7 @@ static int zend_jit_fetch_dim_read(dasm_State **Dst, && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) && (ssa_op+1)->op1_use == ssa_op->result_def && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG))) - && zend_jit_may_avoid_refcounting(opline+1)) { + && zend_jit_may_avoid_refcounting(opline+1, res_info)) { result_avoid_refcounting = 1; ssa->var_info[ssa_op->result_def].avoid_refcounting = 1; } @@ -13225,7 +13226,7 @@ static int zend_jit_fetch_obj(dasm_State **Dst, && !(flags & ZEND_JIT_EXIT_FREE_OP1) && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) && (ssa_op+1)->op1_use == ssa_op->result_def - && zend_jit_may_avoid_refcounting(opline+1)) { + && zend_jit_may_avoid_refcounting(opline+1, res_info)) { result_avoid_refcounting = 1; ssa->var_info[ssa_op->result_def].avoid_refcounting = 1; } diff --git a/ext/opcache/tests/jit/fetch_obj_008.phpt b/ext/opcache/tests/jit/fetch_obj_008.phpt new file mode 100644 index 0000000000000..38c5b8a539889 --- /dev/null +++ b/ext/opcache/tests/jit/fetch_obj_008.phpt @@ -0,0 +1,31 @@ +--TEST-- +JIT: FETCH_OBJ 008 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- +prop = "A $e B"; + $a->prop->prop . $a->prop = "C"; + return "test"; + } +} + +$a = new A; +$a->prop = new B; +?> +DONE +--EXPECTF-- +Warning: Undefined variable $e in %sfetch_obj_008.php on line 9 + +Warning: Attempt to read property "prop" on string in %sfetch_obj_008.php on line 10 +DONE From c787f42ceb9b2f0961f8f5accd59dfcd4a1f1342 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 13 Dec 2021 22:38:23 +0300 Subject: [PATCH 30/75] Combine ADDREF/DELREF --- Zend/zend_execute.c | 7 +-- Zend/zend_vm_def.h | 14 +++--- Zend/zend_vm_execute.h | 112 ++++++++++++++++++++--------------------- 3 files changed, 64 insertions(+), 69 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index a8f5c27071662..e13092491b59f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1295,14 +1295,12 @@ static zend_always_inline int zend_binary_op(zval *ret, zval *op1, zval *op2 OPL return zend_binary_ops[opcode - ZEND_ADD](ret, op1, op2); } -static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval *property OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zval *property OPLINE_DC EXECUTE_DATA_DC) { zval *value; zval *z; zval rv, res; - zend_object *obj = Z_OBJ_P(object); - GC_ADDREF(obj); value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) { @@ -1323,9 +1321,6 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zval *object, zval * } } FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 0648ddac77055..fca5af71da717 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1203,19 +1203,19 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP2_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - ZEND_VM_C_GOTO(assign_dim_op_ret_null); - } } else if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index a5300d9099b01..f569ff6ba8ff9 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -22288,19 +22288,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -24859,19 +24859,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -27104,19 +27104,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -28887,19 +28887,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -39539,19 +39539,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -43190,19 +43190,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -46012,19 +46012,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = NULL; if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); @@ -48331,19 +48331,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL } if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + zend_object *obj = Z_OBJ_P(container); + + GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = ZVAL_UNDEFINED_OP2(); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - goto assign_dim_op_ret_null; - } } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } - zend_binary_assign_op_obj_dim(container, dim OPLINE_CC EXECUTE_DATA_CC); + zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { ZVAL_UNDEFINED_OP1(); From cd8e6f5f7bf72a8056579d64227acd04926e6b09 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 14 Dec 2021 11:36:33 +0300 Subject: [PATCH 31/75] Preloading: don't remove INCLUDE_OE_EVAL nstructions with used result --- ext/opcache/ZendAccelerator.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index fe19787061ffc..6883979e7d131 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -4075,7 +4075,8 @@ static void preload_remove_empty_includes(void) if (opline->opcode == ZEND_INCLUDE_OR_EVAL && opline->extended_value != ZEND_EVAL && opline->op1_type == IS_CONST && - Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING) { + Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING && + opline->result_type == IS_UNUSED) { zend_string *resolved_path = preload_resolve_path(Z_STR_P(RT_CONSTANT(opline, opline->op1))); @@ -4121,7 +4122,7 @@ static void preload_remove_empty_includes(void) if (resolved_path) { zend_persistent_script *incl = zend_hash_find_ptr(preload_scripts, resolved_path); - if (incl && incl->empty) { + if (incl && incl->empty && opline->result_type == IS_UNUSED) { MAKE_NOP(opline); } else { if (!IS_ABSOLUTE_PATH(Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), Z_STRLEN_P(RT_CONSTANT(opline, opline->op1)))) { From b16fc350a49c2797039d5ecf8341f6a2b5a6b29a Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 14 Dec 2021 15:31:53 +0300 Subject: [PATCH 32/75] Move common code into helper --- Zend/zend_execute.c | 7 +++ Zend/zend_vm_def.h | 17 ++---- Zend/zend_vm_execute.h | 136 +++++++++++++++-------------------------- 3 files changed, 61 insertions(+), 99 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4282023909ba0..a245db9835379 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1431,6 +1431,10 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv zval *z; zval rv, res; + GC_ADDREF(obj); + if (property && UNEXPECTED(Z_ISUNDEF_P(property))) { + property = ZVAL_UNDEFINED_OP2(); + } value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); if ((z = obj->handlers->read_dimension(obj, property, BP_VAR_R, &rv)) != NULL) { @@ -1451,6 +1455,9 @@ static zend_never_inline void zend_binary_assign_op_obj_dim(zend_object *obj, zv } } FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + if (UNEXPECTED(GC_DELREF(obj) == 0)) { + zend_objects_store_del(obj); + } } static zend_never_inline void zend_binary_assign_op_typed_ref(zend_reference *ref, zval *value OPLINE_DC EXECUTE_DATA_DC) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 4199c090e266b..856091fcd5a4f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1150,6 +1150,7 @@ ZEND_VM_HANDLER(27, ZEND_ASSIGN_DIM_OP, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, OP) USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_RW); @@ -1157,19 +1158,20 @@ ZEND_VM_HANDLER(27, ZEND_ASSIGN_DIM_OP, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, OP) if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { ZEND_VM_C_LABEL(assign_dim_op_array): SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); ZEND_VM_C_LABEL(assign_dim_op_new_array): dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); if (OP2_TYPE == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); ZEND_VM_C_GOTO(assign_dim_op_ret_null); } } else { if (OP2_TYPE == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { ZEND_VM_C_GOTO(assign_dim_op_ret_null); @@ -1205,19 +1207,12 @@ ZEND_VM_C_LABEL(assign_dim_op_new_array): if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = GET_OP2_ZVAL_PTR_UNDEF(BP_VAR_R); - if (OP2_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (OP2_TYPE == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (OP1_TYPE == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 67c6eca46983c..362cd8436aeb2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -22392,6 +22392,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -22399,19 +22400,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_CONST == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -22447,19 +22449,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CONST_H if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); - if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -25047,6 +25042,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -25054,19 +25050,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -25102,19 +25099,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_TMPVAR_ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -27340,6 +27330,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -27347,19 +27338,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = NULL; if (IS_UNUSED == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_UNUSED == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -27395,19 +27387,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_UNUSED_ if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = NULL; - if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -29181,6 +29166,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -29188,19 +29174,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = EX_VAR(opline->op2.var); if (IS_CV == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_CV == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -29236,19 +29223,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_VAR_CV_HAND if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); - if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_VAR == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -39889,6 +39869,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = EX_VAR(opline->op1.var); @@ -39896,19 +39877,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = RT_CONSTANT(opline, opline->op2); if (IS_CONST == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_CONST == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -39944,19 +39926,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CONST_HA if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = RT_CONSTANT(opline, opline->op2); - if (IS_CONST == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_CONST == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -43623,6 +43598,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = EX_VAR(opline->op1.var); @@ -43630,19 +43606,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); if ((IS_TMP_VAR|IS_VAR) == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if ((IS_TMP_VAR|IS_VAR) == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -43678,19 +43655,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_TMPVAR_H if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); - if ((IS_TMP_VAR|IS_VAR) == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if ((IS_TMP_VAR|IS_VAR) == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -46492,6 +46462,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = EX_VAR(opline->op1.var); @@ -46499,19 +46470,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = NULL; if (IS_UNUSED == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_UNUSED == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -46547,19 +46519,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_UNUSED_H if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = NULL; - if (IS_UNUSED == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_UNUSED == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { @@ -48864,6 +48829,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL USE_OPLINE zval *var_ptr; zval *value, *container, *dim; + HashTable *ht; SAVE_OPLINE(); container = EX_VAR(opline->op1.var); @@ -48871,19 +48837,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL if (EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { assign_dim_op_array: SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); assign_dim_op_new_array: dim = EX_VAR(opline->op2.var); if (IS_CV == IS_UNUSED) { - var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); + var_ptr = zend_hash_next_index_insert(ht, &EG(uninitialized_zval)); if (UNEXPECTED(!var_ptr)) { zend_cannot_add_element(); goto assign_dim_op_ret_null; } } else { if (IS_CV == IS_CONST) { - var_ptr = zend_fetch_dimension_address_inner_RW_CONST(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW_CONST(ht, dim EXECUTE_DATA_CC); } else { - var_ptr = zend_fetch_dimension_address_inner_RW(Z_ARRVAL_P(container), dim EXECUTE_DATA_CC); + var_ptr = zend_fetch_dimension_address_inner_RW(ht, dim EXECUTE_DATA_CC); } if (UNEXPECTED(!var_ptr)) { goto assign_dim_op_ret_null; @@ -48919,19 +48886,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_OP_SPEC_CV_CV_HANDL if (EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { zend_object *obj = Z_OBJ_P(container); - GC_ADDREF(obj); dim = EX_VAR(opline->op2.var); - if (IS_CV == IS_CV && UNEXPECTED(Z_ISUNDEF_P(dim))) { - dim = ZVAL_UNDEFINED_OP2(); - } else if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { + if (IS_CV == IS_CONST && Z_EXTRA_P(dim) == ZEND_EXTRA_VALUE) { dim++; } zend_binary_assign_op_obj_dim(obj, dim OPLINE_CC EXECUTE_DATA_CC); - if (UNEXPECTED(GC_DELREF(obj) == 0)) { - zend_objects_store_del(obj); - } } else if (EXPECTED(Z_TYPE_P(container) <= IS_FALSE)) { - HashTable *ht; zend_uchar old_type; if (IS_CV == IS_CV && UNEXPECTED(Z_TYPE_INFO_P(container) == IS_UNDEF)) { From f583c4dfd222142b043949c6a3399f87cd8a2d47 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 14 Dec 2021 17:09:59 +0300 Subject: [PATCH 33/75] Use 64-bit multiplication on 64-bit systems --- Zend/zend_string.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Zend/zend_string.h b/Zend/zend_string.h index 0236bad20cf21..19cd926eff7be 100644 --- a/Zend/zend_string.h +++ b/Zend/zend_string.h @@ -429,25 +429,25 @@ static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size ((chunk >> (8 * 7)) & 0xff); # else hash = - hash * 33 * 33 * 33 * 33 + - str[0] * 33 * 33 * 33 + - str[1] * 33 * 33 + - str[2] * 33 + + hash * Z_L(33 * 33 * 33 * 33) + + str[0] * Z_L(33 * 33 * 33) + + str[1] * Z_L(33 * 33) + + str[2] * Z_L(33) + str[3]; hash = - hash * 33 * 33 * 33 * 33 + - str[4] * 33 * 33 * 33 + - str[5] * 33 * 33 + - str[6] * 33 + + hash * Z_L(33 * 33 * 33 * 33) + + str[4] * Z_L(33 * 33 * 33) + + str[5] * Z_L(33 * 33) + + str[6] * Z_L(33) + str[7]; # endif } if (len >= 4) { hash = - hash * 33 * 33 * 33 * 33 + - str[0] * 33 * 33 * 33 + - str[1] * 33 * 33 + - str[2] * 33 + + hash * Z_L(33 * 33 * 33 * 33) + + str[0] * Z_L(33 * 33 * 33) + + str[1] * Z_L(33 * 33) + + str[2] * Z_L(33) + str[3]; len -= 4; str += 4; @@ -455,18 +455,18 @@ static zend_always_inline zend_ulong zend_inline_hash_func(const char *str, size if (len >= 2) { if (len > 2) { hash = - hash * 33 * 33 * 33 + - str[0] * 33 * 33 + - str[1] * 33 + + hash * Z_L(33 * 33 * 33) + + str[0] * Z_L(33 * 33) + + str[1] * Z_L(33) + str[2]; } else { hash = - hash * 33 * 33 + - str[0] * 33 + + hash * Z_L(33 * 33) + + str[0] * Z_L(33) + str[1]; } } else if (len != 0) { - hash = hash * 33 + *str; + hash = hash * Z_L(33) + *str; } #else /* variant with the hash unrolled eight times */ From 75b2973974414fb52a19c0466c8f2afc2081eb49 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 15 Dec 2021 12:20:37 +0300 Subject: [PATCH 34/75] Fix array clobbering by user error handler Fixes oss-fuzz #42363 --- Zend/tests/falsetoarray_003.phpt | 16 ++++++++++++++++ Zend/zend_vm_def.h | 5 ++++- Zend/zend_vm_execute.h | 25 ++++++++++++++++++++----- 3 files changed, 40 insertions(+), 6 deletions(-) create mode 100644 Zend/tests/falsetoarray_003.phpt diff --git a/Zend/tests/falsetoarray_003.phpt b/Zend/tests/falsetoarray_003.phpt new file mode 100644 index 0000000000000..11b32771e1fc1 --- /dev/null +++ b/Zend/tests/falsetoarray_003.phpt @@ -0,0 +1,16 @@ +--TEST-- +Autovivification of false to array with data clobbering by error handler +--FILE-- + +DONE +--EXPECTF-- +Err: Implicit conversion from float %f to int loses precision +Err: Undefined array key %i +DONE diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 856091fcd5a4f..6920bc7632a2f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9670,7 +9670,10 @@ ZEND_VM_C_LABEL(fetch_dim_r_index_array): if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, OP2_TYPE OPLINE_CC EXECUTE_DATA_CC); + FREE_OP1(); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, ZEND_VM_C_LABEL(fetch_dim_r_index_undef)); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 362cd8436aeb2..42f5310cd026e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -8318,7 +8318,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, (IS_TMP_VAR|IS_VAR|IS_CV) OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, fetch_dim_r_index_undef); @@ -16126,7 +16129,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, IS_CONST OPLINE_CC EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, fetch_dim_r_index_undef); @@ -16178,7 +16184,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, (IS_TMP_VAR|IS_VAR|IS_CV) OPLINE_CC EXECUTE_DATA_CC); + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, fetch_dim_r_index_undef); @@ -42928,7 +42937,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, IS_CONST OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, fetch_dim_r_index_undef); @@ -42980,7 +42992,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_DIM_R_INDEX_ if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) { offset = Z_LVAL_P(dim); } else { - offset = zval_get_long_ex(dim, /* is_strict */ true); + SAVE_OPLINE(); + zend_fetch_dimension_address_read_R(container, dim, (IS_TMP_VAR|IS_VAR|IS_CV) OPLINE_CC EXECUTE_DATA_CC); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } ht = Z_ARRVAL_P(container); ZEND_HASH_INDEX_FIND(ht, offset, value, fetch_dim_r_index_undef); From 8eee0d6130c778d9e9d638ac2fbe53dfe5bed38e Mon Sep 17 00:00:00 2001 From: Tim Starling Date: Thu, 16 Dec 2021 00:38:35 +1100 Subject: [PATCH 35/75] Make strtolower() and strtoupper() do ASCII case conversion (#7506) Implement RFC https://wiki.php.net/rfc/strtolower-ascii --- UPGRADING | 8 + Zend/tests/lc_ctype_inheritance.phpt | 25 +- Zend/zend_operators.c | 8 +- ext/pdo_dblib/dblib_stmt.c | 1 - ext/standard/string.c | 122 ++----- ext/standard/tests/strings/bug79986.phpt | 13 - .../tests/strings/strtolower-win32.phpt | 340 ----------------- ext/standard/tests/strings/strtolower.phpt | 151 +++++++- ext/standard/tests/strings/strtoupper.phpt | 20 - .../tests/strings/strtoupper1-win32.phpt | 342 ------------------ ext/standard/tests/strings/strtoupper1.phpt | 152 ++++++-- ext/xml/xml.c | 1 - 12 files changed, 318 insertions(+), 865 deletions(-) delete mode 100644 ext/standard/tests/strings/bug79986.phpt delete mode 100644 ext/standard/tests/strings/strtolower-win32.phpt delete mode 100644 ext/standard/tests/strings/strtoupper.phpt delete mode 100644 ext/standard/tests/strings/strtoupper1-win32.phpt diff --git a/UPGRADING b/UPGRADING index 8b016ba30255b..ccc211f5b508a 100644 --- a/UPGRADING +++ b/UPGRADING @@ -19,6 +19,14 @@ PHP 8.2 UPGRADE NOTES 1. Backward Incompatible Changes ======================================== +- Standard: + . strtolower() and strtoupper() are no longer locale-sensitive. They now + perform ASCII case conversion, as if the locale were "C". Use + mb_strtolower() if you want localized case conversion. Similarly, stristr, + stripos, strripos, lcfirst, ucfirst, ucwords, str_ireplace, + array_change_key_case and sorting with SORT_FLAG_CASE use ASCII case + conversion. + ======================================== 2. New Features ======================================== diff --git a/Zend/tests/lc_ctype_inheritance.phpt b/Zend/tests/lc_ctype_inheritance.phpt index 8c968f0615e6e..bcfd4ff463d75 100644 --- a/Zend/tests/lc_ctype_inheritance.phpt +++ b/Zend/tests/lc_ctype_inheritance.phpt @@ -9,17 +9,30 @@ LC_CTYPE=de_DE --FILE-- --EXPECTF-- +inherited +ctype_lower(\xe4): n +preg_match(\w, \xe4): int(0) string(%d) "C%r(\.UTF-8)?%r" -string(2) "e4" -int(0) +ctype_lower(\xe4): n +preg_match(\w, \xe4): int(0) +de_DE bool(true) -string(2) "c4" -int(1) +ctype_lower(\xe4): y +preg_match(\w, \xe4): int(1) diff --git a/Zend/zend_operators.c b/Zend/zend_operators.c index ca93f48603f58..de3664f5c653f 100644 --- a/Zend/zend_operators.c +++ b/Zend/zend_operators.c @@ -126,9 +126,9 @@ ZEND_API const unsigned char zend_toupper_map[256] = { * Functions using locale lowercase: zend_binary_strncasecmp_l zend_binary_strcasecmp_l + * Functions using ascii lowercase: string_compare_function_ex string_case_compare_function - * Functions using ascii lowercase: zend_str_tolower_copy zend_str_tolower_dup zend_str_tolower @@ -1997,7 +1997,7 @@ ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, bool int ret; if (case_insensitive) { - ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1)); + ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1)); } else { ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2)); } @@ -2037,13 +2037,13 @@ ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* if (Z_STR_P(op1) == Z_STR_P(op2)) { return 0; } else { - return zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); + return zend_binary_strcasecmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2)); } } else { zend_string *tmp_str1, *tmp_str2; zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1); zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2); - int ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1)); + int ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1)); zend_tmp_string_release(tmp_str1); zend_tmp_string_release(tmp_str2); diff --git a/ext/pdo_dblib/dblib_stmt.c b/ext/pdo_dblib/dblib_stmt.c index f415a8d7f44be..2a946c81dc242 100644 --- a/ext/pdo_dblib/dblib_stmt.c +++ b/ext/pdo_dblib/dblib_stmt.c @@ -21,7 +21,6 @@ #include "php.h" #include "php_ini.h" -#include "ext/standard/php_string.h" #include "ext/standard/info.h" #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" diff --git a/ext/standard/string.c b/ext/standard/string.c index c7c4e193ec378..7c2dce4595b0f 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1346,16 +1346,7 @@ PHP_FUNCTION(strtok) /* {{{ php_strtoupper */ PHPAPI char *php_strtoupper(char *s, size_t len) { - unsigned char *c; - const unsigned char *e; - - c = (unsigned char *)s; - e = (unsigned char *)c+len; - - while (c < e) { - *c = toupper(*c); - c++; - } + zend_str_toupper(s, len); return s; } /* }}} */ @@ -1363,35 +1354,7 @@ PHPAPI char *php_strtoupper(char *s, size_t len) /* {{{ php_string_toupper */ PHPAPI zend_string *php_string_toupper(zend_string *s) { - unsigned char *c; - const unsigned char *e; - - if (EXPECTED(!BG(ctype_string))) { - return zend_string_toupper(s); - } - c = (unsigned char *)ZSTR_VAL(s); - e = c + ZSTR_LEN(s); - - while (c < e) { - if (islower(*c)) { - unsigned char *r; - zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0); - - if (c != (unsigned char*)ZSTR_VAL(s)) { - memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s)); - } - r = c + (ZSTR_VAL(res) - ZSTR_VAL(s)); - while (c < e) { - *r = toupper(*c); - r++; - c++; - } - *r = '\0'; - return res; - } - c++; - } - return zend_string_copy(s); + return zend_string_toupper(s); } /* }}} */ @@ -1404,23 +1367,14 @@ PHP_FUNCTION(strtoupper) Z_PARAM_STR(arg) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(php_string_toupper(arg)); + RETURN_STR(zend_string_toupper(arg)); } /* }}} */ /* {{{ php_strtolower */ PHPAPI char *php_strtolower(char *s, size_t len) { - unsigned char *c; - const unsigned char *e; - - c = (unsigned char *)s; - e = c+len; - - while (c < e) { - *c = tolower(*c); - c++; - } + zend_str_tolower(s, len); return s; } /* }}} */ @@ -1428,32 +1382,7 @@ PHPAPI char *php_strtolower(char *s, size_t len) /* {{{ php_string_tolower */ PHPAPI zend_string *php_string_tolower(zend_string *s) { - if (EXPECTED(!BG(ctype_string))) { - return zend_string_tolower(s); - } - - unsigned char *c = (unsigned char *)ZSTR_VAL(s); - const unsigned char *e = c + ZSTR_LEN(s); - while (c < e) { - if (isupper(*c)) { - unsigned char *r; - zend_string *res = zend_string_alloc(ZSTR_LEN(s), 0); - - if (c != (unsigned char*)ZSTR_VAL(s)) { - memcpy(ZSTR_VAL(res), ZSTR_VAL(s), c - (unsigned char*)ZSTR_VAL(s)); - } - r = c + (ZSTR_VAL(res) - ZSTR_VAL(s)); - while (c < e) { - *r = tolower(*c); - r++; - c++; - } - *r = '\0'; - return res; - } - c++; - } - return zend_string_copy(s); + return zend_string_tolower(s); } /* }}} */ @@ -1466,7 +1395,7 @@ PHP_FUNCTION(strtolower) Z_PARAM_STR(str) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(php_string_tolower(str)); + RETURN_STR(zend_string_tolower(str)); } /* }}} */ @@ -1758,8 +1687,8 @@ PHP_FUNCTION(pathinfo) case insensitive strstr */ PHPAPI char *php_stristr(char *s, char *t, size_t s_len, size_t t_len) { - php_strtolower(s, s_len); - php_strtolower(t, t_len); + zend_str_tolower(s, s_len); + zend_str_tolower(t, t_len); return (char*)php_memnstr(s, t, t_len, s + s_len); } /* }}} */ @@ -1982,8 +1911,8 @@ PHP_FUNCTION(stripos) RETURN_FALSE; } - haystack_dup = php_string_tolower(haystack); - needle_dup = php_string_tolower(needle); + haystack_dup = zend_string_tolower(haystack); + needle_dup = zend_string_tolower(needle); found = (char*)php_memnstr(ZSTR_VAL(haystack_dup) + offset, ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), ZSTR_VAL(haystack_dup) + ZSTR_LEN(haystack)); @@ -2077,10 +2006,9 @@ PHP_FUNCTION(strripos) } e = ZSTR_VAL(haystack) + (ZSTR_LEN(haystack) + (size_t)offset); } - /* Borrow that ord_needle buffer to avoid repeatedly tolower()ing needle */ - lowered = tolower(*ZSTR_VAL(needle)); + lowered = zend_tolower_ascii(*ZSTR_VAL(needle)); while (e >= p) { - if (tolower(*e) == lowered) { + if (zend_tolower_ascii(*e) == lowered) { RETURN_LONG(e - p + (offset > 0 ? offset : 0)); } e--; @@ -2088,7 +2016,7 @@ PHP_FUNCTION(strripos) RETURN_FALSE; } - haystack_dup = php_string_tolower(haystack); + haystack_dup = zend_string_tolower(haystack); if (offset >= 0) { if ((size_t)offset > ZSTR_LEN(haystack)) { zend_string_release_ex(haystack_dup, 0); @@ -2112,7 +2040,7 @@ PHP_FUNCTION(strripos) } } - needle_dup = php_string_tolower(needle); + needle_dup = zend_string_tolower(needle); if ((found = (char *)zend_memnrstr(p, ZSTR_VAL(needle_dup), ZSTR_LEN(needle_dup), e))) { RETVAL_LONG(found - ZSTR_VAL(haystack_dup)); zend_string_release_ex(needle_dup, 0); @@ -2647,7 +2575,7 @@ PHP_FUNCTION(chr) static zend_string* php_ucfirst(zend_string *str) { const unsigned char ch = ZSTR_VAL(str)[0]; - unsigned char r = toupper(ch); + unsigned char r = zend_toupper_ascii(ch); if (r == ch) { return zend_string_copy(str); } else { @@ -2679,7 +2607,7 @@ PHP_FUNCTION(ucfirst) Lowercase the first character of the word in a native string */ static zend_string* php_lcfirst(zend_string *str) { - unsigned char r = tolower(ZSTR_VAL(str)[0]); + unsigned char r = zend_tolower_ascii(ZSTR_VAL(str)[0]); if (r == ZSTR_VAL(str)[0]) { return zend_string_copy(str); } else { @@ -2732,10 +2660,10 @@ PHP_FUNCTION(ucwords) ZVAL_STRINGL(return_value, ZSTR_VAL(str), ZSTR_LEN(str)); r = Z_STRVAL_P(return_value); - *r = toupper((unsigned char) *r); + *r = zend_toupper_ascii((unsigned char) *r); for (r_end = r + Z_STRLEN_P(return_value) - 1; r < r_end; ) { if (mask[(unsigned char)*r++]) { - *r = toupper((unsigned char) *r); + *r = zend_toupper_ascii((unsigned char) *r); } } } @@ -3067,11 +2995,11 @@ static zend_string* php_char_to_str_ex(zend_string *str, char from, char *to, si if (case_sensitivity) { char_count = count_chars(ZSTR_VAL(str), ZSTR_LEN(str), from); } else { - lc_from = tolower(from); char_count = 0; + lc_from = zend_tolower_ascii(from); source_end = ZSTR_VAL(str) + ZSTR_LEN(str); for (source = ZSTR_VAL(str); source < source_end; source++) { - if (tolower(*source) == lc_from) { + if (zend_tolower_ascii(*source) == lc_from) { char_count++; } } @@ -3111,7 +3039,7 @@ static zend_string* php_char_to_str_ex(zend_string *str, char from, char *to, si } else { source_end = ZSTR_VAL(str) + ZSTR_LEN(str); for (source = ZSTR_VAL(str); source < source_end; source++) { - if (tolower(*source) == lc_from) { + if (zend_tolower_ascii(*source) == lc_from) { memcpy(target, to, to_len); target += to_len; } else { @@ -4345,7 +4273,7 @@ static zend_long php_str_replace_in_subject( zend_long old_replace_count = replace_count; if (!lc_subject_str) { - lc_subject_str = php_string_tolower(subject_str); + lc_subject_str = zend_string_tolower(subject_str); } tmp_result = php_str_to_str_i_ex(subject_str, ZSTR_VAL(lc_subject_str), search_str, replace_value, replace_len, &replace_count); @@ -4398,7 +4326,7 @@ static zend_long php_str_replace_in_subject( ZSTR_VAL(search_str), ZSTR_LEN(search_str), ZSTR_VAL(replace_str), ZSTR_LEN(replace_str), &replace_count)); } else { - lc_subject_str = php_string_tolower(subject_str); + lc_subject_str = zend_string_tolower(subject_str); ZVAL_STR(result, php_str_to_str_i_ex(subject_str, ZSTR_VAL(lc_subject_str), search_str, ZSTR_VAL(replace_str), ZSTR_LEN(replace_str), &replace_count)); zend_string_release_ex(lc_subject_str, 0); @@ -4941,7 +4869,7 @@ int php_tag_find(char *tag, size_t len, const char *set) { n = norm; t = tag; - c = tolower(*t); + c = zend_tolower_ascii(*t); /* normalize the tag removing leading and trailing whitespace and turn any into just and any @@ -4969,7 +4897,7 @@ int php_tag_find(char *tag, size_t len, const char *set) { } break; } - c = tolower(*(++t)); + c = zend_tolower_ascii(*(++t)); } *(n++) = '>'; *n = '\0'; diff --git a/ext/standard/tests/strings/bug79986.phpt b/ext/standard/tests/strings/bug79986.phpt deleted file mode 100644 index fcbc72148c242..0000000000000 --- a/ext/standard/tests/strings/bug79986.phpt +++ /dev/null @@ -1,13 +0,0 @@ ---TEST-- -Bug #79986 (str_ireplace bug with diacritics characters) ---SKIPIF-- - ---FILE-- - ---EXPECT-- -11 22 33 diff --git a/ext/standard/tests/strings/strtolower-win32.phpt b/ext/standard/tests/strings/strtolower-win32.phpt deleted file mode 100644 index 516248346cf01..0000000000000 --- a/ext/standard/tests/strings/strtolower-win32.phpt +++ /dev/null @@ -1,340 +0,0 @@ ---TEST-- -Test strtolower() function ---SKIPIF-- - ---FILE-- - ".(bin2hex(strtolower("$char")))."\n"; -} - -echo "*** Testing strlower() with basic strings ***\n"; -$str = "Mary Had A liTTle LAmb and ShE loveD IT So\n"; -var_dump(strtolower($str)); - -echo "\n*** Testing strtolower() with various strings ***"; -/* strings to pass strtolower() */ -$strings = array ( - "", - "string", - "stRINg0234", - "1.233.344StrinG12333", - "$$$$$$!!!!@@@@@@@ ABCDEF !!!***", - "ABCD\0abcdABCD", - TRUE, - FALSE, -); - -$count = 0; -/* loop through to check possible variations */ -foreach ($strings as $string) { - echo "\n-- Iteration $count --\n"; - var_dump( strtolower($string) ); - $count++; -} - -echo "\n*** Testing strtolower() with two different case strings ***\n"; -if (strtolower("HeLLo woRLd") === strtolower("hEllo WORLD")) - echo "strings are same, with Case Insensitive\n"; -else - echo "strings are not same\n"; - -echo "*** Done ***"; -?> ---EXPECTF-- -*** Testing strtolower() with all 256 chars *** -00 => 00 -01 => 01 -02 => 02 -03 => 03 -04 => 04 -05 => 05 -06 => 06 -07 => 07 -08 => 08 -09 => 09 -0a => 0a -0b => 0b -0c => 0c -0d => 0d -0e => 0e -0f => 0f -10 => 10 -11 => 11 -12 => 12 -13 => 13 -14 => 14 -15 => 15 -16 => 16 -17 => 17 -18 => 18 -19 => 19 -1a => 1a -1b => 1b -1c => 1c -1d => 1d -1e => 1e -1f => 1f -20 => 20 -21 => 21 -22 => 22 -23 => 23 -24 => 24 -25 => 25 -26 => 26 -27 => 27 -28 => 28 -29 => 29 -2a => 2a -2b => 2b -2c => 2c -2d => 2d -2e => 2e -2f => 2f -30 => 30 -31 => 31 -32 => 32 -33 => 33 -34 => 34 -35 => 35 -36 => 36 -37 => 37 -38 => 38 -39 => 39 -3a => 3a -3b => 3b -3c => 3c -3d => 3d -3e => 3e -3f => 3f -40 => 40 -41 => 61 -42 => 62 -43 => 63 -44 => 64 -45 => 65 -46 => 66 -47 => 67 -48 => 68 -49 => 69 -4a => 6a -4b => 6b -4c => 6c -4d => 6d -4e => 6e -4f => 6f -50 => 70 -51 => 71 -52 => 72 -53 => 73 -54 => 74 -55 => 75 -56 => 76 -57 => 77 -58 => 78 -59 => 79 -5a => 7a -5b => 5b -5c => 5c -5d => 5d -5e => 5e -5f => 5f -60 => 60 -61 => 61 -62 => 62 -63 => 63 -64 => 64 -65 => 65 -66 => 66 -67 => 67 -68 => 68 -69 => 69 -6a => 6a -6b => 6b -6c => 6c -6d => 6d -6e => 6e -6f => 6f -70 => 70 -71 => 71 -72 => 72 -73 => 73 -74 => 74 -75 => 75 -76 => 76 -77 => 77 -78 => 78 -79 => 79 -7a => 7a -7b => 7b -7c => 7c -7d => 7d -7e => 7e -7f => 7f -80 => 80 -81 => 81 -82 => 82 -83 => 83 -84 => 84 -85 => 85 -86 => 86 -87 => 87 -88 => 88 -89 => 89 -8a => 9a -8b => 8b -8c => 9c -8d => 8d -8e => 9e -8f => 8f -90 => 90 -91 => 91 -92 => 92 -93 => 93 -94 => 94 -95 => 95 -96 => 96 -97 => 97 -98 => 98 -99 => 99 -9a => 9a -9b => 9b -9c => 9c -9d => 9d -9e => 9e -9f => ff -a0 => a0 -a1 => a1 -a2 => a2 -a3 => a3 -a4 => a4 -a5 => a5 -a6 => a6 -a7 => a7 -a8 => a8 -a9 => a9 -aa => aa -ab => ab -ac => ac -ad => ad -ae => ae -af => af -b0 => b0 -b1 => b1 -b2 => b2 -b3 => b3 -b4 => b4 -b5 => b5 -b6 => b6 -b7 => b7 -b8 => b8 -b9 => b9 -ba => ba -bb => bb -bc => bc -bd => bd -be => be -bf => bf -c0 => e0 -c1 => e1 -c2 => e2 -c3 => e3 -c4 => e4 -c5 => e5 -c6 => e6 -c7 => e7 -c8 => e8 -c9 => e9 -ca => ea -cb => eb -cc => ec -cd => ed -ce => ee -cf => ef -d0 => f0 -d1 => f1 -d2 => f2 -d3 => f3 -d4 => f4 -d5 => f5 -d6 => f6 -d7 => d7 -d8 => f8 -d9 => f9 -da => fa -db => fb -dc => fc -dd => fd -de => fe -df => df -e0 => e0 -e1 => e1 -e2 => e2 -e3 => e3 -e4 => e4 -e5 => e5 -e6 => e6 -e7 => e7 -e8 => e8 -e9 => e9 -ea => ea -eb => eb -ec => ec -ed => ed -ee => ee -ef => ef -f0 => f0 -f1 => f1 -f2 => f2 -f3 => f3 -f4 => f4 -f5 => f5 -f6 => f6 -f7 => f7 -f8 => f8 -f9 => f9 -fa => fa -fb => fb -fc => fc -fd => fd -fe => fe -ff => ff -*** Testing strlower() with basic strings *** -string(43) "mary had a little lamb and she loved it so -" - -*** Testing strtolower() with various strings *** --- Iteration 0 -- -string(0) "" - --- Iteration 1 -- -string(6) "string" - --- Iteration 2 -- -string(10) "string0234" - --- Iteration 3 -- -string(20) "1.233.344string12333" - --- Iteration 4 -- -string(31) "$$$$$$!!!!@@@@@@@ abcdef !!!***" - --- Iteration 5 -- -string(13) "abcd%0abcdabcd" - --- Iteration 6 -- -string(1) "1" - --- Iteration 7 -- -string(0) "" - -*** Testing strtolower() with two different case strings *** -strings are same, with Case Insensitive -*** Done *** diff --git a/ext/standard/tests/strings/strtolower.phpt b/ext/standard/tests/strings/strtolower.phpt index 37a38493ce114..6052ccd840d50 100644 --- a/ext/standard/tests/strings/strtolower.phpt +++ b/ext/standard/tests/strings/strtolower.phpt @@ -1,27 +1,10 @@ --TEST-- Test strtolower() function ---SKIPIF-- - --FILE-- ".(bin2hex(strtolower("$char")))."\n"; } @@ -66,7 +49,7 @@ else echo "*** Done ***"; ?> --EXPECTF-- -*** Testing strtolower() with 128 chars *** +*** Testing strtolower() with 256 chars *** 00 => 00 01 => 01 02 => 02 @@ -195,6 +178,134 @@ echo "*** Done ***"; 7d => 7d 7e => 7e 7f => 7f +80 => 80 +81 => 81 +82 => 82 +83 => 83 +84 => 84 +85 => 85 +86 => 86 +87 => 87 +88 => 88 +89 => 89 +8a => 8a +8b => 8b +8c => 8c +8d => 8d +8e => 8e +8f => 8f +90 => 90 +91 => 91 +92 => 92 +93 => 93 +94 => 94 +95 => 95 +96 => 96 +97 => 97 +98 => 98 +99 => 99 +9a => 9a +9b => 9b +9c => 9c +9d => 9d +9e => 9e +9f => 9f +a0 => a0 +a1 => a1 +a2 => a2 +a3 => a3 +a4 => a4 +a5 => a5 +a6 => a6 +a7 => a7 +a8 => a8 +a9 => a9 +aa => aa +ab => ab +ac => ac +ad => ad +ae => ae +af => af +b0 => b0 +b1 => b1 +b2 => b2 +b3 => b3 +b4 => b4 +b5 => b5 +b6 => b6 +b7 => b7 +b8 => b8 +b9 => b9 +ba => ba +bb => bb +bc => bc +bd => bd +be => be +bf => bf +c0 => c0 +c1 => c1 +c2 => c2 +c3 => c3 +c4 => c4 +c5 => c5 +c6 => c6 +c7 => c7 +c8 => c8 +c9 => c9 +ca => ca +cb => cb +cc => cc +cd => cd +ce => ce +cf => cf +d0 => d0 +d1 => d1 +d2 => d2 +d3 => d3 +d4 => d4 +d5 => d5 +d6 => d6 +d7 => d7 +d8 => d8 +d9 => d9 +da => da +db => db +dc => dc +dd => dd +de => de +df => df +e0 => e0 +e1 => e1 +e2 => e2 +e3 => e3 +e4 => e4 +e5 => e5 +e6 => e6 +e7 => e7 +e8 => e8 +e9 => e9 +ea => ea +eb => eb +ec => ec +ed => ed +ee => ee +ef => ef +f0 => f0 +f1 => f1 +f2 => f2 +f3 => f3 +f4 => f4 +f5 => f5 +f6 => f6 +f7 => f7 +f8 => f8 +f9 => f9 +fa => fa +fb => fb +fc => fc +fd => fd +fe => fe +ff => ff *** Testing strlower() with basic strings *** string(43) "mary had a little lamb and she loved it so " diff --git a/ext/standard/tests/strings/strtoupper.phpt b/ext/standard/tests/strings/strtoupper.phpt deleted file mode 100644 index 41bc5e6080643..0000000000000 --- a/ext/standard/tests/strings/strtoupper.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -Test strtoupper on non-ASCII characters ---SKIPIF-- - ---FILE-- - ---EXPECT-- -ÄÖÜ diff --git a/ext/standard/tests/strings/strtoupper1-win32.phpt b/ext/standard/tests/strings/strtoupper1-win32.phpt deleted file mode 100644 index c9328462cf7a9..0000000000000 --- a/ext/standard/tests/strings/strtoupper1-win32.phpt +++ /dev/null @@ -1,342 +0,0 @@ ---TEST-- -Test strtoupper() function ---SKIPIF-- - ---FILE-- - ".(bin2hex(strtoupper("$char")))."\n"; -} - -echo "\n*** Testing strtoupper() with basic strings ***\n"; -$str = "Mary Had A liTTle LAmb and ShE loveD IT So\n"; -var_dump(strtoupper($str)); - -echo "\n*** Testing strtoupper() with various strings ***"; -/* strings to pass strtoupper() */ -$strings = array ( - "", - "string", - "stRINg0234", - "1.233.344StrinG12333", - "$$$$$$!!!!@@@@@@@ ABCDEF !!!***", - "ABCD\0abcdABCD", - TRUE, - FALSE, -); - -$count = 0; -/* loop through to check possible variations */ -foreach ($strings as $string) { - echo "\n-- Iteration $count --\n"; - var_dump( strtoupper($string) ); - $count++; -} - -echo "\n*** Testing strtoupper() with two different case strings ***\n"; -if (strtoupper("HeLLo woRLd") === strtoupper("hEllo WORLD")) - echo "strings are same, with Case Insensitive\n"; -else - echo "strings are not same\n"; - -echo "*** Done ***"; -?> ---EXPECTF-- -*** Testing strtoupper() with all 256 chars *** -00 => 00 -01 => 01 -02 => 02 -03 => 03 -04 => 04 -05 => 05 -06 => 06 -07 => 07 -08 => 08 -09 => 09 -0a => 0a -0b => 0b -0c => 0c -0d => 0d -0e => 0e -0f => 0f -10 => 10 -11 => 11 -12 => 12 -13 => 13 -14 => 14 -15 => 15 -16 => 16 -17 => 17 -18 => 18 -19 => 19 -1a => 1a -1b => 1b -1c => 1c -1d => 1d -1e => 1e -1f => 1f -20 => 20 -21 => 21 -22 => 22 -23 => 23 -24 => 24 -25 => 25 -26 => 26 -27 => 27 -28 => 28 -29 => 29 -2a => 2a -2b => 2b -2c => 2c -2d => 2d -2e => 2e -2f => 2f -30 => 30 -31 => 31 -32 => 32 -33 => 33 -34 => 34 -35 => 35 -36 => 36 -37 => 37 -38 => 38 -39 => 39 -3a => 3a -3b => 3b -3c => 3c -3d => 3d -3e => 3e -3f => 3f -40 => 40 -41 => 41 -42 => 42 -43 => 43 -44 => 44 -45 => 45 -46 => 46 -47 => 47 -48 => 48 -49 => 49 -4a => 4a -4b => 4b -4c => 4c -4d => 4d -4e => 4e -4f => 4f -50 => 50 -51 => 51 -52 => 52 -53 => 53 -54 => 54 -55 => 55 -56 => 56 -57 => 57 -58 => 58 -59 => 59 -5a => 5a -5b => 5b -5c => 5c -5d => 5d -5e => 5e -5f => 5f -60 => 60 -61 => 41 -62 => 42 -63 => 43 -64 => 44 -65 => 45 -66 => 46 -67 => 47 -68 => 48 -69 => 49 -6a => 4a -6b => 4b -6c => 4c -6d => 4d -6e => 4e -6f => 4f -70 => 50 -71 => 51 -72 => 52 -73 => 53 -74 => 54 -75 => 55 -76 => 56 -77 => 57 -78 => 58 -79 => 59 -7a => 5a -7b => 7b -7c => 7c -7d => 7d -7e => 7e -7f => 7f -80 => 80 -81 => 81 -82 => 82 -83 => 83 -84 => 84 -85 => 85 -86 => 86 -87 => 87 -88 => 88 -89 => 89 -8a => 8a -8b => 8b -8c => 8c -8d => 8d -8e => 8e -8f => 8f -90 => 90 -91 => 91 -92 => 92 -93 => 93 -94 => 94 -95 => 95 -96 => 96 -97 => 97 -98 => 98 -99 => 99 -9a => 8a -9b => 9b -9c => 8c -9d => 9d -9e => 8e -9f => 9f -a0 => a0 -a1 => a1 -a2 => a2 -a3 => a3 -a4 => a4 -a5 => a5 -a6 => a6 -a7 => a7 -a8 => a8 -a9 => a9 -aa => aa -ab => ab -ac => ac -ad => ad -ae => ae -af => af -b0 => b0 -b1 => b1 -b2 => b2 -b3 => b3 -b4 => b4 -b5 => b5 -b6 => b6 -b7 => b7 -b8 => b8 -b9 => b9 -ba => ba -bb => bb -bc => bc -bd => bd -be => be -bf => bf -c0 => c0 -c1 => c1 -c2 => c2 -c3 => c3 -c4 => c4 -c5 => c5 -c6 => c6 -c7 => c7 -c8 => c8 -c9 => c9 -ca => ca -cb => cb -cc => cc -cd => cd -ce => ce -cf => cf -d0 => d0 -d1 => d1 -d2 => d2 -d3 => d3 -d4 => d4 -d5 => d5 -d6 => d6 -d7 => d7 -d8 => d8 -d9 => d9 -da => da -db => db -dc => dc -dd => dd -de => de -df => df -e0 => c0 -e1 => c1 -e2 => c2 -e3 => c3 -e4 => c4 -e5 => c5 -e6 => c6 -e7 => c7 -e8 => c8 -e9 => c9 -ea => ca -eb => cb -ec => cc -ed => cd -ee => ce -ef => cf -f0 => d0 -f1 => d1 -f2 => d2 -f3 => d3 -f4 => d4 -f5 => d5 -f6 => d6 -f7 => f7 -f8 => d8 -f9 => d9 -fa => da -fb => db -fc => dc -fd => dd -fe => de -ff => 9f - -*** Testing strtoupper() with basic strings *** -string(43) "MARY HAD A LITTLE LAMB AND SHE LOVED IT SO -" - -*** Testing strtoupper() with various strings *** --- Iteration 0 -- -string(0) "" - --- Iteration 1 -- -string(6) "STRING" - --- Iteration 2 -- -string(10) "STRING0234" - --- Iteration 3 -- -string(20) "1.233.344STRING12333" - --- Iteration 4 -- -string(31) "$$$$$$!!!!@@@@@@@ ABCDEF !!!***" - --- Iteration 5 -- -string(13) "ABCD%0ABCDABCD" - --- Iteration 6 -- -string(1) "1" - --- Iteration 7 -- -string(0) "" - -*** Testing strtoupper() with two different case strings *** -strings are same, with Case Insensitive -*** Done *** diff --git a/ext/standard/tests/strings/strtoupper1.phpt b/ext/standard/tests/strings/strtoupper1.phpt index 7b79f6f457be9..abda0b9d38b28 100644 --- a/ext/standard/tests/strings/strtoupper1.phpt +++ b/ext/standard/tests/strings/strtoupper1.phpt @@ -1,27 +1,9 @@ --TEST-- Test strtoupper() function ---SKIPIF-- - --FILE-- ".(bin2hex(strtoupper("$char")))."\n"; } @@ -65,7 +47,7 @@ else echo "*** Done ***"; ?> --EXPECTF-- -*** Testing strtoupper() with 128 chars *** +*** Testing strtoupper() with 256 chars *** 00 => 00 01 => 01 02 => 02 @@ -194,6 +176,134 @@ echo "*** Done ***"; 7d => 7d 7e => 7e 7f => 7f +80 => 80 +81 => 81 +82 => 82 +83 => 83 +84 => 84 +85 => 85 +86 => 86 +87 => 87 +88 => 88 +89 => 89 +8a => 8a +8b => 8b +8c => 8c +8d => 8d +8e => 8e +8f => 8f +90 => 90 +91 => 91 +92 => 92 +93 => 93 +94 => 94 +95 => 95 +96 => 96 +97 => 97 +98 => 98 +99 => 99 +9a => 9a +9b => 9b +9c => 9c +9d => 9d +9e => 9e +9f => 9f +a0 => a0 +a1 => a1 +a2 => a2 +a3 => a3 +a4 => a4 +a5 => a5 +a6 => a6 +a7 => a7 +a8 => a8 +a9 => a9 +aa => aa +ab => ab +ac => ac +ad => ad +ae => ae +af => af +b0 => b0 +b1 => b1 +b2 => b2 +b3 => b3 +b4 => b4 +b5 => b5 +b6 => b6 +b7 => b7 +b8 => b8 +b9 => b9 +ba => ba +bb => bb +bc => bc +bd => bd +be => be +bf => bf +c0 => c0 +c1 => c1 +c2 => c2 +c3 => c3 +c4 => c4 +c5 => c5 +c6 => c6 +c7 => c7 +c8 => c8 +c9 => c9 +ca => ca +cb => cb +cc => cc +cd => cd +ce => ce +cf => cf +d0 => d0 +d1 => d1 +d2 => d2 +d3 => d3 +d4 => d4 +d5 => d5 +d6 => d6 +d7 => d7 +d8 => d8 +d9 => d9 +da => da +db => db +dc => dc +dd => dd +de => de +df => df +e0 => e0 +e1 => e1 +e2 => e2 +e3 => e3 +e4 => e4 +e5 => e5 +e6 => e6 +e7 => e7 +e8 => e8 +e9 => e9 +ea => ea +eb => eb +ec => ec +ed => ed +ee => ee +ef => ef +f0 => f0 +f1 => f1 +f2 => f2 +f3 => f3 +f4 => f4 +f5 => f5 +f6 => f6 +f7 => f7 +f8 => f8 +f9 => f9 +fa => fa +fb => fb +fc => fc +fd => fd +fe => fe +ff => ff *** Testing strtoupper() with basic strings *** string(43) "MARY HAD A LITTLE LAMB AND SHE LOVED IT SO diff --git a/ext/xml/xml.c b/ext/xml/xml.c index 5c73837c385a1..be69940545cda 100644 --- a/ext/xml/xml.c +++ b/ext/xml/xml.c @@ -23,7 +23,6 @@ #include "php.h" #include "zend_variables.h" -#include "ext/standard/php_string.h" #include "ext/standard/info.h" #include "ext/standard/html.h" From 49380b59d28f6ad7f897bf6189ba2e1ad78d4c8b Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 15 Dec 2021 11:47:44 +0100 Subject: [PATCH 36/75] Fix #81679: Tracing JIT crashes on reattaching When a new process reattaches to OPcache, tracing JIT causes segfaults, because each new process allocates its own `zend_jit_traces` and `zend_jit_exit_groups` in SHM, although these need to be shared between all processes. We solve that by only allocating these structs for the first process, and store the pointers in `accel_shared_globals`, so we can reassign them when a new process reattaches. Closes GH-7776. --- NEWS | 3 +++ ext/opcache/ZendAccelerator.h | 4 ++++ ext/opcache/jit/zend_jit.c | 2 +- ext/opcache/jit/zend_jit_trace.c | 37 +++++++++++++++++++++----------- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index 6f1a19ddd8a76..ddc18717a3294 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,9 @@ PHP NEWS . Fixed bug GH-7765 (php_oci_cleanup_global_handles segfaults at second call). (cmb) +- OPcache: + . Fixed bug #81679 (Tracing JIT crashes on reattaching). (cmb) + - PDO_PGSQL: . Fixed error message allocation of PDO PgSQL. (SATO Kentaro) diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index b9e3f2a81de83..610decd7995db 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -285,6 +285,10 @@ typedef struct _zend_accel_shared_globals { /* uninitialized HashTable Support */ uint32_t uninitialized_bucket[-HT_MIN_MASK]; + /* Tracing JIT */ + void *jit_traces; + const void **jit_exit_groups; + /* Interned Strings Support (must be the last element) */ zend_string_table interned_strings; } zend_accel_shared_globals; diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index bbe879b9fddd2..fdffcbc1034c7 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -4390,7 +4390,7 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, zend_bool reattached) #endif } - if (zend_jit_trace_startup() != SUCCESS) { + if (zend_jit_trace_startup(reattached) != SUCCESS) { return FAILURE; } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index fa29a03997740..dd37f33ad6853 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -48,20 +48,33 @@ static zend_always_inline const char *zend_jit_trace_star_desc(uint8_t trace_fla } } -static int zend_jit_trace_startup(void) +static int zend_jit_trace_startup(zend_bool reattached) { - zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces)); - if (!zend_jit_traces) { - return FAILURE; - } - zend_jit_exit_groups = (const void**)zend_shared_alloc(sizeof(void*) * (ZEND_JIT_TRACE_MAX_EXITS/ZEND_JIT_EXIT_POINTS_PER_GROUP)); - if (!zend_jit_exit_groups) { - return FAILURE; + if (!reattached) { + zend_jit_traces = (zend_jit_trace_info*)zend_shared_alloc(sizeof(zend_jit_trace_info) * JIT_G(max_root_traces)); + if (!zend_jit_traces) { + return FAILURE; + } + zend_jit_exit_groups = (const void**)zend_shared_alloc(sizeof(void*) * (ZEND_JIT_TRACE_MAX_EXITS/ZEND_JIT_EXIT_POINTS_PER_GROUP)); + if (!zend_jit_exit_groups) { + return FAILURE; + } + ZEND_JIT_TRACE_NUM = 1; + ZEND_JIT_COUNTER_NUM = 0; + ZEND_JIT_EXIT_NUM = 0; + ZEND_JIT_EXIT_COUNTERS = 0; + ZCSG(jit_traces) = zend_jit_traces; + ZCSG(jit_exit_groups) = zend_jit_exit_groups; + } else { + zend_jit_traces = ZCSG(jit_traces); + if (!zend_jit_traces) { + return FAILURE; + } + zend_jit_exit_groups = ZCSG(jit_exit_groups); + if (!zend_jit_exit_groups) { + return FAILURE; + } } - ZEND_JIT_TRACE_NUM = 1; - ZEND_JIT_COUNTER_NUM = 0; - ZEND_JIT_EXIT_NUM = 0; - ZEND_JIT_EXIT_COUNTERS = 0; memset(&dummy_op_array, 0, sizeof(dummy_op_array)); dummy_op_array.fn_flags = ZEND_ACC_DONE_PASS_TWO; From 38460c2c94a0d4b110060951a1a56575226adbfc Mon Sep 17 00:00:00 2001 From: Yannis Guyon Date: Wed, 15 Dec 2021 20:00:24 +0100 Subject: [PATCH 37/75] Implement php_handle_avif() using libavifinfo See #80828 and the internals@ mailing list discussion at https://externals.io/message/116543 Use libavifinfo's AvifInfoGetFeaturesStream() in php_handle_avif() to get the width, height, bit depth and channel count from an AVIF payload. Implement stream reading/skipping functions and data struct. Use libavifinfo's AvifInfoIdentifyStream() in php_is_image_avif(). Update the expected features read from "test1pix.avif" in getimagesize.phpt. Closes GH-7711. --- NEWS | 1 + README.REDIST.BINS | 3 +- UPGRADING | 5 + ext/standard/config.m4 | 2 +- ext/standard/config.w32 | 1 + ext/standard/image.c | 136 ++-- ext/standard/libavifinfo/LICENSE | 26 + ext/standard/libavifinfo/PATENTS | 107 +++ ext/standard/libavifinfo/README.md | 11 + ext/standard/libavifinfo/avifinfo.c | 745 +++++++++++++++++++++ ext/standard/libavifinfo/avifinfo.h | 92 +++ ext/standard/tests/image/getimagesize.phpt | 12 +- 12 files changed, 1058 insertions(+), 83 deletions(-) create mode 100644 ext/standard/libavifinfo/LICENSE create mode 100644 ext/standard/libavifinfo/PATENTS create mode 100644 ext/standard/libavifinfo/README.md create mode 100644 ext/standard/libavifinfo/avifinfo.c create mode 100644 ext/standard/libavifinfo/avifinfo.h diff --git a/NEWS b/NEWS index 3bdec63ad2290..ab7fa8554ba37 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ PHP NEWS - Standard: . net_get_interfaces() also reports wireless network interfaces on Windows. (Yurun) + . Finished AVIF support in getimagesize(). (Yannis Guyon) - Zip: . add ZipArchive::clearError() method diff --git a/README.REDIST.BINS b/README.REDIST.BINS index 64123ab004953..19e6a02b18269 100644 --- a/README.REDIST.BINS +++ b/README.REDIST.BINS @@ -15,6 +15,7 @@ 15. ext/phar/zip.c portion extracted from libzip 16. libbcmath (ext/bcmath) see ext/bcmath/libbcmath/LICENSE 17. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP +18. avifinfo (ext/standard/libavifinfo) see ext/standard/libavifinfo/LICENSE 3. pcre2lib (ext/pcre) @@ -591,7 +592,7 @@ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -16. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP +17. ext/mbstring/ucgendat portions based on the ucgendat.c from the OpenLDAP The OpenLDAP Public License Version 2.8, 17 August 2003 diff --git a/UPGRADING b/UPGRADING index ccc211f5b508a..86dd792ca484d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -129,6 +129,11 @@ PHP 8.2 UPGRADE NOTES - OCI8: . The minimum Oracle Client library version required is now 11.2. +- Standard: + . getimagesize() now reports the actual image dimensions, bits and channels + of AVIF images. Previously, the dimensions have been reported as 0x0, and + bits and channels have not been reported at all. + - Zip: . extension updated to 1.20.0 with new methods: ZipArchive::clearError, getStreamName and getStreamIndex diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 5299006892797..9ca92c610b9ed 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -460,7 +460,7 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. http_fopen_wrapper.c php_fopen_wrapper.c credits.c css.c \ var_unserializer.c ftok.c sha1.c user_filters.c uuencode.c \ filters.c proc_open.c streamsfuncs.c http.c password.c \ - random.c net.c hrtime.c crc32_x86.c,,, + random.c net.c hrtime.c crc32_x86.c libavifinfo/avifinfo.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_MAKEFILE_FRAGMENT diff --git a/ext/standard/config.w32 b/ext/standard/config.w32 index 3de43d04c067e..1813210849344 100644 --- a/ext/standard/config.w32 +++ b/ext/standard/config.w32 @@ -37,6 +37,7 @@ EXTENSION("standard", "array.c base64.c basic_functions.c browscap.c \ user_filters.c uuencode.c filters.c proc_open.c password.c \ streamsfuncs.c http.c flock_compat.c random.c hrtime.c", false /* never shared */, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); +ADD_SOURCES("ext/standard/libavifinfo", "avifinfo.c", "standard"); PHP_STANDARD = "yes"; ADD_MAKEFILE_FRAGMENT(); PHP_INSTALL_HEADERS("", "ext/standard"); diff --git a/ext/standard/image.c b/ext/standard/image.c index 85ecda2f3d70b..a614521ae1091 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -22,6 +22,7 @@ #endif #include "fopen_wrappers.h" #include "ext/standard/fsock.h" +#include "libavifinfo/avifinfo.h" #if HAVE_UNISTD_H #include #endif @@ -1155,95 +1156,76 @@ static struct gfxinfo *php_handle_webp(php_stream * stream) } /* }}} */ -/* {{{ php_handle_avif - * There's no simple way to get this information - so, for now, this is unsupported. - * Simply return 0 for everything. - */ -static struct gfxinfo *php_handle_avif(php_stream * stream) { - return ecalloc(1, sizeof(struct gfxinfo)); -} -/* }}} */ - -/* {{{ php_ntohl - * Convert a big-endian network uint32 to host order - - * which may be either little-endian or big-endian. - * Thanks to Rob Pike via Joe Drago: - * https://commandcenter.blogspot.nl/2012/04/byte-order-fallacy.html - */ -static uint32_t php_ntohl(uint32_t val) { - uint8_t data[4]; - - memcpy(&data, &val, sizeof(data)); - return ((uint32_t)data[3] << 0) | - ((uint32_t)data[2] << 8) | - ((uint32_t)data[1] << 16) | - ((uint32_t)data[0] << 24); -} -/* }}} */ - -/* {{{ php_is_image_avif - * detect whether an image is of type AVIF - * - * An AVIF image will start off a header "box". - * This starts with with a four-byte integer containing the number of bytes in the filetype box. - * This must be followed by the string "ftyp". - * Next comes a four-byte string indicating the "major brand". - * If that's "avif" or "avis", this is an AVIF image. - * Next, there's a four-byte "minor version" field, which we can ignore. - * Next comes an array of four-byte strings containing "compatible brands". - * These extend to the end of the box. - * If any of the compatible brands is "avif" or "avis", then this is an AVIF image. - * Otherwise, well, it's not. - * For more, see https://mpeg.chiariglione.org/standards/mpeg-4/iso-base-media-file-format/text-isoiec-14496-12-5th-edition - */ -bool php_is_image_avif(php_stream * stream) { - uint32_t header_size_reversed, header_size, i; - char box_type[4], brand[4]; +/* {{{ User struct and stream read/skip implementations for libavifinfo API */ +struct php_avif_stream { + php_stream* stream; + uint8_t buffer[AVIFINFO_MAX_NUM_READ_BYTES]; +}; - ZEND_ASSERT(stream != NULL); +static const uint8_t* php_avif_stream_read(void* stream, size_t num_bytes) { + struct php_avif_stream* avif_stream = (struct php_avif_stream*)stream; - if (php_stream_read(stream, (char *) &header_size_reversed, 4) != 4) { - return 0; + if (avif_stream == NULL || avif_stream->stream == NULL) { + return NULL; } - - header_size = php_ntohl(header_size_reversed); - - /* If the box type isn't "ftyp", it can't be an AVIF image. */ - if (php_stream_read(stream, box_type, 4) != 4) { - return 0; + if (php_stream_read(avif_stream->stream, (char*)avif_stream->buffer, num_bytes) != num_bytes) { + avif_stream->stream = NULL; /* fail further calls */ + return NULL; } + return avif_stream->buffer; +} - if (memcmp(box_type, "ftyp", 4)) { - return 0; - } - - /* If the major brand is "avif" or "avis", it's an AVIF image. */ - if (php_stream_read(stream, brand, 4) != 4) { - return 0; - } +static void php_avif_stream_skip(void* stream, size_t num_bytes) { + struct php_avif_stream* avif_stream = (struct php_avif_stream*)stream; - if (!memcmp(brand, "avif", 4) || !memcmp(brand, "avis", 4)) { - return 1; + if (avif_stream == NULL || avif_stream->stream == NULL) { + return; } - - /* Skip the next four bytes, which are the "minor version". */ - if (php_stream_read(stream, brand, 4) != 4) { - return 0; + if (php_stream_seek(avif_stream->stream, num_bytes, SEEK_CUR)) { + avif_stream->stream = NULL; /* fail further calls */ } +} +/* }}} */ - /* Look for "avif" or "avis" in any member of compatible_brands[], to the end of the header. - Note we've already read four groups of four bytes. */ +/* {{{ php_handle_avif + * Parse AVIF features + * + * The stream must be positioned at the beginning of a box, so it does not + * matter whether the "ftyp" box was already read by php_is_image_avif() or not. + * It will read bytes from the stream until features are found or the file is + * declared as invalid. Around 450 bytes are usually enough. + * Transforms such as mirror and rotation are not applied on width and height. + */ +static struct gfxinfo *php_handle_avif(php_stream * stream) { + struct gfxinfo* result = NULL; + AvifInfoFeatures features; + struct php_avif_stream avif_stream; + avif_stream.stream = stream; + + if (AvifInfoGetFeaturesStream(&avif_stream, php_avif_stream_read, php_avif_stream_skip, &features) == kAvifInfoOk) { + result = (struct gfxinfo*)ecalloc(1, sizeof(struct gfxinfo)); + result->width = features.width; + result->height = features.height; + result->bits = features.bit_depth; + result->channels = features.num_channels; + } + return result; +} +/* }}} */ - for (i = 16; i < header_size; i += 4) { - if (php_stream_read(stream, brand, 4) != 4) { - return 0; - } +/* {{{ php_is_image_avif + * Detect whether an image is of type AVIF + * + * Only the first "ftyp" box is read. + * For a valid file, 12 bytes are usually read, but more might be necessary. + */ +bool php_is_image_avif(php_stream* stream) { + struct php_avif_stream avif_stream; + avif_stream.stream = stream; - if (!memcmp(brand, "avif", 4) || !memcmp(brand, "avis", 4)) { - return 1; - } + if (AvifInfoIdentifyStream(&avif_stream, php_avif_stream_read, php_avif_stream_skip) == kAvifInfoOk) { + return 1; } - return 0; } /* }}} */ diff --git a/ext/standard/libavifinfo/LICENSE b/ext/standard/libavifinfo/LICENSE new file mode 100644 index 0000000000000..330b6b87bb6e8 --- /dev/null +++ b/ext/standard/libavifinfo/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2021, Alliance for Open Media. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/standard/libavifinfo/PATENTS b/ext/standard/libavifinfo/PATENTS new file mode 100644 index 0000000000000..826644b635355 --- /dev/null +++ b/ext/standard/libavifinfo/PATENTS @@ -0,0 +1,107 @@ +Alliance for Open Media Patent License 1.0 + +1. License Terms. + +1.1. Patent License. Subject to the terms and conditions of this License, each + Licensor, on behalf of itself and successors in interest and assigns, + grants Licensee a non-sublicensable, perpetual, worldwide, non-exclusive, + no-charge, royalty-free, irrevocable (except as expressly stated in this + License) patent license to its Necessary Claims to make, use, sell, offer + for sale, import or distribute any Implementation. + +1.2. Conditions. + +1.2.1. Availability. As a condition to the grant of rights to Licensee to make, + sell, offer for sale, import or distribute an Implementation under + Section 1.1, Licensee must make its Necessary Claims available under + this License, and must reproduce this License with any Implementation + as follows: + + a. For distribution in source code, by including this License in the + root directory of the source code with its Implementation. + + b. For distribution in any other form (including binary, object form, + and/or hardware description code (e.g., HDL, RTL, Gate Level Netlist, + GDSII, etc.)), by including this License in the documentation, legal + notices, and/or other written materials provided with the + Implementation. + +1.2.2. Additional Conditions. This license is directly from Licensor to + Licensee. Licensee acknowledges as a condition of benefiting from it + that no rights from Licensor are received from suppliers, distributors, + or otherwise in connection with this License. + +1.3. Defensive Termination. If any Licensee, its Affiliates, or its agents + initiates patent litigation or files, maintains, or voluntarily + participates in a lawsuit against another entity or any person asserting + that any Implementation infringes Necessary Claims, any patent licenses + granted under this License directly to the Licensee are immediately + terminated as of the date of the initiation of action unless 1) that suit + was in response to a corresponding suit regarding an Implementation first + brought against an initiating entity, or 2) that suit was brought to + enforce the terms of this License (including intervention in a third-party + action by a Licensee). + +1.4. Disclaimers. The Reference Implementation and Specification are provided + "AS IS" and without warranty. The entire risk as to implementing or + otherwise using the Reference Implementation or Specification is assumed + by the implementer and user. Licensor expressly disclaims any warranties + (express, implied, or otherwise), including implied warranties of + merchantability, non-infringement, fitness for a particular purpose, or + title, related to the material. IN NO EVENT WILL LICENSOR BE LIABLE TO + ANY OTHER PARTY FOR LOST PROFITS OR ANY FORM OF INDIRECT, SPECIAL, + INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER FROM ANY CAUSES OF + ACTION OF ANY KIND WITH RESPECT TO THIS LICENSE, WHETHER BASED ON BREACH + OF CONTRACT, TORT (INCLUDING NEGLIGENCE), OR OTHERWISE, AND WHETHER OR + NOT THE OTHER PARTRY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +2. Definitions. + +2.1. Affiliate. "Affiliate" means an entity that directly or indirectly + Controls, is Controlled by, or is under common Control of that party. + +2.2. Control. "Control" means direct or indirect control of more than 50% of + the voting power to elect directors of that corporation, or for any other + entity, the power to direct management of such entity. + +2.3. Decoder. "Decoder" means any decoder that conforms fully with all + non-optional portions of the Specification. + +2.4. Encoder. "Encoder" means any encoder that produces a bitstream that can + be decoded by a Decoder only to the extent it produces such a bitstream. + +2.5. Final Deliverable. "Final Deliverable" means the final version of a + deliverable approved by the Alliance for Open Media as a Final + Deliverable. + +2.6. Implementation. "Implementation" means any implementation, including the + Reference Implementation, that is an Encoder and/or a Decoder. An + Implementation also includes components of an Implementation only to the + extent they are used as part of an Implementation. + +2.7. License. "License" means this license. + +2.8. Licensee. "Licensee" means any person or entity who exercises patent + rights granted under this License. + +2.9. Licensor. "Licensor" means (i) any Licensee that makes, sells, offers + for sale, imports or distributes any Implementation, or (ii) a person + or entity that has a licensing obligation to the Implementation as a + result of its membership and/or participation in the Alliance for Open + Media working group that developed the Specification. + +2.10. Necessary Claims. "Necessary Claims" means all claims of patents or + patent applications, (a) that currently or at any time in the future, + are owned or controlled by the Licensor, and (b) (i) would be an + Essential Claim as defined by the W3C Policy as of February 5, 2004 + (https://www.w3.org/Consortium/Patent-Policy-20040205/#def-essential) + as if the Specification was a W3C Recommendation; or (ii) are infringed + by the Reference Implementation. + +2.11. Reference Implementation. "Reference Implementation" means an Encoder + and/or Decoder released by the Alliance for Open Media as a Final + Deliverable. + +2.12. Specification. "Specification" means the specification designated by + the Alliance for Open Media as a Final Deliverable for which this + License was issued. diff --git a/ext/standard/libavifinfo/README.md b/ext/standard/libavifinfo/README.md new file mode 100644 index 0000000000000..a08c29067f4b9 --- /dev/null +++ b/ext/standard/libavifinfo/README.md @@ -0,0 +1,11 @@ +# AVIF-info + +There is no compact, reliable way to determine the size of an AVIF image. A +standalone C snippet called +[libavifinfo](https://aomedia.googlesource.com/libavifinfo) was created to +partially parse an AVIF payload and to extract the width, height, bit depth and +channel count without depending on the full libavif library. + +`avifinfo.h`, `avifinfo.c`, `LICENSE` and `PATENTS` were copied verbatim from: \ +https://aomedia.googlesource.com/libavifinfo/+/96f34d945ac7dac229feddfa94dbae66e202b838 \ +They can easily be kept up-to-date the same way. diff --git a/ext/standard/libavifinfo/avifinfo.c b/ext/standard/libavifinfo/avifinfo.c new file mode 100644 index 0000000000000..5b93d1997be33 --- /dev/null +++ b/ext/standard/libavifinfo/avifinfo.c @@ -0,0 +1,745 @@ +// Copyright (c) 2021, Alliance for Open Media. All rights reserved +// +// This source code is subject to the terms of the BSD 2 Clause License and +// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +// was not distributed with this source code in the LICENSE file, you can +// obtain it at www.aomedia.org/license/software. If the Alliance for Open +// Media Patent License 1.0 was not distributed with this source code in the +// PATENTS file, you can obtain it at www.aomedia.org/license/patent. + +#include "avifinfo.h" + +#include +#include +#include + +//------------------------------------------------------------------------------ + +// Status returned when reading the content of a box (or file). +typedef enum { + kFound, // Input correctly parsed and information retrieved. + kNotFound, // Input correctly parsed but information is missing or elsewhere. + kTruncated, // Input correctly parsed until missing bytes to continue. + kAborted, // Input correctly parsed until stopped to avoid timeout or crash. + kInvalid, // Input incorrectly parsed. +} AvifInfoInternalStatus; + +static AvifInfoStatus AvifInfoInternalConvertStatus(AvifInfoInternalStatus s) { + return (s == kFound) ? kAvifInfoOk + : (s == kNotFound || s == kTruncated) ? kAvifInfoNotEnoughData + : (s == kAborted) ? kAvifInfoTooComplex + : kAvifInfoInvalidFile; +} + +// uint32_t is used everywhere in this file. It is unlikely to be insufficient +// to parse AVIF headers. +#define AVIFINFO_MAX_SIZE UINT32_MAX +// AvifInfoInternalFeatures uses uint8_t to store values and the number of +// values is clamped to 32 to limit the stack size. +#define AVIFINFO_MAX_VALUE UINT8_MAX +#define AVIFINFO_UNDEFINED 0 +// Maximum number of stored associations. Past that, they are skipped. +#define AVIFINFO_MAX_TILES 16 +#define AVIFINFO_MAX_PROPS 32 +#define AVIFINFO_MAX_FEATURES 8 + +// Reads an unsigned integer from 'input' with most significant bits first. +// 'input' must be at least 'num_bytes'-long. +static uint32_t AvifInfoInternalReadBigEndian(const uint8_t* input, + uint32_t num_bytes) { + uint32_t value = 0; + for (uint32_t i = 0; i < num_bytes; ++i) { + value = (value << 8) | input[i]; + } + return value; +} + +//------------------------------------------------------------------------------ +// Convenience macros. + +#if defined(AVIFINFO_LOG_ERROR) // Toggle to log encountered issues. +static void AvifInfoInternalLogError(const char* file, int line, + AvifInfoInternalStatus status) { + const char* kStr[] = {"Found", "NotFound", "Truncated", "Invalid", "Aborted"}; + fprintf(stderr, " %s:%d: %s\n", file, line, kStr[status]); + // Set a breakpoint here to catch the first detected issue. +} +#define AVIFINFO_RETURN(check_status) \ + do { \ + const AvifInfoInternalStatus status_checked = (check_status); \ + if (status_checked != kFound && status_checked != kNotFound) { \ + AvifInfoInternalLogError(__FILE__, __LINE__, status_checked); \ + } \ + return status_checked; \ + } while (0) +#else +#define AVIFINFO_RETURN(check_status) \ + do { \ + return (check_status); \ + } while (0) +#endif + +#define AVIFINFO_CHECK(check_condition, check_status) \ + do { \ + if (!(check_condition)) AVIFINFO_RETURN(check_status); \ + } while (0) +#define AVIFINFO_CHECK_STATUS_IS(check_status, expected_status) \ + do { \ + const AvifInfoInternalStatus status_returned = (check_status); \ + AVIFINFO_CHECK(status_returned == (expected_status), status_returned); \ + } while (0) +#define AVIFINFO_CHECK_FOUND(check_status) \ + AVIFINFO_CHECK_STATUS_IS((check_status), kFound) +#define AVIFINFO_CHECK_NOT_FOUND(check_status) \ + AVIFINFO_CHECK_STATUS_IS((check_status), kNotFound) + +//------------------------------------------------------------------------------ +// Streamed input struct and helper functions. + +typedef struct { + void* stream; // User-defined data. + read_stream_t read; // Used to fetch more bytes from the 'stream'. + skip_stream_t skip; // Used to advance the position in the 'stream'. + // Fallback to 'read' if 'skip' is null. +} AvifInfoInternalStream; + +// Reads 'num_bytes' from the 'stream'. They are available at '*data'. +// 'num_bytes' must be greater than zero. +static AvifInfoInternalStatus AvifInfoInternalRead( + AvifInfoInternalStream* stream, uint32_t num_bytes, const uint8_t** data) { + *data = stream->read(stream->stream, num_bytes); + AVIFINFO_CHECK(*data != NULL, kTruncated); + return kFound; +} + +// Skips 'num_bytes' from the 'stream'. 'num_bytes' can be zero. +static AvifInfoInternalStatus AvifInfoInternalSkip( + AvifInfoInternalStream* stream, uint32_t num_bytes) { + // Avoid a call to the user-defined function for nothing. + if (num_bytes > 0) { + if (stream->skip == NULL) { + const uint8_t* unused; + while (num_bytes > AVIFINFO_MAX_NUM_READ_BYTES) { + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, AVIFINFO_MAX_NUM_READ_BYTES, &unused)); + num_bytes -= AVIFINFO_MAX_NUM_READ_BYTES; + } + return AvifInfoInternalRead(stream, num_bytes, &unused); + } + stream->skip(stream->stream, num_bytes); + } + return kFound; +} + +//------------------------------------------------------------------------------ +// Features are parsed into temporary property associations. + +typedef struct { + uint8_t tile_item_id; + uint8_t parent_item_id; +} AvifInfoInternalTile; // Tile item id <-> parent item id associations. + +typedef struct { + uint8_t property_index; + uint8_t item_id; +} AvifInfoInternalProp; // Property index <-> item id associations. + +typedef struct { + uint8_t property_index; + uint32_t width, height; +} AvifInfoInternalDimProp; // Property <-> features associations. + +typedef struct { + uint8_t property_index; + uint8_t bit_depth, num_channels; +} AvifInfoInternalChanProp; // Property <-> features associations. + +typedef struct { + uint8_t has_primary_item; // True if "pitm" was parsed. + uint8_t has_alpha; // True if an alpha "auxC" was parsed. + uint8_t primary_item_id; + AvifInfoFeatures primary_item_features; // Deduced from the data below. + uint8_t data_was_skipped; // True if some loops/indices were skipped. + + uint8_t num_tiles; + AvifInfoInternalTile tiles[AVIFINFO_MAX_TILES]; + uint8_t num_props; + AvifInfoInternalProp props[AVIFINFO_MAX_PROPS]; + uint8_t num_dim_props; + AvifInfoInternalDimProp dim_props[AVIFINFO_MAX_FEATURES]; + uint8_t num_chan_props; + AvifInfoInternalChanProp chan_props[AVIFINFO_MAX_FEATURES]; +} AvifInfoInternalFeatures; + +// Generates the features of a given 'target_item_id' from internal features. +static AvifInfoInternalStatus AvifInfoInternalGetItemFeatures( + AvifInfoInternalFeatures* f, uint32_t target_item_id, uint32_t tile_depth) { + for (uint32_t prop_item = 0; prop_item < f->num_props; ++prop_item) { + if (f->props[prop_item].item_id != target_item_id) continue; + const uint32_t property_index = f->props[prop_item].property_index; + + // Retrieve the width and height of the primary item if not already done. + if (target_item_id == f->primary_item_id && + (f->primary_item_features.width == AVIFINFO_UNDEFINED || + f->primary_item_features.height == AVIFINFO_UNDEFINED)) { + for (uint32_t i = 0; i < f->num_dim_props; ++i) { + if (f->dim_props[i].property_index != property_index) continue; + f->primary_item_features.width = f->dim_props[i].width; + f->primary_item_features.height = f->dim_props[i].height; + if (f->primary_item_features.bit_depth != AVIFINFO_UNDEFINED && + f->primary_item_features.num_channels != AVIFINFO_UNDEFINED) { + return kFound; + } + break; + } + } + // Retrieve the bit depth and number of channels of the target item if not + // already done. + if (f->primary_item_features.bit_depth == AVIFINFO_UNDEFINED || + f->primary_item_features.num_channels == AVIFINFO_UNDEFINED) { + for (uint32_t i = 0; i < f->num_chan_props; ++i) { + if (f->chan_props[i].property_index != property_index) continue; + f->primary_item_features.bit_depth = f->chan_props[i].bit_depth; + f->primary_item_features.num_channels = f->chan_props[i].num_channels; + if (f->primary_item_features.width != AVIFINFO_UNDEFINED && + f->primary_item_features.height != AVIFINFO_UNDEFINED) { + return kFound; + } + break; + } + } + } + + // Check for the bit_depth and num_channels in a tile if not yet found. + for (uint32_t tile = 0; tile < f->num_tiles && tile_depth < 3; ++tile) { + if (f->tiles[tile].parent_item_id != target_item_id) continue; + AVIFINFO_CHECK_NOT_FOUND(AvifInfoInternalGetItemFeatures( + f, f->tiles[tile].tile_item_id, tile_depth + 1)); + } + AVIFINFO_RETURN(kNotFound); +} + +// Generates the 'f->primary_item_features' from the AvifInfoInternalFeatures. +// Returns kNotFound if there is not enough information. +static AvifInfoInternalStatus AvifInfoInternalGetPrimaryItemFeatures( + AvifInfoInternalFeatures* f) { + // Nothing to do without the primary item ID. + AVIFINFO_CHECK(f->has_primary_item, kNotFound); + // Early exit. + AVIFINFO_CHECK(f->num_dim_props > 0 && f->num_chan_props, kNotFound); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalGetItemFeatures(f, f->primary_item_id, /*tile_depth=*/0)); + + // "auxC" is parsed before the "ipma" properties so it is known now, if any. + if (f->has_alpha) ++f->primary_item_features.num_channels; + return kFound; +} + +//------------------------------------------------------------------------------ +// Box header parsing and various size checks. + +typedef struct { + uint32_t size; // In bytes. + uint8_t type[4]; // Four characters. + uint32_t version; // 0 or actual version if this is a full box. + uint32_t flags; // 0 or actual value if this is a full box. + uint32_t content_size; // 'size' minus the header size. +} AvifInfoInternalBox; + +// Reads the header of a 'box' starting at the beginning of a 'stream'. +// 'num_remaining_bytes' is the remaining size of the container of the 'box' +// (either the file size itself or the content size of the parent of the 'box'). +static AvifInfoInternalStatus AvifInfoInternalParseBox( + AvifInfoInternalStream* stream, uint32_t num_remaining_bytes, + uint32_t* num_parsed_boxes, AvifInfoInternalBox* box) { + const uint8_t* data; + // See ISO/IEC 14496-12:2012(E) 4.2 + uint32_t box_header_size = 8; // box 32b size + 32b type (at least) + AVIFINFO_CHECK(box_header_size <= num_remaining_bytes, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 8, &data)); + box->size = AvifInfoInternalReadBigEndian(data, sizeof(uint32_t)); + memcpy(box->type, data + 4, 4); + // 'box->size==1' means 64-bit size should be read after the box type. + // 'box->size==0' means this box extends to all remaining bytes. + if (box->size == 1) { + box_header_size += 8; + AVIFINFO_CHECK(box_header_size <= num_remaining_bytes, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 8, &data)); + // Stop the parsing if any box has a size greater than 4GB. + AVIFINFO_CHECK(AvifInfoInternalReadBigEndian(data, sizeof(uint32_t)) == 0, + kAborted); + // Read the 32 least-significant bits. + box->size = AvifInfoInternalReadBigEndian(data + 4, sizeof(uint32_t)); + } else if (box->size == 0) { + box->size = num_remaining_bytes; + } + AVIFINFO_CHECK(box->size >= box_header_size, kInvalid); + AVIFINFO_CHECK(box->size <= num_remaining_bytes, kInvalid); + + const int has_fullbox_header = + !memcmp(box->type, "meta", 4) || !memcmp(box->type, "pitm", 4) || + !memcmp(box->type, "ipma", 4) || !memcmp(box->type, "ispe", 4) || + !memcmp(box->type, "pixi", 4) || !memcmp(box->type, "iref", 4) || + !memcmp(box->type, "auxC", 4); + if (has_fullbox_header) box_header_size += 4; + AVIFINFO_CHECK(box->size >= box_header_size, kInvalid); + box->content_size = box->size - box_header_size; + // Avoid timeouts. The maximum number of parsed boxes is arbitrary. + ++*num_parsed_boxes; + AVIFINFO_CHECK(*num_parsed_boxes < 4096, kAborted); + + box->version = 0; + box->flags = 0; + if (has_fullbox_header) { + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 4, &data)); + box->version = AvifInfoInternalReadBigEndian(data, 1); + box->flags = AvifInfoInternalReadBigEndian(data + 1, 3); + // See AV1 Image File Format (AVIF) 8.1 + // at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when + // https://github.com/AOMediaCodec/av1-avif/pull/170 is merged). + uint32_t is_parsable = 1; + if (!memcmp(box->type, "meta", 4)) is_parsable = (box->version <= 0); + if (!memcmp(box->type, "pitm", 4)) is_parsable = (box->version <= 1); + if (!memcmp(box->type, "ipma", 4)) is_parsable = (box->version <= 1); + if (!memcmp(box->type, "ispe", 4)) is_parsable = (box->version <= 0); + if (!memcmp(box->type, "pixi", 4)) is_parsable = (box->version <= 0); + if (!memcmp(box->type, "iref", 4)) is_parsable = (box->version <= 1); + if (!memcmp(box->type, "auxC", 4)) is_parsable = (box->version <= 0); + // Instead of considering this file as invalid, skip unparsable boxes. + if (!is_parsable) memcpy(box->type, "\0skp", 4); // \0 so not a valid type + } + return kFound; +} + +//------------------------------------------------------------------------------ + +// Parses a 'stream' of an "ipco" box into 'features'. +// "ispe" is used for width and height, "pixi" and "av1C" are used for bit depth +// and number of channels, and "auxC" is used for alpha. +static AvifInfoInternalStatus ParseIpco(AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + uint32_t box_index = 1; // 1-based index. Used for iterating over properties. + do { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, + num_parsed_boxes, &box)); + + if (!memcmp(box.type, "ispe", 4)) { + // See ISO/IEC 23008-12:2017(E) 6.5.3.2 + const uint8_t* data; + AVIFINFO_CHECK(box.content_size >= 8, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 8, &data)); + const uint32_t width = AvifInfoInternalReadBigEndian(data + 0, 4); + const uint32_t height = AvifInfoInternalReadBigEndian(data + 4, 4); + AVIFINFO_CHECK(width != 0 && height != 0, kInvalid); + if (features->num_dim_props < AVIFINFO_MAX_FEATURES && + box_index <= AVIFINFO_MAX_VALUE) { + features->dim_props[features->num_dim_props].property_index = box_index; + features->dim_props[features->num_dim_props].width = width; + features->dim_props[features->num_dim_props].height = height; + ++features->num_dim_props; + } else { + features->data_was_skipped = 1; + } + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size - 8)); + } else if (!memcmp(box.type, "pixi", 4)) { + // See ISO/IEC 23008-12:2017(E) 6.5.6.2 + const uint8_t* data; + AVIFINFO_CHECK(box.content_size >= 1, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 1, &data)); + const uint32_t num_channels = AvifInfoInternalReadBigEndian(data + 0, 1); + AVIFINFO_CHECK(num_channels >= 1, kInvalid); + AVIFINFO_CHECK(box.content_size >= 1 + num_channels, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 1, &data)); + const uint32_t bit_depth = AvifInfoInternalReadBigEndian(data, 1); + AVIFINFO_CHECK(bit_depth >= 1, kInvalid); + for (uint32_t i = 1; i < num_channels; ++i) { + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 1, &data)); + // Bit depth should be the same for all channels. + AVIFINFO_CHECK(AvifInfoInternalReadBigEndian(data, 1) == bit_depth, + kInvalid); + AVIFINFO_CHECK(i <= 32, kAborted); // Be reasonable. + } + if (features->num_chan_props < AVIFINFO_MAX_FEATURES && + box_index <= AVIFINFO_MAX_VALUE && bit_depth <= AVIFINFO_MAX_VALUE && + num_channels <= AVIFINFO_MAX_VALUE) { + features->chan_props[features->num_chan_props].property_index = + box_index; + features->chan_props[features->num_chan_props].bit_depth = bit_depth; + features->chan_props[features->num_chan_props].num_channels = + num_channels; + ++features->num_chan_props; + } else { + features->data_was_skipped = 1; + } + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - (1 + num_channels))); + } else if (!memcmp(box.type, "av1C", 4)) { + // See AV1 Codec ISO Media File Format Binding 2.3.1 + // at https://aomediacodec.github.io/av1-isobmff/#av1c + // Only parse the necessary third byte. Assume that the others are valid. + const uint8_t* data; + AVIFINFO_CHECK(box.content_size >= 3, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 3, &data)); + const int high_bitdepth = (data[2] & 0x40) != 0; + const int twelve_bit = (data[2] & 0x20) != 0; + const int monochrome = (data[2] & 0x10) != 0; + if (twelve_bit) { + AVIFINFO_CHECK(high_bitdepth, kInvalid); + } + if (features->num_chan_props < AVIFINFO_MAX_FEATURES && + box_index <= AVIFINFO_MAX_VALUE) { + features->chan_props[features->num_chan_props].property_index = + box_index; + features->chan_props[features->num_chan_props].bit_depth = + high_bitdepth ? twelve_bit ? 12 : 10 : 8; + features->chan_props[features->num_chan_props].num_channels = + monochrome ? 1 : 3; + ++features->num_chan_props; + } else { + features->data_was_skipped = 1; + } + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size - 3)); + } else if (!memcmp(box.type, "auxC", 4)) { + // See AV1 Image File Format (AVIF) 4 + // at https://aomediacodec.github.io/av1-avif/#auxiliary-images + const char* kAlphaStr = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"; + const uint32_t kAlphaStrLength = 44; // Includes terminating character. + if (box.content_size >= kAlphaStrLength) { + const uint8_t* data; + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, kAlphaStrLength, &data)); + const char* const aux_type = (const char*)data; + if (strcmp(aux_type, kAlphaStr) == 0) { + // Note: It is unlikely but it is possible that this alpha plane does + // not belong to the primary item or a tile. Ignore this issue. + features->has_alpha = 1; + } + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - kAlphaStrLength)); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + ++box_index; + num_remaining_bytes -= box.size; + } while (num_remaining_bytes > 0); + AVIFINFO_RETURN(kNotFound); +} + +// Parses a 'stream' of an "iprp" box into 'features'. The "ipco" box contain +// the properties which are linked to items by the "ipma" box. +static AvifInfoInternalStatus ParseIprp(AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + do { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, + num_parsed_boxes, &box)); + + if (!memcmp(box.type, "ipco", 4)) { + AVIFINFO_CHECK_NOT_FOUND( + ParseIpco(stream, box.content_size, num_parsed_boxes, features)); + } else if (!memcmp(box.type, "ipma", 4)) { + // See ISO/IEC 23008-12:2017(E) 9.3.2 + uint32_t num_read_bytes = 4; + const uint8_t* data; + AVIFINFO_CHECK(box.content_size >= num_read_bytes, kInvalid); + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 4, &data)); + const uint32_t entry_count = AvifInfoInternalReadBigEndian(data, 4); + const uint32_t id_num_bytes = (box.version < 1) ? 2 : 4; + const uint32_t index_num_bytes = (box.flags & 1) ? 2 : 1; + const uint32_t essential_bit_mask = (box.flags & 1) ? 0x8000 : 0x80; + + for (uint32_t entry = 0; entry < entry_count; ++entry) { + if (entry >= AVIFINFO_MAX_PROPS || + features->num_props >= AVIFINFO_MAX_PROPS) { + features->data_was_skipped = 1; + break; + } + num_read_bytes += id_num_bytes + 1; + AVIFINFO_CHECK(box.content_size >= num_read_bytes, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, id_num_bytes + 1, &data)); + const uint32_t item_id = + AvifInfoInternalReadBigEndian(data, id_num_bytes); + const uint32_t association_count = + AvifInfoInternalReadBigEndian(data + id_num_bytes, 1); + + uint32_t property; + for (property = 0; property < association_count; ++property) { + if (property >= AVIFINFO_MAX_PROPS || + features->num_props >= AVIFINFO_MAX_PROPS) { + features->data_was_skipped = 1; + break; + } + num_read_bytes += index_num_bytes; + AVIFINFO_CHECK(box.content_size >= num_read_bytes, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, index_num_bytes, &data)); + const uint32_t value = + AvifInfoInternalReadBigEndian(data, index_num_bytes); + // const int essential = (value & essential_bit_mask); // Unused. + const uint32_t property_index = (value & ~essential_bit_mask); + if (property_index <= AVIFINFO_MAX_VALUE && + item_id <= AVIFINFO_MAX_VALUE) { + features->props[features->num_props].property_index = + property_index; + features->props[features->num_props].item_id = item_id; + ++features->num_props; + } else { + features->data_was_skipped = 1; + } + } + if (property < association_count) break; // Do not read garbage. + } + + // If all features are available now, do not look further. + AVIFINFO_CHECK_NOT_FOUND( + AvifInfoInternalGetPrimaryItemFeatures(features)); + + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - num_read_bytes)); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + num_remaining_bytes -= box.size; + } while (num_remaining_bytes != 0); + AVIFINFO_RETURN(kNotFound); +} + +//------------------------------------------------------------------------------ + +// Parses a 'stream' of an "iref" box into 'features'. +// The "dimg" boxes contain links between tiles and their parent items, which +// can be used to infer bit depth and number of channels for the primary item +// when the latter does not have these properties. +static AvifInfoInternalStatus ParseIref(AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + do { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, + num_parsed_boxes, &box)); + + if (!memcmp(box.type, "dimg", 4)) { + // See ISO/IEC 14496-12:2015(E) 8.11.12.2 + const uint32_t num_bytes_per_id = (box.version == 0) ? 2 : 4; + uint32_t num_read_bytes = num_bytes_per_id + 2; + const uint8_t* data; + AVIFINFO_CHECK(box.content_size >= num_read_bytes, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, num_bytes_per_id + 2, &data)); + const uint32_t from_item_id = + AvifInfoInternalReadBigEndian(data, num_bytes_per_id); + const uint32_t reference_count = + AvifInfoInternalReadBigEndian(data + num_bytes_per_id, 2); + + for (uint32_t i = 0; i < reference_count; ++i) { + if (i >= AVIFINFO_MAX_TILES) { + features->data_was_skipped = 1; + break; + } + num_read_bytes += num_bytes_per_id; + AVIFINFO_CHECK(box.content_size >= num_read_bytes, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, num_bytes_per_id, &data)); + const uint32_t to_item_id = + AvifInfoInternalReadBigEndian(data, num_bytes_per_id); + if (from_item_id <= AVIFINFO_MAX_VALUE && + to_item_id <= AVIFINFO_MAX_VALUE && + features->num_tiles < AVIFINFO_MAX_TILES) { + features->tiles[features->num_tiles].tile_item_id = to_item_id; + features->tiles[features->num_tiles].parent_item_id = from_item_id; + ++features->num_tiles; + } else { + features->data_was_skipped = 1; + } + } + + // If all features are available now, do not look further. + AVIFINFO_CHECK_NOT_FOUND( + AvifInfoInternalGetPrimaryItemFeatures(features)); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + num_remaining_bytes -= box.size; + } while (num_remaining_bytes > 0); + AVIFINFO_RETURN(kNotFound); +} + +//------------------------------------------------------------------------------ + +// Parses a 'stream' of a "meta" box. It looks for the primary item ID in the +// "pitm" box and recurses into other boxes to find its 'features'. +static AvifInfoInternalStatus ParseMeta(AvifInfoInternalStream* stream, + uint32_t num_remaining_bytes, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + do { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, num_remaining_bytes, + num_parsed_boxes, &box)); + + if (!memcmp(box.type, "pitm", 4)) { + // See ISO/IEC 14496-12:2015(E) 8.11.4.2 + const uint32_t num_bytes_per_id = (box.version == 0) ? 2 : 4; + const uint8_t* data; + AVIFINFO_CHECK(num_bytes_per_id <= num_remaining_bytes, kInvalid); + AVIFINFO_CHECK_FOUND( + AvifInfoInternalRead(stream, num_bytes_per_id, &data)); + const uint32_t primary_item_id = + AvifInfoInternalReadBigEndian(data, num_bytes_per_id); + AVIFINFO_CHECK(primary_item_id <= AVIFINFO_MAX_VALUE, kAborted); + features->has_primary_item = 1; + features->primary_item_id = primary_item_id; + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - num_bytes_per_id)); + } else if (!memcmp(box.type, "iprp", 4)) { + AVIFINFO_CHECK_NOT_FOUND( + ParseIprp(stream, box.content_size, num_parsed_boxes, features)); + } else if (!memcmp(box.type, "iref", 4)) { + AVIFINFO_CHECK_NOT_FOUND( + ParseIref(stream, box.content_size, num_parsed_boxes, features)); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + num_remaining_bytes -= box.size; + } while (num_remaining_bytes != 0); + // According to ISO/IEC 14496-12:2012(E) 8.11.1.1 there is at most one "meta". + AVIFINFO_RETURN(features->data_was_skipped ? kAborted : kInvalid); +} + +//------------------------------------------------------------------------------ + +// Parses a file 'stream'. The file type is checked through the "ftyp" box. +static AvifInfoInternalStatus ParseFtyp(AvifInfoInternalStream* stream) { + AvifInfoInternalBox box; + uint32_t num_parsed_boxes = 0; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, AVIFINFO_MAX_SIZE, + &num_parsed_boxes, &box)); + AVIFINFO_CHECK(!memcmp(box.type, "ftyp", 4), kInvalid); + // Iterate over brands. See ISO/IEC 14496-12:2012(E) 4.3.1 + AVIFINFO_CHECK(box.content_size >= 8, kInvalid); // major_brand,minor_version + for (uint32_t i = 0; i + 4 <= box.content_size; i += 4) { + const uint8_t* data; + AVIFINFO_CHECK_FOUND(AvifInfoInternalRead(stream, 4, &data)); + if (i == 4) continue; // Skip minor_version. + if (!memcmp(data, "avif", 4) || !memcmp(data, "avis", 4)) { + AVIFINFO_CHECK_FOUND( + AvifInfoInternalSkip(stream, box.content_size - (i + 4))); + return kFound; + } + AVIFINFO_CHECK(i <= 32 * 4, kAborted); // Be reasonable. + } + AVIFINFO_RETURN(kInvalid); // No AVIF brand no good. +} + +// Parses a file 'stream'. 'features' are extracted from the "meta" box. +static AvifInfoInternalStatus ParseFile(AvifInfoInternalStream* stream, + uint32_t* num_parsed_boxes, + AvifInfoInternalFeatures* features) { + while (1) { + AvifInfoInternalBox box; + AVIFINFO_CHECK_FOUND(AvifInfoInternalParseBox(stream, AVIFINFO_MAX_SIZE, + num_parsed_boxes, &box)); + if (!memcmp(box.type, "meta", 4)) { + return ParseMeta(stream, box.content_size, num_parsed_boxes, features); + } else { + AVIFINFO_CHECK_FOUND(AvifInfoInternalSkip(stream, box.content_size)); + } + } + AVIFINFO_RETURN(kInvalid); // No "meta" no good. +} + +//------------------------------------------------------------------------------ +// Helpers for converting the fixed-size input public API to the streamed one. + +typedef struct { + const uint8_t* data; + size_t data_size; +} AvifInfoInternalForward; + +static const uint8_t* AvifInfoInternalForwardRead(void* stream, + size_t num_bytes) { + AvifInfoInternalForward* forward = (AvifInfoInternalForward*)stream; + if (num_bytes > forward->data_size) return NULL; + const uint8_t* data = forward->data; + forward->data += num_bytes; + forward->data_size -= num_bytes; + return data; +} + +static void AvifInfoInternalForwardSkip(void* stream, size_t num_bytes) { + AvifInfoInternalForward* forward = (AvifInfoInternalForward*)stream; + if (num_bytes > forward->data_size) num_bytes = forward->data_size; + forward->data += num_bytes; + forward->data_size -= num_bytes; +} + +//------------------------------------------------------------------------------ +// Fixed-size input public API + +AvifInfoStatus AvifInfoIdentify(const uint8_t* data, size_t data_size) { + AvifInfoInternalForward stream; + stream.data = data; + stream.data_size = data_size; + // Forward null 'data' as a null 'stream' to handle it the same way. + return AvifInfoIdentifyStream( + (void*)&stream, (data == NULL) ? NULL : AvifInfoInternalForwardRead, + AvifInfoInternalForwardSkip); +} + +AvifInfoStatus AvifInfoGetFeatures(const uint8_t* data, size_t data_size, + AvifInfoFeatures* features) { + AvifInfoInternalForward stream; + stream.data = data; + stream.data_size = data_size; + return AvifInfoGetFeaturesStream( + (void*)&stream, (data == NULL) ? NULL : AvifInfoInternalForwardRead, + AvifInfoInternalForwardSkip, features); +} + +//------------------------------------------------------------------------------ +// Streamed input API + +AvifInfoStatus AvifInfoIdentifyStream(void* stream, read_stream_t read, + skip_stream_t skip) { + if (read == NULL) return kAvifInfoNotEnoughData; + + AvifInfoInternalStream internal_stream; + internal_stream.stream = stream; + internal_stream.read = read; + internal_stream.skip = skip; // Fallbacks to 'read' if null. + return AvifInfoInternalConvertStatus(ParseFtyp(&internal_stream)); +} + +AvifInfoStatus AvifInfoGetFeaturesStream(void* stream, read_stream_t read, + skip_stream_t skip, + AvifInfoFeatures* features) { + if (features != NULL) memset(features, 0, sizeof(*features)); + if (read == NULL) return kAvifInfoNotEnoughData; + + AvifInfoInternalStream internal_stream; + internal_stream.stream = stream; + internal_stream.read = read; + internal_stream.skip = skip; // Fallbacks to 'read' if null. + uint32_t num_parsed_boxes = 0; + AvifInfoInternalFeatures internal_features; + memset(&internal_features, AVIFINFO_UNDEFINED, sizeof(internal_features)); + + // Go through all relevant boxes sequentially. + const AvifInfoInternalStatus status = + ParseFile(&internal_stream, &num_parsed_boxes, &internal_features); + if (status == kFound && features != NULL) { + memcpy(features, &internal_features.primary_item_features, + sizeof(*features)); + } + return AvifInfoInternalConvertStatus(status); +} diff --git a/ext/standard/libavifinfo/avifinfo.h b/ext/standard/libavifinfo/avifinfo.h new file mode 100644 index 0000000000000..4c898c2efcc5c --- /dev/null +++ b/ext/standard/libavifinfo/avifinfo.h @@ -0,0 +1,92 @@ +// Copyright (c) 2021, Alliance for Open Media. All rights reserved +// +// This source code is subject to the terms of the BSD 2 Clause License and +// the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License +// was not distributed with this source code in the LICENSE file, you can +// obtain it at www.aomedia.org/license/software. If the Alliance for Open +// Media Patent License 1.0 was not distributed with this source code in the +// PATENTS file, you can obtain it at www.aomedia.org/license/patent. + +#ifndef AVIFINFO_H_ +#define AVIFINFO_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//------------------------------------------------------------------------------ + +typedef enum { + kAvifInfoOk, // The file was correctly parsed and the requested + // information was extracted. It is not guaranteed + // that the input bitstream is a valid complete + // AVIF file. + kAvifInfoNotEnoughData, // The input bitstream was correctly parsed until + // now but bytes are missing. The request should be + // repeated with more input bytes. + kAvifInfoTooComplex, // The input bitstream was correctly parsed until + // now but it is too complex. The parsing was + // stopped to avoid any timeout or crash. + kAvifInfoInvalidFile, // The input bitstream is not a valid AVIF file, + // truncated or not. +} AvifInfoStatus; + +typedef struct { + uint32_t width, height; // In number of pixels. Ignores mirror and rotation. + uint32_t bit_depth; // Likely 8, 10 or 12 bits per channel per pixel. + uint32_t num_channels; // Likely 1, 2, 3 or 4 channels: + // (1 monochrome or 3 colors) + (0 or 1 alpha) +} AvifInfoFeatures; + +//------------------------------------------------------------------------------ +// Fixed-size input API +// Use this API if a raw byte array of fixed size is available as input. + +// Parses the 'data' and returns kAvifInfoOk if it is identified as an AVIF. +// The file type can be identified in the first 12 bytes of most AVIF files. +AvifInfoStatus AvifInfoIdentify(const uint8_t* data, size_t data_size); + +// Parses the identified AVIF 'data' and extracts its 'features'. +// 'data' can be partial but must point to the beginning of the AVIF file. +// The 'features' can be parsed in the first 450 bytes of most AVIF files. +// 'features' are set to 0 unless kAvifInfoOk is returned. +AvifInfoStatus AvifInfoGetFeatures(const uint8_t* data, size_t data_size, + AvifInfoFeatures* features); + +//------------------------------------------------------------------------------ +// Streamed input API +// Use this API if the input bytes must be fetched and/or if the AVIF payload +// size is unknown. Implement the two function signatures below and pass them to +// AvifInfoRead*() with a 'stream', which can be anything (file, struct etc.). + +// Reads 'num_bytes' from the 'stream'. +// The position in the 'stream' must be advanced by 'num_bytes'. +// Returns a pointer to the 'num_bytes' or null if it cannot be fulfilled. +// The returned data must remain valid until the next read. +typedef const uint8_t* (*read_stream_t)(void* stream, size_t num_bytes); +// Advances the position in the 'stream' by 'num_bytes'. +typedef void (*skip_stream_t)(void* stream, size_t num_bytes); + +// Maximum number of bytes requested per read. There is no limit per skip. +#define AVIFINFO_MAX_NUM_READ_BYTES 64 + +// Same as AvifInfo*() but takes a 'stream' as input. AvifInfo*Stream() does +// not access the 'stream' directly but passes it as is to 'read' and 'skip'. +// 'read' cannot be null. If 'skip' is null, 'read' is called instead. +AvifInfoStatus AvifInfoIdentifyStream(void* stream, read_stream_t read, + skip_stream_t skip); +// Can be called right after AvifInfoIdentifyStream() with the same 'stream'. +AvifInfoStatus AvifInfoGetFeaturesStream(void* stream, read_stream_t read, + skip_stream_t skip, + AvifInfoFeatures* features); + +//------------------------------------------------------------------------------ + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // AVIFINFO_H_ diff --git a/ext/standard/tests/image/getimagesize.phpt b/ext/standard/tests/image/getimagesize.phpt index 0a1002d2934a1..472be1d25e366 100644 --- a/ext/standard/tests/image/getimagesize.phpt +++ b/ext/standard/tests/image/getimagesize.phpt @@ -70,15 +70,19 @@ array(17) { string(9) "image/bmp" } ["test1pix.avif"]=> - array(5) { + array(7) { [0]=> - int(0) + int(102) [1]=> - int(0) + int(121) [2]=> int(19) [3]=> - string(20) "width="0" height="0"" + string(24) "width="102" height="121"" + ["bits"]=> + int(8) + ["channels"]=> + int(4) ["mime"]=> string(10) "image/avif" } From 30a3280df73c0751cab8b342824b8d9a6ba91e3c Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 12 Dec 2021 12:31:07 +0100 Subject: [PATCH 38/75] Oracle Client 10g is no longer supported Thus, we drop respective config option for Windows. --- NEWS | 2 ++ UPGRADING | 5 ++++ ext/oci8/config.w32 | 56 --------------------------------------------- 3 files changed, 7 insertions(+), 56 deletions(-) diff --git a/NEWS b/NEWS index ab7fa8554ba37..0a53434c36a9f 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,8 @@ PHP NEWS - OCI8: . Added oci8.prefetch_lob_size directive to tune LOB query performance + . Support for building against Oracle Client libraries 10.1 and 10.2 has been + dropped. Oracle Client libraries 11.2 or newer are now required. - Standard: . net_get_interfaces() also reports wireless network interfaces on Windows. diff --git a/UPGRADING b/UPGRADING index 86dd792ca484d..b0a3fffb7add2 100644 --- a/UPGRADING +++ b/UPGRADING @@ -157,6 +157,11 @@ PHP 8.2 UPGRADE NOTES . Windows specific error messages are no longer localized, but instead in English to better match PHP error messages. +- OCI8: + . Since building against Oracle Client 10g is no longer supported anyway, + the configuration option --with-oci8 has been dropped. --with-oci8-11g, + --with-oci8-12c and --with-oci8-19 are still supported. + ======================================== 13. Other Changes ======================================== diff --git a/ext/oci8/config.w32 b/ext/oci8/config.w32 index 1c94c1578995c..8d17878c77644 100644 --- a/ext/oci8/config.w32 +++ b/ext/oci8/config.w32 @@ -1,19 +1,5 @@ // vim:ft=javascript -if (PHP_OCI8 != "no" && PHP_OCI8_11G != "no") { - if (!PHP_OCI8_SHARED && !PHP_OCI8_11G_SHARED) { - WARNING("oci8 and oci8-11g provide the same extension and cannot both be built statically"); - PHP_OCI8 = "no" - } -} - -if (PHP_OCI8 != "no" && PHP_OCI8_12C != "no") { - if (!PHP_OCI8_SHARED && !PHP_OCI8_12C_SHARED) { - WARNING("oci8 and oci8-12c provide the same extension and cannot both be built statically"); - PHP_OCI8 = "no" - } -} - if (PHP_OCI8_11G != "no" && PHP_OCI8_12C != "no") { if (!PHP_OCI8_11G_SHARED && !PHP_OCI8_12C_SHARED) { WARNING("oci8-11g and oci8-12c provide the same extension and cannot both be built statically"); @@ -21,13 +7,6 @@ if (PHP_OCI8_11G != "no" && PHP_OCI8_12C != "no") { } } -if (PHP_OCI8 != "no" && PHP_OCI8_19 != "no") { - if (!PHP_OCI8_SHARED && !PHP_OCI8_19_SHARED) { - WARNING("oci8 and oci8-19 provide the same extension and cannot both be built statically"); - PHP_OCI8 = "no" - } -} - if (PHP_OCI8_11G != "no" && PHP_OCI8_19 != "no") { if (!PHP_OCI8_11G_SHARED && !PHP_OCI8_19_SHARED) { WARNING("oci8-11g and oci8-19 provide the same extension and cannot both be built statically"); @@ -42,41 +21,6 @@ if (PHP_OCI8_12C != "no" && PHP_OCI8_19 != "no") { } } -ARG_WITH("oci8", "OCI8 support", "no"); - -if (PHP_OCI8 != "no") { - - oci8_dirs = new Array( - PHP_OCI8 - ); - - oci8_lib_paths = ""; - oci8_inc_paths = ""; - - // find the Oracle install - for (i = 0; i < oci8_dirs.length; i++) { - oci8_lib_paths += oci8_dirs[i] + "\\lib;"; - oci8_lib_paths += oci8_dirs[i] + "\\lib\\msvc;"; - oci8_inc_paths += oci8_dirs[i] + "\\include;"; - } - - oci8_inc_paths += PHP_PHP_BUILD + "\\include\\instantclient;" - oci8_lib_paths += PHP_PHP_BUILD + "\\lib\\instantclient;"; - - if (CHECK_HEADER_ADD_INCLUDE("oci.h", "CFLAGS_OCI8", oci8_inc_paths) && - CHECK_LIB("oci.lib", "oci8", oci8_lib_paths)) - { - EXTENSION('oci8', 'oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c oci8_failover.c'); - - AC_DEFINE('HAVE_OCI8', 1); - AC_DEFINE('HAVE_OCI_INSTANT_CLIENT', 1); - - } else { - WARNING("oci8 not enabled: Oracle Database client libraries or Oracle 10g Instant Client not found"); - PHP_OCI8 = "no" - } -} - ARG_WITH("oci8-11g", "OCI8 support using Oracle 11g Instant Client", "no"); if (PHP_OCI8_11G != "no") { From 3a3eeb4f833613c6bf8e1055e0845d29056bb46b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 16 Dec 2021 12:32:09 +0300 Subject: [PATCH 39/75] Fixed build in separate directory --- ext/standard/config.m4 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/standard/config.m4 b/ext/standard/config.m4 index 9ca92c610b9ed..2e78b2df01888 100644 --- a/ext/standard/config.m4 +++ b/ext/standard/config.m4 @@ -463,5 +463,7 @@ PHP_NEW_EXTENSION(standard, array.c base64.c basic_functions.c browscap.c crc32. random.c net.c hrtime.c crc32_x86.c libavifinfo/avifinfo.c,,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) +PHP_ADD_BUILD_DIR($ext_builddir/libavifinfo) + PHP_ADD_MAKEFILE_FRAGMENT PHP_INSTALL_HEADERS([ext/standard/]) From 79fac32d6bf8c480d0e930da752f61b0d11543e1 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 16 Dec 2021 17:37:01 +0300 Subject: [PATCH 40/75] Don't call zend_attach/detach_symbol_table() for op_arrays without local variables --- Zend/zend_execute.c | 4 +++- Zend/zend_vm_def.h | 15 +++++++++++---- Zend/zend_vm_execute.h | 30 ++++++++++++++++++++++-------- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 8415f9b87d908..c332201a8fe78 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3839,7 +3839,9 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu EX(call) = NULL; EX(return_value) = return_value; - zend_attach_symbol_table(execute_data); + if (op_array->last_var) { + zend_attach_symbol_table(execute_data); + } if (!ZEND_MAP_PTR(op_array->run_time_cache)) { void *ptr; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 9408b66408c8f..7105ca320bc55 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2863,7 +2863,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) LOAD_NEXT_OPLINE(); ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); @@ -2874,7 +2876,9 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - zend_attach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -2905,11 +2909,14 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } old_execute_data = EX(prev_execute_data); while (old_execute_data) { if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->symbol_table == symbol_table + && old_execute_data->func->op_array.last_var > 0) { zend_attach_symbol_table(old_execute_data); } break; diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 6a6476b2ce526..d6e67c16dbd3a 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1145,7 +1145,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper LOAD_NEXT_OPLINE(); ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); @@ -1156,7 +1158,9 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - zend_attach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -1187,11 +1191,14 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } old_execute_data = EX(prev_execute_data); while (old_execute_data) { if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->symbol_table == symbol_table + && old_execute_data->func->op_array.last_var > 0) { zend_attach_symbol_table(old_execute_data); } break; @@ -55398,7 +55405,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) LOAD_NEXT_OPLINE(); ZEND_VM_LEAVE(); } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); @@ -55409,7 +55418,9 @@ ZEND_API void execute_ex(zend_execute_data *ex) execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - zend_attach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -55440,11 +55451,14 @@ ZEND_API void execute_ex(zend_execute_data *ex) } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); - zend_detach_symbol_table(execute_data); + if (EX(func)->op_array.last_var > 0) { + zend_detach_symbol_table(execute_data); + } old_execute_data = EX(prev_execute_data); while (old_execute_data) { if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->symbol_table == symbol_table + && old_execute_data->func->op_array.last_var > 0) { zend_attach_symbol_table(old_execute_data); } break; From 67bb79259baef3586b1bbe1f9026e371ed5e27b7 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 16 Dec 2021 19:42:29 +0300 Subject: [PATCH 41/75] Don't execute INCLUDE for empty op_arrays. --- Zend/zend_vm_def.h | 20 ++++++++--- Zend/zend_vm_execute.h | 80 +++++++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 20 deletions(-) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 7105ca320bc55..4d0b68873a7b1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6286,10 +6286,24 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL, SPEC(OBSER if (RETURN_VALUE_USED(opline)) { ZVAL_TRUE(EX_VAR(opline->result.var)); } - } else if (EXPECTED(new_op_array != NULL)) { + } else if (UNEXPECTED(new_op_array == NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + } else if (new_op_array->last == 1 + && new_op_array->opcodes[0].opcode == ZEND_RETURN + && new_op_array->opcodes[0].op1_type == IS_CONST) { + if (RETURN_VALUE_USED(opline)) { + const zend_op *op = new_op_array->opcodes; + + ZVAL_COPY(EX_VAR(opline->result.var), RT_CONSTANT(op, op->op1)); + } + zend_destroy_static_vars(new_op_array); + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + } else { zval *return_value = NULL; zend_execute_data *call; - if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); } @@ -6328,8 +6342,6 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMPVAR|CV, ANY, EVAL, SPEC(OBSER UNDEF_RESULT(); HANDLE_EXCEPTION(); } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_FALSE(EX_VAR(opline->result.var)); } FREE_OP1(); ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d6e67c16dbd3a..3234a9d711c72 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4864,10 +4864,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN if (RETURN_VALUE_USED(opline)) { ZVAL_TRUE(EX_VAR(opline->result.var)); } - } else if (EXPECTED(new_op_array != NULL)) { + } else if (UNEXPECTED(new_op_array == NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + } else if (new_op_array->last == 1 + && new_op_array->opcodes[0].opcode == ZEND_RETURN + && new_op_array->opcodes[0].op1_type == IS_CONST) { + if (RETURN_VALUE_USED(opline)) { + const zend_op *op = new_op_array->opcodes; + + ZVAL_COPY(EX_VAR(opline->result.var), RT_CONSTANT(op, op->op1)); + } + zend_destroy_static_vars(new_op_array); + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + } else { zval *return_value = NULL; zend_execute_data *call; - if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); } @@ -4906,8 +4920,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HAN UNDEF_RESULT(); HANDLE_EXCEPTION(); } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_FALSE(EX_VAR(opline->result.var)); } ZEND_VM_NEXT_OPCODE(); @@ -4934,10 +4946,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_OBSERVER_ if (RETURN_VALUE_USED(opline)) { ZVAL_TRUE(EX_VAR(opline->result.var)); } - } else if (EXPECTED(new_op_array != NULL)) { + } else if (UNEXPECTED(new_op_array == NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + } else if (new_op_array->last == 1 + && new_op_array->opcodes[0].opcode == ZEND_RETURN + && new_op_array->opcodes[0].op1_type == IS_CONST) { + if (RETURN_VALUE_USED(opline)) { + const zend_op *op = new_op_array->opcodes; + + ZVAL_COPY(EX_VAR(opline->result.var), RT_CONSTANT(op, op->op1)); + } + zend_destroy_static_vars(new_op_array); + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + } else { zval *return_value = NULL; zend_execute_data *call; - if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); } @@ -4976,8 +5002,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_OBSERVER_ UNDEF_RESULT(); HANDLE_EXCEPTION(); } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_FALSE(EX_VAR(opline->result.var)); } FREE_OP(opline->op1_type, opline->op1.var); ZEND_VM_NEXT_OPCODE(); @@ -14502,10 +14526,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HA if (RETURN_VALUE_USED(opline)) { ZVAL_TRUE(EX_VAR(opline->result.var)); } - } else if (EXPECTED(new_op_array != NULL)) { + } else if (UNEXPECTED(new_op_array == NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + } else if (new_op_array->last == 1 + && new_op_array->opcodes[0].opcode == ZEND_RETURN + && new_op_array->opcodes[0].op1_type == IS_CONST) { + if (RETURN_VALUE_USED(opline)) { + const zend_op *op = new_op_array->opcodes; + + ZVAL_COPY(EX_VAR(opline->result.var), RT_CONSTANT(op, op->op1)); + } + zend_destroy_static_vars(new_op_array); + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + } else { zval *return_value = NULL; zend_execute_data *call; - if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); } @@ -14544,8 +14582,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_TMPVAR_HA UNDEF_RESULT(); HANDLE_EXCEPTION(); } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_FALSE(EX_VAR(opline->result.var)); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE(); @@ -38644,10 +38680,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLE if (RETURN_VALUE_USED(opline)) { ZVAL_TRUE(EX_VAR(opline->result.var)); } - } else if (EXPECTED(new_op_array != NULL)) { + } else if (UNEXPECTED(new_op_array == NULL)) { + if (RETURN_VALUE_USED(opline)) { + ZVAL_FALSE(EX_VAR(opline->result.var)); + } + } else if (new_op_array->last == 1 + && new_op_array->opcodes[0].opcode == ZEND_RETURN + && new_op_array->opcodes[0].op1_type == IS_CONST) { + if (RETURN_VALUE_USED(opline)) { + const zend_op *op = new_op_array->opcodes; + + ZVAL_COPY(EX_VAR(opline->result.var), RT_CONSTANT(op, op->op1)); + } + zend_destroy_static_vars(new_op_array); + destroy_op_array(new_op_array); + efree_size(new_op_array, sizeof(zend_op_array)); + } else { zval *return_value = NULL; zend_execute_data *call; - if (RETURN_VALUE_USED(opline)) { return_value = EX_VAR(opline->result.var); } @@ -38686,8 +38736,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INCLUDE_OR_EVAL_SPEC_CV_HANDLE UNDEF_RESULT(); HANDLE_EXCEPTION(); } - } else if (RETURN_VALUE_USED(opline)) { - ZVAL_FALSE(EX_VAR(opline->result.var)); } ZEND_VM_NEXT_OPCODE(); From 192ea91debe10ba23f1576f43a666f5947ac3943 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 16 Dec 2021 21:44:43 +0300 Subject: [PATCH 42/75] Avoid useless symbol table reattaching on retutn from an included op_array --- Zend/zend_compile.h | 1 + Zend/zend_vm_def.h | 36 +++++++++++++-------- Zend/zend_vm_execute.h | 72 ++++++++++++++++++++++++++---------------- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 65d675d77f3fd..3e534e88ac4d2 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -556,6 +556,7 @@ struct _zend_execute_data { /* to prevent optimization in RETURN handler and */ /* keep all local variables for "fcall_end" handler */ #define ZEND_CALL_JIT_RESERVED (1 << 29) /* reserved for tracing JIT */ +#define ZEND_CALL_NEEDS_REATTACH (1 << 30) #define ZEND_CALL_SEND_ARG_BY_REF (1u << 31) #define ZEND_CALL_NESTED_FUNCTION (ZEND_CALL_FUNCTION | ZEND_CALL_NESTED) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 4d0b68873a7b1..4c691fe22b399 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2865,19 +2865,21 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); -#ifdef ZEND_PREFER_RELOAD - call_info = EX_CALL_INFO(); -#endif old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - if (EX(func)->op_array.last_var > 0) { - zend_attach_symbol_table(execute_data); + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } else { + ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); + } } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); @@ -2911,17 +2913,23 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); - } - old_execute_data = EX(prev_execute_data); - while (old_execute_data) { - if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table - && old_execute_data->func->op_array.last_var > 0) { - zend_attach_symbol_table(old_execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; + } + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + old_execute_data = EX(prev_execute_data); + while (old_execute_data) { + if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { + if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->func->op_array.last_var > 0) { + zend_attach_symbol_table(old_execute_data); + } else { + ZEND_ADD_CALL_FLAG(old_execute_data, ZEND_CALL_NEEDS_REATTACH); + } + } + break; } - break; + old_execute_data = old_execute_data->prev_execute_data; } - old_execute_data = old_execute_data->prev_execute_data; } EG(current_execute_data) = EX(prev_execute_data); ZEND_VM_RETURN(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 3234a9d711c72..349974a92e525 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1147,19 +1147,21 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); -#ifdef ZEND_PREFER_RELOAD - call_info = EX_CALL_INFO(); -#endif old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - if (EX(func)->op_array.last_var > 0) { - zend_attach_symbol_table(execute_data); + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } else { + ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); + } } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); @@ -1193,17 +1195,23 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); - } - old_execute_data = EX(prev_execute_data); - while (old_execute_data) { - if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table - && old_execute_data->func->op_array.last_var > 0) { - zend_attach_symbol_table(old_execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; + } + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + old_execute_data = EX(prev_execute_data); + while (old_execute_data) { + if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { + if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->func->op_array.last_var > 0) { + zend_attach_symbol_table(old_execute_data); + } else { + ZEND_ADD_CALL_FLAG(old_execute_data, ZEND_CALL_NEEDS_REATTACH); + } + } + break; } - break; + old_execute_data = old_execute_data->prev_execute_data; } - old_execute_data = old_execute_data->prev_execute_data; } EG(current_execute_data) = EX(prev_execute_data); ZEND_VM_RETURN(); @@ -55455,19 +55463,21 @@ ZEND_API void execute_ex(zend_execute_data *ex) } else if (EXPECTED((call_info & ZEND_CALL_TOP) == 0)) { if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; } zend_destroy_static_vars(&EX(func)->op_array); destroy_op_array(&EX(func)->op_array); efree_size(EX(func), sizeof(zend_op_array)); -#ifdef ZEND_PREFER_RELOAD - call_info = EX_CALL_INFO(); -#endif old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); - if (EX(func)->op_array.last_var > 0) { - zend_attach_symbol_table(execute_data); + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + if (EX(func)->op_array.last_var > 0) { + zend_attach_symbol_table(execute_data); + } else { + ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); + } } if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); @@ -55501,17 +55511,23 @@ ZEND_API void execute_ex(zend_execute_data *ex) if (EX(func)->op_array.last_var > 0) { zend_detach_symbol_table(execute_data); - } - old_execute_data = EX(prev_execute_data); - while (old_execute_data) { - if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { - if (old_execute_data->symbol_table == symbol_table - && old_execute_data->func->op_array.last_var > 0) { - zend_attach_symbol_table(old_execute_data); + call_info |= ZEND_CALL_NEEDS_REATTACH; + } + if (call_info & ZEND_CALL_NEEDS_REATTACH) { + old_execute_data = EX(prev_execute_data); + while (old_execute_data) { + if (old_execute_data->func && (ZEND_CALL_INFO(old_execute_data) & ZEND_CALL_HAS_SYMBOL_TABLE)) { + if (old_execute_data->symbol_table == symbol_table) { + if (old_execute_data->func->op_array.last_var > 0) { + zend_attach_symbol_table(old_execute_data); + } else { + ZEND_ADD_CALL_FLAG(old_execute_data, ZEND_CALL_NEEDS_REATTACH); + } + } + break; } - break; + old_execute_data = old_execute_data->prev_execute_data; } - old_execute_data = old_execute_data->prev_execute_data; } EG(current_execute_data) = EX(prev_execute_data); ZEND_VM_RETURN(); From 66306030ad26da49bbc6c07624fa3b4b1f1d9757 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 17 Dec 2021 12:31:48 +0300 Subject: [PATCH 43/75] JIT: Fix incorrect type store elimination Fixes oss-fuzz #42388 --- ext/opcache/jit/zend_jit_trace.c | 16 +++++----- ext/opcache/tests/jit/assign_048.phpt | 43 +++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 9 deletions(-) create mode 100644 ext/opcache/tests/jit/assign_048.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index dd37f33ad6853..9a310d3e35197 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -4609,15 +4609,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par op2_info = OP2_INFO(); CHECK_OP2_TRACE_TYPE(); op1_info = OP1_INFO(); - if (ssa->vars[ssa_op->op1_use].no_val) { - if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG - || (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_DOUBLE) { - if (STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_LONG - && STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_DOUBLE) { - /* type may be not set */ - op1_info |= MAY_BE_NULL; - } - } + if ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG + || (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_DOUBLE) { + if (STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_LONG + && STACK_MEM_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var)) != IS_DOUBLE) { + /* type may be not set */ + op1_info |= MAY_BE_NULL; + } } CHECK_OP1_TRACE_TYPE(); op1_def_info = OP1_DEF_INFO(); diff --git a/ext/opcache/tests/jit/assign_048.phpt b/ext/opcache/tests/jit/assign_048.phpt new file mode 100644 index 0000000000000..a6bcf14933a78 --- /dev/null +++ b/ext/opcache/tests/jit/assign_048.phpt @@ -0,0 +1,43 @@ +--TEST-- +JIT ASSIGN: incorrect type store elimination +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.protect_memory=1 +opcache.optimization_level=0x7FFEBFFF +--FILE-- + +DONE +--EXPECTF-- +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 + +Warning: Undefined variable $a in %sassign_048.php on line 7 +DONE From 2745cd99973a5b422c66d62b9d9229da22e82a34 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 17 Dec 2021 12:49:58 +0300 Subject: [PATCH 44/75] Fix array clobbering by user error handler Fixes oss-fuzz #42503 --- ext/opcache/jit/zend_jit_helpers.c | 53 +++++++++++++++++++++- ext/opcache/tests/jit/fetch_dim_w_003.phpt | 17 +++++++ 2 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/jit/fetch_dim_w_003.phpt diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index e7cd2796b589d..5257a6af9c819 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -730,10 +730,61 @@ static zval* ZEND_FASTCALL zend_jit_fetch_dim_w_helper(zend_array *ht, zval *dim offset_key = ZSTR_EMPTY_ALLOC(); goto str_index; case IS_DOUBLE: - hval = zend_dval_to_lval_safe(Z_DVAL_P(dim)); + hval = zend_dval_to_lval(Z_DVAL_P(dim)); + if (!zend_is_long_compatible(Z_DVAL_P(dim), hval)) { + /* The array may be destroyed while throwing the notice. + * Temporarily increase the refcount to detect this situation. */ + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(ht); + } + execute_data = EG(current_execute_data); + opline = EX(opline); + zend_incompatible_double_to_long_error(Z_DVAL_P(dim)); + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) { + zend_array_destroy(ht); + if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + if (EG(exception)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } else { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } + return NULL; + } + if (EG(exception)) { + if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + return NULL; + } + } goto num_index; case IS_RESOURCE: + /* The array may be destroyed while throwing the notice. + * Temporarily increase the refcount to detect this situation. */ + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE)) { + GC_ADDREF(ht); + } + execute_data = EG(current_execute_data); + opline = EX(opline); zend_use_resource_as_offset(dim); + if (!(GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) && !GC_DELREF(ht)) { + zend_array_destroy(ht); + if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + if (EG(exception)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } else { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } + return NULL; + } + if (EG(exception)) { + if (opline->result_type & (IS_VAR | IS_TMP_VAR)) { + ZVAL_UNDEF(EX_VAR(opline->result.var)); + } + return NULL; + } hval = Z_RES_HANDLE_P(dim); goto num_index; case IS_FALSE: diff --git a/ext/opcache/tests/jit/fetch_dim_w_003.phpt b/ext/opcache/tests/jit/fetch_dim_w_003.phpt new file mode 100644 index 0000000000000..33fc2ccbb8459 --- /dev/null +++ b/ext/opcache/tests/jit/fetch_dim_w_003.phpt @@ -0,0 +1,17 @@ +--TEST-- +JIT FETCH_DIM_W: 003 +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--FILE-- + +DONE +--EXPECT-- +DONE From a5f782170bcb116d2c2092b68c1333239961ed8d Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 19 Dec 2021 10:04:09 -0500 Subject: [PATCH 45/75] Fix typos in opcache code comments, tests (#7794) --- ext/opcache/ZendAccelerator.c | 4 +- ext/opcache/jit/vtune/jitprofiling.h | 4 +- ext/opcache/jit/zend_jit.h | 2 +- ext/opcache/jit/zend_jit_arm64.dasc | 44 ++++++++++---------- ext/opcache/jit/zend_jit_trace.c | 2 +- ext/opcache/jit/zend_jit_x86.dasc | 8 ++-- ext/opcache/tests/jit/and_001.phpt | 2 +- ext/opcache/tests/jit/assign_045.phpt | 2 +- ext/opcache/tests/jit/assign_046.phpt | 2 +- ext/opcache/tests/jit/assign_dim_op_006.phpt | 2 +- ext/opcache/tests/jit/fetch_r_001.phpt | 2 +- 11 files changed, 37 insertions(+), 37 deletions(-) diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index 2b7c31fe60789..1b976d8656ab4 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2349,7 +2349,7 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_map_ptr_extend(ZCSG(map_ptr_last)); return entry->ce; } - ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be posible ??? + ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be possible ??? } } @@ -3515,7 +3515,7 @@ static void preload_restart(void) } static size_t preload_try_strip_filename(zend_string *filename) { - /*FIXME: better way to hanlde eval()'d code? see COMPILED_STRING_DESCRIPTION_FORMAT */ + /*FIXME: better way to handle eval()'d code? see COMPILED_STRING_DESCRIPTION_FORMAT */ if (ZSTR_LEN(filename) > sizeof(" eval()'d code") && *(ZSTR_VAL(filename) + ZSTR_LEN(filename) - sizeof(" eval()'d code")) == ':') { const char *cfilename = ZSTR_VAL(filename); diff --git a/ext/opcache/jit/vtune/jitprofiling.h b/ext/opcache/jit/vtune/jitprofiling.h index 3e166c04d4359..21d23f8ec7d99 100644 --- a/ext/opcache/jit/vtune/jitprofiling.h +++ b/ext/opcache/jit/vtune/jitprofiling.h @@ -316,7 +316,7 @@ typedef enum _iJIT_IsProfilingActiveFlags */ typedef struct _LineNumberInfo { - unsigned int Offset; /**<\brief Offset from the begining of the code region. */ + unsigned int Offset; /**<\brief Offset from the beginning of the code region. */ unsigned int LineNumber; /**<\brief Matching source line number offset (from beginning of source file). */ } *pLineNumberInfo, LineNumberInfo; @@ -670,7 +670,7 @@ unsigned int JITAPI iJIT_GetNewMethodID(void); iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void); /** - * @brief Reports infomation about JIT-compiled code to the agent. + * @brief Reports information about JIT-compiled code to the agent. * * The reported information is used to attribute samples obtained from any * Intel(R) VTune(TM) Amplifier collector. This API needs to be called diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h index 21d1774c111b6..d22422181af9c 100644 --- a/ext/opcache/jit/zend_jit.h +++ b/ext/opcache/jit/zend_jit.h @@ -75,7 +75,7 @@ #define ZEND_JIT_DEBUG_TRACE_TSSA (1<<19) #define ZEND_JIT_DEBUG_TRACE_EXIT_INFO (1<<20) -#define ZEND_JIT_DEBUG_PERSISTENT 0x1f0 /* profile and debbuger flags can't be changed at run-time */ +#define ZEND_JIT_DEBUG_PERSISTENT 0x1f0 /* profile and debugger flags can't be changed at run-time */ #define ZEND_JIT_TRACE_MAX_LENGTH 1024 /* max length of single trace */ #define ZEND_JIT_TRACE_MAX_EXITS 512 /* max number of side exits per trace */ diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc index ee89defac900f..7bae3752d7137 100644 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ b/ext/opcache/jit/zend_jit_arm64.dasc @@ -1106,7 +1106,7 @@ static bool logical_immediate_p(uint64_t value, uint32_t reg_size) | // In x64, if the range of this LONG value can be represented via INT type, only move the low 32 bits into dst_addr. | // Note that imm32 is signed extended to 64 bits during mov. | // In aarch64, we choose to handle both cases in the same way. Even though 4 mov's are used for 64-bit value and 2 mov's are -| // needed for 32-bit value, an extra ext insn is needed for 32-bit vlaue. +| // needed for 32-bit value, an extra ext insn is needed for 32-bit value. | SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) || } || } @@ -1794,7 +1794,7 @@ static int zend_jit_interrupt_handler_stub(dasm_State **Dst) | ldp x29, x30, [sp], # SPAD // stack alignment | JMP_IP TMP1 } else { - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #1 // ZEND_VM_ENTER | ret @@ -1821,7 +1821,7 @@ static int zend_jit_exception_handler_stub(dasm_State **Dst) } else { | mov FCARG1x, FP | EXT_CALL handler, REG0 - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | tbnz RETVALw, #31, >1 | mov RETVALw, #1 // ZEND_VM_ENTER @@ -1909,7 +1909,7 @@ static int zend_jit_leave_function_stub(dasm_State **Dst) | ldp x29, x30, [sp], # SPAD // stack alignment } else { | mov FCARG2x, FP - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment } | TST_32_WITH_CONST FCARG1w, ZEND_CALL_TOP, TMP1w @@ -1947,7 +1947,7 @@ static int zend_jit_leave_throw_stub(dasm_State **Dst) |5: | // opline = EG(exception_op); | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2 - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #2 // ZEND_VM_LEAVE | ret @@ -2418,7 +2418,7 @@ static int zend_jit_trace_halt_stub(dasm_State **Dst) | mov IP, xzr // PC must be zero | ret } else { - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | movn RETVALx, #0 // ZEND_VM_RETURN (-1) | ret @@ -2492,7 +2492,7 @@ static int zend_jit_trace_exit_stub(dasm_State **Dst) | ldp x29, x30, [sp], # SPAD // stack alignment | JMP_IP TMP1 } else { - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #1 // ZEND_VM_ENTER | ret @@ -2536,7 +2536,7 @@ static int zend_jit_trace_exit_stub(dasm_State **Dst) | tst RETVALw, RETVALw | blt ->trace_halt | - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #1 // ZEND_VM_ENTER | ret @@ -2556,7 +2556,7 @@ static int zend_jit_trace_escape_stub(dasm_State **Dst) | ldp x29, x30, [sp], # SPAD // stack alignment | JMP_IP, TMP1 } else { - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #1 // ZEND_VM_ENTER | ret @@ -3038,7 +3038,7 @@ static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size if (((ins ^ (uint32_t)delta) & 0x01ffffffu) == 0) { delta = (uint32_t*)to_addr - ins_ptr; if (((delta + 0x02000000) >> 26) != 0) { - abort(); // brnach target out of range + abort(); // branch target out of range } *ins_ptr = (ins & 0xfc000000u) | ((uint32_t)delta & 0x03ffffffu); ret++; @@ -3056,10 +3056,10 @@ static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size if (veneer) { delta = (uint32_t*)veneer - ins_ptr; if (((delta + 0x40000) >> 19) != 0) { - abort(); // brnach target out of range + abort(); // branch target out of range } } else { - abort(); // brnach target out of range + abort(); // branch target out of range } } *ins_ptr = (ins & 0xff00001fu) | (((uint32_t)delta & 0x7ffffu) << 5); @@ -3074,10 +3074,10 @@ static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size if (veneer) { delta = (uint32_t*)veneer - ins_ptr; if (((delta + 0x2000) >> 14) != 0) { - abort(); // brnach target out of range + abort(); // branch target out of range } } else { - abort(); // brnach target out of range + abort(); // branch target out of range } } *ins_ptr = (ins & 0xfff8001fu) | (((uint32_t)delta & 0x3fffu) << 5); @@ -3169,7 +3169,7 @@ static int zend_jit_trace_return(dasm_State **Dst, bool original_handler, const | ldr REG0, [IP, REG0] | blr REG0 } - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment if (!original_handler || !opline || (opline->opcode != ZEND_RETURN @@ -3452,7 +3452,7 @@ static int zend_jit_tail_handler(dasm_State **Dst, const zend_op *opline) | ldp x29, x30, [sp], # SPAD // stack alignment } else { | mov FCARG1x, FP - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment } | EXT_JMP handler, REG0 @@ -4972,7 +4972,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2x, op2_addr | EXT_CALL zend_jit_fast_assign_concat_helper, REG0 - /* concatination with itself may reduce refcount */ + /* concatenation with itself may reduce refcount */ op2_info |= MAY_BE_RC1; } else { if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { @@ -4986,7 +4986,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, | EXT_CALL zend_jit_fast_concat_tmp_helper, REG0 } } - /* concatination with empty string may increase refcount */ + /* concatenation with empty string may increase refcount */ op2_info |= MAY_BE_RCN; | FREE_OP op2_type, op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 |5: @@ -5011,7 +5011,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, | LOAD_ZVAL_ADDR CARG3, op2_addr | SET_EX_OPLINE opline, REG0 | EXT_CALL concat_function, REG0 - /* concatination with empty string may increase refcount */ + /* concatenation with empty string may increase refcount */ op1_info |= MAY_BE_RCN; op2_info |= MAY_BE_RCN; | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 @@ -9528,7 +9528,7 @@ static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend | ldp x29, x30, [sp], # SPAD // stack alignment | JMP_IP TMP1 } else { - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #1 // ZEND_VM_ENTER | ret @@ -10865,7 +10865,7 @@ static int zend_jit_leave_func(dasm_State **Dst, // the value of execute_data in execute_ex() | NIY // TODO #else - | ldp FP, RX, T2 // retore FP and IP + | ldp FP, RX, T2 // restore FP and IP | ldp x29, x30, [sp], # NR_SPAD // stack alignment | mov RETVALx, #2 // ZEND_VM_LEAVE ???? | ret @@ -14832,7 +14832,7 @@ static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline, | IF_NOT_ZVAL_TYPE var_addr, IS_INDIRECT, &exit_addr, ZREG_TMP1 | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 } else { - /* May be already loaded into FCARG1a or RAX by previus FETCH_OBJ_W/DIM_W */ + /* May be already loaded into FCARG1a or RAX by previous FETCH_OBJ_W/DIM_W */ if (opline->op1_type != IS_VAR || (opline-1)->result_type != IS_VAR || (opline-1)->result.var != opline->op1.var || diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index ab3faca7e05dc..b941447f86103 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -7854,7 +7854,7 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf zend_jit_trace_info *t = &zend_jit_traces[trace_num]; int repeat_last_opline = 0; - /* Deoptimizatoion of VM stack state */ + /* Deoptimization of VM stack state */ uint32_t i; uint32_t stack_size = t->exit_info[exit_num].stack_size; zend_jit_trace_stack *stack = t->stack_map + t->exit_info[exit_num].stack_offset; diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 825a58207822d..bc5c298650e2f 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -5425,7 +5425,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, } | LOAD_ZVAL_ADDR FCARG2a, op2_addr | EXT_CALL zend_jit_fast_assign_concat_helper, r0 - /* concatination with itself may reduce refcount */ + /* concatenation with itself may reduce refcount */ op2_info |= MAY_BE_RC1; } else { if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { @@ -5447,7 +5447,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, | add r4, 12 |.endif } - /* concatination with empty string may increase refcount */ + /* concatenation with empty string may increase refcount */ op2_info |= MAY_BE_RCN; | FREE_OP op2_type, op2, op2_info, 0, opline |5: @@ -5481,7 +5481,7 @@ static int zend_jit_concat_helper(dasm_State **Dst, |.if not(X64) | add r4, 12 |.endif - /* concatination with empty string may increase refcount */ + /* concatenation with empty string may increase refcount */ op1_info |= MAY_BE_RCN; op2_info |= MAY_BE_RCN; | FREE_OP op1_type, op1, op1_info, 0, NULL @@ -15700,7 +15700,7 @@ static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline, | IF_NOT_ZVAL_TYPE var_addr, IS_INDIRECT, &exit_addr | GET_ZVAL_PTR FCARG1a, var_addr } else { - /* May be already loaded into FCARG1a or RAX by previus FETCH_OBJ_W/DIM_W */ + /* May be already loaded into FCARG1a or RAX by previous FETCH_OBJ_W/DIM_W */ if (opline->op1_type != IS_VAR || (opline-1)->result_type != IS_VAR || (opline-1)->result.var != opline->op1.var || diff --git a/ext/opcache/tests/jit/and_001.phpt b/ext/opcache/tests/jit/and_001.phpt index f44bb4e13fb87..273310f1f5efd 100644 --- a/ext/opcache/tests/jit/and_001.phpt +++ b/ext/opcache/tests/jit/and_001.phpt @@ -1,5 +1,5 @@ --TEST-- -JIT BW_AND: 001 (emty string) +JIT BW_AND: 001 (empty string) --INI-- opcache.enable=1 opcache.enable_cli=1 diff --git a/ext/opcache/tests/jit/assign_045.phpt b/ext/opcache/tests/jit/assign_045.phpt index 6c5c204f66f4f..f9e7d31db5d2f 100644 --- a/ext/opcache/tests/jit/assign_045.phpt +++ b/ext/opcache/tests/jit/assign_045.phpt @@ -1,5 +1,5 @@ --TEST-- -JIT ASSIGN: incorrect assumption about in-memeory zval type +JIT ASSIGN: incorrect assumption about in-memory zval type --INI-- opcache.enable=1 opcache.enable_cli=1 diff --git a/ext/opcache/tests/jit/assign_046.phpt b/ext/opcache/tests/jit/assign_046.phpt index fe27bdd3a2933..201f619f11bdf 100644 --- a/ext/opcache/tests/jit/assign_046.phpt +++ b/ext/opcache/tests/jit/assign_046.phpt @@ -1,5 +1,5 @@ --TEST-- -JIT ASSIGN: incorrect assumption about in-memeory zval type +JIT ASSIGN: incorrect assumption about in-memory zval type --INI-- opcache.enable=1 opcache.enable_cli=1 diff --git a/ext/opcache/tests/jit/assign_dim_op_006.phpt b/ext/opcache/tests/jit/assign_dim_op_006.phpt index 075a6c34e95d9..0ed14cf9ae8ed 100644 --- a/ext/opcache/tests/jit/assign_dim_op_006.phpt +++ b/ext/opcache/tests/jit/assign_dim_op_006.phpt @@ -1,5 +1,5 @@ --TEST-- -JIT ASSIGN_DIM_OP 006: Cloberring array be user error handler +JIT ASSIGN_DIM_OP 006: Clobbering array be user error handler --INI-- opcache.enable=1 opcache.enable_cli=1 diff --git a/ext/opcache/tests/jit/fetch_r_001.phpt b/ext/opcache/tests/jit/fetch_r_001.phpt index db5b7ba42bd74..53b49a98d8922 100644 --- a/ext/opcache/tests/jit/fetch_r_001.phpt +++ b/ext/opcache/tests/jit/fetch_r_001.phpt @@ -1,5 +1,5 @@ --TEST-- -FETCH_R: 001 result reference counter may be decremented befor use +FETCH_R: 001 result reference counter may be decremented before use --INI-- opcache.enable=1 opcache.enable_cli=1 From 9a594174456b4c0938894a1e3ba61091222f6471 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Sun, 19 Dec 2021 10:12:35 -0500 Subject: [PATCH 46/75] [skip ci] Document how to quickly check if jit .dasc files transpile, how to test the jit in different architectures. (#7768) --- ext/opcache/jit/Dockerfile.arm64.example | 15 +++ ext/opcache/jit/README.md | 116 ++++++++++++++++++++++- sapi/fuzzer/README.md | 2 +- 3 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 ext/opcache/jit/Dockerfile.arm64.example diff --git a/ext/opcache/jit/Dockerfile.arm64.example b/ext/opcache/jit/Dockerfile.arm64.example new file mode 100644 index 0000000000000..e7b6a03b2db89 --- /dev/null +++ b/ext/opcache/jit/Dockerfile.arm64.example @@ -0,0 +1,15 @@ +# Force this to build with arm64 even when the host architecture is different. +# This requires that cross-compilation support be enabled with the steps in https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/ +FROM --platform=arm64 ubuntu:20.04 +RUN apt-get update -y +# DEBIAN_FRONTEND=noninteractive is needed to stop the tzdata installation from hanging. +ENV DEBIAN_FRONTEND=noninteractive +RUN apt-get install -y tzdata +RUN apt-get install -y pkg-config build-essential autoconf bison re2c \ + libxml2-dev libsqlite3-dev + +ADD . /php-src/ +WORKDIR /php-src +RUN ./buildconf +# Compile a minimal debug build. --enable-debug adds runtime assertions and is slower than regular builds. +RUN ./configure --enable-debug --disable-all --enable-opcache && make clean && make -j$(nproc) diff --git a/ext/opcache/jit/README.md b/ext/opcache/jit/README.md index 2cc08d2827a23..3119f37811cf8 100644 --- a/ext/opcache/jit/README.md +++ b/ext/opcache/jit/README.md @@ -24,5 +24,119 @@ was almost 100 times slower, making it prohibitively expensive to use. [The unofficial DynASM Documentation](https://corsix.github.io/dynasm-doc/tutorial.html) has a tutorial, reference, and instruction listing. -`zend_jit_x86.dasc` gets automatically converted to `zend_jit_x86.c` by the bundled +In x86 builds, `zend_jit_x86.dasc` gets automatically converted to `zend_jit_x86.c` by the bundled `dynasm` during `make`. + +In arm64 builds, `zend_jit_arm64.dasc` gets automatically converted to `zend_jit_arm64.c` by the bundled +`dynasm` during `make`. + +Running tests of the JIT +------------------------ + +Then, to test the JIT, e.g. with opcache.jit=tracing, an example command +based on what is used to test in Azure CI: + +``` +make test TESTS="-d opcache.jit_buffer_size=16M -d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit=tracing --repeat 2 --show-diff -j$(nproc) ext/opcache Zend" +``` + +- `opcache.jit_buffer_size=16M` enables the JIT in tests by providing 16 megabytes of + memory to use with the JIT to test with. +- `opcache.protect_memory=1` will detect writing to memory that is meant to be + read-only, which is sometimes the cause of opcache bugs. +- `--repeat 2` is optional, but used in CI since some JIT bugs only show up after processing a + request multiple times (the first request compiles the trace and the second executes it) +- `-j$(nproc)` runs as many workers to run tests as there are CPUs. +- `ext/opcache/` and `Zend` are the folders with the tests to run, in this case opcache + and the Zend engine itself. If no folders are provided, all tests are run. + +When investigating test failures such as segmentation faults, +configuring the build of php with `--enable-address-sanitizer` to enable +[AddressSanitizer](https://github.com/google/sanitizers/wiki/AddressSanitizer) is often useful. + +Some of the time, adding `-m --show-mem` to the `TESTS` configuration is also useful to test with [valgrind](https://valgrind.org/) to detect out of bounds memory accesses. +Using valgrind is slower at detecting invalid memory read/writes than AddressSanitizer when running large numbers of tests, but does not require rebuilding php. + +Note that the JIT supports 3 different architectures: `X86_64`, `i386`, and `arm64`. + +Miscellaneous +------------- + +### Checking dasc files for in a different architecture + +The following command can be run to manually check if the modified `.dasc code` is at least transpilable +for an architecture you're not using, e.g.: + +For arm64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D ARM64=1 -o ext/opcache/jit/zend_jit_arm64.ignored.c ext/opcache/jit/zend_jit_arm64.dasc` + +For x86_64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D X64=1 -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc` + +For i386 (i.e. 32-bit): `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc` + +### How to build 32-bit builds on x86_64 environments + +Refer to [../../../azure/i386](../../../azure/i386/apt.yml) for examples of +dependencies to install. + +If you are running this natively (outside of Docker or a VM): + +- Consider running in docker/a VM instead if you are unfamiliar with this. +- Avoid purging packages. +- Avoid `-y` - if the package manager warns you that the dependencies conflict + then **don't** try to force install them. + +#### Prerequisites for 32-bit builds + +This assumes you are using a Debian-based Linux distribution and have already +set up prerequisites for regular development. + +``` +sudo dpkg --add-architecture i386 +sudo apt-get update -y +# As well as anything else from azure/i386/apt.yml that you're testing locally +sudo apt-get install \ + gcc-multilib g++-multilib \ + libxml2-dev:i386 \ + libc6:i386 +``` + +#### Compiling 32-bit builds + +This assumes you are using a Debian-based Linux distribution and have already +set up prerequisites for 32-bit development. + +``` +export LDFLAGS=-L/usr/lib/i386-linux-gnu +export CFLAGS='-m32' +export CXXFLAGS='-m32' +export PKG_CONFIG=/usr/bin/i686-linux-gnu-pkg-config +./configure --disable-all --enable-opcache --build=i686-pc-linux-gnu +make -j$(nproc) +``` + +#### Running tests of the JIT on 32-bit builds + +See the section "Running tests of the JIT". + +### Testing the jit with arm64 on x86 computers + +https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/ +may be useful for local development. + +Note that this is slower than compiling and testing natively. + +``` +# After following steps in https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/ +cp .gitignore .dockerignore +echo .git >> .dockerignore + +docker build --network=host -t php-src-arm64-example -f ext/opcache/jit/Dockerfile.arm64.example . +docker run -it --rm php-src-arm64-example +``` + +Then, the docker image can be used to run tests with `make test`. +For example, to test `ext/opcache` in parallel with the tracing JIT enabled: + +``` +docker run -it php-src-arms-example make test TESTS="-d opcache.jit_buffer_size=16M -d opcache.enable=1 -d opcache.enable_cli=1 -d opcache.protect_memory=1 -d opcache.jit=tracing --repeat 2 --show-diff -j$(nproc) ext/opcache" +``` diff --git a/sapi/fuzzer/README.md b/sapi/fuzzer/README.md index 2099a34bfbf40..63de20aa1ca76 100644 --- a/sapi/fuzzer/README.md +++ b/sapi/fuzzer/README.md @@ -1,7 +1,7 @@ Fuzzing SAPI for PHP -------------------- -The following `./configure` options can be used to enable the fuzzing SAPI, as well as all availablefuzzers. If you don't build the exif/json/mbstring extensions, fuzzers for these extensions will not be built. +The following `./configure` options can be used to enable the fuzzing SAPI, as well as all available fuzzers. If you don't build the exif/json/mbstring extensions, fuzzers for these extensions will not be built. ```sh CC=clang CXX=clang++ \ From 3587e13ab3dc256ff2ebfe0f7aabc46bc5441cb7 Mon Sep 17 00:00:00 2001 From: Yifan Tong Date: Sun, 19 Dec 2021 05:39:54 +0100 Subject: [PATCH 47/75] Fix FILTER_FLAG_NO_RES_RANGE flag `2001:10::/28` is a reserved IPv6 range. But there's a typo in GH-7476, which caused IPv6 address like `240b:0010::1` will be filtered by the flag `FILTER_FLAG_NO_RES_RANGE`. http://www.faqs.org/rfcs/rfc6890.html Closes GH-7790. --- NEWS | 3 +++ ext/filter/logical_filters.c | 2 +- ext/filter/tests/bug47435.phpt | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index ddc18717a3294..ae1d224b6268d 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,9 @@ PHP NEWS . Fixed bug #81585 (cached_chunks are not counted to real_size on shutdown). (cmb) +- Filter: + . Fixed FILTER_FLAG_NO_RES_RANGE flag. (Yifan Tong) + - Hash: . Fixed bug GH-7759 (Incorrect return types for hash() and hash_hmac()). (cmb) diff --git a/ext/filter/logical_filters.c b/ext/filter/logical_filters.c index 6bf5e9a7cfb1d..1bf7c00d13c68 100644 --- a/ext/filter/logical_filters.c +++ b/ext/filter/logical_filters.c @@ -929,7 +929,7 @@ void php_filter_validate_ip(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */ && ip[4] == 0 && ip[5] == 0 && ip[6] == 0 && (ip[7] == 0 || ip[7] == 1)) || (ip[0] == 0x5f) || (ip[0] >= 0xfe80 && ip[0] <= 0xfebf) - || ((ip[0] == 0x2001 && ip[1] == 0x0db8) || (ip[1] >= 0x0010 && ip[1] <= 0x001f)) + || (ip[0] == 0x2001 && (ip[1] == 0x0db8 || (ip[1] >= 0x0010 && ip[1] <= 0x001f))) || (ip[0] == 0x3ff3) ) { RETURN_VALIDATION_FAILED diff --git a/ext/filter/tests/bug47435.phpt b/ext/filter/tests/bug47435.phpt index e17142aad963d..1e1c466702408 100644 --- a/ext/filter/tests/bug47435.phpt +++ b/ext/filter/tests/bug47435.phpt @@ -14,6 +14,10 @@ var_dump(filter_var("fe80:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); var_dump(filter_var("fe80:5:6::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); var_dump(filter_var("2001:0db8::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); var_dump(filter_var("2001:0db8::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); +var_dump(filter_var("2001:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); +var_dump(filter_var("2001:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); +var_dump(filter_var("240b:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); +var_dump(filter_var("240b:0010::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); var_dump(filter_var("5f::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); var_dump(filter_var("5f::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 | FILTER_FLAG_NO_RES_RANGE)); var_dump(filter_var("3ff3::1", FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)); @@ -30,6 +34,10 @@ string(11) "fe80:5:6::1" bool(false) string(12) "2001:0db8::1" bool(false) +string(12) "2001:0010::1" +bool(false) +string(12) "240b:0010::1" +string(12) "240b:0010::1" string(5) "5f::1" bool(false) string(7) "3ff3::1" From 1481d66343a5acfc682e846eae14bf71d135ae7a Mon Sep 17 00:00:00 2001 From: Joe Rowell Date: Fri, 17 Dec 2021 10:20:10 +0000 Subject: [PATCH 48/75] [ci skip] Fix "The Mysterious PHP RFC Process" link. Closes GH-7785. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index df94bd50e5f69..450c25fddbd66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,7 +80,7 @@ repository. Mailing list subscription is explained on the [mailing lists page](https://www.php.net/mailing-lists.php). You may also want to read -[The Mysterious PHP RFC Process](https://blogs.oracle.com/opal/entry/the_mysterious_php_rfc_process) +[The Mysterious PHP RFC Process](https://blogs.oracle.com/opal/post/the-mysterious-php-rfc-process-and-how-you-can-change-the-web) for additional notes on the best way to approach submitting an RFC. ## Writing tests From 29696dd54b4a39f6c2acafbd947be41bfacd7e80 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 19 Dec 2021 15:38:30 +0100 Subject: [PATCH 49/75] Add triage label when removing feedback label --- .github/workflows/remove-needs-feedback.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/remove-needs-feedback.yml b/.github/workflows/remove-needs-feedback.yml index 6f8e5a3362cb1..8f6dfc47f1664 100644 --- a/.github/workflows/remove-needs-feedback.yml +++ b/.github/workflows/remove-needs-feedback.yml @@ -13,3 +13,6 @@ jobs: - uses: actions-ecosystem/action-remove-labels@v1 with: labels: "Status: Needs Feedback" + - uses: actions-ecosystem/action-add-labels@v1 + with: + labels: "Status: Needs Triage" From f18bb2477fba864d20d2c3b7422e5b9ce88f1f79 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 20 Dec 2021 11:40:11 +0300 Subject: [PATCH 50/75] Fix type inference for INIT_ARRAY with invalid index Fixes oss-fuzz #42568 --- ext/opcache/Optimizer/zend_inference.c | 4 +++- ext/opcache/tests/opt/inference_002.phpt | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 ext/opcache/tests/opt/inference_002.phpt diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index e4bb7ec3454a9..feb469303c497 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -3002,7 +3002,9 @@ static zend_always_inline int _zend_update_type_info( if (ssa_op->result_use >= 0) { tmp |= ssa_var_info[ssa_op->result_use].type; } - if (opline->op1_type != IS_UNUSED) { + if (opline->op1_type != IS_UNUSED + && (opline->op2_type == IS_UNUSED + || (t2 & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE|MAY_BE_RESOURCE|MAY_BE_STRING)))) { tmp |= (t1 & MAY_BE_ANY) << MAY_BE_ARRAY_SHIFT; if (t1 & MAY_BE_UNDEF) { tmp |= MAY_BE_ARRAY_OF_NULL; diff --git a/ext/opcache/tests/opt/inference_002.phpt b/ext/opcache/tests/opt/inference_002.phpt new file mode 100644 index 0000000000000..70412426c2fcc --- /dev/null +++ b/ext/opcache/tests/opt/inference_002.phpt @@ -0,0 +1,15 @@ +--TEST-- +Type inference 002: Type inference for INIT_ARRAY with invalid index +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- +&$x]); +?> +--EXPECTF-- +Fatal error: Uncaught TypeError: Illegal offset type in %sinference_002.php:2 +Stack trace: +#0 {main} + thrown in %sinference_002.php on line 2 \ No newline at end of file From 7c674e1aa7d688086aace0cc3e5bb7635b595417 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 20 Dec 2021 12:48:48 +0300 Subject: [PATCH 51/75] JIT: Fix register clobbering Fixes oss-fuzz #42657 --- ext/opcache/jit/zend_jit_x86.dasc | 63 ++++++++++++++++++++---------- ext/opcache/tests/jit/add_012.phpt | 19 +++++++++ 2 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 ext/opcache/tests/jit/add_012.phpt diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index cb41c6a2656e9..543d78a1dd278 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -772,17 +772,12 @@ static void* dasm_labels[zend_lb_MAX]; || } |.endmacro -|.macro LONG_OP, long_ins, reg, addr +|.macro LONG_OP, long_ins, reg, addr, tmp_reg || if (Z_MODE(addr) == IS_CONST_ZVAL) { | .if X64 || if (!IS_SIGNED_32BIT(Z_LVAL_P(Z_ZV(addr)))) { -|| if (reg != ZREG_R0) { -| mov64 r0, Z_LVAL_P(Z_ZV(addr)) -| long_ins Ra(reg), r0 -|| } else { -| mov64 r1, Z_LVAL_P(Z_ZV(addr)) -| long_ins Ra(reg), r1 -|| } +| mov64 tmp_reg, Z_LVAL_P(Z_ZV(addr)) +| long_ins Ra(reg), tmp_reg || } else { | long_ins Ra(reg), Z_LVAL_P(Z_ZV(addr)) || } @@ -862,25 +857,25 @@ static void* dasm_labels[zend_lb_MAX]; || } |.endmacro -|.macro LONG_MATH, opcode, reg, addr +|.macro LONG_MATH, opcode, reg, addr, tmp_reg || switch (opcode) { || case ZEND_ADD: -| LONG_OP add, reg, addr +| LONG_OP add, reg, addr, Ra(tmp_reg) || break; || case ZEND_SUB: -| LONG_OP sub, reg, addr +| LONG_OP sub, reg, addr, Ra(tmp_reg) || break; || case ZEND_MUL: -| LONG_OP imul, reg, addr +| LONG_OP imul, reg, addr, Ra(tmp_reg) || break; || case ZEND_BW_OR: -| LONG_OP or, reg, addr +| LONG_OP or, reg, addr, Ra(tmp_reg) || break; || case ZEND_BW_AND: -| LONG_OP and, reg, addr +| LONG_OP and, reg, addr, Ra(tmp_reg) || break; || case ZEND_BW_XOR: -| LONG_OP xor, reg, addr +| LONG_OP xor, reg, addr, Ra(tmp_reg) || break; || default: || ZEND_UNREACHABLE(); @@ -4390,7 +4385,16 @@ static int zend_jit_math_long_long(dasm_State **Dst, } else if (same_ops && opcode != ZEND_DIV) { | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg) } else { - | LONG_MATH opcode, result_reg, op2_addr + zend_reg tmp_reg; + + if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) { + tmp_reg = ZREG_R1; + } else if (result_reg != ZREG_R0) { + tmp_reg = ZREG_R0; + } else { + tmp_reg = ZREG_R1; + } + | LONG_MATH opcode, result_reg, op2_addr, tmp_reg } } if (may_overflow) { @@ -5117,12 +5121,20 @@ static int zend_jit_long_math_helper(dasm_State **Dst, } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) { zval tmp; zend_jit_addr tmp_addr; + zend_reg tmp_reg; /* Optimisation for mod of power of 2 */ ZVAL_LONG(&tmp, op2_lval - 1); tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp); + if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) { + tmp_reg = ZREG_R1; + } else if (result_reg != ZREG_R0) { + tmp_reg = ZREG_R0; + } else { + tmp_reg = ZREG_R1; + } | GET_ZVAL_LVAL result_reg, op1_addr - | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr + | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, tmp_reg } else { if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) { | mov aword T1, r0 // save @@ -5210,8 +5222,17 @@ static int zend_jit_long_math_helper(dasm_State **Dst, | GET_ZVAL_LVAL result_reg, op1_addr | LONG_MATH_REG opcode, Ra(result_reg), Ra(result_reg) } else { + zend_reg tmp_reg; + + if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_R0) { + tmp_reg = ZREG_R1; + } else if (result_reg != ZREG_R0) { + tmp_reg = ZREG_R0; + } else { + tmp_reg = ZREG_R1; + } | GET_ZVAL_LVAL result_reg, op1_addr - | LONG_MATH opcode, result_reg, op2_addr + | LONG_MATH opcode, result_reg, op2_addr, tmp_reg } if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) { @@ -7025,13 +7046,13 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { | test Ra(Z_REG(op1_addr)), Ra(Z_REG(op1_addr)) } else { - | LONG_OP cmp, Z_REG(op1_addr), op2_addr + | LONG_OP cmp, Z_REG(op1_addr), op2_addr, r0 } } else if (Z_MODE(op2_addr) == IS_REG) { if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) { | test Ra(Z_REG(op2_addr)), Ra(Z_REG(op2_addr)) } else { - | LONG_OP cmp, Z_REG(op2_addr), op1_addr + | LONG_OP cmp, Z_REG(op2_addr), op1_addr, r0 } swap = 1; } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) { @@ -7044,7 +7065,7 @@ static int zend_jit_cmp_long_long(dasm_State **Dst, if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { | test r0, r0 } else { - | LONG_OP cmp, ZREG_R0, op2_addr + | LONG_OP cmp, ZREG_R0, op2_addr, r0 } } diff --git a/ext/opcache/tests/jit/add_012.phpt b/ext/opcache/tests/jit/add_012.phpt new file mode 100644 index 0000000000000..645f8f4bdd9b5 --- /dev/null +++ b/ext/opcache/tests/jit/add_012.phpt @@ -0,0 +1,19 @@ +--TEST-- +JIT ADD: 012 register allocation for 64-bit constant +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE \ No newline at end of file From e004e844f74998878853517d900f99dbc1e9db3d Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 20 Dec 2021 15:06:32 +0300 Subject: [PATCH 52/75] Fix incorrect optimization of ASSIGN_OP that may lead to memory leak Fixes oss-fuzz #42506 --- ext/opcache/Optimizer/dfa_pass.c | 13 +++++++--- ext/opcache/tests/opt/assign_op_001.phpt | 30 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 ext/opcache/tests/opt/assign_op_001.phpt diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index 823eccdb4f23f..496ff5618e175 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -323,7 +323,7 @@ static inline zend_bool can_elide_return_type_check( } static zend_bool opline_supports_assign_contraction( - zend_ssa *ssa, zend_op *opline, int src_var, uint32_t cv_var) { + zend_op_array *op_array, zend_ssa *ssa, zend_op *opline, int src_var, uint32_t cv_var) { if (opline->opcode == ZEND_NEW) { /* see Zend/tests/generators/aborted_yield_during_new.phpt */ return 0; @@ -357,6 +357,13 @@ static zend_bool opline_supports_assign_contraction( return opline->op1_type != IS_CV || opline->op1.var != cv_var; } + if (opline->opcode == ZEND_ASSIGN_OP + && opline->op1_type == IS_CV + && opline->op1.var == cv_var + && zend_may_throw(opline, &ssa->ops[ssa->vars[src_var].definition], op_array, ssa)) { + return 0; + } + return 1; } @@ -1310,7 +1317,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx && !ssa->vars[src_var].phi_use_chain && !ssa->vars[src_var].sym_use_chain && opline_supports_assign_contraction( - ssa, &op_array->opcodes[ssa->vars[src_var].definition], + op_array, ssa, &op_array->opcodes[ssa->vars[src_var].definition], src_var, opline->result.var) && !variable_defined_or_used_in_range(ssa, EX_VAR_TO_NUM(opline->result.var), ssa->vars[src_var].definition+1, op_1) @@ -1467,7 +1474,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx && !ssa->vars[src_var].phi_use_chain && !ssa->vars[src_var].sym_use_chain && opline_supports_assign_contraction( - ssa, &op_array->opcodes[ssa->vars[src_var].definition], + op_array, ssa, &op_array->opcodes[ssa->vars[src_var].definition], src_var, opline->op1.var) && !variable_defined_or_used_in_range(ssa, EX_VAR_TO_NUM(opline->op1.var), ssa->vars[src_var].definition+1, op_1) diff --git a/ext/opcache/tests/opt/assign_op_001.phpt b/ext/opcache/tests/opt/assign_op_001.phpt new file mode 100644 index 0000000000000..b9db4202b46c0 --- /dev/null +++ b/ext/opcache/tests/opt/assign_op_001.phpt @@ -0,0 +1,30 @@ +--TEST-- +ASSIGN_OP 001: Incrrect optimization of ASSIGN_OP may lead to memory leak +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $a in %sassign_op_001.php on line 4 + +Warning: Undefined variable $a in %sassign_op_001.php on line 4 + +Warning: Undefined array key "b" in %sassign_op_001.php on line 7 + +Fatal error: Uncaught TypeError: Unsupported operand types: array + bool in %sassign_op_001.php:4 +Stack trace: +#0 %sassign_op_001.php(10): test() +#1 {main} + thrown in %sassign_op_001.php on line 4 \ No newline at end of file From 069bbf3e8009795bfeec2d46cd4bb39d6907d29a Mon Sep 17 00:00:00 2001 From: Petr Sumbera Date: Tue, 14 Dec 2021 10:57:22 +0100 Subject: [PATCH 53/75] Fix zend_fibers.c build with ZEND_FIBER_UCONTEXT Avoids (Solaris SPARC) issue: zend_fibers.c:77:9: error: unknown type name 'ucontext_t' Closes GH-7773. --- NEWS | 1 + Zend/zend_fibers.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index af3a74ae1f293..a3b9a4c6c00a0 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ PHP NEWS (cmb) . Fixed bug GH-7757 (Multi-inherited final constant causes fatal error). (cmb) + . Fixed zend_fibers.c build with ZEND_FIBER_UCONTEXT. (Petr Sumbera) - Filter: . Fixed FILTER_FLAG_NO_RES_RANGE flag. (Yifan Tong) diff --git a/Zend/zend_fibers.c b/Zend/zend_fibers.c index 92ae9b8837cb7..dd06f86ae8da6 100644 --- a/Zend/zend_fibers.c +++ b/Zend/zend_fibers.c @@ -32,6 +32,10 @@ # include #endif +#ifdef ZEND_FIBER_UCONTEXT +# include +#endif + #ifndef ZEND_WIN32 # include # include @@ -118,7 +122,6 @@ static zend_always_inline void zend_fiber_restore_vm_state(zend_fiber_vm_state * } #ifdef ZEND_FIBER_UCONTEXT -# include ZEND_TLS zend_fiber_transfer *transfer_data; #else /* boost_context_data is our customized definition of struct transfer_t as From 3414ae6c0c4e66107a3d6a1a35119cede31803c4 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Fri, 10 Dec 2021 19:41:00 +0000 Subject: [PATCH 54/75] sockets: add SO_INCOMING_CPU constant get/set the cpu attached to a socket, no special treatment needed, it is simply an integer. Closes GH-7753. --- UPGRADING | 3 +++ ext/sockets/sockets.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/UPGRADING b/UPGRADING index b0a3fffb7add2..4d918a85bfc17 100644 --- a/UPGRADING +++ b/UPGRADING @@ -145,6 +145,9 @@ PHP 8.2 UPGRADE NOTES - COM_DOTNET: . LOCALE_NEUTRAL +- Sockets: + . SO_INCOMING_CPU + ======================================== 11. Changes to INI File Handling ======================================== diff --git a/ext/sockets/sockets.c b/ext/sockets/sockets.c index 1df6eaa09d659..6b52bb5c7cc56 100644 --- a/ext/sockets/sockets.c +++ b/ext/sockets/sockets.c @@ -545,6 +545,9 @@ static PHP_MINIT_FUNCTION(sockets) #ifdef SO_MARK REGISTER_LONG_CONSTANT("SO_MARK", SO_MARK, CONST_CS | CONST_PERSISTENT); #endif +#ifdef SO_INCOMING_CPU + REGISTER_LONG_CONSTANT("SO_INCOMING_CPU", SO_INCOMING_CPU, CONST_CS | CONST_PERSISTENT); +#endif #ifdef TCP_NODELAY REGISTER_LONG_CONSTANT("TCP_NODELAY", TCP_NODELAY, CONST_CS | CONST_PERSISTENT); #endif From 32e2d97a265a3137eaa642857156e5d49521d846 Mon Sep 17 00:00:00 2001 From: Tyson Andre Date: Mon, 20 Dec 2021 09:27:06 -0500 Subject: [PATCH 55/75] Allow internal functions to declare if they support compile-time evaluation, add functions. (#7780) https://wiki.php.net/rfc/strtolower-ascii means that these functions no longer depend on the current locale in php 8.2. Before that, this was unsafe to evaluate at compile time. Followup to GH-7506 Add strcmp/strcasecmp/strtolower/strtoupper functions Add bin2hex/hex2bin and related functions Update test of garbage collection using strtolower to use something else to create a refcounted string --- Zend/Optimizer/sccp.c | 60 ++------ Zend/tests/bug38623.phpt | 8 +- Zend/zend_API.h | 11 ++ Zend/zend_builtin_functions.stub.php | 4 + Zend/zend_builtin_functions_arginfo.h | 10 +- Zend/zend_compile.h | 5 +- build/gen_stub.php | 12 ++ ext/pcre/php_pcre.stub.php | 1 + ext/pcre/php_pcre_arginfo.h | 4 +- ext/standard/basic_functions.stub.php | 189 +++++++++++++++++++++---- ext/standard/basic_functions_arginfo.h | 140 +++++++++--------- 11 files changed, 290 insertions(+), 154 deletions(-) diff --git a/Zend/Optimizer/sccp.c b/Zend/Optimizer/sccp.c index ff11daa8d3720..631037a2a8e8e 100644 --- a/Zend/Optimizer/sccp.c +++ b/Zend/Optimizer/sccp.c @@ -799,59 +799,21 @@ static inline zend_result ct_eval_array_key_exists(zval *result, zval *op1, zval return SUCCESS; } -static bool can_ct_eval_func_call(zend_string *name, uint32_t num_args, zval **args) { - /* Functions in this list must always produce the same result for the same arguments, +static bool can_ct_eval_func_call(zend_function *func, zend_string *name, uint32_t num_args, zval **args) { + /* Precondition: func->type == ZEND_INTERNAL_FUNCTION, this is a global function */ + /* Functions setting ZEND_ACC_COMPILE_TIME_EVAL (@compile-time-eval) must always produce the same result for the same arguments, * and have no dependence on global state (such as locales). It is okay if they throw * or warn on invalid arguments, as we detect this and will discard the evaluation result. */ - if (false - || zend_string_equals_literal(name, "array_diff") - || zend_string_equals_literal(name, "array_diff_assoc") - || zend_string_equals_literal(name, "array_diff_key") - || zend_string_equals_literal(name, "array_flip") - || zend_string_equals_literal(name, "array_is_list") - || zend_string_equals_literal(name, "array_key_exists") - || zend_string_equals_literal(name, "array_keys") - || zend_string_equals_literal(name, "array_merge") - || zend_string_equals_literal(name, "array_merge_recursive") - || zend_string_equals_literal(name, "array_replace") - || zend_string_equals_literal(name, "array_replace_recursive") - || zend_string_equals_literal(name, "array_unique") - || zend_string_equals_literal(name, "array_values") - || zend_string_equals_literal(name, "base64_decode") - || zend_string_equals_literal(name, "base64_encode") + if (func->common.fn_flags & ZEND_ACC_COMPILE_TIME_EVAL) { + /* This has @compile-time-eval in stub info and uses a macro such as ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE */ + return true; + } #ifndef ZEND_WIN32 - /* On Windows this function may be code page dependent. */ - || zend_string_equals_literal(name, "dirname") -#endif - || zend_string_equals_literal(name, "explode") - || zend_string_equals_literal(name, "imagetypes") - || zend_string_equals_literal(name, "in_array") - || zend_string_equals_literal(name, "implode") - || zend_string_equals_literal(name, "ltrim") - || zend_string_equals_literal(name, "php_sapi_name") - || zend_string_equals_literal(name, "php_uname") - || zend_string_equals_literal(name, "phpversion") - || zend_string_equals_literal(name, "pow") - || zend_string_equals_literal(name, "preg_quote") - || zend_string_equals_literal(name, "rawurldecode") - || zend_string_equals_literal(name, "rawurlencode") - || zend_string_equals_literal(name, "rtrim") - || zend_string_equals_literal(name, "serialize") - || zend_string_equals_literal(name, "str_contains") - || zend_string_equals_literal(name, "str_ends_with") - || zend_string_equals_literal(name, "str_replace") - || zend_string_equals_literal(name, "str_split") - || zend_string_equals_literal(name, "str_starts_with") - || zend_string_equals_literal(name, "strpos") - || zend_string_equals_literal(name, "strstr") - || zend_string_equals_literal(name, "substr") - || zend_string_equals_literal(name, "trim") - || zend_string_equals_literal(name, "urldecode") - || zend_string_equals_literal(name, "urlencode") - || zend_string_equals_literal(name, "version_compare") - ) { + /* On Windows this function may be code page dependent. */ + if (zend_string_equals_literal(name, "dirname")) { return true; } +#endif if (num_args == 2) { if (zend_string_equals_literal(name, "str_repeat")) { @@ -918,7 +880,7 @@ static inline zend_result ct_eval_func_call( } } - if (!can_ct_eval_func_call(name, num_args, args)) { + if (!can_ct_eval_func_call(func, name, num_args, args)) { return FAILURE; } diff --git a/Zend/tests/bug38623.phpt b/Zend/tests/bug38623.phpt index 873cdf42d4616..5060850054d10 100644 --- a/Zend/tests/bug38623.phpt +++ b/Zend/tests/bug38623.phpt @@ -2,8 +2,14 @@ Bug #38623 (leaks in a tricky code with switch() and exceptions) --FILE-- aliasType = $aliasType; $this->alias = $alias; $this->isDeprecated = $isDeprecated; + $this->supportsCompileTimeEval = $supportsCompileTimeEval; $this->verify = $verify; $this->args = $args; $this->return = $return; @@ -1155,6 +1159,10 @@ public function getFunctionEntry(): string { "\tZEND_NS_FE(\"%s\", %s, %s)\n", addslashes($namespace), $declarationName, $this->getArgInfoName()); } else { + if ($this->supportsCompileTimeEval) { + return sprintf( + "\tZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(%s, %s)\n", $declarationName, $this->getArgInfoName()); + } return sprintf("\tZEND_FE(%s, %s)\n", $declarationName, $this->getArgInfoName()); } } else { @@ -2232,6 +2240,7 @@ function parseFunctionLike( $aliasType = null; $alias = null; $isDeprecated = false; + $supportsCompileTimeEval = false; $verify = true; $docReturnType = null; $tentativeReturnType = false; @@ -2267,6 +2276,8 @@ function parseFunctionLike( $docParamTypes[$tag->getVariableName()] = $tag->getType(); } else if ($tag->name === 'refcount') { $refcount = $tag->getValue(); + } else if ($tag->name === 'compile-time-eval') { + $supportsCompileTimeEval = true; } } } @@ -2355,6 +2366,7 @@ function parseFunctionLike( $aliasType, $alias, $isDeprecated, + $supportsCompileTimeEval, $verify, $args, $return, diff --git a/ext/pcre/php_pcre.stub.php b/ext/pcre/php_pcre.stub.php index 498219b3c41e5..006e740008745 100644 --- a/ext/pcre/php_pcre.stub.php +++ b/ext/pcre/php_pcre.stub.php @@ -35,6 +35,7 @@ function preg_replace_callback_array(array $pattern, string|array $subject, int */ function preg_split(string $pattern, string $subject, int $limit = -1, int $flags = 0): array|false {} +/** @compile-time-eval */ function preg_quote(string $str, ?string $delimiter = null): string {} /** @refcount 1 */ diff --git a/ext/pcre/php_pcre_arginfo.h b/ext/pcre/php_pcre_arginfo.h index 96c8331c0d611..bb16a6079a2b5 100644 --- a/ext/pcre/php_pcre_arginfo.h +++ b/ext/pcre/php_pcre_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: bc6f31ac17d4f5d1a60dd3dad5f671058f40a224 */ + * Stub hash: 39a19378fb1f1aca34bfdd483f5d3095558f0e09 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_preg_match, 0, 2, MAY_BE_LONG|MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, pattern, IS_STRING, 0) @@ -84,7 +84,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(preg_replace_callback, arginfo_preg_replace_callback) ZEND_FE(preg_replace_callback_array, arginfo_preg_replace_callback_array) ZEND_FE(preg_split, arginfo_preg_split) - ZEND_FE(preg_quote, arginfo_preg_quote) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(preg_quote, arginfo_preg_quote) ZEND_FE(preg_grep, arginfo_preg_grep) ZEND_FE(preg_last_error, arginfo_preg_last_error) ZEND_FE(preg_last_error_msg, arginfo_preg_last_error_msg) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index 1719b1453795a..51751b7776dac 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -126,8 +126,10 @@ function pos(array|object $array): mixed {} function key(array|object $array): int|string|null {} +/** @compile-time-eval */ function min(mixed $value, mixed ...$values): mixed {} +/** @compile-time-eval */ function max(mixed $value, mixed ...$values): mixed {} /** @return true */ @@ -136,8 +138,14 @@ function array_walk(array|object &$array, callable $callback, mixed $arg = UNKNO /** @return true */ function array_walk_recursive(array|object &$array, callable $callback, mixed $arg = UNKNOWN): bool {} +/** + * @compile-time-eval + */ function in_array(mixed $needle, array $haystack, bool $strict = false): bool {} +/** + * @compile-time-eval + */ function array_search(mixed $needle, array $haystack, bool $strict = false): int|string|false {} /** @prefer-ref $array */ @@ -176,24 +184,48 @@ function array_splice(array &$array, int $offset, ?int $length = null, mixed $re function array_slice(array $array, int $offset, ?int $length = null, bool $preserve_keys = false): array {} +/** + * @compile-time-eval + */ function array_merge(array ...$arrays): array {} +/** + * @compile-time-eval + */ function array_merge_recursive(array ...$arrays): array {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function array_replace(array $array, array ...$replacements): array {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function array_replace_recursive(array $array, array ...$replacements): array {} -/** @return array */ +/** + * @return array + * @compile-time-eval + */ function array_keys(array $array, mixed $filter_value = UNKNOWN, bool $strict = false): array {} +/** + * @compile-time-eval + */ function array_key_first(array $array): int|string|null {} +/** + * @compile-time-eval + */ function array_key_last(array $array): int|string|null {} -/** @return array */ +/** + * @return array + * @compile-time-eval + */ function array_values(array $array): array {} /** @@ -213,12 +245,19 @@ function array_pad(array $array, int $length, mixed $value): array {} /** * @return array * @refcount 1 + * @compile-time-eval */ function array_flip(array $array): array {} -/** @refcount 1 */ +/** + * @refcount 1 + * @compile-time-eval + */ function array_change_key_case(array $array, int $case = CASE_LOWER): array {} +/** + * @compile-time-eval + */ function array_unique(array $array, int $flags = SORT_STRING): array {} /** @refcount 1 */ @@ -260,15 +299,22 @@ function array_intersect_uassoc(array $array, ...$rest): array {} */ function array_uintersect_uassoc(array $array, ...$rest): array {} -/** @refcount 1 */ +/** + * @refcount 1 + * @compile-time-eval + */ function array_diff_key(array $array, array ...$arrays): array {} /** * @param array|callable $rest * @refcount 1 + * @compile-time-eval */ function array_diff_ukey(array $array, ...$rest): array {} +/** + * @compile-time-eval + */ function array_diff(array $array, array ...$arrays): array {} /** @@ -277,7 +323,10 @@ function array_diff(array $array, array ...$arrays): array {} */ function array_udiff(array $array, ...$rest): array {} -/** @refcount 1 */ +/** + * @refcount 1 + * @compile-time-eval + */ function array_diff_assoc(array $array, array ...$arrays): array {} /** @@ -336,10 +385,16 @@ function array_is_list(array $array): bool {} /* base64.c */ -/** @refcount 1 */ +/** + * @refcount 1 + * @compile-time-eval + */ function base64_encode(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function base64_decode(string $string, bool $strict = false): string|false {} /* basic_functions.c */ @@ -517,6 +572,7 @@ function get_browser(?string $user_agent = null, bool $return_array = false): ob /* crc32.c */ +/** @compile-time-eval */ function crc32(string $string): int {} /* crypt.c */ @@ -708,10 +764,16 @@ function assert_options(int $option, mixed $value = UNKNOWN): mixed {} /* string.c */ -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function bin2hex(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function hex2bin(string $string): string|false {} function strspn(string $string, string $characters, int $offset = 0, ?int $length = null): int {} @@ -725,13 +787,16 @@ function nl_langinfo(int $item): string|false {} function strcoll(string $string1, string $string2): int {} +/** @compile-time-eval */ function trim(string $string, string $characters = " \n\r\t\v\0"): string {} +/** @compile-time-eval */ function rtrim(string $string, string $characters = " \n\r\t\v\0"): string {} /** @alias rtrim */ function chop(string $string, string $characters = " \n\r\t\v\0"): string {} +/** @compile-time-eval */ function ltrim(string $string, string $characters = " \n\r\t\v\0"): string {} /** @refcount 1 */ @@ -740,9 +805,13 @@ function wordwrap(string $string, int $width = 75, string $break = "\n", bool $c /** * @return array * @refcount 1 + * @compile-time-eval */ function explode(string $separator, string $string, int $limit = PHP_INT_MAX): array {} +/** + * @compile-time-eval + */ function implode(string|array $separator, ?array $array = null): string {} /** @alias implode */ @@ -751,8 +820,10 @@ function join(string|array $separator, ?array $array = null): string {} /** @refcount 1 */ function strtok(string $string, ?string $token = null): string|false {} +/** @compile-time-eval */ function strtoupper(string $string): string {} +/** @compile-time-eval */ function strtolower(string $string): string {} /** @refcount 1 */ @@ -776,26 +847,34 @@ function strstr(string $haystack, string $needle, bool $before_needle = false): /** @alias strstr */ function strchr(string $haystack, string $needle, bool $before_needle = false): string|false {} +/** @compile-time-eval */ function strpos(string $haystack, string $needle, int $offset = 0): int|false {} +/** @compile-time-eval */ function stripos(string $haystack, string $needle, int $offset = 0): int|false {} +/** @compile-time-eval */ function strrpos(string $haystack, string $needle, int $offset = 0): int|false {} +/** @compile-time-eval */ function strripos(string $haystack, string $needle, int $offset = 0): int|false {} /** @refcount 1 */ function strrchr(string $haystack, string $needle): string|false {} +/** @compile-time-eval */ function str_contains(string $haystack, string $needle): bool {} +/** @compile-time-eval */ function str_starts_with(string $haystack, string $needle): bool {} +/** @compile-time-eval */ function str_ends_with(string $haystack, string $needle): bool {} /** @refcount 1 */ function chunk_split(string $string, int $length = 76, string $separator = "\r\n"): string {} +/** @compile-time-eval */ function substr(string $string, int $offset, ?int $length = null): string {} /** @return string|array */ @@ -804,21 +883,33 @@ function substr_replace(array|string $string, array|string $replace, array|int $ /** @refcount 1 */ function quotemeta(string $string): string {} +/** @compile-time-eval */ function ord(string $character): int {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function chr(int $codepoint): string {} +/** @compile-time-eval */ function ucfirst(string $string): string {} +/** @compile-time-eval */ function lcfirst(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function ucwords(string $string, string $separators = " \t\r\n\f\v"): string {} function strtr(string $string, string|array $from, ?string $to = null): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function strrev(string $string): string {} /** @param float $percent */ @@ -837,12 +928,14 @@ function stripslashes(string $string): string {} /** * @param int $count * @return string|array + * @compile-time-eval */ function str_replace(array|string $search, array|string $replace, string|array $subject, &$count = null): string|array {} /** * @param int $count * @return string|array + * @compile-time-eval */ function str_ireplace(array|string $search, array|string $replace, string|array $subject, &$count = null): string|array {} @@ -913,6 +1006,7 @@ function str_word_count(string $string, int $format = 0, ?string $characters = n /** * @return array * @refcount 1 + * @compile-time-eval */ function str_split(string $string, int $length = 1): array {} @@ -1324,16 +1418,25 @@ function getimagesizefromstring(string $string, &$image_info = null): array|fals /** @return true */ function phpinfo(int $flags = INFO_ALL): bool {} // make return type void -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function phpversion(?string $extension = null): string|false {} /** @return true */ -function phpcredits(int $flags = CREDITS_ALL): bool {} // make return type void +function phpcredits(int $flags = CREDITS_ALL): bool {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function php_sapi_name(): string|false {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function php_uname(string $mode = "a"): string {} /** @refcount 1 */ @@ -1414,16 +1517,22 @@ function expm1(float $num): float {} function log1p(float $num): float {} +/** @compile-time-eval */ function pi(): float {} +/** @compile-time-eval */ function is_finite(float $num): bool {} +/** @compile-time-eval */ function is_nan(float $num): bool {} +/** @compile-time-eval */ function intdiv(int $num1, int $num2): int {} +/** @compile-time-eval */ function is_infinite(float $num): bool {} +/** @compile-time-eval */ function pow(mixed $num, mixed $exponent): int|float|object {} function exp(float $num): float {} @@ -1440,19 +1549,31 @@ function deg2rad(float $num): float {} function rad2deg(float $num): float {} +/** @compile-time-eval */ function bindec(string $binary_string): int|float {} +/** @compile-time-eval */ function hexdec(string $hex_string): int|float {} +/** @compile-time-eval */ function octdec(string $octal_string): int|float {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function decbin(int $num): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function decoct(int $num): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function dechex(int $num): string {} /** @refcount 1 */ @@ -1847,16 +1968,28 @@ function uniqid(string $prefix = "", bool $more_entropy = false): string {} */ function parse_url(string $url, int $component = -1): int|string|array|null|false {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function urlencode(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function urldecode(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function rawurlencode(string $string): string {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function rawurldecode(string $string): string {} /** @@ -1911,7 +2044,10 @@ function var_export(mixed $value, bool $return = false): ?string {} function debug_zval_dump(mixed $value, mixed ...$values): void {} -/** @refcount 1 */ +/** + * @compile-time-eval + * @refcount 1 + */ function serialize(mixed $value): string {} function unserialize(string $data, array $options = []): mixed {} @@ -1922,6 +2058,7 @@ function memory_get_peak_usage(bool $real_usage = false): int {} /* versioning.c */ +/** @compile-time-eval */ function version_compare(string $version1, string $version2, ?string $operator = null): int|bool {} /* win32/codepage.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index ab7776d630919..155266c5d436d 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 96393b26861733e5c7fc9a12095a29c07ed73928 */ + * Stub hash: 0191861a660a4055650879e5a0dafd0853a6776b */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) @@ -2888,12 +2888,12 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(current, arginfo_current) ZEND_FALIAS(pos, current, arginfo_pos) ZEND_FE(key, arginfo_key) - ZEND_FE(min, arginfo_min) - ZEND_FE(max, arginfo_max) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(min, arginfo_min) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(max, arginfo_max) ZEND_FE(array_walk, arginfo_array_walk) ZEND_FE(array_walk_recursive, arginfo_array_walk_recursive) - ZEND_FE(in_array, arginfo_in_array) - ZEND_FE(array_search, arginfo_array_search) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(in_array, arginfo_in_array) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_search, arginfo_array_search) ZEND_FE(extract, arginfo_extract) ZEND_FE(compact, arginfo_compact) ZEND_FE(array_fill, arginfo_array_fill) @@ -2905,21 +2905,21 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(array_unshift, arginfo_array_unshift) ZEND_FE(array_splice, arginfo_array_splice) ZEND_FE(array_slice, arginfo_array_slice) - ZEND_FE(array_merge, arginfo_array_merge) - ZEND_FE(array_merge_recursive, arginfo_array_merge_recursive) - ZEND_FE(array_replace, arginfo_array_replace) - ZEND_FE(array_replace_recursive, arginfo_array_replace_recursive) - ZEND_FE(array_keys, arginfo_array_keys) - ZEND_FE(array_key_first, arginfo_array_key_first) - ZEND_FE(array_key_last, arginfo_array_key_last) - ZEND_FE(array_values, arginfo_array_values) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_merge, arginfo_array_merge) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_merge_recursive, arginfo_array_merge_recursive) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_replace, arginfo_array_replace) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_replace_recursive, arginfo_array_replace_recursive) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_keys, arginfo_array_keys) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_key_first, arginfo_array_key_first) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_key_last, arginfo_array_key_last) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_values, arginfo_array_values) ZEND_FE(array_count_values, arginfo_array_count_values) ZEND_FE(array_column, arginfo_array_column) ZEND_FE(array_reverse, arginfo_array_reverse) ZEND_FE(array_pad, arginfo_array_pad) - ZEND_FE(array_flip, arginfo_array_flip) - ZEND_FE(array_change_key_case, arginfo_array_change_key_case) - ZEND_FE(array_unique, arginfo_array_unique) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_flip, arginfo_array_flip) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_change_key_case, arginfo_array_change_key_case) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_unique, arginfo_array_unique) ZEND_FE(array_intersect_key, arginfo_array_intersect_key) ZEND_FE(array_intersect_ukey, arginfo_array_intersect_ukey) ZEND_FE(array_intersect, arginfo_array_intersect) @@ -2928,11 +2928,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(array_uintersect_assoc, arginfo_array_uintersect_assoc) ZEND_FE(array_intersect_uassoc, arginfo_array_intersect_uassoc) ZEND_FE(array_uintersect_uassoc, arginfo_array_uintersect_uassoc) - ZEND_FE(array_diff_key, arginfo_array_diff_key) - ZEND_FE(array_diff_ukey, arginfo_array_diff_ukey) - ZEND_FE(array_diff, arginfo_array_diff) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_key, arginfo_array_diff_key) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_ukey, arginfo_array_diff_ukey) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff, arginfo_array_diff) ZEND_FE(array_udiff, arginfo_array_udiff) - ZEND_FE(array_diff_assoc, arginfo_array_diff_assoc) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(array_diff_assoc, arginfo_array_diff_assoc) ZEND_FE(array_diff_uassoc, arginfo_array_diff_uassoc) ZEND_FE(array_udiff_assoc, arginfo_array_udiff_assoc) ZEND_FE(array_udiff_uassoc, arginfo_array_udiff_uassoc) @@ -2948,8 +2948,8 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(array_chunk, arginfo_array_chunk) ZEND_FE(array_combine, arginfo_array_combine) ZEND_FE(array_is_list, arginfo_array_is_list) - ZEND_FE(base64_encode, arginfo_base64_encode) - ZEND_FE(base64_decode, arginfo_base64_decode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(base64_encode, arginfo_base64_encode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(base64_decode, arginfo_base64_decode) ZEND_FE(constant, arginfo_constant) ZEND_FE(ip2long, arginfo_ip2long) ZEND_FE(long2ip, arginfo_long2ip) @@ -3017,7 +3017,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(sys_getloadavg, arginfo_sys_getloadavg) #endif ZEND_FE(get_browser, arginfo_get_browser) - ZEND_FE(crc32, arginfo_crc32) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(crc32, arginfo_crc32) ZEND_FE(crypt, arginfo_crypt) #if HAVE_STRPTIME ZEND_DEP_FE(strptime, arginfo_strptime) @@ -3090,57 +3090,57 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(get_html_translation_table, arginfo_get_html_translation_table) ZEND_FE(assert, arginfo_assert) ZEND_FE(assert_options, arginfo_assert_options) - ZEND_FE(bin2hex, arginfo_bin2hex) - ZEND_FE(hex2bin, arginfo_hex2bin) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(bin2hex, arginfo_bin2hex) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(hex2bin, arginfo_hex2bin) ZEND_FE(strspn, arginfo_strspn) ZEND_FE(strcspn, arginfo_strcspn) #if HAVE_NL_LANGINFO ZEND_FE(nl_langinfo, arginfo_nl_langinfo) #endif ZEND_FE(strcoll, arginfo_strcoll) - ZEND_FE(trim, arginfo_trim) - ZEND_FE(rtrim, arginfo_rtrim) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(trim, arginfo_trim) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(rtrim, arginfo_rtrim) ZEND_FALIAS(chop, rtrim, arginfo_chop) - ZEND_FE(ltrim, arginfo_ltrim) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(ltrim, arginfo_ltrim) ZEND_FE(wordwrap, arginfo_wordwrap) - ZEND_FE(explode, arginfo_explode) - ZEND_FE(implode, arginfo_implode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(explode, arginfo_explode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(implode, arginfo_implode) ZEND_FALIAS(join, implode, arginfo_join) ZEND_FE(strtok, arginfo_strtok) - ZEND_FE(strtoupper, arginfo_strtoupper) - ZEND_FE(strtolower, arginfo_strtolower) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtoupper, arginfo_strtoupper) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strtolower, arginfo_strtolower) ZEND_FE(basename, arginfo_basename) ZEND_FE(dirname, arginfo_dirname) ZEND_FE(pathinfo, arginfo_pathinfo) ZEND_FE(stristr, arginfo_stristr) ZEND_FE(strstr, arginfo_strstr) ZEND_FALIAS(strchr, strstr, arginfo_strchr) - ZEND_FE(strpos, arginfo_strpos) - ZEND_FE(stripos, arginfo_stripos) - ZEND_FE(strrpos, arginfo_strrpos) - ZEND_FE(strripos, arginfo_strripos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strpos, arginfo_strpos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(stripos, arginfo_stripos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strrpos, arginfo_strrpos) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strripos, arginfo_strripos) ZEND_FE(strrchr, arginfo_strrchr) - ZEND_FE(str_contains, arginfo_str_contains) - ZEND_FE(str_starts_with, arginfo_str_starts_with) - ZEND_FE(str_ends_with, arginfo_str_ends_with) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_contains, arginfo_str_contains) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_starts_with, arginfo_str_starts_with) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_ends_with, arginfo_str_ends_with) ZEND_FE(chunk_split, arginfo_chunk_split) - ZEND_FE(substr, arginfo_substr) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(substr, arginfo_substr) ZEND_FE(substr_replace, arginfo_substr_replace) ZEND_FE(quotemeta, arginfo_quotemeta) - ZEND_FE(ord, arginfo_ord) - ZEND_FE(chr, arginfo_chr) - ZEND_FE(ucfirst, arginfo_ucfirst) - ZEND_FE(lcfirst, arginfo_lcfirst) - ZEND_FE(ucwords, arginfo_ucwords) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(ord, arginfo_ord) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(chr, arginfo_chr) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(ucfirst, arginfo_ucfirst) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(lcfirst, arginfo_lcfirst) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(ucwords, arginfo_ucwords) ZEND_FE(strtr, arginfo_strtr) - ZEND_FE(strrev, arginfo_strrev) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(strrev, arginfo_strrev) ZEND_FE(similar_text, arginfo_similar_text) ZEND_FE(addcslashes, arginfo_addcslashes) ZEND_FE(addslashes, arginfo_addslashes) ZEND_FE(stripcslashes, arginfo_stripcslashes) ZEND_FE(stripslashes, arginfo_stripslashes) - ZEND_FE(str_replace, arginfo_str_replace) - ZEND_FE(str_ireplace, arginfo_str_ireplace) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_replace, arginfo_str_replace) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_ireplace, arginfo_str_ireplace) ZEND_FE(hebrev, arginfo_hebrev) ZEND_FE(nl2br, arginfo_nl2br) ZEND_FE(strip_tags, arginfo_strip_tags) @@ -3158,7 +3158,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(str_rot13, arginfo_str_rot13) ZEND_FE(str_shuffle, arginfo_str_shuffle) ZEND_FE(str_word_count, arginfo_str_word_count) - ZEND_FE(str_split, arginfo_str_split) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(str_split, arginfo_str_split) ZEND_FE(strpbrk, arginfo_strpbrk) ZEND_FE(substr_compare, arginfo_substr_compare) ZEND_FE(utf8_encode, arginfo_utf8_encode) @@ -3278,10 +3278,10 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(getimagesize, arginfo_getimagesize) ZEND_FE(getimagesizefromstring, arginfo_getimagesizefromstring) ZEND_FE(phpinfo, arginfo_phpinfo) - ZEND_FE(phpversion, arginfo_phpversion) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(phpversion, arginfo_phpversion) ZEND_FE(phpcredits, arginfo_phpcredits) - ZEND_FE(php_sapi_name, arginfo_php_sapi_name) - ZEND_FE(php_uname, arginfo_php_uname) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(php_sapi_name, arginfo_php_sapi_name) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(php_uname, arginfo_php_uname) ZEND_FE(php_ini_scanned_files, arginfo_php_ini_scanned_files) ZEND_FE(php_ini_loaded_file, arginfo_php_ini_loaded_file) ZEND_FE(iptcembed, arginfo_iptcembed) @@ -3319,12 +3319,12 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(acosh, arginfo_acosh) ZEND_FE(expm1, arginfo_expm1) ZEND_FE(log1p, arginfo_log1p) - ZEND_FE(pi, arginfo_pi) - ZEND_FE(is_finite, arginfo_is_finite) - ZEND_FE(is_nan, arginfo_is_nan) - ZEND_FE(intdiv, arginfo_intdiv) - ZEND_FE(is_infinite, arginfo_is_infinite) - ZEND_FE(pow, arginfo_pow) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(pi, arginfo_pi) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_finite, arginfo_is_finite) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_nan, arginfo_is_nan) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(intdiv, arginfo_intdiv) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(is_infinite, arginfo_is_infinite) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(pow, arginfo_pow) ZEND_FE(exp, arginfo_exp) ZEND_FE(log, arginfo_log) ZEND_FE(log10, arginfo_log10) @@ -3332,12 +3332,12 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(hypot, arginfo_hypot) ZEND_FE(deg2rad, arginfo_deg2rad) ZEND_FE(rad2deg, arginfo_rad2deg) - ZEND_FE(bindec, arginfo_bindec) - ZEND_FE(hexdec, arginfo_hexdec) - ZEND_FE(octdec, arginfo_octdec) - ZEND_FE(decbin, arginfo_decbin) - ZEND_FE(decoct, arginfo_decoct) - ZEND_FE(dechex, arginfo_dechex) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(bindec, arginfo_bindec) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(hexdec, arginfo_hexdec) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(octdec, arginfo_octdec) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(decbin, arginfo_decbin) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(decoct, arginfo_decoct) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(dechex, arginfo_dechex) ZEND_FE(base_convert, arginfo_base_convert) ZEND_FE(number_format, arginfo_number_format) ZEND_FE(fmod, arginfo_fmod) @@ -3459,10 +3459,10 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(uniqid, arginfo_uniqid) #endif ZEND_FE(parse_url, arginfo_parse_url) - ZEND_FE(urlencode, arginfo_urlencode) - ZEND_FE(urldecode, arginfo_urldecode) - ZEND_FE(rawurlencode, arginfo_rawurlencode) - ZEND_FE(rawurldecode, arginfo_rawurldecode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(urlencode, arginfo_urlencode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(urldecode, arginfo_urldecode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(rawurlencode, arginfo_rawurlencode) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(rawurldecode, arginfo_rawurldecode) ZEND_FE(get_headers, arginfo_get_headers) ZEND_FE(stream_bucket_make_writeable, arginfo_stream_bucket_make_writeable) ZEND_FE(stream_bucket_prepend, arginfo_stream_bucket_prepend) @@ -3475,11 +3475,11 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(var_dump, arginfo_var_dump) ZEND_FE(var_export, arginfo_var_export) ZEND_FE(debug_zval_dump, arginfo_debug_zval_dump) - ZEND_FE(serialize, arginfo_serialize) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(serialize, arginfo_serialize) ZEND_FE(unserialize, arginfo_unserialize) ZEND_FE(memory_get_usage, arginfo_memory_get_usage) ZEND_FE(memory_get_peak_usage, arginfo_memory_get_peak_usage) - ZEND_FE(version_compare, arginfo_version_compare) + ZEND_SUPPORTS_COMPILE_TIME_EVAL_FE(version_compare, arginfo_version_compare) #if defined(PHP_WIN32) ZEND_FE(sapi_windows_cp_set, arginfo_sapi_windows_cp_set) #endif From d4920f42841b068a50cd681ef4b055ff4f94ab00 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Mon, 20 Dec 2021 18:12:10 +0000 Subject: [PATCH 56/75] Move ctype test out from Zend and into ctype extension --- {Zend => ext/ctype}/tests/lc_ctype_inheritance.phpt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {Zend => ext/ctype}/tests/lc_ctype_inheritance.phpt (100%) diff --git a/Zend/tests/lc_ctype_inheritance.phpt b/ext/ctype/tests/lc_ctype_inheritance.phpt similarity index 100% rename from Zend/tests/lc_ctype_inheritance.phpt rename to ext/ctype/tests/lc_ctype_inheritance.phpt From f07c1935839bf87e9d5a26a82a0ed8747c4f178f Mon Sep 17 00:00:00 2001 From: Alex Dowad Date: Sun, 5 Dec 2021 19:29:00 +0200 Subject: [PATCH 57/75] mb_convert_encoding will not auto-detect input string as UUEncode, Base64, QPrint In a2bc57e0e5, mb_detect_encoding was modified to ensure it would never return 'UUENCODE', 'QPrint', or other non-encodings as the "detected text encoding". Before mb_detect_encoding was enhanced so that it could detect any supported text encoding, those were never returned, and they are not desired. Actually, we want to eventually remove them completely from mbstring, since PHP already contains other implementations of UUEncode, QPrint, Base64, and HTML entities. For more clarity on why we need to suppress UUEncode, etc. from being detected by mb_detect_encoding, the existing UUEncode implementation in mbstring *never* treats any input as erroneous. It just accepts everything. This means that it would *always* be treated as a valid choice by mb_detect_encoding, and would be returned in many, many cases where the input is obviously not UUEncoded. It turns out that the form of mb_convert_encoding where the user passes multiple candidate encodings (and mbstring auto-detects which one to use) was also affected by the same issue. Apply the same fix. --- ext/mbstring/mbstring.c | 38 ++++++++++++--------- ext/mbstring/tests/mb_convert_encoding.phpt | 25 +++++--------- 2 files changed, 30 insertions(+), 33 deletions(-) diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 92a3d865bbd1d..a9bbb3e47e1a5 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -2491,6 +2491,23 @@ MBSTRING_API HashTable *php_mb_convert_encoding_recursive(HashTable *input, cons } /* }}} */ +static void remove_non_encodings_from_elist(const mbfl_encoding **elist, size_t *size) +{ + /* mbstring supports some 'text encodings' which aren't really text encodings + * at all, but really 'byte encodings', like Base64, QPrint, and so on. + * These should never be returned by `mb_detect_encoding`. */ + int shift = 0; + for (int i = 0; i < *size; i++) { + const mbfl_encoding *encoding = elist[i]; + if (encoding->no_encoding <= mbfl_no_encoding_charset_min) { + shift++; /* Remove this encoding from the list */ + } else if (shift) { + elist[i - shift] = encoding; + } + } + *size -= shift; +} + /* {{{ Returns converted string in desired encoding */ PHP_FUNCTION(mb_convert_encoding) { @@ -2531,6 +2548,10 @@ PHP_FUNCTION(mb_convert_encoding) free_from_encodings = 0; } + if (num_from_encodings > 1) { + remove_non_encodings_from_elist(from_encodings, &num_from_encodings); + } + if (!num_from_encodings) { efree(ZEND_VOIDP(from_encodings)); zend_argument_value_error(3, "must specify at least one encoding"); @@ -2664,23 +2685,6 @@ PHP_FUNCTION(mb_strtolower) } /* }}} */ -static void remove_non_encodings_from_elist(const mbfl_encoding **elist, size_t *size) -{ - /* mbstring supports some 'text encodings' which aren't really text encodings - * at all, but really 'byte encodings', like Base64, QPrint, and so on. - * These should never be returned by `mb_detect_encoding`. */ - int shift = 0; - for (int i = 0; i < *size; i++) { - const mbfl_encoding *encoding = elist[i]; - if (encoding->no_encoding <= mbfl_no_encoding_charset_min) { - shift++; /* Remove this encoding from the list */ - } else if (shift) { - elist[i - shift] = encoding; - } - } - *size -= shift; -} - /* {{{ Encodings of the given string is returned (as a string) */ PHP_FUNCTION(mb_detect_encoding) { diff --git a/ext/mbstring/tests/mb_convert_encoding.phpt b/ext/mbstring/tests/mb_convert_encoding.phpt index 257873f313079..2c8353e638fe4 100644 --- a/ext/mbstring/tests/mb_convert_encoding.phpt +++ b/ext/mbstring/tests/mb_convert_encoding.phpt @@ -9,33 +9,24 @@ mbstring.language=Japanese 'JIS', 1=>'UTF-8', 2=>'EUC-JP', 3=>'SJIS'); +$a = ['JIS', 'UTF-8', 'EUC-JP', 'SJIS']; $s = $jis; $s = bin2hex(mb_convert_encoding($s, 'EUC-JP', $a)); print("EUC-JP: $s\n"); // EUC-JP @@ -69,6 +59,8 @@ $s = $euc_jp; $s = mb_convert_encoding($s, 'JIS', $a); print("JIS: ".base64_encode($s)."\n"); // JIS +// Regression test for bug #81676 +echo "UTF-8: " . mb_convert_encoding('test', 'UTF-8', mb_list_encodings()), "\n"; // Using Detect Order echo "== DETECT ORDER ==\n"; @@ -117,6 +109,7 @@ JIS: GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg== EUC-JP: c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3 SJIS: k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg== JIS: GyRCRnxLXDhsJUYlLSU5JUgkRyQ5ISMbKEIwMTIzNBskQiM1IzYjNyM4IzkhIxsoQg== +UTF-8: test == DETECT ORDER == EUC-JP: c6fccbdcb8eca5c6a5ada5b9a5c8a4c7a4b9a1a33031323334a3b5a3b6a3b7a3b8a3b9a1a3 SJIS: k/qWe4zqg2WDTINYg2eCxYK3gUIwMTIzNIJUglWCVoJXgliBQg== From 6d5922bed5930b3ed453e9364c16ccd33ff45a86 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Mon, 20 Dec 2021 23:52:46 +0300 Subject: [PATCH 58/75] JIT: Fix incorrect JIT prologur size for CLANG/x86 build Fixes oss-fuzz #42724 --- ext/opcache/jit/zend_jit_x86.dasc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 543d78a1dd278..48527b1076c04 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -3440,7 +3440,7 @@ static int zend_jit_trace_link_to_root(dasm_State **Dst, zend_jit_trace_info *t, #if defined(__x86_64__) || defined(_M_X64) prologue_size = 17; #else - prologue_size = 12; + prologue_size = 13; #endif } link_addr = (const void*)((const char*)t->code_start + prologue_size); From cb10ac1d53249df9c367815ab60f346b57f4d015 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 21 Dec 2021 00:02:45 +0300 Subject: [PATCH 59/75] Fixed compilation warning --- ext/opcache/jit/zend_jit_x86.dasc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 48527b1076c04..54b1f1ce09c90 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -4395,6 +4395,7 @@ static int zend_jit_math_long_long(dasm_State **Dst, tmp_reg = ZREG_R1; } | LONG_MATH opcode, result_reg, op2_addr, tmp_reg + (void)tmp_reg; } } if (may_overflow) { @@ -5135,6 +5136,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst, } | GET_ZVAL_LVAL result_reg, op1_addr | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, tmp_reg + (void)tmp_reg; } else { if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RAX) { | mov aword T1, r0 // save @@ -5233,6 +5235,7 @@ static int zend_jit_long_math_helper(dasm_State **Dst, } | GET_ZVAL_LVAL result_reg, op1_addr | LONG_MATH opcode, result_reg, op2_addr, tmp_reg + (void)tmp_reg; } if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) { From aa35499b1c6a7adfa5de453736a0f0626378f69a Mon Sep 17 00:00:00 2001 From: Arnaud Le Blanc Date: Tue, 21 Dec 2021 07:17:12 +0100 Subject: [PATCH 60/75] Use new param API in ext/pcntl (#7751) --- ext/pcntl/pcntl.c | 161 ++++++++++++++++++++++++++-------------------- 1 file changed, 92 insertions(+), 69 deletions(-) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 645b211952b9f..61fe69d123e93 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -521,9 +521,7 @@ PHP_FUNCTION(pcntl_fork) { pid_t id; - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); id = fork(); if (id == -1) { @@ -540,9 +538,9 @@ PHP_FUNCTION(pcntl_alarm) { zend_long seconds; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &seconds) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(seconds); + ZEND_PARSE_PARAMETERS_END(); RETURN_LONG((zend_long) alarm(seconds)); } @@ -592,9 +590,13 @@ PHP_FUNCTION(pcntl_waitpid) struct rusage rusage; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|lz", &pid, &z_status, &options, &z_rusage) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 4) + Z_PARAM_LONG(pid) + Z_PARAM_ZVAL(z_status) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(options) + Z_PARAM_ZVAL(z_rusage) + ZEND_PARSE_PARAMETERS_END(); status = zval_get_long(z_status); @@ -641,9 +643,12 @@ PHP_FUNCTION(pcntl_wait) struct rusage rusage; #endif - if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|lz", &z_status, &options, &z_rusage) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_ZVAL(z_status) + Z_PARAM_OPTIONAL + Z_PARAM_LONG(options) + Z_PARAM_ZVAL(z_rusage) + ZEND_PARSE_PARAMETERS_END(); status = zval_get_long(z_status); #ifdef HAVE_WAIT3 @@ -689,9 +694,9 @@ PHP_FUNCTION(pcntl_wifexited) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WIFEXITED int int_status_word = (int) status_word; @@ -709,9 +714,9 @@ PHP_FUNCTION(pcntl_wifstopped) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WIFSTOPPED int int_status_word = (int) status_word; @@ -729,9 +734,9 @@ PHP_FUNCTION(pcntl_wifsignaled) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WIFSIGNALED int int_status_word = (int) status_word; @@ -743,14 +748,15 @@ PHP_FUNCTION(pcntl_wifsignaled) RETURN_FALSE; } /* }}} */ + /* {{{ Returns true if the child status code represents a process that was resumed due to a SIGCONT signal */ PHP_FUNCTION(pcntl_wifcontinued) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef HAVE_WCONTINUED int int_status_word = (int) status_word; @@ -768,9 +774,9 @@ PHP_FUNCTION(pcntl_wexitstatus) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WEXITSTATUS int int_status_word = (int) status_word; @@ -786,9 +792,9 @@ PHP_FUNCTION(pcntl_wtermsig) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WTERMSIG int int_status_word = (int) status_word; @@ -804,9 +810,9 @@ PHP_FUNCTION(pcntl_wstopsig) { zend_long status_word; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &status_word) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(status_word) + ZEND_PARSE_PARAMETERS_END(); #ifdef WSTOPSIG int int_status_word = (int) status_word; @@ -833,9 +839,12 @@ PHP_FUNCTION(pcntl_exec) size_t path_len; zend_ulong key_num; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "p|aa", &path, &path_len, &args, &envs) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_PATH(path, path_len) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY(args) + Z_PARAM_ARRAY(envs) + ZEND_PARSE_PARAMETERS_END(); if (ZEND_NUM_ARGS() > 1) { /* Build argument list */ @@ -932,9 +941,12 @@ PHP_FUNCTION(pcntl_signal) bool restart_syscalls_is_null = 1; char *error = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "lz|b!", &signo, &handle, &restart_syscalls, &restart_syscalls_is_null) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_LONG(signo) + Z_PARAM_ZVAL(handle) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL_OR_NULL(restart_syscalls, restart_syscalls_is_null) + ZEND_PARSE_PARAMETERS_END(); if (signo < 1) { zend_argument_value_error(1, "must be greater than or equal to 1"); @@ -1011,9 +1023,9 @@ PHP_FUNCTION(pcntl_signal_get_handler) zval *prev_handle; zend_long signo; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &signo) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(signo) + ZEND_PARSE_PARAMETERS_END(); if (signo < 1 || signo > 32) { zend_argument_value_error(1, "must be between 1 and 32"); @@ -1030,9 +1042,7 @@ PHP_FUNCTION(pcntl_signal_get_handler) /* {{{ Dispatch signals to signal handlers */ PHP_FUNCTION(pcntl_signal_dispatch) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); pcntl_signal_dispatch(); RETURN_TRUE; @@ -1047,9 +1057,12 @@ PHP_FUNCTION(pcntl_sigprocmask) zval *user_set, *user_oldset = NULL, *user_signo; sigset_t set, oldset; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "la|z", &how, &user_set, &user_oldset) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_LONG(how) + Z_PARAM_ARRAY(user_set) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(user_oldset) + ZEND_PARSE_PARAMETERS_END(); if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) { PCNTL_G(last_error) = errno; @@ -1103,13 +1116,19 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{ struct timespec timeout; if (timedwait) { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|zll", &user_set, &user_siginfo, &tv_sec, &tv_nsec) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 4) + Z_PARAM_ARRAY(user_set) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(user_siginfo) + Z_PARAM_LONG(tv_sec) + Z_PARAM_LONG(tv_nsec) + ZEND_PARSE_PARAMETERS_END(); } else { - if (zend_parse_parameters(ZEND_NUM_ARGS(), "a|z", &user_set, &user_siginfo) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_ARRAY(user_set) + Z_PARAM_OPTIONAL + Z_PARAM_ZVAL(user_siginfo) + ZEND_PARSE_PARAMETERS_END(); } if (sigemptyset(&set) != 0) { @@ -1231,9 +1250,11 @@ PHP_FUNCTION(pcntl_getpriority) bool pid_is_null = 1; int pri; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!l", &pid, &pid_is_null, &who) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(pid, pid_is_null) + Z_PARAM_LONG(who) + ZEND_PARSE_PARAMETERS_END(); /* needs to be cleared, since any returned value is valid */ errno = 0; @@ -1270,9 +1291,12 @@ PHP_FUNCTION(pcntl_setpriority) bool pid_is_null = 1; zend_long pri; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l!l", &pri, &pid, &pid_is_null, &who) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 3) + Z_PARAM_LONG(pri) + Z_PARAM_OPTIONAL + Z_PARAM_LONG_OR_NULL(pid, pid_is_null) + Z_PARAM_LONG(who) + ZEND_PARSE_PARAMETERS_END(); if (setpriority(who, pid_is_null ? getpid() : pid, pri)) { PCNTL_G(last_error) = errno; @@ -1304,9 +1328,7 @@ PHP_FUNCTION(pcntl_setpriority) /* {{{ Retrieve the error number set by the last pcntl function which failed. */ PHP_FUNCTION(pcntl_get_last_error) { - if (zend_parse_parameters_none() == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_NONE(); RETURN_LONG(PCNTL_G(last_error)); } @@ -1317,9 +1339,9 @@ PHP_FUNCTION(pcntl_strerror) { zend_long error; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &error) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(error) + ZEND_PARSE_PARAMETERS_END(); RETURN_STRING(strerror(error)); } @@ -1437,9 +1459,10 @@ PHP_FUNCTION(pcntl_async_signals) { bool on, on_is_null = 1; - if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b!", &on, &on_is_null) == FAILURE) { - RETURN_THROWS(); - } + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_BOOL_OR_NULL(on, on_is_null) + ZEND_PARSE_PARAMETERS_END(); if (on_is_null) { RETURN_BOOL(PCNTL_G(async_signals)); From 1a4d2dd96276b14ecb456faeb98c354985102908 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 21 Dec 2021 06:18:11 +0000 Subject: [PATCH 61/75] zend alloc USE_ZEND_ALLOC_HUGE_PAGES option support on solaris based systems (#7789) --- Zend/zend_alloc.c | 20 ++++++++++++++------ configure.ac | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index 12b4ce900e041..ace032e5e72d5 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -662,6 +662,18 @@ static zend_always_inline int zend_mm_bitset_is_free_range(zend_mm_bitset *bitse /* Chunks */ /**********/ +static zend_always_inline void zend_mm_hugepage(void* ptr, size_t size) +{ +#if defined(MADV_HUGEPAGE) + (void)madvise(ptr, size, MADV_HUGEPAGE); +#elif defined(HAVE_MEMCNTL) + struct memcntl_mha m = {.mha_cmd = MHA_MAPSIZE_VA, .mha_pagesize = ZEND_MM_CHUNK_SIZE, .mha_flags = 0}; + (void)memcntl(ptr, size, MC_HAT_ADVISE, (char *)&m, 0, 0); +#else + zend_error_noreturn(E_WARNING, "huge_pages: thp unsupported on this platform"); +#endif +} + static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) { void *ptr = zend_mm_mmap(size); @@ -669,11 +681,9 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) if (ptr == NULL) { return NULL; } else if (ZEND_MM_ALIGNED_OFFSET(ptr, alignment) == 0) { -#ifdef MADV_HUGEPAGE if (zend_mm_use_huge_pages) { - madvise(ptr, size, MADV_HUGEPAGE); + zend_mm_hugepage(ptr, size); } -#endif return ptr; } else { size_t offset; @@ -702,11 +712,9 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) if (alignment > REAL_PAGE_SIZE) { zend_mm_munmap((char*)ptr + size, alignment - REAL_PAGE_SIZE); } -# ifdef MADV_HUGEPAGE if (zend_mm_use_huge_pages) { - madvise(ptr, size, MADV_HUGEPAGE); + zend_mm_hugepage(ptr, size); } -# endif #endif return ptr; } diff --git a/configure.ac b/configure.ac index db1cac4ca6018..6ad00bc22217c 100644 --- a/configure.ac +++ b/configure.ac @@ -587,6 +587,7 @@ inet_ntop \ inet_pton \ localtime_r \ lchown \ +memcntl \ memmove \ mkstemp \ mmap \ From 62bcb31706975b383d7911d529c6e88a7b8d9d3b Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sat, 11 Dec 2021 09:07:42 +0000 Subject: [PATCH 62/75] zend gdb detection fix on FreeBSD. --- Zend/zend_gdb.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Zend/zend_gdb.c b/Zend/zend_gdb.c index ce6dc6a7850f9..8ba40f01d22f9 100644 --- a/Zend/zend_gdb.c +++ b/Zend/zend_gdb.c @@ -25,6 +25,11 @@ #include #include +#if defined(__FreeBSD__) +# include +# include +#endif + enum { ZEND_GDBJIT_NOACTION, ZEND_GDBJIT_REGISTER, @@ -105,6 +110,7 @@ ZEND_API void zend_gdb_unregister_all(void) ZEND_API bool zend_gdb_present(void) { bool ret = 0; +#if defined(__linux__) /* netbsd while having this procfs part, does not hold the tracer pid */ int fd = open("/proc/self/status", O_RDONLY); if (fd > 0) { @@ -136,6 +142,17 @@ ZEND_API bool zend_gdb_present(void) close(fd); } +#elif defined(__FreeBSD__) + struct kinfo_proc *proc = kinfo_getproc(getpid()); + + if (proc) { + if ((proc->ki_flag & P_TRACED) != 0) { + struct kinfo_proc *dbg = kinfo_getproc(proc->ki_tracer); + + ret = (dbg && strstr(dbg->ki_comm, "gdb")); + } + } +#endif return ret; } From ebace1d7d04a15d8eb3e88cee6c990b60b745ed4 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Tue, 21 Dec 2021 06:23:22 +0000 Subject: [PATCH 63/75] pcntl add ECAPMODE from FreeBSD (#7716) --- ext/pcntl/pcntl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 61fe69d123e93..463dca61891cf 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -446,6 +446,9 @@ static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS) #ifdef EUSERS REGISTER_PCNTL_ERRNO_CONSTANT(EUSERS); #endif +#ifdef ECAPMODE + REGISTER_PCNTL_ERRNO_CONSTANT(ECAPMODE); +#endif } static PHP_GINIT_FUNCTION(pcntl) From 51647eb23e61d214cdeb4167fcee1e2c38924bfe Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sun, 21 Nov 2021 19:57:07 +0000 Subject: [PATCH 64/75] socket: ancillary credentials build fix for non linux systems. for systems using SO_PASSCRED sockopt flag but not using ucred struct. --- ext/sockets/config.m4 | 28 ++++++++++++++++++++++++++++ ext/sockets/conversions.c | 9 ++++++++- ext/sockets/sendrecvmsg.c | 9 +++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/ext/sockets/config.m4 b/ext/sockets/config.m4 index b78186ee11ba6..d4f92082c3b2d 100644 --- a/ext/sockets/config.m4 +++ b/ext/sockets/config.m4 @@ -62,6 +62,34 @@ if test "$PHP_SOCKETS" != "no"; then AC_DEFINE(HAVE_AI_IDN,1,[Whether you have AI_IDN]) fi + dnl Check for struct ucred + dnl checking the header is not enough (eg DragonFlyBSD) + AC_CACHE_CHECK([if ancillary credentials uses ucred],[ac_cv_ucred], + [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include + ]], [[struct ucred u = {.gid = 0};]])], + [ac_cv_ucred=yes], [ac_cv_ucred=no]) + ]) + + if test "$ac_cv_ucred" = yes; then + AC_DEFINE(ANC_CREDS_UCRED,1,[Uses ucred struct]) + fi + + dnl Check for struct cmsgcred + AC_CACHE_CHECK([if ancillary credentials uses cmsgcred],[ac_cv_cmsgcred], + [ + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include + ]], [[struct cmsgcred c = {0};]])], + [ac_cv_cmsgcred=yes], [ac_cv_cmsgcred=no]) + ]) + + if test "$ac_cv_cmsgcred" = yes; then + AC_DEFINE(ANC_CREDS_CMSGCRED,1,[Uses cmsgcred struct]) + fi + + PHP_SOCKETS_CFLAGS=-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 case $host_alias in *darwin*) PHP_SOCKETS_CFLAGS="$PHP_SOCKETS_CFLAGS -D__APPLE_USE_RFC_3542" diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index 4eaa217b73805..ecf3fb47b508d 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -1297,13 +1297,20 @@ void to_zval_read_in6_pktinfo(const char *data, zval *zv, res_context *ctx) } #endif -/* CONVERSIONS for struct ucred */ +/* CONVERSIONS for struct ucred/cmsgcred */ #ifdef SO_PASSCRED static const field_descriptor descriptors_ucred[] = { +#if defined(ANC_CREDS_UCRED) {"pid", sizeof("pid"), 1, offsetof(struct ucred, pid), from_zval_write_pid_t, to_zval_read_pid_t}, {"uid", sizeof("uid"), 1, offsetof(struct ucred, uid), from_zval_write_uid_t, to_zval_read_uid_t}, /* assume the type gid_t is the same as uid_t: */ {"gid", sizeof("gid"), 1, offsetof(struct ucred, gid), from_zval_write_uid_t, to_zval_read_uid_t}, +#elif defined(ANC_CREDS_CMSGCRED) + {"pid", sizeof("pid"), 1, offsetof(struct cmsgcred, cmcred_pid), from_zval_write_pid_t, to_zval_read_pid_t}, + {"uid", sizeof("uid"), 1, offsetof(struct cmsgcred, cmcred_uid), from_zval_write_uid_t, to_zval_read_uid_t}, + /* assume the type gid_t is the same as uid_t: */ + {"gid", sizeof("gid"), 1, offsetof(struct cmsgcred, cmcred_gid), from_zval_write_uid_t, to_zval_read_uid_t}, +#endif {0} }; void from_zval_write_ucred(const zval *container, char *ucred_c, ser_context *ctx) diff --git a/ext/sockets/sendrecvmsg.c b/ext/sockets/sendrecvmsg.c index e5dbc52fb1e5b..906e6b81007b5 100644 --- a/ext/sockets/sendrecvmsg.c +++ b/ext/sockets/sendrecvmsg.c @@ -121,8 +121,13 @@ static void init_ancillary_registry(void) #endif #ifdef SO_PASSCRED +#ifdef ANC_CREDS_UCRED PUT_ENTRY(sizeof(struct ucred), 0, 0, from_zval_write_ucred, to_zval_read_ucred, SOL_SOCKET, SCM_CREDENTIALS); +#else + PUT_ENTRY(sizeof(struct cmsgcred), 0, 0, from_zval_write_ucred, + to_zval_read_ucred, SOL_SOCKET, SCM_CREDS); +#endif #endif #ifdef SCM_RIGHTS @@ -436,7 +441,11 @@ void php_socket_sendrecvmsg_init(INIT_FUNC_ARGS) REGISTER_LONG_CONSTANT("SCM_RIGHTS", SCM_RIGHTS, CONST_CS | CONST_PERSISTENT); #endif #ifdef SO_PASSCRED +#ifdef SCM_CREDENTIALS REGISTER_LONG_CONSTANT("SCM_CREDENTIALS", SCM_CREDENTIALS, CONST_CS | CONST_PERSISTENT); +#else + REGISTER_LONG_CONSTANT("SCM_CREDS", SCM_CREDS, CONST_CS | CONST_PERSISTENT); +#endif REGISTER_LONG_CONSTANT("SO_PASSCRED", SO_PASSCRED, CONST_CS | CONST_PERSISTENT); #endif From 80b02275bb2f0e7b3b448989910097cf897e7c93 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Sat, 11 Dec 2021 06:26:16 +0000 Subject: [PATCH 65/75] socket cmsg credential test fixes, "backporting" from the FreeBSD PR. --- ext/sockets/tests/socket_cmsg_credentials.phpt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/sockets/tests/socket_cmsg_credentials.phpt b/ext/sockets/tests/socket_cmsg_credentials.phpt index f2b56018d68c8..1a58b300c20ae 100644 --- a/ext/sockets/tests/socket_cmsg_credentials.phpt +++ b/ext/sockets/tests/socket_cmsg_credentials.phpt @@ -14,10 +14,6 @@ die('skip not for AIX'); if (!defined('SO_PASSCRED')) { die('skip SO_PASSCRED is not defined'); } ---CLEAN-- - +--CLEAN-- + Date: Wed, 21 Jul 2021 19:22:19 +0200 Subject: [PATCH 66/75] New internal interface for fast text conversion in mbstring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When converting text to/from wchars, mbstring makes one function call for each and every byte or wchar to be converted. Typically, each of these conversion functions contains a state machine, and its state has to be restored and then saved for every single one of these calls. It doesn't take much to see that this is grossly inefficient. Instead of converting one byte or wchar on each call, the new conversion functions will either fill up or drain a whole buffer of wchars on each call. In benchmarks, this is about 3-10× faster. Adding the new, faster conversion functions for all supported legacy text encodings still needs some work. Also, all the code which uses the old-style conversion functions needs to be converted to use the new ones. After that, the old code can be dropped. (The mailparse extension will also have to be fixed up so it will still compile.) --- ext/mbstring/libmbfl/filters/mbfilter_7bit.c | 2 + .../libmbfl/filters/mbfilter_base64.c | 2 + ext/mbstring/libmbfl/filters/mbfilter_big5.c | 8 +- .../libmbfl/filters/mbfilter_cp5022x.c | 12 +- .../libmbfl/filters/mbfilter_cp51932.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_cp932.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_cp936.c | 4 +- .../libmbfl/filters/mbfilter_euc_cn.c | 4 +- .../libmbfl/filters/mbfilter_euc_jp.c | 128 ++- .../libmbfl/filters/mbfilter_euc_jp_2004.c | 4 +- .../libmbfl/filters/mbfilter_euc_jp_win.c | 4 +- .../libmbfl/filters/mbfilter_euc_kr.c | 4 +- .../libmbfl/filters/mbfilter_euc_tw.c | 4 +- .../libmbfl/filters/mbfilter_gb18030.c | 4 +- .../libmbfl/filters/mbfilter_htmlent.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_hz.c | 4 +- .../libmbfl/filters/mbfilter_iso2022_jp_ms.c | 4 +- .../libmbfl/filters/mbfilter_iso2022_kr.c | 4 +- .../libmbfl/filters/mbfilter_iso2022jp_2004.c | 4 +- .../filters/mbfilter_iso2022jp_mobile.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_jis.c | 225 ++++- .../libmbfl/filters/mbfilter_qprint.c | 2 + .../libmbfl/filters/mbfilter_singlebyte.c | 766 +++++++++++------- ext/mbstring/libmbfl/filters/mbfilter_sjis.c | 119 ++- .../libmbfl/filters/mbfilter_sjis_2004.c | 4 +- .../libmbfl/filters/mbfilter_sjis_mac.c | 4 +- .../libmbfl/filters/mbfilter_sjis_mobile.c | 12 +- ext/mbstring/libmbfl/filters/mbfilter_ucs2.c | 133 ++- ext/mbstring/libmbfl/filters/mbfilter_ucs4.c | 140 +++- ext/mbstring/libmbfl/filters/mbfilter_uhc.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_utf16.c | 205 ++++- ext/mbstring/libmbfl/filters/mbfilter_utf32.c | 149 +++- ext/mbstring/libmbfl/filters/mbfilter_utf7.c | 283 ++++++- .../libmbfl/filters/mbfilter_utf7imap.c | 4 +- ext/mbstring/libmbfl/filters/mbfilter_utf8.c | 161 +++- .../libmbfl/filters/mbfilter_utf8_mobile.c | 16 +- .../libmbfl/filters/mbfilter_uuencode.c | 2 + ext/mbstring/libmbfl/mbfl/mbfilter.c | 95 ++- ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c | 4 +- ext/mbstring/libmbfl/mbfl/mbfilter_pass.c | 2 + ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c | 2 + ext/mbstring/libmbfl/mbfl/mbfl_convert.c | 93 +++ ext/mbstring/libmbfl/mbfl/mbfl_convert.h | 3 + ext/mbstring/libmbfl/mbfl/mbfl_encoding.h | 93 ++- ext/mbstring/mbstring.c | 12 +- ext/mbstring/tests/armscii8_encoding.phpt | 4 + ext/mbstring/tests/bug65045.phpt | 24 +- ext/mbstring/tests/cp1252_encoding.phpt | 4 + ext/mbstring/tests/cp1254_encoding.phpt | 4 + ext/mbstring/tests/cp850_encoding.phpt | 6 +- ext/mbstring/tests/cp866_encoding.phpt | 3 + ext/mbstring/tests/encoding_tests.inc | 8 + .../tests/illformed_utf_sequences.phpt | 1 - ext/mbstring/tests/iso2022jp_encoding.phpt | 1 + ext/mbstring/tests/iso8859_encodings.phpt | 4 + ext/mbstring/tests/koi8r_encoding.phpt | 3 + ext/mbstring/tests/koi8u_encoding.phpt | 3 + .../mb_substitute_character_variation2.phpt | 2 +- ext/mbstring/tests/utf_encodings.phpt | 38 +- 59 files changed, 2436 insertions(+), 414 deletions(-) diff --git a/ext/mbstring/libmbfl/filters/mbfilter_7bit.c b/ext/mbstring/libmbfl/filters/mbfilter_7bit.c index dbf8993128472..0a6fe78957084 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_7bit.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_7bit.c @@ -39,6 +39,8 @@ const mbfl_encoding mbfl_encoding_7bit = { NULL, MBFL_ENCTYPE_SBCS, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_base64.c b/ext/mbstring/libmbfl/filters/mbfilter_base64.c index 04161c94ab3bc..86700c84990da 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_base64.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_base64.c @@ -39,6 +39,8 @@ const mbfl_encoding mbfl_encoding_base64 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_big5.c b/ext/mbstring/libmbfl/filters/mbfilter_big5.c index 561ab8c225ae0..2ba32ee04563d 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_big5.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_big5.c @@ -63,7 +63,9 @@ const mbfl_encoding mbfl_encoding_big5 = { mblen_table_big5, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_big5_wchar, - &vtbl_wchar_big5 + &vtbl_wchar_big5, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_cp950 = { @@ -74,7 +76,9 @@ const mbfl_encoding mbfl_encoding_cp950 = { mblen_table_big5, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp950_wchar, - &vtbl_wchar_cp950 + &vtbl_wchar_cp950, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_big5_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c index deb6e8ee0204f..a67b538bb4311 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c @@ -55,7 +55,9 @@ const mbfl_encoding mbfl_encoding_cp50220 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp50220_wchar, - &vtbl_wchar_cp50220 + &vtbl_wchar_cp50220, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_cp50221 = { @@ -66,7 +68,9 @@ const mbfl_encoding mbfl_encoding_cp50221 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp50221_wchar, - &vtbl_wchar_cp50221 + &vtbl_wchar_cp50221, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_cp50222 = { @@ -77,7 +81,9 @@ const mbfl_encoding mbfl_encoding_cp50222 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp50222_wchar, - &vtbl_wchar_cp50222 + &vtbl_wchar_cp50222, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_cp50220_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c index c0069a93fb98b..2f7193462e025 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp51932.c @@ -65,7 +65,9 @@ const mbfl_encoding mbfl_encoding_cp51932 = { mblen_table_eucjp, 0, &vtbl_cp51932_wchar, - &vtbl_wchar_cp51932 + &vtbl_wchar_cp51932, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_cp51932_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp932.c b/ext/mbstring/libmbfl/filters/mbfilter_cp932.c index 9c24fa64494f2..06ac6b22b26f2 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp932.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp932.c @@ -64,7 +64,9 @@ const mbfl_encoding mbfl_encoding_cp932 = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp932_wchar, - &vtbl_wchar_cp932 + &vtbl_wchar_cp932, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_cp932_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp936.c b/ext/mbstring/libmbfl/filters/mbfilter_cp936.c index 22a759ee79ff4..f12523dedca2a 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp936.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp936.c @@ -63,7 +63,9 @@ const mbfl_encoding mbfl_encoding_cp936 = { mblen_table_cp936, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_cp936_wchar, - &vtbl_wchar_cp936 + &vtbl_wchar_cp936, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_cp936_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c index 01c48e433eedd..0465a814ff3d8 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_cn.c @@ -63,7 +63,9 @@ const mbfl_encoding mbfl_encoding_euc_cn = { mblen_table_euccn, 0, &vtbl_euccn_wchar, - &vtbl_wchar_euccn + &vtbl_wchar_euccn, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_euccn_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c index 7dd095862ec87..d83c47bd67006 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp.c @@ -34,6 +34,8 @@ #include "unicode_table_jis.h" static int mbfl_filt_conv_eucjp_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_eucjp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_eucjp(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); const unsigned char mblen_table_eucjp[] = { /* 0xA1-0xFE */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -64,7 +66,9 @@ const mbfl_encoding mbfl_encoding_euc_jp = { mblen_table_eucjp, 0, &vtbl_eucjp_wchar, - &vtbl_wchar_eucjp + &vtbl_wchar_eucjp, + mb_eucjp_to_wchar, + mb_wchar_to_eucjp }; const struct mbfl_convert_vtbl vtbl_eucjp_wchar = { @@ -243,3 +247,125 @@ mbfl_filt_conv_wchar_eucjp(int c, mbfl_convert_filter *filter) return 0; } + +static size_t mb_eucjp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + + if (c < 0x80) { + *out++ = c; + } else if (c >= 0xA1 && c <= 0xFE && p < e) { + /* JISX 0208 */ + unsigned char c2 = *p++; + if (c2 >= 0xA1 && c2 <= 0xFE) { + unsigned int s = (c - 0xA1)*94 + c2 - 0xA1; + if (s < jisx0208_ucs_table_size) { + uint32_t w = jisx0208_ucs_table[s]; + if (!w) + w = MBFL_BAD_INPUT; + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else if (c == 0x8E && p < e) { + /* Kana */ + unsigned char c2 = *p++; + *out++ = (c2 >= 0xA1 && c2 <= 0xDF) ? 0xFEC0 + c2 : MBFL_BAD_INPUT; + } else if (c == 0x8F) { + /* JISX 0212 */ + if ((e - p) >= 2) { + unsigned char c2 = *p++; + unsigned char c3 = *p++; + if (c3 >= 0xA1 && c3 <= 0xFE && c2 >= 0xA1 && c2 <= 0xFE) { + unsigned int s = (c2 - 0xA1)*94 + c3 - 0xA1; + if (s < jisx0212_ucs_table_size) { + uint32_t w = jisx0212_ucs_table[s]; + if (!w) + w = MBFL_BAD_INPUT; + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else { + *out++ = MBFL_BAD_INPUT; + p = e; /* Jump to end of string */ + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_eucjp(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + unsigned int s = 0; + + if (w == 0xAF) { /* U+00AF is MACRON */ + s = 0xA2B4; /* Use JIS X 0212 overline */ + } else if (w >= ucs_a1_jis_table_min && w < ucs_a1_jis_table_max) { + s = ucs_a1_jis_table[w - ucs_a1_jis_table_min]; + } else if (w >= ucs_a2_jis_table_min && w < ucs_a2_jis_table_max) { + s = ucs_a2_jis_table[w - ucs_a2_jis_table_min]; + } else if (w >= ucs_i_jis_table_min && w < ucs_i_jis_table_max) { + s = ucs_i_jis_table[w - ucs_i_jis_table_min]; + } else if (w >= ucs_r_jis_table_min && w < ucs_r_jis_table_max) { + s = ucs_r_jis_table[w - ucs_r_jis_table_min]; + } + + if (s == 0) { + if (w == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ + s = 0x2140; + } else if (w == 0x2225) { /* PARALLEL TO */ + s = 0x2142; + } else if (w == 0xFF0D) { /* FULLWIDTH HYPHEN-MINUS */ + s = 0x215D; + } else if (w == 0xFFE0) { /* FULLWIDTH CENT SIGN */ + s = 0x2171; + } else if (w == 0xFFE1) { /* FULLWIDTH POUND SIGN */ + s = 0x2172; + } else if (w == 0xFFE2) { /* FULLWIDTH NOT SIGN */ + s = 0x224C; + } else if (w == 0) { + out = mb_convert_buf_add(out, 0); + continue; + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_eucjp); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + continue; + } + } + + if (s < 0x80) { + out = mb_convert_buf_add(out, s); + } else if (s < 0x100) { + out = mb_convert_buf_add2(out, 0x8E, s); + } else if (s < 0x8080) { + out = mb_convert_buf_add2(out, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); + } else { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 3); + out = mb_convert_buf_add3(out, 0x8F, ((s >> 8) & 0xFF) | 0x80, (s & 0xFF) | 0x80); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_2004.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_2004.c index 0709a9f12d075..e4f919304e2b8 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_2004.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_2004.c @@ -43,7 +43,9 @@ const mbfl_encoding mbfl_encoding_eucjp2004 = { mblen_table_eucjp, 0, &vtbl_eucjp2004_wchar, - &vtbl_wchar_eucjp2004 + &vtbl_wchar_eucjp2004, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_eucjp2004_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c index 1209e63148f75..49e7f9dccd279 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_jp_win.c @@ -65,7 +65,9 @@ const mbfl_encoding mbfl_encoding_eucjp_win = { mblen_table_eucjp, 0, &vtbl_eucjpwin_wchar, - &vtbl_wchar_eucjpwin + &vtbl_wchar_eucjpwin, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_eucjpwin_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c index 8362138d15a13..70c4e3f9d5949 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_kr.c @@ -62,7 +62,9 @@ const mbfl_encoding mbfl_encoding_euc_kr = { mblen_table_euckr, 0, &vtbl_euckr_wchar, - &vtbl_wchar_euckr + &vtbl_wchar_euckr, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_euckr_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c b/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c index e2c3bceaa509a..f505ca17a3923 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_euc_tw.c @@ -64,7 +64,9 @@ const mbfl_encoding mbfl_encoding_euc_tw = { mblen_table_euctw, 0, &vtbl_euctw_wchar, - &vtbl_wchar_euctw + &vtbl_wchar_euctw, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_euctw_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c b/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c index 4a8939523a5bf..00494daf358f0 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_gb18030.c @@ -45,7 +45,9 @@ const mbfl_encoding mbfl_encoding_gb18030 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_gb18030_wchar, - &vtbl_wchar_gb18030 + &vtbl_wchar_gb18030, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_gb18030_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c b/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c index 3a7e879ceaab4..bf6a0ec2cc479 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c @@ -61,7 +61,9 @@ const mbfl_encoding mbfl_encoding_html_ent = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_html_wchar, - &vtbl_wchar_html + &vtbl_wchar_html, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_wchar_html = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_hz.c b/ext/mbstring/libmbfl/filters/mbfilter_hz.c index 722d73dd40c64..3370cd93ef88b 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_hz.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_hz.c @@ -43,7 +43,9 @@ const mbfl_encoding mbfl_encoding_hz = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_hz_wchar, - &vtbl_wchar_hz + &vtbl_wchar_hz, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_hz_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c index 41d4088c475e8..f26cbbeb8aa97 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_jp_ms.c @@ -46,7 +46,9 @@ const mbfl_encoding mbfl_encoding_2022jpms = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_2022jpms_wchar, - &vtbl_wchar_2022jpms + &vtbl_wchar_2022jpms, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jpms_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c index f012656b1974b..cbb32bd635e3f 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022_kr.c @@ -47,7 +47,9 @@ const mbfl_encoding mbfl_encoding_2022kr = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_2022kr_wchar, - &vtbl_wchar_2022kr + &vtbl_wchar_2022kr, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_wchar_2022kr = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_2004.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_2004.c index c54941f23dcbb..45b71a8a98bde 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_2004.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_2004.c @@ -43,7 +43,9 @@ const mbfl_encoding mbfl_encoding_2022jp_2004 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_2022jp_2004_wchar, - &vtbl_wchar_2022jp_2004 + &vtbl_wchar_2022jp_2004, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jp_2004_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c index 3d289f1191595..450ac0c932f8c 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_iso2022jp_mobile.c @@ -48,7 +48,9 @@ const mbfl_encoding mbfl_encoding_2022jp_kddi = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_2022jp_kddi_wchar, - &vtbl_wchar_2022jp_kddi + &vtbl_wchar_2022jp_kddi, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_2022jp_kddi_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_jis.c b/ext/mbstring/libmbfl/filters/mbfilter_jis.c index 9de18964ccef2..b175743a4afbe 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_jis.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_jis.c @@ -34,6 +34,8 @@ #include "unicode_table_jis.h" static int mbfl_filt_conv_jis_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_iso2022jp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_iso2022jp(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); const mbfl_encoding mbfl_encoding_jis = { mbfl_no_encoding_jis, @@ -43,7 +45,9 @@ const mbfl_encoding mbfl_encoding_jis = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_jis_wchar, - &vtbl_wchar_jis + &vtbl_wchar_jis, + mb_iso2022jp_to_wchar, + NULL }; const mbfl_encoding mbfl_encoding_2022jp = { @@ -54,7 +58,9 @@ const mbfl_encoding mbfl_encoding_2022jp = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_2022jp_wchar, - &vtbl_wchar_2022jp + &vtbl_wchar_2022jp, + mb_iso2022jp_to_wchar, + mb_wchar_to_iso2022jp }; const struct mbfl_convert_vtbl vtbl_jis_wchar = { @@ -446,3 +452,218 @@ mbfl_filt_conv_any_jis_flush(mbfl_convert_filter *filter) return 0; } + +#define ASCII 0 +#define JISX_0201_LATIN 1 +#define JISX_0201_KANA 2 +#define JISX_0208 3 +#define JISX_0212 4 + +static size_t mb_iso2022jp_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + + if (c == 0x1B) { + /* ESC seen; this is an escape sequence */ + if ((e - p) < 2) { + *out++ = MBFL_BAD_INPUT; + continue; + } + + unsigned char c2 = *p++; + if (c2 == '$') { + unsigned char c3 = *p++; + if (c3 == '@' || c3 == 'B') { + *state = JISX_0208; + } else if (c3 == '(') { + if (p == e) { + *out++ = MBFL_BAD_INPUT; + break; + } + unsigned char c4 = *p++; + if (c4 == '@' || c4 == 'B') { + *state = JISX_0208; + } else if (c4 == 'D') { + *state = JISX_0212; + } else { + if ((limit - out) < 3) { + p -= 4; + break; + } + *out++ = MBFL_BAD_INPUT; + *out++ = '$'; + *out++ = '('; + p--; + } + } else { + if ((limit - out) < 2) { + p -= 3; + break; + } + *out++ = MBFL_BAD_INPUT; + *out++ = '$'; + p--; + } + } else if (c2 == '(') { + unsigned char c3 = *p++; + if (c3 == 'B' || c3 == 'H') { + *state = ASCII; + } else if (c3 == 'J') { + *state = JISX_0201_LATIN; + } else if (c3 == 'I') { + *state = JISX_0201_KANA; + } else { + if ((limit - out) < 2) { + p -= 3; + break; + } + *out++ = MBFL_BAD_INPUT; + *out++ = '('; + p--; + } + } else { + *out++ = MBFL_BAD_INPUT; + p--; + } + } else if (c == 0xE) { + /* "Kana In" marker; this is just for JIS-7/8, but we also accept it for ISO-2022-JP */ + *state = JISX_0201_KANA; + } else if (c == 0xF) { + /* "Kana Out" marker */ + *state = ASCII; + } else if (*state == JISX_0201_LATIN && c == 0x5C) { /* YEN SIGN */ + *out++ = 0xA5; + } else if (*state == JISX_0201_LATIN && c == 0x7E) { /* OVER LINE */ + *out++ = 0x203E; + } else if (*state == JISX_0201_KANA && c > 0x20 && c < 0x60) { + *out++ = 0xFF40 + c; + } else if (*state >= JISX_0208 && c > 0x20 && c < 0x7F) { + if (p == e) { + *out++ = MBFL_BAD_INPUT; + break; + } + unsigned char c2 = *p++; + if (c2 > 0x20 && c2 < 0x7F) { + unsigned int s = (c - 0x21)*94 + c2 - 0x21; + uint32_t w = 0; + if (*state == JISX_0208) { + if (s < jisx0208_ucs_table_size) { + w = jisx0208_ucs_table[s]; + } + if (!w) { + w = MBFL_BAD_INPUT; + } + } else { + if (s < jisx0212_ucs_table_size) { + w = jisx0212_ucs_table[s]; + } + if (!w) { + w = MBFL_BAD_INPUT; + } + } + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } else if (c < 0x80) { + *out++ = c; + } else if (c >= 0xA1 && c <= 0xDF) { + *out++ = 0xFEC0 + c; + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_iso2022jp(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + unsigned int s = 0; + + if (w >= ucs_a1_jis_table_min && w < ucs_a1_jis_table_max) { + s = ucs_a1_jis_table[w - ucs_a1_jis_table_min]; + } else if (w >= ucs_a2_jis_table_min && w < ucs_a2_jis_table_max) { + s = ucs_a2_jis_table[w - ucs_a2_jis_table_min]; + } else if (w >= ucs_i_jis_table_min && w < ucs_i_jis_table_max) { + s = ucs_i_jis_table[w - ucs_i_jis_table_min]; + } else if (w >= ucs_r_jis_table_min && w < ucs_r_jis_table_max) { + s = ucs_r_jis_table[w - ucs_r_jis_table_min]; + } + + if (s == 0) { + if (w == 0xA5) { /* YEN SIGN */ + s = 0x1005C; + } else if (w == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ + s = 0x2140; + } else if (w == 0x2225) { /* PARALLEL TO */ + s = 0x2142; + } else if (w == 0xFF0D) { /* FULLWIDTH HYPHEN-MINUS */ + s = 0x215D; + } else if (w == 0xFFE0) { /* FULLWIDTH CENT SIGN */ + s = 0x2171; + } else if (w == 0xFFE1) { /* FULLWIDTH POUND SIGN */ + s = 0x2172; + } else if (w == 0xFFE2) { /* FULLWIDTH NOT SIGN */ + s = 0x224C; + } else if (w != 0) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_iso2022jp); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + continue; + } + } else if ((s >= 0x80 && s < 0x2121) || (s > 0x8080)) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_iso2022jp); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + continue; + } + + if (s < 0x80) { /* ASCII */ + if (buf->state != ASCII) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add3(out, 0x1B, '(', 'B'); + buf->state = ASCII; + } + out = mb_convert_buf_add(out, s); + } else if (s < 0x8080) { /* JIS X 0208 */ + if (buf->state != JISX_0208) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 5); + out = mb_convert_buf_add3(out, 0x1B, '$', 'B'); + buf->state = JISX_0208; + } + out = mb_convert_buf_add2(out, (s >> 8) & 0x7F, s & 0x7F); + } else if (s < 0x10000) { /* JIS X 0212 */ + if (buf->state != JISX_0212) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 6); + out = mb_convert_buf_add4(out, 0x1B, '$', '(', 'D'); + buf->state = JISX_0212; + } + out = mb_convert_buf_add2(out, (s >> 8) & 0x7F, s & 0x7F); + } else { /* X 0201 Latin */ + if (buf->state != JISX_0201_LATIN) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add3(out, 0x1B, '(', 'J'); + buf->state = JISX_0201_LATIN; + } + out = mb_convert_buf_add(out, s & 0x7F); + } + } + + if (end && buf->state != ASCII) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, 3); + out = mb_convert_buf_add3(out, 0x1B, '(', 'B'); + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_qprint.c b/ext/mbstring/libmbfl/filters/mbfilter_qprint.c index 2c9e82348726d..8f3aa16b9c579 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_qprint.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_qprint.c @@ -41,6 +41,8 @@ const mbfl_encoding mbfl_encoding_qprint = { NULL, MBFL_ENCTYPE_GL_UNSAFE, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c index 43ab8a2e48718..2020bc3ab09d0 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_singlebyte.c @@ -16,16 +16,18 @@ #define CK(statement) do { if ((statement) < 0) return (-1); } while (0) +static inline uint32_t coalesce(uint32_t a, uint32_t b) +{ + return a ? a : b; +} + /* Helper for single-byte encodings which use a conversion table */ static int mbfl_conv_singlebyte_table(int c, mbfl_convert_filter *filter, int tbl_min, const unsigned short tbl[]) { if (c < tbl_min) { CK((*filter->output_function)(c, filter->data)); } else { - int s = tbl[c - tbl_min]; - if (!s) - s = MBFL_BAD_INPUT; - CK((*filter->output_function)(s, filter->data)); + CK((*filter->output_function)(coalesce(tbl[c - tbl_min], MBFL_BAD_INPUT), filter->data)); } return 0; } @@ -52,6 +54,8 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int #define DEF_SB(id, name, mime_name, aliases) \ static int mbfl_filt_conv_##id##_wchar(int c, mbfl_convert_filter *filter); \ static int mbfl_filt_conv_wchar_##id(int c, mbfl_convert_filter *filter); \ + static size_t mb_##id##_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); \ + static void mb_wchar_to_##id(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); \ static const struct mbfl_convert_vtbl vtbl_##id##_wchar = { \ mbfl_no_encoding_##id, \ mbfl_no_encoding_wchar, \ @@ -78,7 +82,9 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int NULL, \ MBFL_ENCTYPE_SBCS, \ &vtbl_##id##_wchar, \ - &vtbl_wchar_##id \ + &vtbl_wchar_##id, \ + mb_##id##_to_wchar, \ + mb_wchar_to_##id \ } /* For single-byte encodings which use a conversion table */ @@ -89,6 +95,41 @@ static int mbfl_conv_reverselookup_table(int c, mbfl_convert_filter *filter, int static int mbfl_filt_conv_wchar_##id(int c, mbfl_convert_filter *filter) { \ return mbfl_conv_reverselookup_table(c, filter, tbl_min, tbl); \ } \ + static size_t mb_##id##_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) \ + { \ + unsigned char *p = *in, *e = p + *in_len; \ + uint32_t *out = buf, *limit = buf + bufsize; \ + while (p < e && out < limit) { \ + unsigned char c = *p++; \ + *out++ = (c < tbl_min) ? c : coalesce(tbl[c - tbl_min], MBFL_BAD_INPUT); \ + } \ + *in_len = e - p; \ + *in = p; \ + return out - buf; \ + } \ + static void mb_wchar_to_##id(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) \ + { \ + unsigned char *out, *limit; \ + MB_CONVERT_BUF_LOAD(buf, out, limit); \ + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); \ + while (len--) { \ + uint32_t w = *in++; \ + if (w < tbl_min) { \ + out = mb_convert_buf_add(out, w & 0xFF); \ + } else { \ + for (int i = 0; i < 256 - tbl_min; i++) { \ + if (w == tbl[i]) { \ + out = mb_convert_buf_add(out, i + tbl_min); \ + goto next_iteration; \ + } \ + } \ + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_##id); \ + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); \ + next_iteration: ; \ + } \ + } \ + MB_CONVERT_BUF_STORE(buf, out, limit); \ + } \ DEF_SB(id, name, mime_name, aliases) /* The grand-daddy of them all: ASCII */ @@ -97,11 +138,7 @@ DEF_SB(ascii, "ASCII", "US-ASCII", ascii_aliases); static int mbfl_filt_conv_ascii_wchar(int c, mbfl_convert_filter *filter) { - if (c < 0x80) { - CK((*filter->output_function)(c, filter->data)); - } else { - CK((*filter->output_function)(MBFL_BAD_INPUT, filter->data)); - } + CK((*filter->output_function)((c < 0x80) ? c : MBFL_BAD_INPUT, filter->data)); return 0; } @@ -115,6 +152,40 @@ static int mbfl_filt_conv_wchar_ascii(int c, mbfl_convert_filter *filter) return 0; } +static size_t mb_ascii_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + *out++ = (c < 0x80) ? c : MBFL_BAD_INPUT; + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_ascii(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + while (len--) { + uint32_t w = *in++; + if (w < 0x80) { + out = mb_convert_buf_add(out, w & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_ascii); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + /* ISO-8859-X */ static const char *iso8859_1_aliases[] = {"ISO8859-1", "latin1", NULL}; @@ -135,260 +206,293 @@ static int mbfl_filt_conv_wchar_8859_1(int c, mbfl_convert_filter *filter) return 0; } +static size_t mb_8859_1_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + *out++ = *p++; + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_8859_1(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + while (len--) { + uint32_t w = *in++; + if (w < 0x100) { + out = mb_convert_buf_add(out, w); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_8859_1); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + static const char *iso8859_2_aliases[] = {"ISO8859-2", "latin2", NULL}; static const unsigned short iso8859_2_ucs_table[] = { - 0X00A0, 0X0104, 0X02D8, 0X0141, 0X00A4, 0X013D, 0X015A, 0X00A7, - 0X00A8, 0X0160, 0X015E, 0X0164, 0X0179, 0X00AD, 0X017D, 0X017B, - 0X00B0, 0X0105, 0X02DB, 0X0142, 0X00B4, 0X013E, 0X015B, 0X02C7, - 0X00B8, 0X0161, 0X015F, 0X0165, 0X017A, 0X02DD, 0X017E, 0X017C, - 0X0154, 0X00C1, 0X00C2, 0X0102, 0X00C4, 0X0139, 0X0106, 0X00C7, - 0X010C, 0X00C9, 0X0118, 0X00CB, 0X011A, 0X00CD, 0X00CE, 0X010E, - 0X0110, 0X0143, 0X0147, 0X00D3, 0X00D4, 0X0150, 0X00D6, 0X00D7, - 0X0158, 0X016E, 0X00DA, 0X0170, 0X00DC, 0X00DD, 0X0162, 0X00DF, - 0X0155, 0X00E1, 0X00E2, 0X0103, 0X00E4, 0X013A, 0X0107, 0X00E7, - 0X010D, 0X00E9, 0X0119, 0X00EB, 0X011B, 0X00ED, 0X00EE, 0X010F, - 0X0111, 0X0144, 0X0148, 0X00F3, 0X00F4, 0X0151, 0X00F6, 0X00F7, - 0X0159, 0X016F, 0X00FA, 0X0171, 0X00FC, 0X00FD, 0X0163, 0X02D9 + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 }; DEF_SB_TBL(8859_2, "ISO-8859-2", "ISO-8859-2", iso8859_2_aliases, 0xA0, iso8859_2_ucs_table); static const char *iso8859_3_aliases[] = {"ISO8859-3", "latin3", NULL}; static const unsigned short iso8859_3_ucs_table[] = { - 0X00A0, 0X0126, 0X02D8, 0X00A3, 0X00A4, 0X0000, 0X0124, 0X00A7, - 0X00A8, 0X0130, 0X015E, 0X011E, 0X0134, 0X00AD, 0X0000, 0X017B, - 0X00B0, 0X0127, 0X00B2, 0X00B3, 0X00B4, 0X00B5, 0X0125, 0X00B7, - 0X00B8, 0X0131, 0X015F, 0X011F, 0X0135, 0X00BD, 0X0000, 0X017C, - 0X00C0, 0X00C1, 0X00C2, 0X0000, 0X00C4, 0X010A, 0X0108, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X0000, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X0120, 0X00D6, 0X00D7, - 0X011C, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X016C, 0X015C, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X0000, 0X00E4, 0X010B, 0X0109, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X0000, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X0121, 0X00F6, 0X00F7, - 0X011D, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X016D, 0X015D, 0X02D9 + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0000, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x0000, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x0000, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0000, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0000, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0000, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 }; DEF_SB_TBL(8859_3, "ISO-8859-3", "ISO-8859-3", iso8859_3_aliases, 0xA0, iso8859_3_ucs_table); static const char *iso8859_4_aliases[] = {"ISO8859-4", "latin4", NULL}; static const unsigned short iso8859_4_ucs_table[] = { - 0X00A0, 0X0104, 0X0138, 0X0156, 0X00A4, 0X0128, 0X013B, 0X00A7, - 0X00A8, 0X0160, 0X0112, 0X0122, 0X0166, 0X00AD, 0X017D, 0X00AF, - 0X00B0, 0X0105, 0X02DB, 0X0157, 0X00B4, 0X0129, 0X013C, 0X02C7, - 0X00B8, 0X0161, 0X0113, 0X0123, 0X0167, 0X014A, 0X017E, 0X014B, - 0X0100, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X012E, - 0X010C, 0X00C9, 0X0118, 0X00CB, 0X0116, 0X00CD, 0X00CE, 0X012A, - 0X0110, 0X0145, 0X014C, 0X0136, 0X00D4, 0X00D5, 0X00D6, 0X00D7, - 0X00D8, 0X0172, 0X00DA, 0X00DB, 0X00DC, 0X0168, 0X016A, 0X00DF, - 0X0101, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X012F, - 0X010D, 0X00E9, 0X0119, 0X00EB, 0X0117, 0X00ED, 0X00EE, 0X012B, - 0X0111, 0X0146, 0X014D, 0X0137, 0X00F4, 0X00F5, 0X00F6, 0X00F7, - 0X00F8, 0X0173, 0X00FA, 0X00FB, 0X00FC, 0X0169, 0X016B, 0X02D9 + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9 }; DEF_SB_TBL(8859_4, "ISO-8859-4", "ISO-8859-4", iso8859_4_aliases, 0xA0, iso8859_4_ucs_table); static const char *iso8859_5_aliases[] = {"ISO8859-5", "cyrillic", NULL}; static const unsigned short iso8859_5_ucs_table[] = { - 0x00a0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, - 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x00ad, 0x040e, 0x040f, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041d, 0x041e, 0x041f, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, 0x042c, 0x042d, 0x042e, 0x042f, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x00a7, 0x045e, 0x045f + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F }; DEF_SB_TBL(8859_5, "ISO-8859-5", "ISO-8859-5", iso8859_5_aliases, 0xA0, iso8859_5_ucs_table); static const char *iso8859_6_aliases[] = {"ISO8859-6", "arabic", NULL}; static const unsigned short iso8859_6_ucs_table[] = { - 0X00A0, 0X0000, 0X0000, 0X0000, 0X00A4, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X060C, 0X00AD, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X061B, 0X0000, 0X0000, 0X0000, 0X061F, - 0X0000, 0X0621, 0X0622, 0X0623, 0X0624, 0X0625, 0X0626, 0X0627, - 0X0628, 0X0629, 0X062A, 0X062B, 0X062C, 0X062D, 0X062E, 0X062F, - 0X0630, 0X0631, 0X0632, 0X0633, 0X0634, 0X0635, 0X0636, 0X0637, - 0X0638, 0X0639, 0X063A, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0640, 0X0641, 0X0642, 0X0643, 0X0644, 0X0645, 0X0646, 0X0647, - 0X0648, 0X0649, 0X064A, 0X064B, 0X064C, 0X064D, 0X064E, 0X064F, - 0X0650, 0X0651, 0X0652, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000 + 0x00A0, 0x0000, 0x0000, 0x0000, 0x00A4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x060C, 0x00AD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x061B, 0x0000, 0x0000, 0x0000, 0x061F, + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; DEF_SB_TBL(8859_6, "ISO-8859-6", "ISO-8859-6", iso8859_6_aliases, 0xA0, iso8859_6_ucs_table); static const char *iso8859_7_aliases[] = {"ISO8859-7", "greek", NULL}; static const unsigned short iso8859_7_ucs_table[] = { - 0X00A0, 0X2018, 0X2019, 0X00A3, 0X20AC, 0X20AF, 0X00A6, 0X00A7, - 0X00A8, 0X00A9, 0X037A, 0X00AB, 0X00AC, 0X00AD, 0X0000, 0X2015, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X0384, 0X0385, 0X0386, 0X00B7, - 0X0388, 0X0389, 0X038A, 0X00BB, 0X038C, 0X00BD, 0X038E, 0X038F, - 0X0390, 0X0391, 0X0392, 0X0393, 0X0394, 0X0395, 0X0396, 0X0397, - 0X0398, 0X0399, 0X039A, 0X039B, 0X039C, 0X039D, 0X039E, 0X039F, - 0X03A0, 0X03A1, 0X0000, 0X03A3, 0X03A4, 0X03A5, 0X03A6, 0X03A7, - 0X03A8, 0X03A9, 0X03AA, 0X03AB, 0X03AC, 0X03AD, 0X03AE, 0X03AF, - 0X03B0, 0X03B1, 0X03B2, 0X03B3, 0X03B4, 0X03B5, 0X03B6, 0X03B7, - 0X03B8, 0X03B9, 0X03BA, 0X03BB, 0X03BC, 0X03BD, 0X03BE, 0X03BF, - 0X03C0, 0X03C1, 0X03C2, 0X03C3, 0X03C4, 0X03C5, 0X03C6, 0X03C7, - 0X03C8, 0X03C9, 0X03CA, 0X03CB, 0X03CC, 0X03CD, 0X03CE, 0X0000 + 0x00A0, 0x2018, 0x2019, 0x00A3, 0x20AC, 0x20AF, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x037A, 0x00AB, 0x00AC, 0x00AD, 0x0000, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 }; DEF_SB_TBL(8859_7, "ISO-8859-7", "ISO-8859-7", iso8859_7_aliases, 0xA0, iso8859_7_ucs_table); static const char *iso8859_8_aliases[] = {"ISO8859-8", "hebrew", NULL}; static const unsigned short iso8859_8_ucs_table[] = { - 0X00A0, 0X0000, 0X00A2, 0X00A3, 0X00A4, 0X00A5, 0X00A6, 0X00A7, - 0X00A8, 0X00A9, 0X00D7, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00AF, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X00B4, 0X00B5, 0X00B6, 0X00B7, - 0X00B8, 0X00B9, 0X00F7, 0X00BB, 0X00BC, 0X00BD, 0X00BE, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, - 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X0000, 0X2017, - 0X05D0, 0X05D1, 0X05D2, 0X05D3, 0X05D4, 0X05D5, 0X05D6, 0X05D7, - 0X05D8, 0X05D9, 0X05DA, 0X05DB, 0X05DC, 0X05DD, 0X05DE, 0X05DF, - 0X05E0, 0X05E1, 0X05E2, 0X05E3, 0X05E4, 0X05E5, 0X05E6, 0X05E7, - 0X05E8, 0X05E9, 0X05EA, 0X0000, 0X0000, 0X200E, 0X200F, 0X0000 + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000 }; DEF_SB_TBL(8859_8, "ISO-8859-8", "ISO-8859-8", iso8859_8_aliases, 0xA0, iso8859_8_ucs_table); static const char *iso8859_9_aliases[] = {"ISO8859-9", "latin5", NULL}; static const unsigned short iso8859_9_ucs_table[] = { - 0X00A0, 0X00A1, 0X00A2, 0X00A3, 0X00A4, 0X00A5, 0X00A6, 0X00A7, - 0X00A8, 0X00A9, 0X00AA, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00AF, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X00B4, 0X00B5, 0X00B6, 0X00B7, - 0X00B8, 0X00B9, 0X00BA, 0X00BB, 0X00BC, 0X00BD, 0X00BE, 0X00BF, - 0X00C0, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X011E, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X00D7, - 0X00D8, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X0130, 0X015E, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X011F, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X00F7, - 0X00F8, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X0131, 0X015F, 0X00FF + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF }; DEF_SB_TBL(8859_9, "ISO-8859-9", "ISO-8859-9", iso8859_9_aliases, 0xA0, iso8859_9_ucs_table); static const char *iso8859_10_aliases[] = {"ISO8859-10", "latin6", NULL}; static const unsigned short iso8859_10_ucs_table[] = { - 0X00A0, 0X0104, 0X0112, 0X0122, 0X012A, 0X0128, 0X0136, 0X00A7, - 0X013B, 0X0110, 0X0160, 0X0166, 0X017D, 0X00AD, 0X016A, 0X014A, - 0X00B0, 0X0105, 0X0113, 0X0123, 0X012B, 0X0129, 0X0137, 0X00B7, - 0X013C, 0X0111, 0X0161, 0X0167, 0X017E, 0X2015, 0X016B, 0X014B, - 0X0100, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X012E, - 0X010C, 0X00C9, 0X0118, 0X00CB, 0X0116, 0X00CD, 0X00CE, 0X00CF, - 0X00D0, 0X0145, 0X014C, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X0168, - 0X00D8, 0X0172, 0X00DA, 0X00DB, 0X00DC, 0X00DD, 0X00DE, 0X00DF, - 0X0101, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X012F, - 0X010D, 0X00E9, 0X0119, 0X00EB, 0X0117, 0X00ED, 0X00EE, 0X00EF, - 0X00F0, 0X0146, 0X014D, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X0169, - 0X00F8, 0X0173, 0X00FA, 0X00FB, 0X00FC, 0X00FD, 0X00FE, 0X0138 + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138 }; DEF_SB_TBL(8859_10, "ISO-8859-10", "ISO-8859-10", iso8859_10_aliases, 0xA0, iso8859_10_ucs_table); static const char *iso8859_13_aliases[] = {"ISO8859-13", NULL}; static const unsigned short iso8859_13_ucs_table[] = { - 0X00A0, 0X201D, 0X00A2, 0X00A3, 0X00A4, 0X201E, 0X00A6, 0X00A7, - 0X00D8, 0X00A9, 0X0156, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00C6, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X201C, 0X00B5, 0X00B6, 0X00B7, - 0X00F8, 0X00B9, 0X0157, 0X00BB, 0X00BC, 0X00BD, 0X00BE, 0X00E6, - 0X0104, 0X012E, 0X0100, 0X0106, 0X00C4, 0X00C5, 0X0118, 0X0112, - 0X010C, 0X00C9, 0X0179, 0X0116, 0X0122, 0X0136, 0X012A, 0X013B, - 0X0160, 0X0143, 0X0145, 0X00D3, 0X014C, 0X00D5, 0X00D6, 0X00D7, - 0X0172, 0X0141, 0X015A, 0X016A, 0X00DC, 0X017B, 0X017D, 0X00DF, - 0X0105, 0X012F, 0X0101, 0X0107, 0X00E4, 0X00E5, 0X0119, 0X0113, - 0X010D, 0X00E9, 0X017A, 0X0117, 0X0123, 0X0137, 0X012B, 0X013C, - 0X0161, 0X0144, 0X0146, 0X00F3, 0X014D, 0X00F5, 0X00F6, 0X00F7, - 0X0173, 0X0142, 0X015B, 0X016B, 0X00FC, 0X017C, 0X017E, 0X2019 + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019 }; DEF_SB_TBL(8859_13, "ISO-8859-13", "ISO-8859-13", iso8859_13_aliases, 0xA0, iso8859_13_ucs_table); static const char *iso8859_14_aliases[] = {"ISO8859-14", "latin8", NULL}; static const unsigned short iso8859_14_ucs_table[] = { - 0X00A0, 0X1E02, 0X1E03, 0X00A3, 0X010A, 0X010B, 0X1E0A, 0X00A7, - 0X1E80, 0X00A9, 0X1E82, 0X1E0B, 0X1EF2, 0X00AD, 0X00AE, 0X0178, - 0X1E1E, 0X1E1F, 0X0120, 0X0121, 0X1E40, 0X1E41, 0X00B6, 0X1E56, - 0X1E81, 0X1E57, 0X1E83, 0X1E60, 0X1EF3, 0X1E84, 0X1E85, 0X1E61, - 0X00C0, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X0174, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X1E6A, - 0X00D8, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X00DD, 0X0176, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X0175, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X1E6B, - 0X00F8, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X00FD, 0X0177, 0X00FF + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF }; DEF_SB_TBL(8859_14, "ISO-8859-14", "ISO-8859-14", iso8859_14_aliases, 0xA0, iso8859_14_ucs_table); static const char *iso8859_15_aliases[] = {"ISO8859-15", NULL}; static const unsigned short iso8859_15_ucs_table[] = { - 0X00A0, 0X00A1, 0X00A2, 0X00A3, 0X20AC, 0X00A5, 0X0160, 0X00A7, - 0X0161, 0X00A9, 0X00AA, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00AF, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X017D, 0X00B5, 0X00B6, 0X00B7, - 0X017E, 0X00B9, 0X00BA, 0X00BB, 0X0152, 0X0153, 0X0178, 0X00BF, - 0X00C0, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X00D0, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X00D7, - 0X00D8, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X00DD, 0X00DE, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X00F0, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X00F7, - 0X00F8, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X00FD, 0X00FE, 0X00FF + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF }; DEF_SB_TBL(8859_15, "ISO-8859-15", "ISO-8859-15", iso8859_15_aliases, 0xA0, iso8859_15_ucs_table); static const char *iso8859_16_aliases[] = {"ISO8859-16", NULL}; static const unsigned short iso8859_16_ucs_table[] = { - 0X00A0, 0X0104, 0X0105, 0X0141, 0X20AC, 0X201E, 0X0160, 0X00A7, - 0X0161, 0X00A9, 0X0218, 0X00AB, 0X0179, 0X00AD, 0X017A, 0X017B, - 0X00B0, 0X00B1, 0X010C, 0X0142, 0X017D, 0X201D, 0X00B6, 0X00B7, - 0X017E, 0X010D, 0X0219, 0X00BB, 0X0152, 0X0153, 0X0178, 0X017C, - 0X00C0, 0X00C1, 0X00C2, 0X0102, 0X00C4, 0X0106, 0X00C6, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X0110, 0X0143, 0X00D2, 0X00D3, 0X00D4, 0X0150, 0X00D6, 0X015A, - 0X0170, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X0118, 0X021A, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X0103, 0X00E4, 0X0107, 0X00E6, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X0111, 0X0144, 0X00F2, 0X00F3, 0X00F4, 0X0151, 0X00F6, 0X015B, - 0X0171, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X0119, 0X021B, 0X00FF + 0x00A0, 0x0104, 0x0105, 0x0141, 0x20AC, 0x201E, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x0218, 0x00AB, 0x0179, 0x00AD, 0x017A, 0x017B, + 0x00B0, 0x00B1, 0x010C, 0x0142, 0x017D, 0x201D, 0x00B6, 0x00B7, + 0x017E, 0x010D, 0x0219, 0x00BB, 0x0152, 0x0153, 0x0178, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0106, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x0143, 0x00D2, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x015A, + 0x0170, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0118, 0x021A, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x0107, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x0144, 0x00F2, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x015B, + 0x0171, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0119, 0x021B, 0x00FF }; DEF_SB_TBL(8859_16, "ISO-8859-16", "ISO-8859-16", iso8859_16_aliases, 0xA0, iso8859_16_ucs_table); static const char *cp1251_aliases[] = {"CP1251", "CP-1251", "WINDOWS-1251", NULL}; static const unsigned short cp1251_ucs_table[] = { - 0X0402, 0X0403, 0X201A, 0X0453, 0X201E, 0X2026, 0X2020, 0X2021, - 0X20AC, 0X2030, 0X0409, 0X2039, 0X040A, 0X040C, 0X040B, 0X040F, - 0X0452, 0X2018, 0X2019, 0X201C, 0X201D, 0X2022, 0X2013, 0X2014, - 0X0000, 0X2122, 0X0459, 0X203A, 0X045A, 0X045C, 0X045B, 0X045F, - 0X00A0, 0X040E, 0X045E, 0X0408, 0X00A4, 0X0490, 0X00A6, 0X00A7, - 0X0401, 0X00A9, 0X0404, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X0407, - 0X00B0, 0X00B1, 0X0406, 0X0456, 0X0491, 0X00B5, 0X00B6, 0X00B7, - 0X0451, 0X2116, 0X0454, 0X00BB, 0X0458, 0X0405, 0X0455, 0X0457, - 0X0410, 0X0411, 0X0412, 0X0413, 0X0414, 0X0415, 0X0416, 0X0417, - 0X0418, 0X0419, 0X041A, 0X041B, 0X041C, 0X041D, 0X041E, 0X041F, - 0X0420, 0X0421, 0X0422, 0X0423, 0X0424, 0X0425, 0X0426, 0X0427, - 0X0428, 0X0429, 0X042A, 0X042B, 0X042C, 0X042D, 0X042E, 0X042F, - 0X0430, 0X0431, 0X0432, 0X0433, 0X0434, 0X0435, 0X0436, 0X0437, - 0X0438, 0X0439, 0X043A, 0X043B, 0X043C, 0X043D, 0X043E, 0X043F, - 0X0440, 0X0441, 0X0442, 0X0443, 0X0444, 0X0445, 0X0446, 0X0447, - 0X0448, 0X0449, 0X044A, 0X044B, 0X044C, 0X044D, 0X044E, 0X044F + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F }; DEF_SB_TBL(cp1251, "Windows-1251", "Windows-1251", cp1251_aliases, 0x80, cp1251_ucs_table); static const char *cp1252_aliases[] = {"cp1252", NULL}; static const unsigned short cp1252_ucs_table[] = { - 0X20AC,0X0000,0X201A,0X0192,0X201E,0X2026,0X2020,0X2021, - 0X02C6,0X2030,0X0160,0X2039,0X0152,0X0000,0X017D,0X0000, - 0X0000,0X2018,0X2019,0X201C,0X201D,0X2022,0X2013,0X2014, - 0X02DC,0X2122,0X0161,0X203A,0X0153,0X0000,0X017E,0X0178 + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178 }; DEF_SB(cp1252, "Windows-1252", "Windows-1252", cp1252_aliases); static int mbfl_filt_conv_wchar_cp1252(int c, mbfl_convert_filter *filter) { - if (c >= 0x100) { + if (c >= 0x100) { for (int n = 0; n < 32; n++) { if (c == cp1252_ucs_table[n]) { CK((*filter->output_function)(0x80 + n, filter->data)); @@ -407,157 +511,193 @@ static int mbfl_filt_conv_wchar_cp1252(int c, mbfl_convert_filter *filter) static int mbfl_filt_conv_cp1252_wchar(int c, mbfl_convert_filter *filter) { int s; - if (c >= 0x80 && c < 0xA0) { - s = cp1252_ucs_table[c - 0x80]; - if (!s) - s = MBFL_BAD_INPUT; + s = coalesce(cp1252_ucs_table[c - 0x80], MBFL_BAD_INPUT); } else { s = c; } - CK((*filter->output_function)(s, filter->data)); return 0; } +static size_t mb_cp1252_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + + if (c >= 0x80 && c < 0xA0) { + *out++ = coalesce(cp1252_ucs_table[c - 0x80], MBFL_BAD_INPUT); + } else { + *out++ = c; + } + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_cp1252(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + while (len--) { + uint32_t w = *in++; + + if (w >= 0x100) { + for (int i = 0; i < 32; i++) { + if (w == cp1252_ucs_table[i]) { + out = mb_convert_buf_add(out, i + 0x80); + goto continue_cp1252; + } + } + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_cp1252); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } else if (w <= 0x7F || w >= 0xA0) { + out = mb_convert_buf_add(out, w); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_cp1252); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } + continue_cp1252: ; + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + static const char *cp1254_aliases[] = {"CP1254", "CP-1254", "WINDOWS-1254", NULL}; static const unsigned short cp1254_ucs_table[] = { - 0X20AC, 0X0000, 0X201A, 0X0192, 0X201E, 0X2026, 0X2020, 0X2021, - 0X02C6, 0X2030, 0X0160, 0X2039, 0X0152, 0X0000, 0X0000, 0X0000, - 0X0000, 0X2018, 0X2019, 0X201C, 0X201D, 0X2022, 0X2013, 0X2014, - 0X02DC, 0X2122, 0X0161, 0X203A, 0X0153, 0X0000, 0X0000, 0X0178, - 0X00A0, 0X00A1, 0X00A2, 0X00A3, 0X00A4, 0X00A5, 0X00A6, 0X00A7, - 0X00A8, 0X00A9, 0X00AA, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00AF, - 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X00B4, 0X00B5, 0X00B6, 0X00B7, - 0X00B8, 0X00B9, 0X00BA, 0X00BB, 0X00BC, 0X00BD, 0X00BE, 0X00BF, - 0X00C0, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X00C7, - 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, - 0X011E, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X00D7, - 0X00D8, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X0130, 0X015E, 0X00DF, - 0X00E0, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X00E7, - 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, - 0X011F, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X00F7, - 0X00F8, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X0131, 0X015F, 0X00FF + 0x20AC, 0X0000, 0X201A, 0X0192, 0X201E, 0X2026, 0X2020, 0X2021, + 0X02C6, 0X2030, 0X0160, 0X2039, 0X0152, 0X0000, 0X0000, 0X0000, + 0X0000, 0X2018, 0X2019, 0X201C, 0X201D, 0X2022, 0X2013, 0X2014, + 0X02DC, 0X2122, 0X0161, 0X203A, 0X0153, 0X0000, 0X0000, 0X0178, + 0X00A0, 0X00A1, 0X00A2, 0X00A3, 0X00A4, 0X00A5, 0X00A6, 0X00A7, + 0X00A8, 0X00A9, 0X00AA, 0X00AB, 0X00AC, 0X00AD, 0X00AE, 0X00AF, + 0X00B0, 0X00B1, 0X00B2, 0X00B3, 0X00B4, 0X00B5, 0X00B6, 0X00B7, + 0X00B8, 0X00B9, 0X00BA, 0X00BB, 0X00BC, 0X00BD, 0X00BE, 0X00BF, + 0X00C0, 0X00C1, 0X00C2, 0X00C3, 0X00C4, 0X00C5, 0X00C6, 0X00C7, + 0X00C8, 0X00C9, 0X00CA, 0X00CB, 0X00CC, 0X00CD, 0X00CE, 0X00CF, + 0X011E, 0X00D1, 0X00D2, 0X00D3, 0X00D4, 0X00D5, 0X00D6, 0X00D7, + 0X00D8, 0X00D9, 0X00DA, 0X00DB, 0X00DC, 0X0130, 0X015E, 0X00DF, + 0X00E0, 0X00E1, 0X00E2, 0X00E3, 0X00E4, 0X00E5, 0X00E6, 0X00E7, + 0X00E8, 0X00E9, 0X00EA, 0X00EB, 0X00EC, 0X00ED, 0X00EE, 0X00EF, + 0X011F, 0X00F1, 0X00F2, 0X00F3, 0X00F4, 0X00F5, 0X00F6, 0X00F7, + 0X00F8, 0X00F9, 0X00FA, 0X00FB, 0X00FC, 0X0131, 0X015F, 0X00FF }; DEF_SB_TBL(cp1254, "Windows-1254", "Windows-1254", cp1254_aliases, 0x80, cp1254_ucs_table); static const char *cp866_aliases[] = {"CP-866", "IBM866", "IBM-866", NULL}; static const unsigned short cp866_ucs_table[] = { - 0X0410, 0X0411, 0X0412, 0X0413, 0X0414, 0X0415, 0X0416, 0X0417, - 0X0418, 0X0419, 0X041A, 0X041B, 0X041C, 0X041D, 0X041E, 0X041F, - 0X0420, 0X0421, 0X0422, 0X0423, 0X0424, 0X0425, 0X0426, 0X0427, - 0X0428, 0X0429, 0X042A, 0X042B, 0X042C, 0X042D, 0X042E, 0X042F, - 0X0430, 0X0431, 0X0432, 0X0433, 0X0434, 0X0435, 0X0436, 0X0437, - 0X0438, 0X0439, 0X043A, 0X043B, 0X043C, 0X043D, 0X043E, 0X043F, - 0X2591, 0X2592, 0X2593, 0X2502, 0X2524, 0X2561, 0X2562, 0X2556, - 0X2555, 0X2563, 0X2551, 0X2557, 0X255D, 0X255C, 0X255B, 0X2510, - 0X2514, 0X2534, 0X252C, 0X251C, 0X2500, 0X253C, 0X255E, 0X255F, - 0X255A, 0X2554, 0X2569, 0X2566, 0X2560, 0X2550, 0X256C, 0X2567, - 0X2568, 0X2564, 0X2565, 0X2559, 0X2558, 0X2552, 0X2553, 0X256B, - 0X256A, 0X2518, 0X250C, 0X2588, 0X2584, 0X258C, 0X2590, 0X2580, - 0X0440, 0X0441, 0X0442, 0X0443, 0X0444, 0X0445, 0X0446, 0X0447, - 0X0448, 0X0449, 0X044A, 0X044B, 0X044C, 0X044D, 0X044E, 0X044F, - 0X0401, 0X0451, 0X0404, 0X0454, 0X0407, 0X0457, 0X040E, 0X045E, - 0X00B0, 0X2219, 0X00B7, 0X221A, 0X2116, 0X00A4, 0X25A0, 0X00A0 + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 }; DEF_SB_TBL(cp866, "CP866", "CP866", cp866_aliases, 0x80, cp866_ucs_table); static const char *cp850_aliases[] = {"CP-850", "IBM850", "IBM-850", NULL}; static const unsigned short cp850_ucs_table[] = { - 0X00C7, 0X00FC, 0X00E9, 0X00E2, 0X00E4, 0X00E0, 0X00E5, 0X00E7, - 0X00EA, 0X00EB, 0X00E8, 0X00EF, 0X00EE, 0X00EC, 0X00C4, 0X00C5, - 0X00C9, 0X00E6, 0X00C6, 0X00F4, 0X00F6, 0X00F2, 0X00FB, 0X00F9, - 0X00FF, 0X00D6, 0X00DC, 0X00F8, 0X00A3, 0X00D8, 0X00D7, 0X0192, - 0X00E1, 0X00ED, 0X00F3, 0X00FA, 0X00F1, 0X00D1, 0X00AA, 0X00BA, - 0X00BF, 0X00AE, 0X00AC, 0X00BD, 0X00BC, 0X00A1, 0X00AB, 0X00BB, - 0X2591, 0X2592, 0X2593, 0X2502, 0X2524, 0X00C1, 0X00C2, 0X00C0, - 0X00A9, 0X2563, 0X2551, 0X2557, 0X255D, 0X00A2, 0X00A5, 0X2510, - 0X2514, 0X2534, 0X252C, 0X251C, 0X2500, 0X253C, 0X00E3, 0X00C3, - 0X255A, 0X2554, 0X2569, 0X2566, 0X2560, 0X2550, 0X256C, 0X00A4, - 0X00F0, 0X00D0, 0X00CA, 0X00CB, 0X00C8, 0X0131, 0X00CD, 0X00CE, - 0X00CF, 0X2518, 0X250C, 0X2588, 0X2584, 0X00A6, 0X00CC, 0X2580, - 0X00D3, 0X00DF, 0X00D4, 0X00D2, 0X00F5, 0X00D5, 0X00B5, 0X00FE, - 0X00DE, 0X00DA, 0X00DB, 0X00D9, 0X00FD, 0X00DD, 0X00AF, 0X00B4, - 0X00AD, 0X00B1, 0X2017, 0X00BE, 0X00B6, 0X00A7, 0X00F7, 0X00B8, - 0X00B0, 0X00A8, 0X00B7, 0X00B9, 0X00B3, 0X00B2, 0X25A0, 0X00A0 + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 }; DEF_SB_TBL(cp850, "CP850", "CP850", cp850_aliases, 0x80, cp850_ucs_table); static const char *koi8r_aliases[] = {"KOI8R", NULL}; static const unsigned short koi8r_ucs_table[] = { - 0X2500, 0X2502, 0X250C, 0X2510, 0X2514, 0X2518, 0X251C, 0X2524, - 0X252C, 0X2534, 0X253C, 0X2580, 0X2584, 0X2588, 0X258C, 0X2590, - 0X2591, 0X2592, 0X2593, 0X2320, 0X25A0, 0X2219, 0X221A, 0X2248, - 0X2264, 0X2265, 0X00A0, 0X2321, 0X00B0, 0X00B2, 0X00B7, 0X00F7, - 0X2550, 0X2551, 0X2552, 0X0451, 0X2553, 0X2554, 0X2555, 0X2556, - 0X2557, 0X2558, 0X2559, 0X255A, 0X255B, 0X255C, 0X255D, 0X255E, - 0X255F, 0X2560, 0X2561, 0X0401, 0X2562, 0X2563, 0X2564, 0X2565, - 0X2566, 0X2567, 0X2568, 0X2569, 0X256A, 0X256B, 0X256C, 0X00A9, - 0X044E, 0X0430, 0X0431, 0X0446, 0X0434, 0X0435, 0X0444, 0X0433, - 0X0445, 0X0438, 0X0439, 0X043A, 0X043B, 0X043C, 0X043D, 0X043E, - 0X043F, 0X044F, 0X0440, 0X0441, 0X0442, 0X0443, 0X0436, 0X0432, - 0X044C, 0X044B, 0X0437, 0X0448, 0X044D, 0X0449, 0X0447, 0X044A, - 0X042E, 0X0410, 0X0411, 0X0426, 0X0414, 0X0415, 0X0424, 0X0413, - 0X0425, 0X0418, 0X0419, 0X041A, 0X041B, 0X041C, 0X041D, 0X041E, - 0X041F, 0X042F, 0X0420, 0X0421, 0X0422, 0X0423, 0X0416, 0X0412, - 0X042C, 0X042B, 0X0417, 0X0428, 0X042D, 0X0429, 0X0427, 0X042A + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; DEF_SB_TBL(koi8r, "KOI8-R", "KOI8-R", koi8r_aliases, 0x80, koi8r_ucs_table); static const char *koi8u_aliases[] = {"KOI8U", NULL}; static const unsigned short koi8u_ucs_table[] = { - 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, - 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, - 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, - 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, - 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, - 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, - 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, - 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, - 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, - 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, - 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, - 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, - 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, - 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A }; DEF_SB_TBL(koi8u, "KOI8-U", "KOI8-U", koi8u_aliases, 0x80, koi8u_ucs_table); static const char *armscii8_aliases[] = {"ArmSCII8", "ARMSCII-8", "ARMSCII8", NULL}; static const unsigned short armscii8_ucs_table[] = { - 0X00A0, 0X0000, 0X0587, 0X0589, 0X0029, 0X0028, 0X00BB, 0X00AB, - 0X2014, 0X002E, 0X055D, 0X002C, 0X002D, 0X058A, 0X2026, 0X055C, - 0X055B, 0X055E, 0X0531, 0X0561, 0X0532, 0X0562, 0X0533, 0X0563, - 0X0534, 0X0564, 0X0535, 0X0565, 0X0536, 0X0566, 0X0537, 0X0567, - 0X0538, 0X0568, 0X0539, 0X0569, 0X053A, 0X056A, 0X053B, 0X056B, - 0X053C, 0X056C, 0X053D, 0X056D, 0X053E, 0X056E, 0X053F, 0X056F, - 0X0540, 0X0570, 0X0541, 0X0571, 0X0542, 0X0572, 0X0543, 0X0573, - 0X0544, 0X0574, 0X0545, 0X0575, 0X0546, 0X0576, 0X0547, 0X0577, - 0X0548, 0X0578, 0X0549, 0X0579, 0X054A, 0X057A, 0X054B, 0X057B, - 0X054C, 0X057C, 0X054D, 0X057D, 0X054E, 0X057E, 0X054F, 0X057F, - 0X0550, 0X0580, 0X0551, 0X0581, 0X0552, 0X0582, 0X0553, 0X0583, - 0X0554, 0X0584, 0X0555, 0X0585, 0X0556, 0X0586, 0X055A, 0X0000 + 0x00A0, 0x0000, 0x0587, 0x0589, 0x0029, 0x0028, 0x00BB, 0x00AB, + 0x2014, 0x002E, 0x055D, 0x002C, 0x002D, 0x058A, 0x2026, 0x055C, + 0x055B, 0x055E, 0x0531, 0x0561, 0x0532, 0x0562, 0x0533, 0x0563, + 0x0534, 0x0564, 0x0535, 0x0565, 0x0536, 0x0566, 0x0537, 0x0567, + 0x0538, 0x0568, 0x0539, 0x0569, 0x053A, 0x056A, 0x053B, 0x056B, + 0x053C, 0x056C, 0x053D, 0x056D, 0x053E, 0x056E, 0x053F, 0x056F, + 0x0540, 0x0570, 0x0541, 0x0571, 0x0542, 0x0572, 0x0543, 0x0573, + 0x0544, 0x0574, 0x0545, 0x0575, 0x0546, 0x0576, 0x0547, 0x0577, + 0x0548, 0x0578, 0x0549, 0x0579, 0x054A, 0x057A, 0x054B, 0x057B, + 0x054C, 0x057C, 0x054D, 0x057D, 0x054E, 0x057E, 0x054F, 0x057F, + 0x0550, 0x0580, 0x0551, 0x0581, 0x0552, 0x0582, 0x0553, 0x0583, + 0x0554, 0x0584, 0x0555, 0x0585, 0x0556, 0x0586, 0x055A, 0x0000 }; static const unsigned char ucs_armscii8_table[] = { - 0XA5, 0XA4, 0X2A, 0X2B, 0XAB, 0XAC, 0XA9, 0X2F + 0xA5, 0xA4, 0x2A, 0x2B, 0xAB, 0xAC, 0xA9, 0x2F }; DEF_SB(armscii8, "ArmSCII-8", "ArmSCII-8", armscii8_aliases); static int mbfl_filt_conv_armscii8_wchar(int c, mbfl_convert_filter *filter) { - int s; - - if (c < 0xA0) { - s = c; - } else { - s = armscii8_ucs_table[c - 0xA0]; - if (!s) - s = MBFL_BAD_INPUT; - } - - CK((*filter->output_function)(s, filter->data)); + CK((*filter->output_function)((c < 0xA0) ? c : coalesce(armscii8_ucs_table[c - 0xA0], MBFL_BAD_INPUT), filter->data)); return 0; } @@ -580,3 +720,47 @@ static int mbfl_filt_conv_wchar_armscii8(int c, mbfl_convert_filter *filter) } return 0; } + +static size_t mb_armscii8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + *out++ = (c < 0xA0) ? c : coalesce(armscii8_ucs_table[c - 0xA0], MBFL_BAD_INPUT); + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_armscii8(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + while (len--) { + uint32_t w = *in++; + + if (w >= 0x28 && w <= 0x2F) { + out = mb_convert_buf_add(out, ucs_armscii8_table[w - 0x28]); + } else if (w < 0xA0) { + out = mb_convert_buf_add(out, w); + } else { + for (int i = 0; i < 0x60; i++) { + if (w == armscii8_ucs_table[i]) { + out = mb_convert_buf_add(out, 0xA0 + i); + goto continue_armscii8; + } + } + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_armscii8); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } + continue_armscii8: ; + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis.c index ef59026a9eea1..1fd372edc8f47 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis.c @@ -37,6 +37,8 @@ #include "unicode_table_jis.h" static int mbfl_filt_conv_sjis_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_sjis_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_sjis(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); const unsigned char mblen_table_sjis[] = { /* 0x80-0x9f,0xE0-0xFF */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -67,7 +69,9 @@ const mbfl_encoding mbfl_encoding_sjis = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_wchar, - &vtbl_wchar_sjis + &vtbl_wchar_sjis, + mb_sjis_to_wchar, + mb_wchar_to_sjis }; const struct mbfl_convert_vtbl vtbl_sjis_wchar = { @@ -256,3 +260,116 @@ int mbfl_filt_conv_wchar_sjis(int c, mbfl_convert_filter *filter) return 0; } + +static size_t mb_sjis_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + + if (c == 0x5C) { + *out++ = 0xA5; + } else if (c == 0x7E) { + *out++ = 0x203E; + } else if (c <= 0x7F) { + *out++ = c; + } else if (c >= 0xA1 && c <= 0xDF) { /* Kana */ + *out++ = 0xFEC0 + c; + } else if (c > 0x80 && c <= 0xEF && c != 0xA0 && p < e) { + unsigned char c2 = *p++; + if (c2 >= 0x40 && c2 <= 0xFC && c2 != 0x7F) { + unsigned int s1, s2; + SJIS_DECODE(c, c2, s1, s2); + uint32_t w = (s1 - 0x21)*94 + s2 - 0x21; + if (w < jisx0208_ucs_table_size) { + w = jisx0208_ucs_table[w]; + if (!w) + w = MBFL_BAD_INPUT; + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_sjis(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + unsigned int s = 0; + + if (w == 0x5C) { + /* Unicode 0x5C is a backslash; but Shift-JIS uses 0x5C for the + * Yen sign. JIS X 0208 kuten 0x2140 is a backslash. */ + s = 0x2140; + } else if (w == 0x7E) { + /* Unicode 0x7E is a tilde, but Shift-JIS uses 0x7E for overline (or + * macron). JIS X 0208 kuten 0x2141 is 'WAVE DASH' */ + s = 0x2141; + } else if (w == 0xAF || w == 0x203E) { /* U+00AF is MACRON, U+203E is OVERLINE */ + s = 0x7E; /* Halfwidth overline/macron */ + } else if (w >= ucs_a1_jis_table_min && w < ucs_a1_jis_table_max) { + s = ucs_a1_jis_table[w - ucs_a1_jis_table_min]; + } else if (w >= ucs_a2_jis_table_min && w < ucs_a2_jis_table_max) { + s = ucs_a2_jis_table[w - ucs_a2_jis_table_min]; + } else if (w >= ucs_i_jis_table_min && w < ucs_i_jis_table_max) { + s = ucs_i_jis_table[w - ucs_i_jis_table_min]; + } else if (w >= ucs_r_jis_table_min && w < ucs_r_jis_table_max) { + s = ucs_r_jis_table[w - ucs_r_jis_table_min]; + } + + if (s == 0) { + if (w == 0xA5) { /* YEN SIGN */ + s = 0x5C; + } else if (w == 0xFF3C) { /* FULLWIDTH REVERSE SOLIDUS */ + s = 0x2140; + } else if (w == 0x2225) { /* PARALLEL TO */ + s = 0x2142; + } else if (w == 0xFF0D) { /* FULLWIDTH HYPHEN-MINUS */ + s = 0x215D; + } else if (w == 0xFFE0) { /* FULLWIDTH CENT SIGN */ + s = 0x2171; + } else if (w == 0xFFE1) { /* FULLWIDTH POUND SIGN */ + s = 0x2172; + } else if (w == 0xFFE2) { /* FULLWIDTH NOT SIGN */ + s = 0x224C; + } else if (w != 0) { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjis); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + continue; + } + } else if (s >= 0x8080) { /* JIS X 0212; not supported */ + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_sjis); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + continue; + } + + if (s <= 0xFF) { + /* Latin/Kana */ + out = mb_convert_buf_add(out, s); + } else { + /* Kanji */ + unsigned int c1 = (s >> 8) & 0xFF, c2 = s & 0xFF, s2; + SJIS_ENCODE(c1, c2, s, s2); + out = mb_convert_buf_add2(out, s, s2); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c index 19602dd9da4da..993fc151dec4a 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis_2004.c @@ -48,7 +48,9 @@ const mbfl_encoding mbfl_encoding_sjis2004 = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis2004_wchar, - &vtbl_wchar_sjis2004 + &vtbl_wchar_sjis2004, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis2004_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis_mac.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis_mac.c index e24e0b1a3f7cb..97fbb59e50583 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis_mac.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis_mac.c @@ -50,7 +50,9 @@ const mbfl_encoding mbfl_encoding_sjis_mac = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_mac_wchar, - &vtbl_wchar_sjis_mac + &vtbl_wchar_sjis_mac, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis_mac_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_sjis_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_sjis_mobile.c index 4eaa1c2557512..38ec5fe11d89f 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_sjis_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_sjis_mobile.c @@ -52,7 +52,9 @@ const mbfl_encoding mbfl_encoding_sjis_docomo = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_docomo_wchar, - &vtbl_wchar_sjis_docomo + &vtbl_wchar_sjis_docomo, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_sjis_kddi = { @@ -63,7 +65,9 @@ const mbfl_encoding mbfl_encoding_sjis_kddi = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_kddi_wchar, - &vtbl_wchar_sjis_kddi + &vtbl_wchar_sjis_kddi, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_sjis_sb = { @@ -74,7 +78,9 @@ const mbfl_encoding mbfl_encoding_sjis_sb = { mblen_table_sjis, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_sjis_sb_wchar, - &vtbl_wchar_sjis_sb + &vtbl_wchar_sjis_sb, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_sjis_docomo_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c index 388a901fe66d2..9ee1e4bf63a89 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs2.c @@ -31,6 +31,11 @@ #include "mbfilter_ucs2.h" static int mbfl_filt_conv_ucs2_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_ucs2_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static size_t mb_ucs2be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_ucs2be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_ucs2le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_ucs2le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static const char *mbfl_encoding_ucs2_aliases[] = {"ISO-10646-UCS-2", "UCS2" , "UNICODE", NULL}; @@ -49,7 +54,9 @@ const mbfl_encoding mbfl_encoding_ucs2 = { NULL, MBFL_ENCTYPE_WCS2, &vtbl_ucs2_wchar, - &vtbl_wchar_ucs2 + &vtbl_wchar_ucs2, + mb_ucs2_to_wchar, + mb_wchar_to_ucs2be }; const mbfl_encoding mbfl_encoding_ucs2be = { @@ -60,7 +67,9 @@ const mbfl_encoding mbfl_encoding_ucs2be = { NULL, MBFL_ENCTYPE_WCS2, &vtbl_ucs2be_wchar, - &vtbl_wchar_ucs2be + &vtbl_wchar_ucs2be, + mb_ucs2be_to_wchar, + mb_wchar_to_ucs2be }; const mbfl_encoding mbfl_encoding_ucs2le = { @@ -71,7 +80,9 @@ const mbfl_encoding mbfl_encoding_ucs2le = { NULL, MBFL_ENCTYPE_WCS2, &vtbl_ucs2le_wchar, - &vtbl_wchar_ucs2le + &vtbl_wchar_ucs2le, + mb_ucs2le_to_wchar, + mb_wchar_to_ucs2le }; const struct mbfl_convert_vtbl vtbl_ucs2_wchar = { @@ -216,3 +227,119 @@ static int mbfl_filt_conv_ucs2_wchar_flush(mbfl_convert_filter *filter) return 0; } + +#define DETECTED_BE 1 +#define DETECTED_LE 2 + +static size_t mb_ucs2_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + if (*state == DETECTED_BE) { + return mb_ucs2be_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*state == DETECTED_LE) { + return mb_ucs2le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*in_len >= 2) { + unsigned char *p = *in; + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint32_t w = (c1 << 8) | c2; + + if (w == 0xFFFE) { + /* Little-endian BOM */ + *in = p; + *in_len -= 2; + *state = DETECTED_LE; + return mb_ucs2le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (w == 0xFEFF) { + /* Big-endian BOM; don't send it to output */ + *in = p; + *in_len -= 2; + } + } + + *state = DETECTED_BE; + return mb_ucs2be_to_wchar(in, in_len, buf, bufsize, NULL); +} + +static size_t mb_ucs2be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~1); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint32_t w = (c1 << 8) | c2; + *out++ = w; + } + + if (p == e && (*in_len & 0x1) && out < limit) { + /* There is 1 trailing byte, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p++; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_ucs2be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + if (w < MBFL_WCSPLANE_UCS2MAX) { + out = mb_convert_buf_add2(out, (w >> 8) & 0xFF, w & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_ucs2be); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + +static size_t mb_ucs2le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~1); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint32_t w = (c2 << 8) | c1; + *out++ = w; + } + + if (p == e && (*in_len & 0x1) && out < limit) { + /* There is 1 trailing byte, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p++; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_ucs2le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + if (w < MBFL_WCSPLANE_UCS2MAX) { + out = mb_convert_buf_add2(out, w & 0xFF, (w >> 8) & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_ucs2le); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c index 6676f67c3ac22..c7f5fb2ac04fa 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_ucs4.c @@ -30,6 +30,12 @@ #include "mbfilter.h" #include "mbfilter_ucs4.h" +static size_t mb_ucs4_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static size_t mb_ucs4be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_ucs4be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_ucs4le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_ucs4le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); + static const char *mbfl_encoding_ucs4_aliases[] = {"ISO-10646-UCS-4", "UCS4", NULL}; /* This library historically had encodings called 'byte4be' and 'byte4le' @@ -48,7 +54,9 @@ const mbfl_encoding mbfl_encoding_ucs4 = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_ucs4_wchar, - &vtbl_wchar_ucs4 + &vtbl_wchar_ucs4, + mb_ucs4_to_wchar, + mb_wchar_to_ucs4be }; const mbfl_encoding mbfl_encoding_ucs4be = { @@ -59,7 +67,9 @@ const mbfl_encoding mbfl_encoding_ucs4be = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_ucs4be_wchar, - &vtbl_wchar_ucs4be + &vtbl_wchar_ucs4be, + mb_ucs4be_to_wchar, + mb_wchar_to_ucs4be }; const mbfl_encoding mbfl_encoding_ucs4le = { @@ -70,7 +80,9 @@ const mbfl_encoding mbfl_encoding_ucs4le = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_ucs4le_wchar, - &vtbl_wchar_ucs4le + &vtbl_wchar_ucs4le, + mb_ucs4le_to_wchar, + mb_wchar_to_ucs4le }; const struct mbfl_convert_vtbl vtbl_ucs4_wchar = { @@ -296,3 +308,125 @@ static int mbfl_filt_conv_ucs4_wchar_flush(mbfl_convert_filter *filter) return 0; } + +#define DETECTED_BE 1 +#define DETECTED_LE 2 + +static size_t mb_ucs4_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + if (*state == DETECTED_BE) { + return mb_ucs4be_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*state == DETECTED_LE) { + return mb_ucs4le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*in_len >= 4) { + unsigned char *p = *in; + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; + + if (w == 0xFFFE0000) { + /* Little-endian BOM */ + *in = p; + *in_len -= 4; + *state = DETECTED_LE; + return mb_ucs4le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (w == 0xFEFF) { + /* Big-endian BOM; don't send it to output */ + *in = p; + *in_len -= 4; + } + } + + *state = DETECTED_BE; + return mb_ucs4be_to_wchar(in, in_len, buf, bufsize, NULL); +} + +static size_t mb_ucs4be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~3); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; + *out++ = w; + } + + if (p == e && (*in_len & 0x3) && out < limit) { + /* There are 1-3 trailing bytes, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p = *in + *in_len; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_ucs4be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + + while (len--) { + uint32_t w = *in++; + if (w != MBFL_BAD_INPUT) { + out = mb_convert_buf_add4(out, (w >> 24) & 0xFF, (w >> 16) & 0xFF, (w >> 8) & 0xFF, w & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_ucs4be); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + +static size_t mb_ucs4le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~3); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c4 << 24) | (c3 << 16) | (c2 << 8) | c1; + *out++ = w; + } + + if (p == e && (*in_len & 0x3) && out < limit) { + /* There are 1-3 trailing bytes, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p = *in + *in_len; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_ucs4le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + + while (len--) { + uint32_t w = *in++; + if (w != MBFL_BAD_INPUT) { + out = mb_convert_buf_add4(out, w & 0xFF, (w >> 8) & 0xFF, (w >> 16) & 0xFF, (w >> 24) & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_ucs4le); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_uhc.c b/ext/mbstring/libmbfl/filters/mbfilter_uhc.c index 06300404b6e27..e465fbe2b4d4e 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_uhc.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_uhc.c @@ -67,7 +67,9 @@ const mbfl_encoding mbfl_encoding_uhc = { mblen_table_uhc, 0, &vtbl_uhc_wchar, - &vtbl_wchar_uhc + &vtbl_wchar_uhc, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_uhc_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c index 8477367f79d87..3a3b1d5269094 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf16.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf16.c @@ -31,6 +31,11 @@ #include "mbfilter_utf16.h" static int mbfl_filt_conv_utf16_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_utf16_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static const char *mbfl_encoding_utf16_aliases[] = {"utf16", NULL}; @@ -42,7 +47,9 @@ const mbfl_encoding mbfl_encoding_utf16 = { NULL, 0, &vtbl_utf16_wchar, - &vtbl_wchar_utf16 + &vtbl_wchar_utf16, + mb_utf16_to_wchar, + mb_wchar_to_utf16be }; const mbfl_encoding mbfl_encoding_utf16be = { @@ -53,7 +60,9 @@ const mbfl_encoding mbfl_encoding_utf16be = { NULL, 0, &vtbl_utf16be_wchar, - &vtbl_wchar_utf16be + &vtbl_wchar_utf16be, + mb_utf16be_to_wchar, + mb_wchar_to_utf16be }; const mbfl_encoding mbfl_encoding_utf16le = { @@ -64,7 +73,9 @@ const mbfl_encoding mbfl_encoding_utf16le = { NULL, 0, &vtbl_utf16le_wchar, - &vtbl_wchar_utf16le + &vtbl_wchar_utf16le, + mb_utf16le_to_wchar, + mb_wchar_to_utf16le }; const struct mbfl_convert_vtbl vtbl_utf16_wchar = { @@ -322,3 +333,191 @@ static int mbfl_filt_conv_utf16_wchar_flush(mbfl_convert_filter *filter) return 0; } + +#define DETECTED_BE 1 +#define DETECTED_LE 2 + +static size_t mb_utf16_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + if (*state == DETECTED_BE) { + return mb_utf16be_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*state == DETECTED_LE) { + return mb_utf16le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*in_len >= 2) { + unsigned char *p = *in; + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint16_t n = (c1 << 8) | c2; + + if (n == 0xFFFE) { + /* Little-endian BOM */ + *in = p; + *in_len -= 2; + *state = DETECTED_LE; + return mb_utf16le_to_wchar(in, in_len, buf, bufsize, NULL); + } if (n == 0xFEFF) { + /* Big-endian BOM; don't send to output */ + *in = p; + *in_len -= 2; + } + } + + *state = DETECTED_BE; + return mb_utf16be_to_wchar(in, in_len, buf, bufsize, NULL); +} + +static size_t mb_utf16be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + /* We only want to read 16-bit words out of `str`; any trailing byte will be handled at the end */ + unsigned char *p = *in, *e = p + (*in_len & ~1); + /* Set `limit` to one less than the actual amount of space in the buffer; this is because + * on some iterations of the below loop, we might produce two output words */ + uint32_t *out = buf, *limit = buf + bufsize - 1; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint16_t n = (c1 << 8) | c2; + + if (n >= 0xD800 && n <= 0xDBFF) { + /* Handle surrogate */ + if (p < e) { + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint16_t n2 = (c3 << 8) | c4; + + if (n2 >= 0xD800 && n2 <= 0xDBFF) { + /* Wrong; that's the first half of a surrogate pair, when we were expecting the second */ + *out++ = MBFL_BAD_INPUT; + p -= 2; + } else if (n2 >= 0xDC00 && n2 <= 0xDFFF) { + *out++ = (((n & 0x3FF) << 10) | (n2 & 0x3FF)) + 0x10000; + } else { + /* The first half of a surrogate pair was followed by a 'normal' codepoint */ + *out++ = MBFL_BAD_INPUT; + *out++ = n2; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else if (n >= 0xDC00 && n <= 0xDFFF) { + /* This is wrong; second part of surrogate pair has come first */ + *out++ = MBFL_BAD_INPUT; + } else { + *out++ = n; + } + } + + if (p == e && (*in_len & 0x1) && out < limit) { + /* There is an extra trailing byte (which shouldn't be there) */ + *out++ = MBFL_BAD_INPUT; + p++; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_utf16be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + + if (w < MBFL_WCSPLANE_UCS2MAX) { + out = mb_convert_buf_add2(out, (w >> 8) & 0xFF, w & 0xFF); + } else if (w < MBFL_WCSPLANE_UTF32MAX) { + uint16_t n1 = ((w >> 10) - 0x40) | 0xD800; + uint16_t n2 = (w & 0x3FF) | 0xDC00; + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add4(out, (n1 >> 8) & 0xFF, n1 & 0xFF, (n2 >> 8) & 0xFF, n2 & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16be); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + +static size_t mb_utf16le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + /* We only want to read 16-bit words out of `str`; any trailing byte will be handled at the end */ + unsigned char *p = *in, *e = p + (*in_len & ~1); + /* Set `limit` to one less than the actual amount of space in the buffer; this is because + * on some iterations of the below loop, we might produce two output words */ + uint32_t *out = buf, *limit = buf + bufsize - 1; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + uint16_t n = (c2 << 8) | c1; + + if (n >= 0xD800 && n <= 0xDBFF) { + /* Handle surrogate */ + if (p < e) { + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint16_t n2 = (c4 << 8) | c3; + + if (n2 >= 0xD800 && n2 <= 0xDBFF) { + /* Wrong; that's the first half of a surrogate pair, when we were expecting the second */ + *out++ = MBFL_BAD_INPUT; + p -= 2; + } else if (n2 >= 0xDC00 && n2 <= 0xDFFF) { + *out++ = (((n & 0x3FF) << 10) | (n2 & 0x3FF)) + 0x10000; + } else { + /* The first half of a surrogate pair was followed by a 'normal' codepoint */ + *out++ = MBFL_BAD_INPUT; + *out++ = n2; + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else if (n >= 0xDC00 && n <= 0xDFFF) { + /* This is wrong; second part of surrogate pair has come first */ + *out++ = MBFL_BAD_INPUT; + } else { + *out++ = n; + } + } + + if (p == e && (*in_len & 0x1) && out < limit) { + /* There is an extra trailing byte (which shouldn't be there) */ + *out++ = MBFL_BAD_INPUT; + p++; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_utf16le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + + while (len--) { + uint32_t w = *in++; + + if (w < MBFL_WCSPLANE_UCS2MAX) { + out = mb_convert_buf_add2(out, w & 0xFF, (w >> 8) & 0xFF); + } else if (w < MBFL_WCSPLANE_UTF32MAX) { + uint16_t n1 = ((w >> 10) - 0x40) | 0xD800; + uint16_t n2 = (w & 0x3FF) | 0xDC00; + MB_CONVERT_BUF_ENSURE(buf, out, limit, (len * 2) + 4); + out = mb_convert_buf_add4(out, n1 & 0xFF, (n1 >> 8) & 0xFF, n2 & 0xFF, (n2 >> 8) & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf16le); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 2); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c index ec9945e13ef50..c654e4cf51020 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf32.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf32.c @@ -31,6 +31,11 @@ #include "mbfilter_utf32.h" static int mbfl_filt_conv_utf32_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_utf32_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static size_t mb_utf32be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf32be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); +static size_t mb_utf32le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf32le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static const char *mbfl_encoding_utf32_aliases[] = {"utf32", NULL}; @@ -42,7 +47,9 @@ const mbfl_encoding mbfl_encoding_utf32 = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_utf32_wchar, - &vtbl_wchar_utf32 + &vtbl_wchar_utf32, + mb_utf32_to_wchar, + mb_wchar_to_utf32be }; const mbfl_encoding mbfl_encoding_utf32be = { @@ -53,7 +60,9 @@ const mbfl_encoding mbfl_encoding_utf32be = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_utf32be_wchar, - &vtbl_wchar_utf32be + &vtbl_wchar_utf32be, + mb_utf32be_to_wchar, + mb_wchar_to_utf32be }; const mbfl_encoding mbfl_encoding_utf32le = { @@ -64,7 +73,9 @@ const mbfl_encoding mbfl_encoding_utf32le = { NULL, MBFL_ENCTYPE_WCS4, &vtbl_utf32le_wchar, - &vtbl_wchar_utf32le + &vtbl_wchar_utf32le, + mb_utf32le_to_wchar, + mb_wchar_to_utf32le }; const struct mbfl_convert_vtbl vtbl_utf32_wchar = { @@ -229,3 +240,135 @@ static int mbfl_filt_conv_utf32_wchar_flush(mbfl_convert_filter *filter) return 0; } + +#define DETECTED_BE 1 +#define DETECTED_LE 2 + +static size_t mb_utf32_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + if (*state == DETECTED_BE) { + return mb_utf32be_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*state == DETECTED_LE) { + return mb_utf32le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (*in_len >= 4) { + unsigned char *p = *in; + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; + + if (w == 0xFFFE0000) { + /* Little-endian BOM */ + *in = p; + *in_len -= 4; + *state = DETECTED_LE; + return mb_utf32le_to_wchar(in, in_len, buf, bufsize, NULL); + } else if (w == 0xFEFF) { + /* Big-endian BOM; don't send it to output */ + *in = p; + *in_len -= 4; + } + } + + *state = DETECTED_BE; + return mb_utf32be_to_wchar(in, in_len, buf, bufsize, NULL); +} + +static size_t mb_utf32be_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~3); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c1 << 24) | (c2 << 16) | (c3 << 8) | c4; + + if (w < MBFL_WCSPLANE_UTF32MAX && (w < 0xD800 || w > 0xDFFF)) { + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + if (p == e && (*in_len & 0x3) && out < limit) { + /* There are 1-3 trailing bytes, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p = *in + *in_len; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_utf32be(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + + while (len--) { + uint32_t w = *in++; + if (w < MBFL_WCSPLANE_UTF32MAX) { + out = mb_convert_buf_add4(out, (w >> 24) & 0xFF, (w >> 16) & 0xFF, (w >> 8) & 0xFF, w & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf32be); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} + +static size_t mb_utf32le_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + (*in_len & ~3); + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c1 = *p++; + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + uint32_t w = (c4 << 24) | (c3 << 16) | (c2 << 8) | c1; + + if (w < MBFL_WCSPLANE_UTF32MAX && (w < 0xD800 || w > 0xDFFF)) { + *out++ = w; + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + if (p == e && (*in_len & 0x3) && out < limit) { + /* There are 1-3 trailing bytes, which shouldn't be there */ + *out++ = MBFL_BAD_INPUT; + p = *in + *in_len; + } + + *in_len -= (p - *in); + *in = p; + return out - buf; +} + +static void mb_wchar_to_utf32le(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + + while (len--) { + uint32_t w = *in++; + if (w < MBFL_WCSPLANE_UTF32MAX) { + out = mb_convert_buf_add4(out, w & 0xFF, (w >> 8) & 0xFF, (w >> 16) & 0xFF, (w >> 24) & 0xFF); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf32le); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len * 4); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf7.c b/ext/mbstring/libmbfl/filters/mbfilter_utf7.c index c3144b4779584..7f843f88bb603 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf7.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf7.c @@ -31,6 +31,8 @@ #include "mbfilter_utf7.h" static int mbfl_filt_conv_utf7_wchar_flush(mbfl_convert_filter *filter); +static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf7(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); static const unsigned char mbfl_base64_table[] = { /* 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', */ @@ -55,7 +57,9 @@ const mbfl_encoding mbfl_encoding_utf7 = { NULL, MBFL_ENCTYPE_GL_UNSAFE, &vtbl_utf7_wchar, - &vtbl_wchar_utf7 + &vtbl_wchar_utf7, + mb_utf7_to_wchar, + mb_wchar_to_utf7 }; const struct mbfl_convert_vtbl vtbl_utf7_wchar = { @@ -401,3 +405,280 @@ int mbfl_filt_conv_wchar_utf7_flush(mbfl_convert_filter *filter) return 0; } + +/* Ways which a Base64-encoded section can end: */ +#define DASH 0xFD +#define ASCII 0xFE +#define ILLEGAL 0xFF + +static inline bool is_base64_end(unsigned char c) +{ + return c >= DASH; +} + +static unsigned char decode_base64(unsigned char c) +{ + if (c >= 'A' && c <= 'Z') { + return c - 65; + } else if (c >= 'a' && c <= 'z') { + return c - 71; + } else if (c >= '0' && c <= '9') { + return c + 4; + } else if (c == '+') { + return 62; + } else if (c == '/') { + return 63; + } else if (c == '-') { + return DASH; + } else if (c <= 0x7F) { + return ASCII; + } + return ILLEGAL; +} + +static uint32_t* handle_utf16_cp(uint16_t cp, uint32_t *out, uint16_t *surrogate1) +{ +retry: + if (*surrogate1) { + if (cp >= 0xDC00 && cp <= 0xDFFF) { + *out++ = ((*surrogate1 & 0x3FF) << 10) + (cp & 0x3FF) + 0x10000; + *surrogate1 = 0; + } else { + *out++ = MBFL_BAD_INPUT; + *surrogate1 = 0; + goto retry; + } + } else if (cp >= 0xD800 && cp <= 0xDBFF) { + *surrogate1 = cp; + } else if (cp >= 0xDC00 && cp <= 0xDFFF) { + /* 2nd part of surrogate pair came unexpectedly */ + *out++ = MBFL_BAD_INPUT; + } else { + *out++ = cp; + } + return out; +} + +static uint32_t* handle_base64_end(unsigned char n, unsigned char **p, uint32_t *out, bool *base64, bool abrupt, uint16_t *surrogate1) +{ + if (abrupt || *surrogate1) { + *out++ = MBFL_BAD_INPUT; + *surrogate1 = 0; + } + + if (n == ILLEGAL) { + *out++ = MBFL_BAD_INPUT; + } else if (n == ASCII) { + (*p)--; /* Unconsume byte */ + } + + *base64 = false; + return out; +} + +static size_t mb_utf7_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + ZEND_ASSERT(bufsize >= 4); /* This function will infinite-loop if called with a tiny output buffer */ + + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + bool base64 = *state & 1; + uint16_t surrogate1 = (*state >> 1); /* First half of a surrogate pair which still needs 2nd half */ + + while (p < e && out < limit) { + if (base64) { + /* Base64 section */ + if ((limit - out) < 4) { + break; + } + + unsigned char n1 = decode_base64(*p++); + if (is_base64_end(n1)) { + out = handle_base64_end(n1, &p, out, &base64, false, &surrogate1); + continue; + } else if (p == e) { + out = handle_base64_end(n1, &p, out, &base64, true, &surrogate1); + continue; + } + unsigned char n2 = decode_base64(*p++); + if (is_base64_end(n2) || p == e) { + out = handle_base64_end(n2, &p, out, &base64, true, &surrogate1); + continue; + } + unsigned char n3 = decode_base64(*p++); + if (is_base64_end(n3)) { + out = handle_base64_end(n3, &p, out, &base64, true, &surrogate1); + continue; + } + out = handle_utf16_cp((n1 << 10) | (n2 << 4) | ((n3 & 0x3C) >> 2), out, &surrogate1); + if (p == e) { + /* It is an error if trailing padding bits are not zeroes or if we were + * expecting the 2nd part of a surrogate pair when Base64 section ends */ + if ((n3 & 0x3) || surrogate1) + *out++ = MBFL_BAD_INPUT; + break; + } + + unsigned char n4 = decode_base64(*p++); + if (is_base64_end(n4) || p == e) { + out = handle_base64_end(n4, &p, out, &base64, n3 & 0x3, &surrogate1); + continue; + } + unsigned char n5 = decode_base64(*p++); + if (is_base64_end(n5) || p == e) { + out = handle_base64_end(n5, &p, out, &base64, true, &surrogate1); + continue; + } + unsigned char n6 = decode_base64(*p++); + if (is_base64_end(n6)) { + out = handle_base64_end(n6, &p, out, &base64, true, &surrogate1); + continue; + } + out = handle_utf16_cp((n3 << 14) | (n4 << 8) | (n5 << 2) | ((n6 & 0x30) >> 4), out, &surrogate1); + if (p == e) { + if ((n6 & 0xF) || surrogate1) + *out++ = MBFL_BAD_INPUT; + break; + } + + unsigned char n7 = decode_base64(*p++); + if (is_base64_end(n7) || p == e) { + out = handle_base64_end(n7, &p, out, &base64, n6 & 0xF, &surrogate1); + continue; + } + unsigned char n8 = decode_base64(*p++); + if (is_base64_end(n8)) { + out = handle_base64_end(n8, &p, out, &base64, true, &surrogate1); + continue; + } + out = handle_utf16_cp((n6 << 12) | (n7 << 6) | n8, out, &surrogate1); + } else { + /* ASCII text section */ + unsigned char c = *p++; + + if (c == '+') { + if (p < e) { + if (*p == '-') { + *out++ = '+'; + p++; + } else { + base64 = true; + } + } + /* If a + comes at the end of the input string... do nothing about it */ + } else if (c <= 0x7F) { + *out++ = c; + } else { + *out++ = MBFL_BAD_INPUT; + } + } + } + + *state = (surrogate1 << 1) | base64; + *in_len = e - p; + *in = p; + return out - buf; +} + +static bool can_end_base64(uint32_t c) +{ + return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\'' || c == '(' || c == ')' || c == ',' || c == '.' || c == ':' || c == '?'; +} + +static bool should_direct_encode(uint32_t c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '\0' || c == '/' || c == '-' || can_end_base64(c); +} + +#define SAVE_CONVERSION_STATE() buf->state = (cache << 4) | (nbits << 1) | base64 +#define RESTORE_CONVERSION_STATE() base64 = (buf->state & 1); nbits = (buf->state >> 1) & 0x7; cache = (buf->state >> 4) + +static void mb_wchar_to_utf7(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + + /* Make enough space such that if the input string is all ASCII (not including '+'), + * we can copy it to the output buffer without checking for available space. + * However, if we find anything which is not plain ASCII, additional checks for + * output buffer space will be needed. */ + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + bool base64; + unsigned char nbits, cache; /* `nbits` is the number of cached bits; either 0, 2, or 4 */ + RESTORE_CONVERSION_STATE(); + + while (len--) { + uint32_t w = *in++; + if (base64) { + if (should_direct_encode(w)) { + /* End of Base64 section. Drain buffered bits (if any), close Base64 section */ + base64 = false; + in--; len++; /* Unconsume codepoint; it will be handled by 'ASCII section' code below */ + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + if (nbits) { + out = mb_convert_buf_add(out, mbfl_base64_table[(cache << (6 - nbits)) & 0x3F]); + } + nbits = cache = 0; + if (!can_end_base64(w)) { + out = mb_convert_buf_add(out, '-'); + } + } else if (w >= MBFL_WCSPLANE_UTF32MAX) { + /* Make recursive call to add an error marker character */ + SAVE_CONVERSION_STATE(); + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf7); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + RESTORE_CONVERSION_STATE(); + } else { + /* Encode codepoint, preceded by any cached bits, as Base64 */ + uint64_t bits; + if (w >= MBFL_WCSPLANE_SUPMIN) { + /* Must use surrogate pair */ + MB_CONVERT_BUF_ENSURE(buf, out, limit, 6); + w -= 0x10000; + bits = ((uint64_t)cache << 32) | 0xD800DC00L | ((w & 0xFFC00) << 6) | (w & 0x3FF); + nbits += 32; + } else { + MB_CONVERT_BUF_ENSURE(buf, out, limit, 3); + bits = (cache << 16) | w; + nbits += 16; + } + + while (nbits >= 6) { + out = mb_convert_buf_add(out, mbfl_base64_table[(bits >> (nbits - 6)) & 0x3F]); + nbits -= 6; + } + cache = bits; + } + } else { + /* ASCII section */ + if (should_direct_encode(w)) { + out = mb_convert_buf_add(out, w); + } else if (w >= MBFL_WCSPLANE_UTF32MAX) { + buf->state = 0; + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf7); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + RESTORE_CONVERSION_STATE(); + } else { + out = mb_convert_buf_add(out, '+'); + base64 = true; + in--; len++; /* Unconsume codepoint; it will be handled by Base64 code above */ + } + } + } + + if (end) { + if (nbits) { + out = mb_convert_buf_add(out, mbfl_base64_table[(cache << (6 - nbits)) & 0x3F]); + } + if (base64) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, 1); + out = mb_convert_buf_add(out, '-'); + } + } else { + SAVE_CONVERSION_STATE(); + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c b/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c index 473a1f56c1396..7de68dea3cc22 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf7imap.c @@ -91,7 +91,9 @@ const mbfl_encoding mbfl_encoding_utf7imap = { NULL, 0, &vtbl_utf7imap_wchar, - &vtbl_wchar_utf7imap + &vtbl_wchar_utf7imap, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_utf7imap_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c index 7c371d2e4d138..83d2158c37d10 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c @@ -49,6 +49,9 @@ const unsigned char mblen_table_utf8[] = { 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; +static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state); +static void mb_wchar_to_utf8(uint32_t *in, size_t len, mb_convert_buf *buf, bool end); + static const char *mbfl_encoding_utf8_aliases[] = {"utf8", NULL}; const mbfl_encoding mbfl_encoding_utf8 = { @@ -59,7 +62,9 @@ const mbfl_encoding mbfl_encoding_utf8 = { mblen_table_utf8, 0, &vtbl_utf8_wchar, - &vtbl_wchar_utf8 + &vtbl_wchar_utf8, + mb_utf8_to_wchar, + mb_wchar_to_utf8 }; const struct mbfl_convert_vtbl vtbl_utf8_wchar = { @@ -216,3 +221,157 @@ int mbfl_filt_conv_wchar_utf8(int c, mbfl_convert_filter *filter) return 0; } + +static size_t mb_utf8_to_wchar(unsigned char **in, size_t *in_len, uint32_t *buf, size_t bufsize, unsigned int *state) +{ + unsigned char *p = *in, *e = p + *in_len; + uint32_t *out = buf, *limit = buf + bufsize; + + while (p < e && out < limit) { + unsigned char c = *p++; + + if (c < 0x80) { + *out++ = c; + } else if (c >= 0xC2 && c <= 0xDF) { /* 2 byte character */ + if (p < e) { + unsigned char c2 = *p++; + if ((c2 & 0xC0) != 0x80) { + *out++ = MBFL_BAD_INPUT; + if (c2 < 0x80 || (c2 >= 0xC2 && c2 <= 0xF4)) { + p--; + } + } else { + *out++ = ((c & 0x1F) << 6) | (c2 & 0x3F); + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } else if (c >= 0xE0 && c <= 0xEF) { /* 3 byte character */ + if ((e - p) >= 2) { + unsigned char c2 = *p++; + unsigned char c3 = *p++; + if ((c2 & 0xC0) != 0x80 || !((c2 >= 0x80 && c2 <= 0xBF) && ((c == 0xE0 && c2 >= 0xA0) || (c == 0xED && c2 < 0xA0) || (c > 0xE0 && c != 0xED)))) { + *out++ = MBFL_BAD_INPUT; + if (c2 < 0x80 || (c2 >= 0xC2 && c2 <= 0xF4)) { + p -= 2; + } else { + p--; + } + } else if ((c3 & 0xC0) != 0x80) { + *out++ = MBFL_BAD_INPUT; + if (c3 < 0x80 || (c3 >= 0xC2 && c3 <= 0xF4)) { + p--; + } + } else { + uint32_t decoded = ((c & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F); + if (decoded >= 0xD800 && decoded <= 0xDFFF) { + *out++ = MBFL_BAD_INPUT; + } else { + *out++ = (decoded < 0x800) ? MBFL_BAD_INPUT : decoded; + } + } + } else { + *out++ = MBFL_BAD_INPUT; + /* Skip over some number of bytes to duplicate error-handling behavior of old implementation */ + while (p < e) { + c = *p; + if ((c & 0xC0) != 0x80) { + if (c >= 0x80 && (c < 0xC2 || c > 0xF4)) + p++; + break; + } + p++; + } + } + } else if (c >= 0xF0 && c <= 0xF4) { /* 4 byte character */ + if ((e - p) >= 3) { + unsigned char c2 = *p++; + unsigned char c3 = *p++; + unsigned char c4 = *p++; + if ((c2 & 0xC0) != 0x80) { + *out++ = MBFL_BAD_INPUT; + if (c2 < 0x80 || (c2 >= 0xC2 && c2 <= 0xF4)) { + p -= 3; + } else { + p -= 2; + } + } else if ((c3 & 0xC0) != 0x80 || !((c == 0xF0 && c2 >= 0x90) || (c == 0xF4 && c2 < 0x90) || (c > 0xF0 && c < 0xF4))) { + *out++ = MBFL_BAD_INPUT; + if (!((c == 0xF0 && c2 >= 0x90) || (c == 0xF4 && c2 < 0x90) || (c > 0xF0 && c < 0xF4))) { + if (c2 >= 0x80 && (c2 < 0xC2 || c2 > 0xF4)) { + p -= 2; + } else { + p -= 3; + } + } else if (c3 < 0x80 || (c3 >= 0xC2 && c3 <= 0xF4)) { + p -= 2; + } else { + p--; + } + } else if ((c4 & 0xC0) != 0x80) { + *out++ = MBFL_BAD_INPUT; + if (c4 < 0x80 || (c4 >= 0xC2 && c4 <= 0xF4)) { + p--; + } + } else { + uint32_t decoded = ((c & 0x7) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F); + *out++ = (decoded < 0x10000) ? MBFL_BAD_INPUT : decoded; + } + } else { + *out++ = MBFL_BAD_INPUT; + /* Skip over some number of bytes to duplicate error-handling behavior of old implementation */ + if (p < e) { + unsigned char c2 = *p; + if (!((c == 0xF0 && c2 >= 0x90) || (c == 0xF4 && c2 < 0x90) || (c > 0xF0 && c < 0xF4))) { + if (c2 >= 0x80 && (c2 < 0xC2 || c2 > 0xF4)) + p++; + } else { + while (p < e) { + c = *p; + if ((c & 0xC0) != 0x80) { + if (c >= 0x80 && (c < 0xC2 || c > 0xF4)) + p++; + break; + } + p++; + } + } + } + } + } else { + *out++ = MBFL_BAD_INPUT; + } + } + + *in_len = e - p; + *in = p; + return out - buf; +} + +static void mb_wchar_to_utf8(uint32_t *in, size_t len, mb_convert_buf *buf, bool end) +{ + unsigned char *out, *limit; + MB_CONVERT_BUF_LOAD(buf, out, limit); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + + while (len--) { + uint32_t w = *in++; + if (w < 0x80) { + out = mb_convert_buf_add(out, w & 0xFF); + } else if (w < 0x800) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 2); + out = mb_convert_buf_add2(out, ((w >> 6) & 0x1F) | 0xC0, (w & 0x3F) | 0x80); + } else if (w < 0x10000) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 3); + out = mb_convert_buf_add3(out, ((w >> 12) & 0xF) | 0xE0, ((w >> 6) & 0x3F) | 0x80, (w & 0x3F) | 0x80); + } else if (w < 0x110000) { + MB_CONVERT_BUF_ENSURE(buf, out, limit, len + 4); + out = mb_convert_buf_add4(out, ((w >> 18) & 0x7) | 0xF0, ((w >> 12) & 0x3F) | 0x80, ((w >> 6) & 0x3F) | 0x80, (w & 0x3F) | 0x80); + } else { + MB_CONVERT_ERROR(buf, out, limit, w, mb_wchar_to_utf8); + MB_CONVERT_BUF_ENSURE(buf, out, limit, len); + } + } + + MB_CONVERT_BUF_STORE(buf, out, limit); +} diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c index 14b0094592489..04af4c0939e24 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c @@ -49,7 +49,9 @@ const mbfl_encoding mbfl_encoding_utf8_docomo = { mblen_table_utf8, 0, &vtbl_utf8_docomo_wchar, - &vtbl_wchar_utf8_docomo + &vtbl_wchar_utf8_docomo, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_utf8_kddi_a = { @@ -60,7 +62,9 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_a = { mblen_table_utf8, 0, &vtbl_utf8_kddi_a_wchar, - &vtbl_wchar_utf8_kddi_a + &vtbl_wchar_utf8_kddi_a, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_utf8_kddi_b = { @@ -71,7 +75,9 @@ const mbfl_encoding mbfl_encoding_utf8_kddi_b = { mblen_table_utf8, 0, &vtbl_utf8_kddi_b_wchar, - &vtbl_wchar_utf8_kddi_b + &vtbl_wchar_utf8_kddi_b, + NULL, + NULL }; const mbfl_encoding mbfl_encoding_utf8_sb = { @@ -82,7 +88,9 @@ const mbfl_encoding mbfl_encoding_utf8_sb = { mblen_table_utf8, 0, &vtbl_utf8_sb_wchar, - &vtbl_wchar_utf8_sb + &vtbl_wchar_utf8_sb, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_utf8_docomo_wchar = { diff --git a/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c b/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c index d602274db62cf..9571131aad5b9 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_uuencode.c @@ -38,6 +38,8 @@ const mbfl_encoding mbfl_encoding_uuencode = { NULL, MBFL_ENCTYPE_SBCS, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter.c b/ext/mbstring/libmbfl/mbfl/mbfilter.c index 508f942b287e8..1c93b77a9533b 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter.c @@ -454,49 +454,39 @@ filter_count_output(int c, void *data) return 0; } -size_t -mbfl_strlen(const mbfl_string *string) +size_t mbfl_strlen(const mbfl_string *string) { - size_t len, n, k; - unsigned char *p; + size_t len = 0; const mbfl_encoding *encoding = string->encoding; - len = 0; if (encoding->flag & MBFL_ENCTYPE_SBCS) { len = string->len; } else if (encoding->flag & MBFL_ENCTYPE_WCS2) { len = string->len/2; } else if (encoding->flag & MBFL_ENCTYPE_WCS4) { len = string->len/4; - } else if (encoding->mblen_table != NULL) { + } else if (encoding->mblen_table) { const unsigned char *mbtab = encoding->mblen_table; - n = 0; - p = string->val; - k = string->len; - /* count */ - if (p != NULL) { - while (n < k) { - unsigned m = mbtab[*p]; - n += m; - p += m; - len++; - } + unsigned char *p = string->val, *e = p + string->len; + while (p < e) { + p += mbtab[*p]; + len++; + } + } else if (encoding->to_wchar) { + uint32_t wchar_buf[128]; + unsigned char *in = string->val; + size_t in_len = string->len; + unsigned int state = 0; + + while (in_len) { + len += encoding->to_wchar(&in, &in_len, wchar_buf, 128, &state); } } else { - /* wchar filter */ - mbfl_convert_filter *filter = mbfl_convert_filter_new( - string->encoding, - &mbfl_encoding_wchar, - filter_count_output, 0, &len); + mbfl_convert_filter *filter = mbfl_convert_filter_new(string->encoding, &mbfl_encoding_wchar, filter_count_output, 0, &len); ZEND_ASSERT(filter); - /* count */ - n = string->len; - p = string->val; - if (p != NULL) { - while (n > 0) { - (*filter->filter_function)(*p++, filter); - n--; - } + unsigned char *p = string->val, *e = p + string->len; + while (p < e) { + (*filter->filter_function)(*p++, filter); } mbfl_convert_filter_delete(filter); } @@ -1232,7 +1222,7 @@ mbfl_strcut( /* Some East Asian characters, when printed at a terminal (or the like), require double * the usual amount of horizontal space. We call these "fullwidth" characters. */ -static size_t character_width(int c) +static size_t character_width(unsigned int c) { if (c < FIRST_DOUBLEWIDTH_CODEPOINT) { return 1; @@ -1260,35 +1250,44 @@ static int filter_count_width(int c, void* data) return 0; } -size_t -mbfl_strwidth(mbfl_string *string) +size_t mbfl_strwidth(mbfl_string *string) { - size_t len, n; - unsigned char *p; - mbfl_convert_filter *filter; + if (!string->len) { + return 0; + } - len = 0; - if (string->len > 0 && string->val != NULL) { - /* wchar filter */ - filter = mbfl_convert_filter_new( - string->encoding, - &mbfl_encoding_wchar, - filter_count_width, 0, &len); + size_t width = 0; + + if (string->encoding->to_wchar) { + uint32_t wchar_buf[128]; + unsigned char *in = string->val; + size_t in_len = string->len; + unsigned int state = 0; + + while (in_len) { + size_t out_len = string->encoding->to_wchar(&in, &in_len, wchar_buf, 128, &state); + while (out_len) { + /* NOTE: 'bad input' marker will be counted as 1 unit of width + * If text conversion is performed with an ordinary ASCII character as + * the 'replacement character', this will give us the correct display width. */ + width += character_width(wchar_buf[--out_len]); + } + } + } else { + mbfl_convert_filter *filter = mbfl_convert_filter_new(string->encoding, &mbfl_encoding_wchar, filter_count_width, 0, &width); ZEND_ASSERT(filter); /* feed data */ - p = string->val; - n = string->len; - while (n > 0) { + unsigned char *p = string->val, *e = p + string->len; + while (p < e) { (*filter->filter_function)(*p++, filter); - n--; } mbfl_convert_filter_flush(filter); mbfl_convert_filter_delete(filter); } - return len; + return width; } diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c b/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c index e348ddb69cc57..670b23da8cbb5 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_8bit.c @@ -47,7 +47,9 @@ const mbfl_encoding mbfl_encoding_8bit = { NULL, MBFL_ENCTYPE_SBCS, &vtbl_8bit_wchar, - &vtbl_wchar_8bit + &vtbl_wchar_8bit, + NULL, + NULL }; const struct mbfl_convert_vtbl vtbl_8bit_wchar = { diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c b/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c index e43f746ecca45..3fb7e991141cd 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_pass.c @@ -42,6 +42,8 @@ const mbfl_encoding mbfl_encoding_pass = { NULL, 0, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c b/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c index a2b22c9105acc..5472d792a83cb 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c +++ b/ext/mbstring/libmbfl/mbfl/mbfilter_wchar.c @@ -40,5 +40,7 @@ const mbfl_encoding mbfl_encoding_wchar = { NULL, MBFL_ENCTYPE_WCS4, NULL, + NULL, + NULL, NULL }; diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_convert.c b/ext/mbstring/libmbfl/mbfl/mbfl_convert.c index f6e860a35aead..dc76f67964edd 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_convert.c +++ b/ext/mbstring/libmbfl/mbfl/mbfl_convert.c @@ -347,3 +347,96 @@ int mbfl_filt_conv_common_flush(mbfl_convert_filter *filter) } return 0; } + +zend_string* mb_fast_convert(zend_string *str, const mbfl_encoding *from, const mbfl_encoding *to, uint32_t replacement_char, unsigned int error_mode, unsigned int *num_errors) +{ + uint32_t wchar_buf[128]; + unsigned char *in = (unsigned char*)ZSTR_VAL(str); + size_t in_len = ZSTR_LEN(str); + unsigned int state = 0; + + mb_convert_buf buf; + mb_convert_buf_init(&buf, in_len, replacement_char, error_mode); + + while (in_len) { + size_t out_len = from->to_wchar(&in, &in_len, wchar_buf, 128, &state); + to->from_wchar(wchar_buf, out_len, &buf, !in_len); + } + + *num_errors = buf.errors; + return mb_convert_buf_result(&buf); +} + +static uint32_t* convert_cp_to_hex(uint32_t cp, uint32_t *out) +{ + bool nonzero = false; + int shift = 28; + + while (shift >= 0) { + int n = (cp >> shift) & 0xF; + if (n || nonzero) { + nonzero = true; + *out++ = mbfl_hexchar_table[n]; + } + shift -= 4; + } + + if (!nonzero) { + /* No hex digits were output by above loop */ + *out++ = '0'; + } + + return out; +} + +static size_t mb_illegal_marker(uint32_t bad_cp, uint32_t *out, unsigned int err_mode, uint32_t replacement_char) +{ + uint32_t *start = out; + + if (bad_cp == MBFL_BAD_INPUT && err_mode != MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE) { + *out++ = replacement_char; + } else { + switch (err_mode) { + case MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR: + *out++ = replacement_char; + break; + + case MBFL_OUTPUTFILTER_ILLEGAL_MODE_LONG: + out[0] = 'U'; + out[1] = '+'; + out = convert_cp_to_hex(bad_cp, &out[2]); + break; + + case MBFL_OUTPUTFILTER_ILLEGAL_MODE_ENTITY: + out[0] = '&'; out[1] = '#'; out[2] = 'x'; + out = convert_cp_to_hex(bad_cp, &out[3]); + *out++ = ';'; + break; + } + } + + return out - start; +} + +void mb_illegal_output(uint32_t bad_cp, mb_from_wchar_fn fn, mb_convert_buf* buf) +{ + buf->errors++; + + uint32_t temp[12]; + uint32_t repl_char = buf->replacement_char; + unsigned int err_mode = buf->error_mode; + + size_t len = mb_illegal_marker(bad_cp, temp, err_mode, repl_char); + + /* Avoid infinite loop if `fn` is not able to handle `repl_char` */ + if (err_mode == MBFL_OUTPUTFILTER_ILLEGAL_MODE_CHAR && repl_char != '?') { + buf->replacement_char = '?'; + } else { + buf->error_mode = MBFL_OUTPUTFILTER_ILLEGAL_MODE_NONE; + } + + fn(temp, len, buf, false); + + buf->replacement_char = repl_char; + buf->error_mode = err_mode; +} diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_convert.h b/ext/mbstring/libmbfl/mbfl/mbfl_convert.h index 563cdda1cfa6f..12c12589b0a57 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_convert.h +++ b/ext/mbstring/libmbfl/mbfl/mbfl_convert.h @@ -81,4 +81,7 @@ MBFLAPI extern int mbfl_filt_conv_common_flush(mbfl_convert_filter *filter); MBFLAPI extern void mbfl_convert_filter_devcat(mbfl_convert_filter *filter, mbfl_memory_device *src); MBFLAPI extern int mbfl_convert_filter_strcat(mbfl_convert_filter *filter, const unsigned char *p); +MBFLAPI extern zend_string* mb_fast_convert(zend_string *str, const mbfl_encoding *from, const mbfl_encoding *to, uint32_t replacement_char, unsigned int error_mode, unsigned int *num_errors); +MBFLAPI extern void mb_illegal_output(uint32_t bad_cp, mb_from_wchar_fn fn, mb_convert_buf* buf); + #endif /* MBFL_CONVERT_H */ diff --git a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h index daeace934c93b..9f6b1e4bf99f2 100644 --- a/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h +++ b/ext/mbstring/libmbfl/mbfl/mbfl_encoding.h @@ -32,6 +32,7 @@ #define MBFL_ENCODING_H #include "mbfl_defs.h" +#include "zend.h" enum mbfl_no_encoding { mbfl_no_encoding_invalid = -1, @@ -129,10 +130,92 @@ struct mbfl_convert_vtbl { void (*filter_copy)(struct _mbfl_convert_filter *src, struct _mbfl_convert_filter *dest); }; -/* - * encoding - */ -typedef struct _mbfl_encoding { +typedef struct { + unsigned char *out; + unsigned char *limit; + uint32_t state; + uint32_t errors; + uint32_t replacement_char; + unsigned int error_mode; + zend_string *str; +} mb_convert_buf; + +typedef size_t (*mb_to_wchar_fn)(unsigned char **in, size_t *in_len, uint32_t *out, size_t out_len, unsigned int *state); +typedef void (*mb_from_wchar_fn)(uint32_t *in, size_t in_len, mb_convert_buf *out, bool end); + +static inline void mb_convert_buf_init(mb_convert_buf *buf, size_t initsize, uint32_t repl_char, unsigned int err_mode) +{ + buf->state = buf->errors = 0; + buf->str = emalloc(_ZSTR_STRUCT_SIZE(initsize)); + buf->out = (unsigned char*)ZSTR_VAL(buf->str); + buf->limit = buf->out + initsize; + buf->replacement_char = repl_char; + buf->error_mode = err_mode; +} + +#define MB_CONVERT_BUF_ENSURE(buf, out, limit, needed) \ + if ((limit - out) < (needed)) { \ + size_t oldsize = limit - (unsigned char*)ZSTR_VAL(buf->str); \ + size_t newsize = oldsize + MAX(oldsize >> 1, needed); \ + zend_string *newstr = erealloc(buf->str, _ZSTR_STRUCT_SIZE(newsize)); \ + out = (unsigned char*)ZSTR_VAL(newstr) + (out - (unsigned char*)ZSTR_VAL(buf->str)); \ + limit = (unsigned char*)ZSTR_VAL(newstr) + newsize; \ + buf->str = newstr; \ + } + +#define MB_CONVERT_BUF_STORE(buf, _out, _limit) buf->out = _out; buf->limit = _limit + +#define MB_CONVERT_BUF_LOAD(buf, _out, _limit) _out = buf->out; _limit = buf->limit + +#define MB_CONVERT_ERROR(buf, out, limit, bad_cp, conv_fn) \ + MB_CONVERT_BUF_STORE(buf, out, limit); \ + mb_illegal_output(bad_cp, conv_fn, buf); \ + MB_CONVERT_BUF_LOAD(buf, out, limit) + +static inline unsigned char* mb_convert_buf_add(unsigned char *out, char c) +{ + *out++ = c; + return out; +} + +static inline unsigned char* mb_convert_buf_add2(unsigned char *out, char c1, char c2) +{ + *out++ = c1; + *out++ = c2; + return out; +} + +static inline unsigned char* mb_convert_buf_add3(unsigned char *out, char c1, char c2, char c3) +{ + *out++ = c1; + *out++ = c2; + *out++ = c3; + return out; +} + +static inline unsigned char* mb_convert_buf_add4(unsigned char *out, char c1, char c2, char c3, char c4) +{ + *out++ = c1; + *out++ = c2; + *out++ = c3; + *out++ = c4; + return out; +} + +static inline zend_string* mb_convert_buf_result(mb_convert_buf *buf) +{ + ZEND_ASSERT(buf->out <= buf->limit); + zend_string *ret = buf->str; + /* See `zend_string_alloc` in zend_string.h */ + GC_SET_REFCOUNT(ret, 1); + GC_TYPE_INFO(ret) = GC_STRING; + ZSTR_H(ret) = 0; + ZSTR_LEN(ret) = buf->out - (unsigned char*)ZSTR_VAL(ret); + *(buf->out) = '\0'; + return ret; +} + +typedef struct { enum mbfl_no_encoding no_encoding; const char *name; const char *mime_name; @@ -141,6 +224,8 @@ typedef struct _mbfl_encoding { unsigned int flag; const struct mbfl_convert_vtbl *input_filter; const struct mbfl_convert_vtbl *output_filter; + mb_to_wchar_fn to_wchar; + mb_from_wchar_fn from_wchar; } mbfl_encoding; MBFLAPI extern const mbfl_encoding *mbfl_name2encoding(const char *name); diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 91b59617ce4ef..bcf2ee51933db 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -2569,7 +2569,16 @@ PHP_FUNCTION(mb_convert_encoding) } if (input_str) { - /* new encoding */ + if (num_from_encodings == 1) { + const mbfl_encoding *from_encoding = from_encodings[0]; + if (from_encoding->to_wchar && to_encoding->from_wchar) { + unsigned int num_errors = 0; + RETVAL_STR(mb_fast_convert(input_str, from_encoding, to_encoding, MBSTRG(current_filter_illegal_substchar), MBSTRG(current_filter_illegal_mode), &num_errors)); + MBSTRG(illegalchars) += num_errors; + goto out; + } + } + size_t size; char *ret = php_mb_convert_encoding(ZSTR_VAL(input_str), ZSTR_LEN(input_str), to_encoding, from_encodings, num_from_encodings, &size); @@ -2587,6 +2596,7 @@ PHP_FUNCTION(mb_convert_encoding) RETVAL_ARR(tmp); } +out: if (free_from_encodings) { efree(ZEND_VOIDP(from_encodings)); } diff --git a/ext/mbstring/tests/armscii8_encoding.phpt b/ext/mbstring/tests/armscii8_encoding.phpt index 37af3820e9206..97006e09a6510 100644 --- a/ext/mbstring/tests/armscii8_encoding.phpt +++ b/ext/mbstring/tests/armscii8_encoding.phpt @@ -33,6 +33,10 @@ mb_substitute_character("long"); convertInvalidString("\xA1", "%", "ARMSCII-8", "UTF-8"); convertInvalidString("\xFF", "%", "ARMSCII-8", "UTF-8"); +// Test replacement character which cannot be encoded in ARMSCII-8 +mb_substitute_character(0x1234); +convertInvalidString("\x23\x45", '?', 'UTF-16BE', 'ARMSCII-8'); + echo "Done!\n"; ?> --EXPECT-- diff --git a/ext/mbstring/tests/bug65045.phpt b/ext/mbstring/tests/bug65045.phpt index cf273627c61da..772533b7e13f8 100644 --- a/ext/mbstring/tests/bug65045.phpt +++ b/ext/mbstring/tests/bug65045.phpt @@ -5,25 +5,21 @@ mbstring --FILE-- --EXPECT-- -bool(true) -bool(true) -bool(true) -bool(true) +efbfbdf0a4ada2f0a4ada2 +f0a4ada2f0a4ada2efbfbd +efbfbdf0a4ada2f0a4ada2 +f0a4ada2f0a4ada2efbfbd diff --git a/ext/mbstring/tests/cp1252_encoding.phpt b/ext/mbstring/tests/cp1252_encoding.phpt index 706e02ceee606..0688fe943134e 100644 --- a/ext/mbstring/tests/cp1252_encoding.phpt +++ b/ext/mbstring/tests/cp1252_encoding.phpt @@ -16,6 +16,10 @@ mb_substitute_character("long"); convertInvalidString("\x81", "%", "CP1252", "UTF-8"); convertInvalidString("\x9D", "%", "CP1252", "UTF-8"); +// Test replacement character which cannot be encoded in CP1252 +mb_substitute_character(0x1234); +convertInvalidString("\x23\x45", '?', 'UTF-16BE', 'CP1252'); + echo "Done!\n"; ?> --EXPECT-- diff --git a/ext/mbstring/tests/cp1254_encoding.phpt b/ext/mbstring/tests/cp1254_encoding.phpt index 7a4f7be2b18ce..08d36ca7e9964 100644 --- a/ext/mbstring/tests/cp1254_encoding.phpt +++ b/ext/mbstring/tests/cp1254_encoding.phpt @@ -16,6 +16,10 @@ mb_substitute_character("long"); convertInvalidString("\x81", "%", "CP1254", "UTF-8"); convertInvalidString("\x9E", "%", "CP1254", "UTF-8"); +// Test replacement character which cannot be encoded in CP1254 +mb_substitute_character(0x1234); +convertInvalidString("\x23\x45", '?', 'UTF-16BE', 'CP1254'); + echo "Done!\n"; ?> --EXPECT-- diff --git a/ext/mbstring/tests/cp850_encoding.phpt b/ext/mbstring/tests/cp850_encoding.phpt index 01e78c4a2a0b3..726e12f2a8479 100644 --- a/ext/mbstring/tests/cp850_encoding.phpt +++ b/ext/mbstring/tests/cp850_encoding.phpt @@ -9,7 +9,11 @@ if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); --FILE-- +testEncodingFromUTF16ConversionTable(__DIR__ . '/data/CP850.txt', 'CP850'); +/* Try replacement character which cannot be encoded in CP850; ? will be used instead */ +mb_substitute_character(0x1234); +convertInvalidString("\x23\x45", '?', 'UTF-16BE', 'CP850'); +?> --EXPECT-- Tested CP850 -> UTF-16BE Tested UTF-16BE -> CP850 diff --git a/ext/mbstring/tests/cp866_encoding.phpt b/ext/mbstring/tests/cp866_encoding.phpt index e6454805883e9..67e47ba543595 100644 --- a/ext/mbstring/tests/cp866_encoding.phpt +++ b/ext/mbstring/tests/cp866_encoding.phpt @@ -10,6 +10,9 @@ if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); --EXPECT-- Tested CP866 -> UTF-16BE diff --git a/ext/mbstring/tests/encoding_tests.inc b/ext/mbstring/tests/encoding_tests.inc index f6fab024ca3d9..cbf5071456df2 100644 --- a/ext/mbstring/tests/encoding_tests.inc +++ b/ext/mbstring/tests/encoding_tests.inc @@ -102,6 +102,14 @@ function testInvalidString($fromString, $toString, $fromEncoding, $toEncoding) { function testAllValidChars($charMap, $fromEncoding, $toEncoding, $bothWays = true) { $goodChars = array_keys($charMap); shuffle($goodChars); + // Try a long string + $fromString = $toString = ''; + foreach ($goodChars as $goodChar) { + $fromString .= $goodChar; + $toString .= $charMap[$goodChar]; + } + testValidString($fromString, $toString, $fromEncoding, $toEncoding, $bothWays); + // Try various shorter ones while (!empty($goodChars)) { $length = min(rand(5,10), count($goodChars)); $fromString = $toString = ''; diff --git a/ext/mbstring/tests/illformed_utf_sequences.phpt b/ext/mbstring/tests/illformed_utf_sequences.phpt index a9c97cce118f8..b29827be44d6f 100644 --- a/ext/mbstring/tests/illformed_utf_sequences.phpt +++ b/ext/mbstring/tests/illformed_utf_sequences.phpt @@ -16,7 +16,6 @@ function chk_enc($str, $n, $enc = "UTF-8") { mb_substitute_character(0xfffd); - echo "UTF-8 redundancy\n"; var_dump(chk_enc("\x31\x32\x33", 0)); var_dump(chk_enc("\x41\x42\x43", 0)); diff --git a/ext/mbstring/tests/iso2022jp_encoding.phpt b/ext/mbstring/tests/iso2022jp_encoding.phpt index 4858f45e41e5b..ea515cb436f85 100644 --- a/ext/mbstring/tests/iso2022jp_encoding.phpt +++ b/ext/mbstring/tests/iso2022jp_encoding.phpt @@ -204,6 +204,7 @@ foreach (['JIS', 'ISO-2022-JP'] as $encoding) { testValidString("\x00\xA5", "\x1B(J\x5C\x1B(B", 'UTF-16BE', $encoding, false); } +testValidString("\x20\x3E", "\x1B\$B!1\x1B(B", 'UTF-16BE', 'ISO-2022-JP', false); echo "Other mappings from Unicode -> ISO-2022-JP are OK\n"; diff --git a/ext/mbstring/tests/iso8859_encodings.phpt b/ext/mbstring/tests/iso8859_encodings.phpt index fac7ce8c0eac9..7aae113c85717 100644 --- a/ext/mbstring/tests/iso8859_encodings.phpt +++ b/ext/mbstring/tests/iso8859_encodings.phpt @@ -21,6 +21,10 @@ mb_substitute_character("long"); convertInvalidString("\xAE", "%", "ISO8859-7", "UTF-8"); convertInvalidString("\xFF", "%", "ISO8859-8", "UTF-8"); +// Test illegal character marker which can't be represented in target encoding +mb_substitute_character(0x1234); +convertInvalidString("\x23\x45", '?', 'UTF-16BE', 'ISO8859-7'); + echo "Done!\n"; ?> --EXPECT-- diff --git a/ext/mbstring/tests/koi8r_encoding.phpt b/ext/mbstring/tests/koi8r_encoding.phpt index ab5430150cdb1..5c4f1657ee923 100644 --- a/ext/mbstring/tests/koi8r_encoding.phpt +++ b/ext/mbstring/tests/koi8r_encoding.phpt @@ -10,6 +10,9 @@ if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); --EXPECT-- Tested KOI8-R -> UTF-16BE diff --git a/ext/mbstring/tests/koi8u_encoding.phpt b/ext/mbstring/tests/koi8u_encoding.phpt index 4bf64ad781750..c28a640c1551e 100644 --- a/ext/mbstring/tests/koi8u_encoding.phpt +++ b/ext/mbstring/tests/koi8u_encoding.phpt @@ -10,6 +10,9 @@ if (getenv("SKIP_SLOW_TESTS")) die("skip slow test"); --EXPECT-- Tested KOI8-U -> UTF-16BE diff --git a/ext/mbstring/tests/mb_substitute_character_variation2.phpt b/ext/mbstring/tests/mb_substitute_character_variation2.phpt index 02d7a37e567e4..c4e0665992b51 100644 --- a/ext/mbstring/tests/mb_substitute_character_variation2.phpt +++ b/ext/mbstring/tests/mb_substitute_character_variation2.phpt @@ -5,7 +5,7 @@ mbstring --FILE-- 0xDFFF) // surrogates; included in UnicodeData.txt + if (($cp < 0xD800 || $cp > 0xDFFF) && $cp !== 0xFEFF) $validCodepoints[pack('N', $cp)] = true; } } @@ -858,7 +858,20 @@ testInvalidCodepoints($invalid, 'UTF-16LE'); testInvalidString("\x00", "\x00\x00\x00%", 'UTF-16LE', 'UTF-32BE'); testInvalidString("A\x00\x01", "\x00\x00\x00A\x00\x00\x00%", 'UTF-16LE', 'UTF-32BE'); -// TODO: test handling of UTF-16 BOM +// Test treatment of BOM +testValidString("\xFE\xFF\x12\x34", "\x00\x00\x12\x34", 'UTF-16', 'UTF-32BE', false); +testValidString("\xFF\xFE\x12\x34", "\x00\x00\x34\x12", 'UTF-16', 'UTF-32BE', false); + +// Test treatment of (illegal) codepoints between U+D800 and U+DFFF +testValidString("\xD8\x00", "\xD8\x00", 'UCS-2BE', 'UTF-16BE', false); +testValidString("\xDB\xFF", "\xDB\xFF", 'UCS-2BE', 'UTF-16BE', false); +testValidString("\xDC\x00", "\xDC\x00", 'UCS-2BE', 'UTF-16BE', false); +testValidString("\xD8\x00", "\x00\xD8", 'UCS-2BE', 'UTF-16LE', false); +testValidString("\xDC\x00", "\x00\xDC", 'UCS-2BE', 'UTF-16LE', false); + +// Try codepoint over U+10FFFF +convertInvalidString("\x00\x11\x56\x78", "\x00%", 'UCS-4BE', 'UTF-16BE'); +convertInvalidString("\x00\x11\x56\x78", "%\x00", 'UCS-4BE', 'UTF-16LE'); echo "== UTF-32 ==\n"; @@ -914,7 +927,16 @@ testInvalidString("\x00\x01\x01", "\x00\x00\x00%", 'UTF-32LE', 'UTF-32BE'); testInvalidString("\x00\x01", "\x00\x00\x00%", 'UTF-32LE', 'UTF-32BE'); testInvalidString("\x00", "\x00\x00\x00%", 'UTF-32LE', 'UTF-32BE'); -// TODO: test handling of UTF-32 BOM +// Test treatment of BOM +testValidString("\x00\x00\xFE\xFF\x00\x00\x12\x34", "\x00\x00\x12\x34", 'UTF-32', 'UTF-32BE', false); +testValidString("\xFF\xFE\x00\x00\x12\x34\x00\x00", "\x00\x00\x34\x12", 'UTF-32', 'UTF-32BE', false); + +// Test treatment of (illegal) codepoints between U+D800 and U+DFFF +testValidString("\xD8\x00", "\x00\x00\xD8\x00", 'UCS-2BE', 'UTF-32BE', false); +testValidString("\xDB\xFF", "\x00\x00\xDB\xFF", 'UCS-2BE', 'UTF-32BE', false); +testValidString("\xDC\x00", "\x00\x00\xDC\x00", 'UCS-2BE', 'UTF-32BE', false); +testValidString("\xD8\x00", "\x00\xD8\x00\x00", 'UCS-2BE', 'UTF-32LE', false); +testValidString("\xDC\x00", "\x00\xDC\x00\x00", 'UCS-2BE', 'UTF-32LE', false); echo "== UTF-7 ==\n"; @@ -1031,6 +1053,7 @@ testInvalidString('+' . rawEncode("\xD8\x01"), "\x00\x00\x00%", 'UTF-7', 'UTF-32 // Truncated string testInvalidString('+' . rawEncode("\x01") . '-', "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); +testInvalidString('+l', "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); // And then, messed up Base64 encoding @@ -1042,6 +1065,15 @@ testInvalidString('+' . $corrupted . '-', "\x00\x00\x12\x34\x00\x00\x00%", 'UTF- // Characters which are not Base64 (and not even ASCII) appearing in Base64 section testInvalidString("+\x80", "\x00\x00\x00%", 'UTF-7', 'UTF-32BE'); +// Try codepoint over U+10FFFF; '+ACU-' is the error marker '%' +convertInvalidString("\x12\x34\x56\x78", "+ACU-", 'UCS-4BE', 'UTF-7'); +convertInvalidString("\x00\x11\x56\x78", "+ACU-", 'UCS-4BE', 'UTF-7'); + +// If error marker character needs to be ASCII-encoded but is able to serve as an +// ending character for a Base64 section, no need to add an additional dash +mb_substitute_character(0x3F); // ? +convertInvalidString("\x1E\xBE", '+AB4?', 'UTF-7', 'UTF-7'); + echo "Done!\n"; ?> From 5d6bc25063e571da936010b1fae822f5d610deca Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 22 Dec 2021 12:54:32 +0300 Subject: [PATCH 67/75] Reset Bucket->key of deleted HastTable elemets to NULL. This allows elimination of some Z_ISUNDEF(Bucket->val) checks. --- Zend/zend_hash.c | 43 +++--- Zend/zend_object_handlers.c | 18 +-- Zend/zend_vm_def.h | 27 ++-- Zend/zend_vm_execute.h | 225 +++++++++++++---------------- ext/opcache/jit/zend_jit_helpers.c | 29 ++-- ext/standard/array.c | 1 - 6 files changed, 152 insertions(+), 191 deletions(-) diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index a52a7fc96912c..680263b5cb07b 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -1404,9 +1404,6 @@ static zend_always_inline void _zend_hash_del_el_ex(HashTable *ht, uint32_t idx, } while (ht->nNumUsed > 0 && (UNEXPECTED(Z_TYPE(ht->arData[ht->nNumUsed-1].val) == IS_UNDEF))); ht->nInternalPointer = MIN(ht->nInternalPointer, ht->nNumUsed); } - if (p->key) { - zend_string_release(p->key); - } if (ht->pDestructor) { zval tmp; ZVAL_COPY_VALUE(&tmp, &p->val); @@ -1435,6 +1432,10 @@ static zend_always_inline void _zend_hash_del_el(HashTable *ht, uint32_t idx, Bu } _zend_hash_del_el_ex(ht, idx, p, prev); + if (p->key) { + zend_string_release(p->key); + p->key = NULL; + } } ZEND_API void ZEND_FASTCALL zend_hash_packed_del_val(HashTable *ht, zval *zv) @@ -1476,6 +1477,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key p->key && zend_string_equal_content(p->key, key))) { _zend_hash_del_el_ex(ht, idx, p, prev); + zend_string_release(p->key); + p->key = NULL; return SUCCESS; } prev = p; @@ -1523,6 +1526,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_hash_del_ind(HashTable *ht, zend_string } } else { _zend_hash_del_el_ex(ht, idx, p, prev); + zend_string_release(p->key); + p->key = NULL; } return SUCCESS; } @@ -1567,6 +1572,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del_ind(HashTable *ht, const ch } } else { _zend_hash_del_el_ex(ht, idx, p, prev); + zend_string_release(p->key); + p->key = NULL; } return SUCCESS; } @@ -1598,6 +1605,8 @@ ZEND_API zend_result ZEND_FASTCALL zend_hash_str_del(HashTable *ht, const char * && (ZSTR_LEN(p->key) == len) && !memcmp(ZSTR_VAL(p->key), str, len)) { _zend_hash_del_el_ex(ht, idx, p, prev); + zend_string_release(p->key); + p->key = NULL; return SUCCESS; } prev = p; @@ -1698,7 +1707,7 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht) if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { ht->pDestructor(&p->val); if (EXPECTED(p->key)) { - zend_string_release(p->key); + zend_string_release(p->key); } } } while (++p != end); @@ -1708,10 +1717,8 @@ ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht) } else { if (!HT_HAS_STATIC_KEYS_ONLY(ht)) { do { - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { - if (EXPECTED(p->key)) { - zend_string_release(p->key); - } + if (EXPECTED(p->key)) { + zend_string_release(p->key); } } while (++p != end); } @@ -1846,21 +1853,11 @@ ZEND_API void ZEND_FASTCALL zend_hash_clean(HashTable *ht) } } else { if (!HT_HAS_STATIC_KEYS_ONLY(ht)) { - if (HT_IS_WITHOUT_HOLES(ht)) { - do { - if (EXPECTED(p->key)) { - zend_string_release(p->key); - } - } while (++p != end); - } else { - do { - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF)) { - if (EXPECTED(p->key)) { - zend_string_release(p->key); - } - } - } while (++p != end); - } + do { + if (EXPECTED(p->key)) { + zend_string_release(p->key); + } + } while (++p != end); } } HT_HASH_RESET(ht); diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 529893b1de882..e75ff8318cb48 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -619,11 +619,10 @@ ZEND_API zval *zend_std_read_property(zend_object *zobj, zend_string *name, int if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; goto exit; } @@ -1754,11 +1753,10 @@ ZEND_API int zend_std_has_property(zend_object *zobj, zend_string *name, int has if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { value = &p->val; goto found; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 4c691fe22b399..d175cb95cfd4d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2083,11 +2083,10 @@ ZEND_VM_C_LABEL(fetch_obj_r_fast_copy): if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { ZEND_VM_C_GOTO(fetch_obj_r_copy); @@ -2248,11 +2247,10 @@ ZEND_VM_C_LABEL(fetch_obj_is_fast_copy): if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (!ZEND_VM_SPEC || (OP1_TYPE & (IS_TMP_VAR|IS_VAR)) != 0) { ZEND_VM_C_GOTO(fetch_obj_is_copy); @@ -8370,11 +8368,10 @@ ZEND_VM_HOT_HANDLER(168, ZEND_BIND_GLOBAL, CV, CONST, CACHE_SLOT) if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == varname) || - (EXPECTED(p->h == ZSTR_H(varname)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, varname))))) { + if (EXPECTED(p->key == varname) || + (EXPECTED(p->h == ZSTR_H(varname)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, varname)))) { value = (zval*)p; /* value = &p->val; */ ZEND_VM_C_GOTO(check_indirect); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 349974a92e525..90b97cfc680a2 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -6302,11 +6302,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -6429,11 +6428,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -8634,11 +8632,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -8761,11 +8758,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -11001,11 +10997,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -11128,11 +11123,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CONST & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -15445,11 +15439,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_CONST_ if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -15572,11 +15565,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CONST if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -16883,11 +16875,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_TMPVAR if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -17010,11 +17001,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_TMPVA if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -18210,11 +18200,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_TMPVAR_CV_HAN if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -18337,11 +18326,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_TMPVAR_CV_HA if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || ((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -31988,11 +31976,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -32158,11 +32145,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_UNUSED_CONST if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -33855,11 +33841,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_TMPVAR if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -34020,11 +34005,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_UNUSED_TMPVA if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -36334,11 +36318,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_UNUSED_CV_HAN if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -36499,11 +36482,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_UNUSED_CV_HA if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_UNUSED & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -40497,11 +40479,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -40667,11 +40648,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CV_CONST_HAN if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -42959,11 +42939,10 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_GLOBAL_SPEC_C if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == varname) || - (EXPECTED(p->h == ZSTR_H(varname)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, varname))))) { + if (EXPECTED(p->key == varname) || + (EXPECTED(p->h == ZSTR_H(varname)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, varname)))) { value = (zval*)p; /* value = &p->val; */ goto check_indirect; @@ -44245,11 +44224,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_TMPVAR_HAN if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -44410,11 +44388,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CV_TMPVAR_HA if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; @@ -49482,11 +49459,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_r_copy; @@ -49647,11 +49623,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_IS_SPEC_CV_CV_HANDLE if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, name))))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { retval = &p->val; if (0 || (IS_CV & (IS_TMP_VAR|IS_VAR)) != 0) { goto fetch_obj_is_copy; diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 3dcc15f2ee75e..cd0743df514d2 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -1552,11 +1552,10 @@ static zend_reference* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_string *v if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == varname) || - (EXPECTED(p->h == ZSTR_H(varname)) && - EXPECTED(p->key != NULL) && - EXPECTED(zend_string_equal_content(p->key, varname))))) { + if (EXPECTED(p->key == varname) || + (EXPECTED(p->h == ZSTR_H(varname)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, varname)))) { value = (zval*)p; /* value = &p->val; */ goto check_indirect; @@ -1649,12 +1648,10 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_r_dynamic(zend_object *zobj, intptr if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(ZSTR_LEN(p->key) == ZSTR_LEN(name)) && - EXPECTED(memcmp(ZSTR_VAL(p->key), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { ZVAL_COPY_DEREF(result, &p->val); return; } @@ -1707,12 +1704,10 @@ static void ZEND_FASTCALL zend_jit_fetch_obj_is_dynamic(zend_object *zobj, intpt if (EXPECTED(idx < zobj->properties->nNumUsed * sizeof(Bucket))) { Bucket *p = (Bucket*)((char*)zobj->properties->arData + idx); - if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && - (EXPECTED(p->key == name) || - (EXPECTED(p->h == ZSTR_H(name)) && - EXPECTED(p->key != NULL) && - EXPECTED(ZSTR_LEN(p->key) == ZSTR_LEN(name)) && - EXPECTED(memcmp(ZSTR_VAL(p->key), ZSTR_VAL(name), ZSTR_LEN(name)) == 0)))) { + if (EXPECTED(p->key == name) || + (EXPECTED(p->h == ZSTR_H(name)) && + EXPECTED(p->key != NULL) && + EXPECTED(zend_string_equal_content(p->key, name)))) { ZVAL_COPY_DEREF(result, &p->val); return; } diff --git a/ext/standard/array.c b/ext/standard/array.c index c3d4c3d7a78a3..aa89e3755b123 100644 --- a/ext/standard/array.c +++ b/ext/standard/array.c @@ -2915,7 +2915,6 @@ static void php_array_data_shuffle(zval *array) /* {{{ */ uint32_t i = hash->nNumUsed; for (; i > 0; p++, i--) { - if (Z_ISUNDEF(p->val)) continue; if (p->key) { zend_string_release(p->key); p->key = NULL; From 713dcb28181895d241e6dbe63f63ee654ba757b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Wed, 22 Dec 2021 10:40:04 +0100 Subject: [PATCH 68/75] Fix the value param of SimpleXMLElement::addAttribute() Closes GH-7811 --- ext/simplexml/simplexml.stub.php | 2 +- ext/simplexml/simplexml_arginfo.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/simplexml/simplexml.stub.php b/ext/simplexml/simplexml.stub.php index a115c8b2defeb..4735573521587 100644 --- a/ext/simplexml/simplexml.stub.php +++ b/ext/simplexml/simplexml.stub.php @@ -44,7 +44,7 @@ public function __construct(string $data, int $options = 0, bool $dataIsURL = fa public function addChild(string $qualifiedName, ?string $value = null, ?string $namespace = null): ?SimpleXMLElement {} /** @tentative-return-type */ - public function addAttribute(string $qualifiedName, ?string $value = null, ?string $namespace = null): void {} + public function addAttribute(string $qualifiedName, string $value, ?string $namespace = null): void {} /** @tentative-return-type */ public function getName(): string {} diff --git a/ext/simplexml/simplexml_arginfo.h b/ext/simplexml/simplexml_arginfo.h index 881051514c595..f6100eb243e31 100644 --- a/ext/simplexml/simplexml_arginfo.h +++ b/ext/simplexml/simplexml_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 46da4d24787a5f975eebeaab3872eb29273a9625 */ + * Stub hash: 06c88dc2fb5582a6d21c11aee6ac0a0538e70cbc */ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_simplexml_load_file, 0, 1, SimpleXMLElement, MAY_BE_FALSE) ZEND_ARG_TYPE_INFO(0, filename, IS_STRING, 0) @@ -67,9 +67,9 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_OBJ_INFO_EX(arginfo_class_SimpleXMLElement_ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, namespace, IS_STRING, 1, "null") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SimpleXMLElement_addAttribute, 0, 1, IS_VOID, 0) +ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SimpleXMLElement_addAttribute, 0, 2, IS_VOID, 0) ZEND_ARG_TYPE_INFO(0, qualifiedName, IS_STRING, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, value, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO(0, value, IS_STRING, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, namespace, IS_STRING, 1, "null") ZEND_END_ARG_INFO() From c5f4ee50ab60ed4ff5ac74a0b11ccdd5e21cef96 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Wed, 22 Dec 2021 23:42:29 +0100 Subject: [PATCH 69/75] $context parameter of get_headers() is nullable Closes GH-7813. --- ext/standard/basic_functions.stub.php | 2 +- ext/standard/basic_functions_arginfo.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/basic_functions.stub.php b/ext/standard/basic_functions.stub.php index acdb56af3ec1c..11f84c5b6e812 100755 --- a/ext/standard/basic_functions.stub.php +++ b/ext/standard/basic_functions.stub.php @@ -1433,7 +1433,7 @@ function rawurlencode(string $string): string {} function rawurldecode(string $string): string {} -/** @param resource $context */ +/** @param resource|null $context */ function get_headers(string $url, bool $associative = false, $context = null): array|false {} /* user_filters.c */ diff --git a/ext/standard/basic_functions_arginfo.h b/ext/standard/basic_functions_arginfo.h index bbd4a16899b3f..ac6e4c65aa1a9 100644 --- a/ext/standard/basic_functions_arginfo.h +++ b/ext/standard/basic_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 2da40c5fd9726f98ff96cf9fb5e0c41521e1e6ae */ + * Stub hash: ff0ec0005317a22c41e61e9c58f67e968d1243c4 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0) ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0) From 096a01c9055c25093872f571d9de9a532321f2d9 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 21 Dec 2021 12:58:31 +0100 Subject: [PATCH 70/75] [ci skip] Update the min curl version in the sync-constants.php script PHP 8.0 bumped the min curl version to 7.29.0 Closes GH-7805. --- ext/curl/sync-constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/curl/sync-constants.php b/ext/curl/sync-constants.php index 2db773d5f80a1..035dbcf6a237d 100755 --- a/ext/curl/sync-constants.php +++ b/ext/curl/sync-constants.php @@ -12,7 +12,7 @@ const SOURCE_FILE = __DIR__ . '/interface.c'; -const MIN_SUPPORTED_CURL_VERSION = '7.15.5'; +const MIN_SUPPORTED_CURL_VERSION = '7.29.0'; const IGNORED_CONSTANTS = [ 'CURLOPT_PROGRESSDATA' From e72b2f32d4d7a5e073cd84ccec5f0e740feb2e10 Mon Sep 17 00:00:00 2001 From: hassan Date: Thu, 23 Dec 2021 15:26:52 +0200 Subject: [PATCH 71/75] Azure CI: remove duplicates and add required libs Closes GH-7727. --- azure/apt.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/azure/apt.yml b/azure/apt.yml index c3b33050d6482..e30aa1d9d918c 100644 --- a/azure/apt.yml +++ b/azure/apt.yml @@ -11,7 +11,6 @@ steps: openssl \ slapd \ language-pack-de \ - re2c \ libgmp-dev \ libicu-dev \ libtidy-dev \ @@ -44,7 +43,6 @@ steps: unixodbc-dev \ llvm \ libc-client-dev \ - libkrb5-dev \ dovecot-core \ dovecot-pop3d \ dovecot-imapd \ @@ -54,6 +52,9 @@ steps: libtokyocabinet-dev \ libdb-dev \ libqdbm-dev \ + libjpeg-dev \ + libpng-dev \ + libfreetype6-dev \ ${{ parameters.packages }} displayName: 'APT' - script: | From eebe91085d1b7fafee9781e1f4da259a1be94eb7 Mon Sep 17 00:00:00 2001 From: "C. Scott Ananian" Date: Thu, 23 Dec 2021 10:02:22 -0500 Subject: [PATCH 72/75] Don't test hidden files that happen to end in .phpt This is a tiny improvement to run-tests.php which helps keep it from tripping over hidden files, including autosave files from various editors, metadata on certain platforms, etc. Closes GH-7783. --- run-tests.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/run-tests.php b/run-tests.php index baf3ddb91cbe6..36ed068d0eac9 100755 --- a/run-tests.php +++ b/run-tests.php @@ -1091,7 +1091,9 @@ function find_files(string $dir, bool $is_ext_dir = false, bool $ignore = false) } // Otherwise we're only interested in *.phpt files. - if (substr($name, -5) == '.phpt') { + // (but not those starting with a dot, which are hidden on + // many platforms) + if (substr($name, -5) == '.phpt' && substr($name, 0, 1) !== '.') { if ($ignore) { $ignored_by_ext++; } else { From 3f0bb673617f29fe7c022f2db86367ebf9c869e2 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Thu, 23 Dec 2021 14:21:47 +0000 Subject: [PATCH 73/75] Avoid void* arithmetic in sockets/multicast.c on NetBSD On NetBSD, ifconf.ifc_buf member, unlike most of platforms, is a void pointer. We also fix the cpuinfo declarations with empty parameter lists. Closes GH-7819. --- NEWS | 3 +++ Zend/zend_cpuinfo.c | 6 +++--- ext/sockets/multicast.c | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index ae1d224b6268d..2eafc4acad89e 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,9 @@ PHP NEWS - PDO_PGSQL: . Fixed error message allocation of PDO PgSQL. (SATO Kentaro) +- Sockets: + . Avoid void* arithmetic in sockets/multicast.c on NetBSD. (David Carlier) + - Spl: . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr Bystry) diff --git a/Zend/zend_cpuinfo.c b/Zend/zend_cpuinfo.c index 529ab529a3361..102b0f8c05d35 100644 --- a/Zend/zend_cpuinfo.c +++ b/Zend/zend_cpuinfo.c @@ -75,7 +75,7 @@ static void __zend_cpuid(uint32_t func, uint32_t subfunc, zend_cpu_info *cpuinfo #if defined(__i386__) || defined(__x86_64__) /* Function based on compiler-rt implementation. */ -static unsigned get_xcr0_eax() { +static unsigned get_xcr0_eax(void) { # if defined(__GNUC__) || defined(__clang__) // Check xgetbv; this uses a .byte sequence instead of the instruction // directly because older assemblers do not include support for xgetbv and @@ -90,7 +90,7 @@ static unsigned get_xcr0_eax() { # endif } -static zend_bool is_avx_supported() { +static zend_bool is_avx_supported(void) { if (!(cpuinfo.ecx & ZEND_CPU_FEATURE_AVX)) { /* No support for AVX */ return 0; @@ -106,7 +106,7 @@ static zend_bool is_avx_supported() { return 1; } #else -static zend_bool is_avx_supported() { +static zend_bool is_avx_supported(void) { return 0; } #endif diff --git a/ext/sockets/multicast.c b/ext/sockets/multicast.c index 321efdc4039bc..25203c0fbccae 100644 --- a/ext/sockets/multicast.c +++ b/ext/sockets/multicast.c @@ -784,7 +784,7 @@ int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *i } for (p = if_conf.ifc_buf; - p < if_conf.ifc_buf + if_conf.ifc_len; + p < ((char *)if_conf.ifc_buf) + if_conf.ifc_len; p += entry_len) { /* p may be misaligned on macos. */ struct ifreq cur_req; From aab52968a370028e674a1188bd8dfa250003953b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 23 Dec 2021 18:31:45 +0300 Subject: [PATCH 74/75] micro-optimization --- Zend/zend_execute.c | 3 +++ Zend/zend_vm_def.h | 4 ++-- Zend/zend_vm_execute.h | 20 ++++++++++---------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c332201a8fe78..5f7c8d10e59c1 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2978,6 +2978,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } return; } + flags &= ZEND_FETCH_OBJ_FLAGS; if (flags) { zend_handle_fetch_obj_flags(result, ptr, NULL, prop_info, flags); } @@ -3023,6 +3024,7 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } ZVAL_INDIRECT(result, ptr); + flags &= ZEND_FETCH_OBJ_FLAGS; if (flags) { zend_property_info *prop_info; @@ -3220,6 +3222,7 @@ static zend_always_inline zend_result zend_fetch_static_property_address(zval ** } } + flags &= ZEND_FETCH_OBJ_FLAGS; if (flags && ZEND_TYPE_IS_SET(property_info->type)) { zend_handle_fetch_obj_flags(NULL, *retval, NULL, property_info, flags); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index d175cb95cfd4d..f0ad4037eb145 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1837,7 +1837,7 @@ ZEND_VM_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type) SAVE_OPLINE(); - if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { + if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); } @@ -2165,7 +2165,7 @@ ZEND_VM_HANDLER(85, ZEND_FETCH_OBJ_W, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, FETCH zend_fetch_property_address( result, container, OP1_TYPE, property, OP2_TYPE, ((OP2_TYPE == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); FREE_OP2(); if (OP1_TYPE == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 90b97cfc680a2..78dab76a303fb 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -846,7 +846,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_fetch_static SAVE_OPLINE(); - if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value & ZEND_FETCH_OBJ_FLAGS OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { + if (UNEXPECTED(zend_fetch_static_property_address(&prop, NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, opline->extended_value OPLINE_CC EXECUTE_DATA_CC) != SUCCESS)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); } @@ -22842,7 +22842,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CONST_HAN zend_fetch_property_address( result, container, IS_VAR, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -25496,7 +25496,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_TMPVAR_HA zend_fetch_property_address( result, container, IS_VAR, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -29616,7 +29616,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_VAR_CV_HANDLE zend_fetch_property_address( result, container, IS_VAR, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_VAR == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -32063,7 +32063,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CONST_ zend_fetch_property_address( result, container, IS_UNUSED, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -33923,7 +33923,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_TMPVAR zend_fetch_property_address( result, container, IS_UNUSED, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -36400,7 +36400,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_UNUSED_CV_HAN zend_fetch_property_address( result, container, IS_UNUSED, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_UNUSED == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -40566,7 +40566,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CONST_HAND zend_fetch_property_address( result, container, IS_CV, property, IS_CONST, ((IS_CONST == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -44306,7 +44306,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_TMPVAR_HAN zend_fetch_property_address( result, container, IS_CV, property, (IS_TMP_VAR|IS_VAR), (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); @@ -49541,7 +49541,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_OBJ_W_SPEC_CV_CV_HANDLER zend_fetch_property_address( result, container, IS_CV, property, IS_CV, ((IS_CV == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) : NULL), - BP_VAR_W, opline->extended_value & ZEND_FETCH_OBJ_FLAGS, 1 OPLINE_CC EXECUTE_DATA_CC); + BP_VAR_W, opline->extended_value, 1 OPLINE_CC EXECUTE_DATA_CC); if (IS_CV == IS_VAR) { FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(opline->op1.var); From 0ed39ed809883043c2c339e00e6ff2d3cc34ba54 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 23 Dec 2021 00:14:44 +0100 Subject: [PATCH 75/75] Fix GH-7809: Cloning a faked SplFileInfo object may segfault While the `path` is not supposed to be `NULL` for normal operation, it is possible to create `SplFileInfo` objects where that is the case, and we must not follow the null pointer. Closes GH-7814. --- NEWS | 1 + ext/spl/spl_directory.c | 8 ++++++-- ext/spl/tests/gh7809.phpt | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 ext/spl/tests/gh7809.phpt diff --git a/NEWS b/NEWS index 58f290ae8b50f..12ef79e2b82c6 100644 --- a/NEWS +++ b/NEWS @@ -53,6 +53,7 @@ PHP NEWS - Spl: . Fixed bug #75917 (SplFileObject::seek broken with CSV flags). (Aliaksandr Bystry) + . Fixed bug GH-7809 (Cloning a faked SplFileInfo object may segfault). (cmb) - Standard: . Fixed bug GH-7748 (gethostbyaddr outputs binary string). (cmb) diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 116185846868d..0ba11f4800715 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -385,8 +385,12 @@ static zend_object *spl_filesystem_object_clone(zend_object *old_object) switch (source->type) { case SPL_FS_INFO: - intern->path = zend_string_copy(source->path); - intern->file_name = zend_string_copy(source->file_name); + if (source->path != NULL) { + intern->path = zend_string_copy(source->path); + } + if (source->file_name != NULL) { + intern->file_name = zend_string_copy(source->file_name); + } break; case SPL_FS_DIR: spl_filesystem_dir_open(intern, source->path); diff --git a/ext/spl/tests/gh7809.phpt b/ext/spl/tests/gh7809.phpt new file mode 100644 index 0000000000000..6406bef6c1438 --- /dev/null +++ b/ext/spl/tests/gh7809.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug GH-7809 (Cloning a faked SplFileInfo object may segfault) +--FILE-- + +--EXPECT--