diff --git a/NEWS b/NEWS index b230ae812e085..484ce8e2c6353 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ PHP NEWS . Fixed bug GH-19780 (InvalidUrlException should check $errors argument). (nielsdos) +- Windows: + . Fix GH-19722 (_get_osfhandle asserts in debug mode when given a socket). + (dktapps) + 11 Sep 2025, PHP 8.5.0beta3 - Core: diff --git a/ext/opcache/jit/ir/ir.c b/ext/opcache/jit/ir/ir.c index 97d32680e4fdd..9d1b698761fbb 100644 --- a/ext/opcache/jit/ir/ir.c +++ b/ext/opcache/jit/ir/ir.c @@ -624,7 +624,7 @@ ir_ref ir_const_bool(ir_ctx *ctx, bool c) ir_ref ir_const_char(ir_ctx *ctx, char c) { ir_val val; - val.i64 = c; + val.i64 = (signed char)c; return ir_const(ctx, val, IR_CHAR); } diff --git a/ext/opcache/jit/ir/ir_aarch64.dasc b/ext/opcache/jit/ir/ir_aarch64.dasc index 476529555e93e..3a2c3687042cd 100644 --- a/ext/opcache/jit/ir/ir_aarch64.dasc +++ b/ext/opcache/jit/ir/ir_aarch64.dasc @@ -397,6 +397,15 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co n++; } break; + case IR_INT2FP: + case IR_FP2INT: + insn = &ctx->ir_base[ref]; + n = 0; + if (IR_IS_CONST_REF(insn->op1)) { + constraints->tmp_regs[n] = IR_TMP_REG(1, ctx->ir_base[insn->op1].type, IR_LOAD_SUB_REF, IR_DEF_SUB_REF); + n++; + } + break; case IR_MUL_PWR2: case IR_DIV_PWR2: case IR_MOD_PWR2: @@ -404,8 +413,6 @@ int ir_get_target_constraints(ir_ctx *ctx, ir_ref ref, ir_target_constraints *co case IR_SHIFT_CONST: case IR_OP_INT: case IR_OP_FP: - case IR_INT2FP: - case IR_FP2INT: case IR_FP2FP: insn = &ctx->ir_base[ref]; n = 0; @@ -1398,7 +1405,7 @@ static void ir_load_local_addr(ir_ctx *ctx, ir_reg reg, ir_ref src) | add Rx(reg), Rx(base), #offset } else { ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); - | add sp, sp, Rx(IR_REG_INT_TMP) + | add Rx(reg), sp, Rx(IR_REG_INT_TMP) } } @@ -1587,19 +1594,31 @@ static void ir_emit_prologue(ir_ctx *ctx) offset = -(ctx->stack_frame_size+16); if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | stp x29, x30, [sp, #offset]! - } else { + } else if (aarch64_may_encode_imm12(ctx->stack_frame_size+16)) { | sub sp, sp, #(ctx->stack_frame_size+16) | stp x29, x30, [sp] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->stack_frame_size+16); + | sub sp, sp, Rx(IR_REG_INT_TMP) + | stp x29, x30, [sp] } | mov x29, sp if (ctx->call_stack_size) { - | sub sp, sp, #(ctx->call_stack_size) + if (aarch64_may_encode_imm12(ctx->call_stack_size)) { + | sub sp, sp, #(ctx->call_stack_size) + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->call_stack_size); + | sub sp, sp, Rx(IR_REG_INT_TMP) + } } } else if (ctx->stack_frame_size + ctx->call_stack_size) { if (ctx->fixed_stack_red_zone) { IR_ASSERT(ctx->stack_frame_size + ctx->call_stack_size <= ctx->fixed_stack_red_zone); + } else if (aarch64_may_encode_imm12(ctx->stack_frame_size + ctx->call_stack_size)) { + | sub sp, sp, #(ctx->stack_frame_size + ctx->call_stack_size) } else { - | sub sp, sp, #(ctx->stack_frame_size + ctx->call_stack_size) + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->stack_frame_size + ctx->call_stack_size); + | sub sp, sp, Rx(IR_REG_INT_TMP) } } if (ctx->used_preserved_regs) { @@ -1623,26 +1642,41 @@ static void ir_emit_prologue(ir_ctx *ctx) offset -= sizeof(void*) * 2; if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | stp Rx(prev), Rx(i), [Rx(fp), #offset] - } else { - IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8)); + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | str Rx(prev), [Rx(fp), #offset] | str Rx(i), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | str Rx(i), [Rx(fp), Rx(IR_REG_INT_TMP)] } prev = IR_REG_NONE; } else { if (prev < IR_REG_FP_FIRST) { offset -= sizeof(void*); - | str Rx(prev), [Rx(fp), #offset] - offset -= sizeof(void*); - | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | str Rx(prev), [Rx(fp), #offset] + offset -= sizeof(void*); + | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + | sub Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } else { offset -= sizeof(void*) * 2; if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | stp Rd(prev-IR_REG_FP_FIRST), Rd(i-IR_REG_FP_FIRST), [Rx(fp), #offset] - } else { - IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8)); + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | str Rd(i-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] } } prev = IR_REG_NONE; @@ -1652,10 +1686,20 @@ static void ir_emit_prologue(ir_ctx *ctx) if (prev != IR_REG_NONE) { if (prev < IR_REG_FP_FIRST) { offset -= sizeof(void*); - | str Rx(prev), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | str Rx(prev), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } else { offset -= sizeof(void*); - | str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset, 8)) { + | str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rd(prev-IR_REG_FP_FIRST), [Rx(fp), Rx(IR_REG_INT_TMP)] + } } } } @@ -1685,10 +1729,14 @@ static void ir_emit_prologue(ir_ctx *ctx) if (prev != IR_REG_NONE) { if (aarch64_may_encode_imm7_addr_offset(offset, 8)) { | stp Rx(prev), Rx(int_reg_params[i]), [Rx(fp), #offset] - } else { - IR_ASSERT(aarch64_may_encode_addr_offset(offset, 8)); + } else if (aarch64_may_encode_addr_offset(offset + 8, 8)) { | str Rx(prev), [Rx(fp), #offset] | str Rx(int_reg_params[i]), [Rx(fp), #(offset+8)] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + | add Rx(IR_REG_INT_TMP), Rx(IR_REG_INT_TMP), #8 + | str Rx(int_reg_params[i]), [Rx(fp), Rx(IR_REG_INT_TMP)] } prev = IR_REG_NONE; offset += sizeof(void*) * 2; @@ -1697,7 +1745,12 @@ static void ir_emit_prologue(ir_ctx *ctx) } } if (prev != IR_REG_NONE) { - | str Rx(prev), [Rx(fp), #offset] + if (aarch64_may_encode_addr_offset(offset + 8, 8)) { + | str Rx(prev), [Rx(fp), #offset] + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, offset); + | str Rx(prev), [Rx(fp), Rx(IR_REG_INT_TMP)] + } offset += sizeof(void*); } } @@ -1782,15 +1835,22 @@ static void ir_emit_epilogue(ir_ctx *ctx) } if (aarch64_may_encode_imm7_addr_offset(ctx->stack_frame_size+16, 8)) { | ldp x29, x30, [sp], #(ctx->stack_frame_size+16) - } else { + } else if (aarch64_may_encode_imm12(ctx->stack_frame_size+16)) { | ldp x29, x30, [sp] | add sp, sp, #(ctx->stack_frame_size+16) + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->stack_frame_size+16); + | ldp x29, x30, [sp] + | add sp, sp, Rx(IR_REG_INT_TMP) } } else if (ctx->stack_frame_size + ctx->call_stack_size) { if (ctx->fixed_stack_red_zone) { IR_ASSERT(ctx->stack_frame_size + ctx->call_stack_size <= ctx->fixed_stack_red_zone); - } else { + } else if (aarch64_may_encode_imm12(ctx->stack_frame_size + ctx->call_stack_size)) { | add sp, sp, #(ctx->stack_frame_size + ctx->call_stack_size) + } else { + ir_emit_load_imm_int(ctx, IR_ADDR, IR_REG_INT_TMP, ctx->stack_frame_size + ctx->call_stack_size); + | add sp, sp, Rx(IR_REG_INT_TMP) } } } @@ -4808,7 +4868,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg fp_param++; } if (dst_reg != IR_REG_NONE) { - if (src_reg == IR_REG_NONE) { + if (IR_IS_CONST_REF(arg) || + src_reg == IR_REG_NONE || + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { /* delay CONST->REG and MEM->REG moves to third pass */ do_pass3 = 1; } else { @@ -4874,7 +4936,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg fp_param++; } if (dst_reg != IR_REG_NONE) { - if (src_reg == IR_REG_NONE) { + if (IR_IS_CONST_REF(arg) || + src_reg == IR_REG_NONE || + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { if (IR_IS_CONST_REF(arg) && IR_IS_TYPE_INT(type)) { if (ir_type_size[type] == 1) { type = IR_ADDR; @@ -5473,7 +5537,8 @@ static void ir_emit_load_params(ir_ctx *ctx) int32_t stack_offset = 0; if (ctx->flags & IR_USE_FRAME_POINTER) { - stack_offset = sizeof(void*) * 2; /* skip old frame pointer and return address */ + /* skip old frame pointer and return address */ + stack_offset = sizeof(void*) * 2 + ctx->stack_frame_size + ctx->call_stack_size; } else { stack_offset = ctx->stack_frame_size + ctx->call_stack_size; } diff --git a/ext/opcache/jit/ir/ir_aarch64.h b/ext/opcache/jit/ir/ir_aarch64.h index 183d3ec2e1d88..9da64b9249f72 100644 --- a/ext/opcache/jit/ir/ir_aarch64.h +++ b/ext/opcache/jit/ir/ir_aarch64.h @@ -174,8 +174,8 @@ typedef struct _ir_tmp_reg { int8_t reg; }; uint8_t type; - uint8_t start; - uint8_t end; + int8_t start; + int8_t end; } ir_tmp_reg; struct _ir_target_constraints { diff --git a/ext/opcache/jit/ir/ir_x86.dasc b/ext/opcache/jit/ir/ir_x86.dasc index d9967d24dbea2..e5c038fce8e5a 100644 --- a/ext/opcache/jit/ir/ir_x86.dasc +++ b/ext/opcache/jit/ir/ir_x86.dasc @@ -9000,7 +9000,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg #endif } if (dst_reg != IR_REG_NONE) { - if (src_reg == IR_REG_NONE) { + if (IR_IS_CONST_REF(arg) || + src_reg == IR_REG_NONE || + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { /* delay CONST->REG and MEM->REG moves to third pass */ do_pass3 = 1; } else { @@ -9068,7 +9070,9 @@ static int32_t ir_emit_arguments(ir_ctx *ctx, ir_ref def, ir_insn *insn, ir_reg #endif } if (dst_reg != IR_REG_NONE) { - if (src_reg == IR_REG_NONE) { + if (IR_IS_CONST_REF(arg) || + src_reg == IR_REG_NONE || + (IR_REG_SPILLED(src_reg) && !IR_REGSET_IN(IR_REGSET_PRESERVED, IR_REG_NUM(src_reg)))) { if (IR_IS_TYPE_INT(type)) { if (IR_IS_CONST_REF(arg)) { if (type == IR_I8 || type == IR_I16) { diff --git a/ext/opcache/jit/ir/ir_x86.h b/ext/opcache/jit/ir/ir_x86.h index 4b86c291bdfc6..06bfa951cf21d 100644 --- a/ext/opcache/jit/ir/ir_x86.h +++ b/ext/opcache/jit/ir/ir_x86.h @@ -218,8 +218,8 @@ typedef struct _ir_tmp_reg { int8_t reg; }; uint8_t type; - uint8_t start; - uint8_t end; + int8_t start; + int8_t end; } ir_tmp_reg; struct _ir_target_constraints { diff --git a/ext/session/session.c b/ext/session/session.c index 66912fb1016c6..489f82d6f142f 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -102,6 +102,7 @@ zend_class_entry *php_session_update_timestamp_iface_entry; static zend_result php_session_send_cookie(void); static zend_result php_session_abort(void); +static void proposed_session_id_to_session_id(zval *proposed_session_id); /* Initialized in MINIT, readonly otherwise. */ static int my_module_number = 0; @@ -369,7 +370,7 @@ PHPAPI zend_string *php_session_create_id(PS_CREATE_SID_ARGS) * ps_modules appropriately */ PHPAPI zend_result php_session_valid_key(const char *key) { - size_t len; + size_t key_len; const char *p; char c; @@ -384,11 +385,11 @@ PHPAPI zend_result php_session_valid_key(const char *key) } } - len = p - key; + key_len = p - key; /* Somewhat arbitrary length limit here, but should be way more than anyone needs and avoids file-level warnings later on if we exceed MAX_PATH */ - if (len == 0 || len > PS_MAX_SID_LENGTH) { + if (key_len == 0 || key_len > PS_MAX_SID_LENGTH) { return FAILURE; } @@ -398,20 +399,21 @@ PHPAPI zend_result php_session_valid_key(const char *key) static zend_long php_session_gc(bool immediate) { - zend_long num = -1; + zend_long sessions_deleted = -1; bool collect = immediate; /* GC must be done before reading session data. */ if ((PS(mod_data) || PS(mod_user_implemented))) { + /* Use probability-based GC if not forced and probability is configured */ if (!collect && PS(gc_probability) > 0) { collect = php_random_range(PS(random), 0, PS(gc_divisor) - 1) < PS(gc_probability); } if (collect) { - PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &num); + PS(mod)->s_gc(&PS(mod_data), PS(gc_maxlifetime), &sessions_deleted); } } - return num; + return sessions_deleted; } static zend_result php_session_initialize(void) @@ -1441,37 +1443,132 @@ static zend_result php_session_send_cookie(void) PHPAPI const ps_module *_php_find_ps_module(const char *name) { - const ps_module *ret = NULL; - const ps_module **mod; - int i; + const ps_module *found_module = NULL; + const ps_module **current_module; + int module_index; - for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) { - if (*mod && !strcasecmp(name, (*mod)->s_name)) { - ret = *mod; + for (module_index = 0, current_module = ps_modules; module_index < MAX_MODULES; module_index++, current_module++) { + if (*current_module && !strcasecmp(name, (*current_module)->s_name)) { + found_module = *current_module; break; } } - return ret; + return found_module; } PHPAPI const ps_serializer *_php_find_ps_serializer(const char *name) { - const ps_serializer *ret = NULL; - const ps_serializer *mod; + const ps_serializer *found_serializer = NULL; + const ps_serializer *current_serializer; - for (mod = ps_serializers; mod->name; mod++) { - if (!strcasecmp(name, mod->name)) { - ret = mod; + for (current_serializer = ps_serializers; current_serializer->name; current_serializer++) { + if (!strcasecmp(name, current_serializer->name)) { + found_serializer = current_serializer; break; } } - return ret; + return found_serializer; +} + +static bool should_invalidate_session_for_external_referer(void) +{ + zval *referer_data; + + /* No external referer check configured */ + if (!PS(id) || PS(extern_referer_chk)[0] == '\0') { + return false; + } + + /* No SERVER globals available */ + if (Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER])) { + return false; + } + + /* Get HTTP_REFERER header */ + referer_data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRL("HTTP_REFERER")); + if (!referer_data || Z_TYPE_P(referer_data) != IS_STRING || Z_STRLEN_P(referer_data) == 0) { + return false; + } + + /* Check if referer contains expected string */ + return strstr(Z_STRVAL_P(referer_data), PS(extern_referer_chk)) == NULL; +} + +static void try_find_session_id_in_global(const char *global_name, size_t global_name_len) +{ + zval *global_data, *potential_session_id; + + if (PS(id)) { + return; + } + + global_data = zend_hash_str_find(&EG(symbol_table), global_name, global_name_len); + if (!global_data) { + return; + } + + ZVAL_DEREF(global_data); + if (Z_TYPE_P(global_data) != IS_ARRAY) { + return; + } + + potential_session_id = zend_hash_find(Z_ARRVAL_P(global_data), PS(session_name)); + if (potential_session_id) { + proposed_session_id_to_session_id(potential_session_id); + } +} + +static bool php_can_change_session_setting(const char *setting_name, bool check_cookies) +{ + if (PS(session_status) == php_session_active) { + char error_msg[256]; + snprintf(error_msg, sizeof(error_msg), "Session %s cannot be changed when a session is active", setting_name); + php_session_session_already_started_error(E_WARNING, error_msg); + + return false; + } + + if (SG(headers_sent) && (!check_cookies || PS(use_cookies))) { + char error_msg[256]; + snprintf(error_msg, sizeof(error_msg), "Session %s cannot be changed after headers have already been sent", setting_name); + php_session_headers_already_sent_error(E_WARNING, error_msg); + + return false; + } + + return true; +} + +static void try_find_session_id_in_cookies(void) +{ + zval *cookie_data, *potential_session_id; + + if (!PS(use_cookies) || PS(id)) { + return; + } + + cookie_data = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_COOKIE")); + if (!cookie_data) { + return; + } + + ZVAL_DEREF(cookie_data); + if (Z_TYPE_P(cookie_data) != IS_ARRAY) { + return; + } + + potential_session_id = zend_hash_find(Z_ARRVAL_P(cookie_data), PS(session_name)); + if (potential_session_id) { + proposed_session_id_to_session_id(potential_session_id); + PS(send_cookie) = 0; + PS(define_sid) = 0; + } } -static void ppid2sid(zval *ppid) { - ZVAL_DEREF(ppid); - if (Z_TYPE_P(ppid) == IS_STRING) { - PS(id) = zend_string_copy(Z_STR_P(ppid)); +static void proposed_session_id_to_session_id(zval *proposed_session_id) { + ZVAL_DEREF(proposed_session_id); + if (Z_TYPE_P(proposed_session_id) == IS_STRING) { + PS(id) = zend_string_copy(Z_STR_P(proposed_session_id)); PS(send_cookie) = 0; } else { PS(id) = NULL; @@ -1483,7 +1580,7 @@ static void ppid2sid(zval *ppid) { PHPAPI zend_result php_session_reset_id(void) { int module_number = PS(module_number); - zval *sid, *data, *ppid; + zval *sid, *data, *potential_session_id; bool apply_trans_sid; if (!PS(id)) { @@ -1545,8 +1642,8 @@ PHPAPI zend_result php_session_reset_id(void) (data = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_COOKIE")))) { ZVAL_DEREF(data); if (Z_TYPE_P(data) == IS_ARRAY && - (ppid = zend_hash_find(Z_ARRVAL_P(data), PS(session_name)))) { - ZVAL_DEREF(ppid); + (potential_session_id = zend_hash_find(Z_ARRVAL_P(data), PS(session_name)))) { + ZVAL_DEREF(potential_session_id); apply_trans_sid = 0; } } @@ -1561,8 +1658,6 @@ PHPAPI zend_result php_session_reset_id(void) PHPAPI zend_result php_session_start(void) { - zval *ppid; - zval *data; char *value; switch (PS(session_status)) { @@ -1607,37 +1702,13 @@ PHPAPI zend_result php_session_start(void) */ if (!PS(id)) { - if (PS(use_cookies) && (data = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_COOKIE")))) { - ZVAL_DEREF(data); - if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_find(Z_ARRVAL_P(data), PS(session_name)))) { - ppid2sid(ppid); - PS(send_cookie) = 0; - PS(define_sid) = 0; - } - } - /* Initialize session ID from non cookie values */ + try_find_session_id_in_cookies(); + if (!PS(use_only_cookies)) { - if (!PS(id) && (data = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_GET")))) { - ZVAL_DEREF(data); - if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_find(Z_ARRVAL_P(data), PS(session_name)))) { - ppid2sid(ppid); - } - } - if (!PS(id) && (data = zend_hash_str_find(&EG(symbol_table), ZEND_STRL("_POST")))) { - ZVAL_DEREF(data); - if (Z_TYPE_P(data) == IS_ARRAY && (ppid = zend_hash_find(Z_ARRVAL_P(data), PS(session_name)))) { - ppid2sid(ppid); - } - } - /* Check whether the current request was referred to by - * an external site which invalidates the previously found id. */ - if (PS(id) && PS(extern_referer_chk)[0] != '\0' && - !Z_ISUNDEF(PG(http_globals)[TRACK_VARS_SERVER]) && - (data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), ZEND_STRL("HTTP_REFERER"))) && - Z_TYPE_P(data) == IS_STRING && - Z_STRLEN_P(data) != 0 && - strstr(Z_STRVAL_P(data), PS(extern_referer_chk)) == NULL - ) { + try_find_session_id_in_global(ZEND_STRL("_GET")); + try_find_session_id_in_global(ZEND_STRL("_POST")); + + if (should_invalidate_session_for_external_referer()) { zend_string_release_ex(PS(id), 0); PS(id) = NULL; } @@ -1923,13 +1994,7 @@ PHP_FUNCTION(session_name) RETURN_THROWS(); } - if (name && PS(session_status) == php_session_active) { - php_session_session_already_started_error(E_WARNING, "Session name cannot be changed when a session is active"); - RETURN_FALSE; - } - - if (name && SG(headers_sent)) { - php_session_headers_already_sent_error(E_WARNING, "Session name cannot be changed after headers have already been sent"); + if (name && !php_can_change_session_setting("name", false)) { RETURN_FALSE; } @@ -1952,13 +2017,7 @@ PHP_FUNCTION(session_module_name) RETURN_THROWS(); } - if (name && PS(session_status) == php_session_active) { - php_session_session_already_started_error(E_WARNING, "Session save handler module cannot be changed when a session is active"); - RETURN_FALSE; - } - - if (name && SG(headers_sent)) { - php_session_headers_already_sent_error(E_WARNING, "Session save handler module cannot be changed after headers have already been sent"); + if (name && !php_can_change_session_setting("save handler module", false)) { RETURN_FALSE; } @@ -2227,13 +2286,7 @@ PHP_FUNCTION(session_save_path) RETURN_THROWS(); } - if (name && PS(session_status) == php_session_active) { - php_session_session_already_started_error(E_WARNING, "Session save path cannot be changed when a session is active"); - RETURN_FALSE; - } - - if (name && SG(headers_sent)) { - php_session_headers_already_sent_error(E_WARNING, "Session save path cannot be changed after headers have already been sent"); + if (name && !php_can_change_session_setting("save path", false)) { RETURN_FALSE; } @@ -2255,13 +2308,7 @@ PHP_FUNCTION(session_id) RETURN_THROWS(); } - if (name && PS(session_status) == php_session_active) { - php_session_session_already_started_error(E_WARNING, "Session ID cannot be changed when a session is active"); - RETURN_FALSE; - } - - if (name && PS(use_cookies) && SG(headers_sent)) { - php_session_headers_already_sent_error(E_WARNING, "Session ID cannot be changed after headers have already been sent"); + if (name && !php_can_change_session_setting("ID", true)) { RETURN_FALSE; } @@ -2962,24 +3009,24 @@ static PHP_MSHUTDOWN_FUNCTION(session) static PHP_MINFO_FUNCTION(session) { - const ps_module **mod; - ps_serializer *ser; + const ps_module **current_save_handler; + ps_serializer *current_serializer; smart_str save_handlers = {0}; smart_str ser_handlers = {0}; - int i; + int handler_index; - /* Get save handlers */ - for (i = 0, mod = ps_modules; i < MAX_MODULES; i++, mod++) { - if (*mod && (*mod)->s_name) { - smart_str_appends(&save_handlers, (*mod)->s_name); + /* Collect names of all available save handlers */ + for (handler_index = 0, current_save_handler = ps_modules; handler_index < MAX_MODULES; handler_index++, current_save_handler++) { + if (*current_save_handler && (*current_save_handler)->s_name) { + smart_str_appends(&save_handlers, (*current_save_handler)->s_name); smart_str_appendc(&save_handlers, ' '); } } - /* Get serializer handlers */ - for (i = 0, ser = ps_serializers; i < MAX_SERIALIZERS; i++, ser++) { - if (ser->name) { - smart_str_appends(&ser_handlers, ser->name); + /* Collect names of all available serializers */ + for (handler_index = 0, current_serializer = ps_serializers; handler_index < MAX_SERIALIZERS; handler_index++, current_serializer++) { + if (current_serializer->name) { + smart_str_appends(&ser_handlers, current_serializer->name); smart_str_appendc(&ser_handlers, ' '); } } @@ -3019,16 +3066,16 @@ static const zend_module_dep session_deps[] = { static bool early_find_sid_in(zval *dest, int where, php_session_rfc1867_progress *progress) { - zval *ppid; + zval *potential_session_id; if (Z_ISUNDEF(PG(http_globals)[where])) { return 0; } - if ((ppid = zend_hash_find(Z_ARRVAL(PG(http_globals)[where]), PS(session_name))) - && Z_TYPE_P(ppid) == IS_STRING) { + if ((potential_session_id = zend_hash_find(Z_ARRVAL(PG(http_globals)[where]), PS(session_name))) + && Z_TYPE_P(potential_session_id) == IS_STRING) { zval_ptr_dtor(dest); - ZVAL_COPY_DEREF(dest, ppid); + ZVAL_COPY_DEREF(dest, potential_session_id); return 1; } diff --git a/ext/standard/string.c b/ext/standard/string.c index a5acb28ddb3bc..fffd796d94a8f 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -1026,7 +1026,11 @@ PHPAPI void php_implode(const zend_string *glue, HashTable *pieces, zval *return } cptr -= ZSTR_LEN(glue); - memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue)); + if (ZSTR_LEN(glue) == 1) { + *cptr = ZSTR_VAL(glue)[0]; + } else { + memcpy(cptr, ZSTR_VAL(glue), ZSTR_LEN(glue)); + } } free_alloca(strings, use_heap); diff --git a/ext/standard/tests/serialize/gh12265.phpt b/ext/standard/tests/serialize/gh12265.phpt new file mode 100644 index 0000000000000..5f49a62fee29f --- /dev/null +++ b/ext/standard/tests/serialize/gh12265.phpt @@ -0,0 +1,47 @@ +--TEST-- +GH-12265 (Cloning an object breaks serialization recursion) - __serialize variation +--FILE-- + new A($this)]; + } +} + +class C { + public B $b; + + public function __construct() { + $this->b = new B; + } +} + +$b = new B(); +$sb = serialize($b); +$stb = serialize(new B); + +printf("serialized original: %s\n", $sb); +printf("serialized temp : %s\n", $stb); + +$c = new C; +$sc = serialize($c); +$stc = serialize(new C); + +printf("serialized original: %s\n", $sc); +printf("serialized temp : %s\n", $stc); + +?> +--EXPECT-- +serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} +serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} diff --git a/ext/standard/tests/serialize/gh12265b.phpt b/ext/standard/tests/serialize/gh12265b.phpt new file mode 100644 index 0000000000000..2b9d80a848cee --- /dev/null +++ b/ext/standard/tests/serialize/gh12265b.phpt @@ -0,0 +1,48 @@ +--TEST-- +GH-12265 (Cloning an object breaks serialization recursion) - __sleep variation +--FILE-- +a = new A($this); + return ['a']; + } +} + +class C { + public B $b; + + public function __construct() { + $this->b = new B; + } +} + +$b = new B(); +$sb = serialize($b); +$stb = serialize(new B); + +printf("serialized original: %s\n", $sb); +printf("serialized temp : %s\n", $stb); + +$c = new C; +$sc = serialize($c); +$stc = serialize(new C); + +printf("serialized original: %s\n", $sc); +printf("serialized temp : %s\n", $stc); + +?> +--EXPECT-- +serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}} +serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} +serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}} diff --git a/ext/standard/var.c b/ext/standard/var.c index 1c2b0eb164a1c..70a086f87f8b1 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -737,7 +737,10 @@ static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var, b return 0; } else if (!in_rcn_array && Z_REFCOUNT_P(var) == 1 - && (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1)) { + && (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1) + /* __serialize and __sleep may arbitrarily increase the refcount */ + && Z_OBJCE_P(var)->__serialize == NULL + && zend_hash_find_known_hash(&Z_OBJCE_P(var)->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP)) == NULL) { return 0; } diff --git a/win32/build/config.w32.h.in b/win32/build/config.w32.h.in index d8ff0c9dc6a50..7b1bb4d932d33 100644 --- a/win32/build/config.w32.h.in +++ b/win32/build/config.w32.h.in @@ -38,8 +38,6 @@ #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2 -#undef HAVE_ADABAS -#undef HAVE_SOLID #undef HAVE_SYMLINK /* its in win32/time.c */ diff --git a/win32/select.c b/win32/select.c index dec149b665ff5..0cd7b8529559d 100644 --- a/win32/select.c +++ b/win32/select.c @@ -66,8 +66,10 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e /* build an array of handles for non-sockets */ for (i = 0; (uint32_t)i < max_fd; i++) { if (SAFE_FD_ISSET(i, rfds) || SAFE_FD_ISSET(i, wfds) || SAFE_FD_ISSET(i, efds)) { - handles[n_handles] = (HANDLE)(uintptr_t)_get_osfhandle(i); - if (handles[n_handles] == INVALID_HANDLE_VALUE) { + int _type; + int _len = sizeof(_type); + + if (getsockopt((SOCKET)i, SOL_SOCKET, SO_TYPE, (char*)&_type, &_len) == 0 || WSAGetLastError() != WSAENOTSOCK) { /* socket */ if (SAFE_FD_ISSET(i, rfds)) { FD_SET((uint32_t)i, &sock_read); @@ -82,11 +84,14 @@ PHPAPI int php_select(php_socket_t max_fd, fd_set *rfds, fd_set *wfds, fd_set *e sock_max_fd = i; } } else { - if (SAFE_FD_ISSET(i, rfds) && GetFileType(handles[n_handles]) == FILE_TYPE_PIPE) { - num_read_pipes++; + handles[n_handles] = (HANDLE)(uintptr_t)_get_osfhandle(i); + if (handles[n_handles] != INVALID_HANDLE_VALUE) { + if (SAFE_FD_ISSET(i, rfds) && GetFileType(handles[n_handles]) == FILE_TYPE_PIPE) { + num_read_pipes++; + } + handle_slot_to_fd[n_handles] = i; + n_handles++; } - handle_slot_to_fd[n_handles] = i; - n_handles++; } } }