From 2e47442a6b1e9a47d449008df2a853e6e99fada3 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 1 Apr 2025 18:58:31 +0100 Subject: [PATCH 1/4] Fix GH-18212: fseek with SEEK_CUR and negative offset crash on debug Triggers the assertion as with SEEK_CUR the stream position is set to a negative value so we force the failure without affecting its position instead. close GH-18224 --- NEWS | 2 ++ ext/standard/tests/file/gh18212.phpt | 13 +++++++++++++ ext/standard/tests/file/stream_rfc2397_007.phpt | 2 +- main/streams/streams.c | 4 ++++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 ext/standard/tests/file/gh18212.phpt diff --git a/NEWS b/NEWS index 37a320d27be07..335903eee23c0 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,8 @@ PHP NEWS . Fixed bug GH-18145 (php8ts crashes in php_clear_stat_cache()). (Jakub Zelenka) . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) + . Fixed bug GH-18212 (fseek with SEEK_CUR whence value and negative offset + leads to negative stream position). (David Carlier) 10 Apr 2025, PHP 8.3.20 diff --git a/ext/standard/tests/file/gh18212.phpt b/ext/standard/tests/file/gh18212.phpt new file mode 100644 index 0000000000000..6e4d8ad9bd328 --- /dev/null +++ b/ext/standard/tests/file/gh18212.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-18212: fseek with SEEK_CUR and negative offset leads to negative file stream position. +--FILE-- + +--EXPECT-- +int(-1) +int(-1) + diff --git a/ext/standard/tests/file/stream_rfc2397_007.phpt b/ext/standard/tests/file/stream_rfc2397_007.phpt index dcbe5beeb3dc9..49a037e855fbd 100644 --- a/ext/standard/tests/file/stream_rfc2397_007.phpt +++ b/ext/standard/tests/file/stream_rfc2397_007.phpt @@ -118,7 +118,7 @@ int(2) bool(false) ===S:-10,C=== int(-1) -bool(false) +int(2) bool(false) ===S:3,S=== int(0) diff --git a/main/streams/streams.c b/main/streams/streams.c index 7a5dc2a58aaf1..4e0aaa53b443e 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1390,6 +1390,10 @@ PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) } whence = SEEK_SET; break; + case SEEK_SET: + if (offset < 0) { + return -1; + } } ret = stream->ops->seek(stream, offset, whence, &stream->position); From 79dc7a2d269c2c3ff38e51c1aad12f6fc6d96a1b Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 2 Apr 2025 16:20:09 +0300 Subject: [PATCH 2/4] Update IR IR commit: 8d17022fb61ebfed9f6be81a8182ea31202697ed --- ext/opcache/jit/ir/ir_x86.dasc | 70 ++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index ad785d3b891eb..d01a8c41359aa 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -650,6 +650,26 @@ IR_ALWAYS_INLINE ir_mem IR_MEM(ir_reg base, int32_t offset, ir_reg index, int32_ || } |.endmacro +/* Like ASM_REG_IMM_OP, but op1 accepts r16,r32,r64 (not r8) */ +|.macro ASM_REG16_IMM_OP, op, type, op1, op2 +|| switch (ir_type_size[type]) { +|| default: +|| IR_ASSERT(0); +|| case 1: +|| case 2: +| op Rw(op1), (op2 & 0xffff) +|| break; +|| case 4: +| op Rd(op1), op2 +|| break; +|.if X64 +|| case 8: +| op Rq(op1), op2 +|| break; +|.endif +|| } +|.endmacro + |.macro ASM_MEM_REG_OP, op, type, op1, op2 | ASM_EXPAND_OP1_MEM ASM_EXPAND_TYPE_MEM_REG, op, type, op1, op2 |.endmacro @@ -1066,6 +1086,7 @@ const char *ir_reg_name(int8_t reg, ir_type type) _(SSE_CEIL) \ _(SSE_TRUNC) \ _(SSE_NEARBYINT) \ + _(BIT_OP) \ #define IR_LEA_FIRST IR_LEA_OB #define IR_LEA_LAST IR_LEA_O_SYM @@ -1400,6 +1421,7 @@ op2_const: case IR_DIV_PWR2: case IR_OP_INT: case IR_OP_FP: + case IR_BIT_OP: flags = IR_DEF_REUSES_OP1_REG | IR_USE_MUST_BE_IN_REG | IR_OP1_SHOULD_BE_IN_REG; break; case IR_MOD_PWR2: @@ -2280,6 +2302,9 @@ binop_fp: // return IR_COPY_INT; } else if (op2_insn->val.i64 == -1) { // -1 + } else if (IR_IS_POWER_OF_TWO(op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) { + /* OR(X, PWR2) => BTS */ + return IR_BIT_OP; } } goto binop_int; @@ -2294,6 +2319,9 @@ binop_fp: // 0 } else if (op2_insn->val.i64 == -1) { // return IR_COPY_INT; + } else if (IR_IS_POWER_OF_TWO(~op2_insn->val.u64) && !IR_IS_SIGNED_32BIT(op2_insn->val.i64)) { + /* AND(X, ~PWR2) => BTR */ + return IR_BIT_OP; } } goto binop_int; @@ -4341,6 +4369,45 @@ static void ir_emit_mul_div_mod_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn) } } +static void ir_emit_bit_op(ir_ctx *ctx, ir_ref def, ir_insn *insn) +{ + ir_backend_data *data = ctx->data; + dasm_State **Dst = &data->dasm_state; + ir_type type = insn->type; + ir_ref op1 = insn->op1; + ir_reg def_reg = IR_REG_NUM(ctx->regs[def][0]); + ir_reg op1_reg = ctx->regs[def][1]; + + IR_ASSERT(IR_IS_CONST_REF(insn->op2)); + IR_ASSERT(!IR_IS_SYM_CONST(ctx->ir_base[insn->op2].op)); + IR_ASSERT(def_reg != IR_REG_NONE); + + if (op1_reg != IR_REG_NONE && IR_REG_SPILLED(op1_reg)) { + op1_reg = IR_REG_NUM(op1_reg); + ir_emit_load(ctx, type, op1_reg, op1); + } + if (def_reg != op1_reg) { + if (op1_reg != IR_REG_NONE) { + ir_emit_mov(ctx, type, def_reg, op1_reg); + } else { + ir_emit_load(ctx, type, def_reg, op1); + } + } + if (insn->op == IR_OR) { + uint32_t bit = IR_LOG2(ctx->ir_base[insn->op2].val.u64); + + | ASM_REG16_IMM_OP, bts, type, def_reg, bit + } else { + IR_ASSERT(insn->op == IR_AND); + uint32_t bit = IR_LOG2(~ctx->ir_base[insn->op2].val.u64); + + | ASM_REG16_IMM_OP, btr, type, def_reg, bit + } + if (IR_REG_SPILLED(ctx->regs[def][0])) { + ir_emit_store(ctx, type, def, def_reg); + } +} + static void ir_emit_sdiv_pwr2(ir_ctx *ctx, ir_ref def, ir_insn *insn) { ir_backend_data *data = ctx->data; @@ -10668,6 +10735,9 @@ void *ir_emit_code(ir_ctx *ctx, size_t *size_ptr) case IR_MOD_PWR2: ir_emit_mul_div_mod_pwr2(ctx, i, insn); break; + case IR_BIT_OP: + ir_emit_bit_op(ctx, i, insn); + break; case IR_SDIV_PWR2: ir_emit_sdiv_pwr2(ctx, i, insn); break; From 1f6fdde6469675058509a27f2bd3325b2b01910b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 16 Oct 2024 18:58:42 +0200 Subject: [PATCH 3/4] Implement asymmetric visibility for static properties https://wiki.php.net/rfc/static-aviz Optimally, this would be moved to zend_fetch_static_property_address(). However, this isn't currently effective for opcache, because R and RW/W/UNSET cache slots are merged. This will circumvent the visibility check if the cache is primed by a R instruction. Closes GH-16486 --- UPGRADING | 2 + .../asymmetric_visibility/static_props.phpt | 139 +++++++++++++++++- Zend/zend_compile.c | 4 - Zend/zend_vm_def.h | 43 +++++- Zend/zend_vm_execute.h | 43 +++++- 5 files changed, 224 insertions(+), 7 deletions(-) diff --git a/UPGRADING b/UPGRADING index c8d45b54544d6..9dfc984f8917d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -122,6 +122,8 @@ PHP 8.5 UPGRADE NOTES it can be used to suppress warnings emitted by #[\NoDiscard] and possibly also diagnostics emitted by external IDEs or static analysis tools. RFC: https://wiki.php.net/rfc/marking_return_value_as_important + . Added asymmetric visibility support for static properties. + RFC: https://wiki.php.net/rfc/static-aviz - Curl: . Added support for share handles that are persisted across multiple PHP diff --git a/Zend/tests/asymmetric_visibility/static_props.phpt b/Zend/tests/asymmetric_visibility/static_props.phpt index 65fd3aa1923d2..f47dcf70b6f74 100644 --- a/Zend/tests/asymmetric_visibility/static_props.phpt +++ b/Zend/tests/asymmetric_visibility/static_props.phpt @@ -5,8 +5,145 @@ Asymmetric visibility on static props class C { public private(set) static int $prop; + public private(set) static array $prop2; + public private(set) static stdClass $prop3; + public private(set) static object $unset; + + public static function reset() { + self::$prop = 1; + self::$prop2 = []; + self::$prop3 = new stdClass(); + } + + public static function setProp($prop) { + self::$prop = $prop; + } + + public static function addProp2($prop2) { + self::$prop2[] = $prop2; + } +} + +function test() { + C::reset(); + + try { + C::$prop = 2; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + C::setProp(3); + var_dump(C::$prop); + + try { + ++C::$prop; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop += str_repeat('a', 10); + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + $ref = &C::$prop; + $ref++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + $ref = 4; + C::$prop = &$ref; + $ref++; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop); + + try { + C::$prop2[] = 'foo'; + } catch (Error $e) { + echo $e->getMessage(), "\n"; + } + var_dump(C::$prop2); + + C::addProp2('bar'); + var_dump(C::$prop2); + + C::$prop3->foo = 'foo'; + var_dump(C::$prop3); + + unset(C::$unset->foo); } +test(); +echo "\nRepeat:\n"; +test(); + ?> --EXPECTF-- -Fatal error: Static property may not have asymmetric visibility in %s on line %d +Cannot modify private(set) property C::$prop from global scope +int(1) +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop2 from global scope +array(0) { +} +array(1) { + [0]=> + string(3) "bar" +} +object(stdClass)#%d (1) { + ["foo"]=> + string(3) "foo" +} + +Repeat: +Cannot modify private(set) property C::$prop from global scope +int(1) +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop from global scope +int(3) +Cannot indirectly modify private(set) property C::$prop2 from global scope +array(0) { +} +array(1) { + [0]=> + string(3) "bar" +} +object(stdClass)#%d (1) { + ["foo"]=> + string(3) "foo" +} diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c1988fdaa1535..2e405de30ea62 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8694,10 +8694,6 @@ static void zend_compile_prop_decl(zend_ast *ast, zend_ast *type_ast, uint32_t f zend_error_noreturn(E_COMPILE_ERROR, "Property cannot be both final and private"); } - if ((flags & ZEND_ACC_STATIC) && (flags & ZEND_ACC_PPP_SET_MASK)) { - zend_error_noreturn(E_COMPILE_ERROR, "Static property may not have asymmetric visibility"); - } - if (ce->ce_flags & ZEND_ACC_INTERFACE) { if (flags & ZEND_ACC_FINAL) { zend_error_noreturn(E_COMPILE_ERROR, "Property in interface cannot be final"); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 563928c9dbf59..162b7e84cefbe 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -1116,6 +1116,14 @@ ZEND_VM_HANDLER(29, ZEND_ASSIGN_STATIC_PROP_OP, ANY, ANY, OP) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + FREE_OP_DATA(); + HANDLE_EXCEPTION(); + } + value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); do { @@ -1430,6 +1438,13 @@ ZEND_VM_HANDLER(38, ZEND_PRE_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_pre_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -1457,6 +1472,13 @@ ZEND_VM_HANDLER(40, ZEND_POST_INC_STATIC_PROP, ANY, ANY, CACHE_SLOT) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_post_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -1836,18 +1858,29 @@ ZEND_VM_INLINE_HELPER(zend_fetch_static_prop_helper, ANY, ANY, int type) { USE_OPLINE zval *prop; + zend_property_info *prop_info; SAVE_OPLINE(); prop = zend_fetch_static_property_address( - NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, + &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); + } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + if (Z_TYPE_P(prop) == IS_OBJECT) { + ZEND_VM_C_GOTO(copy_deref); + } else if (type != BP_VAR_UNSET || Z_TYPE_P(prop) != IS_UNDEF) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + } + prop = &EG(uninitialized_zval); } if (type == BP_VAR_R || type == BP_VAR_IS) { +ZEND_VM_C_LABEL(copy_deref): ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop); } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), prop); @@ -2893,6 +2926,14 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + FREE_OP_DATA(); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 97466dab76a94..902e254ff2424 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -783,6 +783,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_OP_SPEC_HAN HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + HANDLE_EXCEPTION(); + } + value = get_op_data_zval_ptr_r((opline+1)->op1_type, (opline+1)->op1); do { @@ -826,6 +834,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PRE_INC_STATIC_PROP_SPEC_HANDL HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_pre_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -847,6 +862,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_POST_INC_STATIC_PROP_SPEC_HAND HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + zend_post_incdec_property_zval(prop, ZEND_TYPE_IS_SET(prop_info->type) ? prop_info : NULL OPLINE_CC EXECUTE_DATA_CC); @@ -858,18 +880,29 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET zend_fetch_static_prop_helper_ { USE_OPLINE zval *prop; + zend_property_info *prop_info; SAVE_OPLINE(); prop = zend_fetch_static_property_address( - NULL, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, + &prop_info, opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS, type, type == BP_VAR_W ? opline->extended_value : 0 OPLINE_CC EXECUTE_DATA_CC); if (UNEXPECTED(!prop)) { ZEND_ASSERT(EG(exception) || (type == BP_VAR_IS)); prop = &EG(uninitialized_zval); + } else if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && (type == BP_VAR_W || type == BP_VAR_RW || type == BP_VAR_UNSET) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + if (Z_TYPE_P(prop) == IS_OBJECT) { + goto copy_deref; + } else if (type != BP_VAR_UNSET || Z_TYPE_P(prop) != IS_UNDEF) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + } + prop = &EG(uninitialized_zval); } if (type == BP_VAR_R || type == BP_VAR_IS) { +copy_deref: ZVAL_COPY_DEREF(EX_VAR(opline->result.var), prop); } else { ZVAL_INDIRECT(EX_VAR(opline->result.var), prop); @@ -1105,6 +1138,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA HANDLE_EXCEPTION(); } + if (UNEXPECTED(prop_info->flags & ZEND_ACC_PPP_SET_MASK) + && UNEXPECTED(!zend_asymmetric_property_has_set_access(prop_info))) { + zend_asymmetric_visibility_property_modification_error(prop_info, "indirectly modify"); + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } + value_ptr = get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, BP_VAR_W); if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { From c10afa9643cd4f9f11b63769e6cd18f01fcb9173 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Wed, 2 Apr 2025 17:33:02 +0200 Subject: [PATCH 4/4] Simplify curl gc handlers (#18227) Since these objects are final and have no dynamic properties, we don't have to build a property table. --- ext/curl/interface.c | 4 +++- ext/curl/multi.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 5be9327566b19..aebb336378bc0 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -546,7 +546,9 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_use(gc_buffer, table, n); - return zend_std_get_properties(object); + /* CurlHandle can never have properties as it's final and has strict-properties on. + * Avoid building a hash table. */ + return NULL; } zend_result curl_cast_object(zend_object *obj, zval *result, int type) diff --git a/ext/curl/multi.c b/ext/curl/multi.c index 3d97b581be764..fd0a8316646f6 100644 --- a/ext/curl/multi.c +++ b/ext/curl/multi.c @@ -594,7 +594,9 @@ static HashTable *curl_multi_get_gc(zend_object *object, zval **table, int *n) zend_get_gc_buffer_use(gc_buffer, table, n); - return zend_std_get_properties(object); + /* CurlMultiHandle can never have properties as it's final and has strict-properties on. + * Avoid building a hash table. */ + return NULL; } static zend_object_handlers curl_multi_handlers;