diff options
47 files changed, 798 insertions, 126 deletions
@@ -95,6 +95,11 @@ PHP 7.1 UPGRADE NOTES - Core: . Support for ftok() +- FCGI + . PHP_FCGI_CHILDREN is respected. If this environment variable is defined, + the first php-fcgi.exe process will exec the specified number of children. + Those will share the same TCP socket. + ======================================== 13. Other Changes ======================================== diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index f187129416..298dfb53fa 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -284,7 +284,7 @@ char *alloca(); # endif # elif defined(_MSC_VER) # define zend_always_inline __forceinline -# define zend_never_inline +# define zend_never_inline __declspec(noinline) # else # if __has_attribute(always_inline) # define zend_always_inline inline __attribute__((always_inline)) diff --git a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c index 77736a051b..75d249fbe8 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_cp5022x.c @@ -278,7 +278,7 @@ retry: w = cp932ext1_ucs_table[s - cp932ext1_ucs_table_min]; } else if (s >= cp932ext2_ucs_table_min && s < cp932ext2_ucs_table_max) { w = cp932ext2_ucs_table[s - cp932ext2_ucs_table_min]; - } else if (s >= cp932ext3_ucs_table_min && s < cp932ext2_ucs_table_max) { + } else if (s >= cp932ext3_ucs_table_min && s < cp932ext3_ucs_table_max) { w = cp932ext3_ucs_table[s - cp932ext3_ucs_table_min]; } else if (s >= 94 * 94 && s < 114 * 94) { /* user-defined => PUA (Microsoft extended) */ diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index 4fdb3d5b2e..b5812cb402 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -4145,9 +4145,10 @@ PHP_FUNCTION(mb_send_mail) suppressed_hdrs.cnt_type = 1; } - if ((s = zend_hash_str_find_ptr(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1))) { + if ((s = zend_hash_str_find(&ht_headers, "CONTENT-TRANSFER-ENCODING", sizeof("CONTENT-TRANSFER-ENCODING") - 1))) { enum mbfl_no_encoding _body_enc; + ZEND_ASSERT(Z_TYPE_P(s) == IS_STRING); _body_enc = mbfl_name2no_encoding(Z_STRVAL_P(s)); switch (_body_enc) { case mbfl_no_encoding_base64: diff --git a/ext/mysqlnd/mysqlnd_connection.c b/ext/mysqlnd/mysqlnd_connection.c index 2cefe755d8..6f350cfd79 100644 --- a/ext/mysqlnd/mysqlnd_connection.c +++ b/ext/mysqlnd/mysqlnd_connection.c @@ -40,7 +40,7 @@ PHPAPI const char * const mysqlnd_server_gone = "MySQL server has gone away"; PHPAPI const char * const mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now"; PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory"; -PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL; +PHPAPI MYSQLND_STATS * mysqlnd_global_stats = NULL; /* {{{ mysqlnd_upsert_status::reset */ @@ -152,8 +152,8 @@ MYSQLND_CLASS_METHODS_END; /* {{{ mysqlnd_error_info_init */ -enum_func_status -mysqlnd_error_info_init(MYSQLND_ERROR_INFO * const info, zend_bool persistent) +PHPAPI enum_func_status +mysqlnd_error_info_init(MYSQLND_ERROR_INFO * const info, const zend_bool persistent) { DBG_ENTER("mysqlnd_error_info_init"); info->m = mysqlnd_error_info_get_methods(); @@ -163,12 +163,28 @@ mysqlnd_error_info_init(MYSQLND_ERROR_INFO * const info, zend_bool persistent) if (info->error_list) { zend_llist_init(info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t) mysqlnd_error_list_pdtor, persistent); } - + info->persistent = persistent; DBG_RETURN(info->error_list? PASS:FAIL); } /* }}} */ +/* {{{ mysqlnd_error_info_free_contents */ +PHPAPI void +mysqlnd_error_info_free_contents(MYSQLND_ERROR_INFO * const info) +{ + DBG_ENTER("mysqlnd_error_info_free_contents"); + info->m->reset(info); + if (info->error_list) { + mnd_pefree(info->error_list, info->persistent); + info->error_list = NULL; + } + + DBG_VOID_RETURN; +} +/* }}} */ + + /* {{{ mysqlnd_connection_state::get */ @@ -200,10 +216,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_connection_state) MYSQLND_CLASS_METHODS_END; - - /* {{{ mysqlnd_upsert_status_init */ -void +PHPAPI void mysqlnd_connection_state_init(struct st_mysqlnd_connection_state * const state) { DBG_ENTER("mysqlnd_error_info_init"); @@ -214,6 +228,7 @@ mysqlnd_connection_state_init(struct st_mysqlnd_connection_state * const state) /* }}} */ + /* {{{ mysqlnd_conn_data::free_options */ static void MYSQLND_METHOD(mysqlnd_conn_data, free_options)(MYSQLND_CONN_DATA * conn) @@ -318,11 +333,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, free_contents)(MYSQLND_CONN_DATA * conn) mnd_pefree(conn->last_message.s, pers); conn->last_message.s = NULL; } - if (conn->error_info->error_list) { - zend_llist_clean(conn->error_info->error_list); - mnd_pefree(conn->error_info->error_list, pers); - conn->error_info->error_list = NULL; - } + conn->charset = NULL; conn->greet_charset = NULL; @@ -341,6 +352,11 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor)(MYSQLND_CONN_DATA * conn) conn->m->free_contents(conn); conn->m->free_options(conn); + if (conn->error_info) { + mysqlnd_error_info_free_contents(conn->error_info); + conn->error_info = NULL; + } + if (conn->protocol_frame_codec) { mysqlnd_pfc_free(conn->protocol_frame_codec, conn->stats, conn->error_info); conn->protocol_frame_codec = NULL; diff --git a/ext/mysqlnd/mysqlnd_connection.h b/ext/mysqlnd/mysqlnd_connection.h index cdffe594d9..0668d09d92 100644 --- a/ext/mysqlnd/mysqlnd_connection.h +++ b/ext/mysqlnd/mysqlnd_connection.h @@ -67,12 +67,13 @@ void mysqlnd_upsert_status_init(MYSQLND_UPSERT_STATUS * const upsert_status); } -enum_func_status mysqlnd_error_info_init(MYSQLND_ERROR_INFO * const info, zend_bool persistent); +PHPAPI enum_func_status mysqlnd_error_info_init(MYSQLND_ERROR_INFO * const info, const zend_bool persistent); +PHPAPI void mysqlnd_error_info_free_contents(MYSQLND_ERROR_INFO * const info); #define GET_CONNECTION_STATE(state_struct) (state_struct)->m->get((state_struct)) #define SET_CONNECTION_STATE(state_struct, s) (state_struct)->m->set((state_struct), (s)) -void mysqlnd_connection_state_init(struct st_mysqlnd_connection_state * const state); +PHPAPI void mysqlnd_connection_state_init(struct st_mysqlnd_connection_state * const state); #endif /* MYSQLND_CONNECTION_H */ diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 35a0f3b16c..cc5e2b7ac4 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -32,6 +32,9 @@ #define MYSQLND_CLASS_METHODS_START(class) MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(class) = { #define MYSQLND_CLASS_METHODS_END } +#define MYSQLND_CLASS_METHODS_INSTANCE_NAME(class) mysqlnd_##class##_methods_ptr +#define MYSQLND_CLASS_METHODS_INSTANCE_DECLARE(class) extern const MYSQLND_CLASS_METHODS_TYPE(class) * MYSQLND_CLASS_METHODS_INSTANCE_NAME(class) +#define MYSQLND_CLASS_METHODS_INSTANCE_DEFINE(class) const MYSQLND_CLASS_METHODS_TYPE(class) * MYSQLND_CLASS_METHODS_INSTANCE_NAME(class) = & MYSQLND_CLASS_METHOD_TABLE_NAME(class) typedef struct st_mysqlnd_string { @@ -154,6 +157,7 @@ struct st_mysqlnd_error_info unsigned int error_no; zend_llist * error_list; + zend_bool persistent; MYSQLND_CLASS_METHODS_TYPE(mysqlnd_error_info) *m; }; diff --git a/ext/opcache/Optimizer/dfa_pass.c b/ext/opcache/Optimizer/dfa_pass.c index a1872e3d81..02dfdd5b7e 100644 --- a/ext/opcache/Optimizer/dfa_pass.c +++ b/ext/opcache/Optimizer/dfa_pass.c @@ -34,6 +34,11 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, { uint32_t build_flags; + if (op_array->last_try_catch) { + /* TODO: we can't analyze functions with try/catch/finally ??? */ + return FAILURE; + } + /* Build SSA */ memset(ssa, 0, sizeof(zend_ssa)); @@ -41,7 +46,8 @@ int zend_dfa_analyze_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx, return FAILURE; } - if (*flags & ZEND_FUNC_TOO_DYNAMIC) { + if (*flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) { + /* TODO: we can't analyze functions with indirect variable access ??? */ return FAILURE; } diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 728d586026..b8121808d2 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -251,10 +251,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b /* Build CFG, Step 1: Find basic blocks starts, calculate number of blocks */ BB_START(0); - if ((op_array->fn_flags & ZEND_ACC_CLOSURE) && op_array->static_variables) { - // FIXME: Really we should try to perform variable initialization - flags |= ZEND_FUNC_TOO_DYNAMIC; - } for (i = 0; i < op_array->last; i++) { zend_op *opline = op_array->opcodes + i; switch(opline->opcode) { @@ -268,9 +264,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } break; case ZEND_INCLUDE_OR_EVAL: + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; case ZEND_YIELD: case ZEND_YIELD_FROM: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (build_flags & ZEND_CFG_STACKLESS) { BB_START(i + 1); } @@ -296,15 +292,17 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) { if (fn->type == ZEND_INTERNAL_FUNCTION) { if (zend_string_equals_literal(Z_STR_P(zv), "extract")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; - } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; - } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") && + opline->extended_value == 1) { + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } else if (zend_string_equals_literal(Z_STR_P(zv), "func_num_args")) { flags |= ZEND_FUNC_VARARG; } else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_arg")) { @@ -316,12 +314,10 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } break; case ZEND_FAST_CALL: - flags |= ZEND_FUNC_TOO_DYNAMIC; BB_START(OP_JMP_ADDR(opline, opline->op1) - op_array->opcodes); BB_START(i + 1); break; case ZEND_FAST_RET: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (i + 1 < op_array->last) { BB_START(i + 1); } @@ -350,7 +346,6 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b BB_START(i + 1); break; case ZEND_CATCH: - flags |= ZEND_FUNC_TOO_DYNAMIC; if (!opline->result.num) { BB_START(ZEND_OFFSET_TO_OPLINE_NUM(op_array, opline, opline->extended_value)); } @@ -370,8 +365,9 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b BB_START(i + 1); break; case ZEND_UNSET_VAR: + case ZEND_ISSET_ISEMPTY_VAR: if (!(opline->extended_value & ZEND_QUICK_SET)) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } break; case ZEND_FETCH_R: @@ -381,11 +377,11 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b case ZEND_FETCH_IS: case ZEND_FETCH_UNSET: if ((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_LOCAL) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } else if (((opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL || (opline->extended_value & ZEND_FETCH_TYPE_MASK) == ZEND_FETCH_GLOBAL_LOCK) && !op_array->function_name) { - flags |= ZEND_FUNC_TOO_DYNAMIC; + flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; } break; } diff --git a/ext/opcache/Optimizer/zend_dump.c b/ext/opcache/Optimizer/zend_dump.c index 53458644fc..46952c1159 100644 --- a/ext/opcache/Optimizer/zend_dump.c +++ b/ext/opcache/Optimizer/zend_dump.c @@ -305,8 +305,14 @@ void zend_dump_ssa_var(const zend_op_array *op_array, const zend_ssa *ssa, int s } } -static void zend_dump_pi_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_pi_range *r) +static void zend_dump_pi_constraint(const zend_op_array *op_array, const zend_ssa *ssa, const zend_ssa_pi_constraint *r) { + if (r->type_mask != (uint32_t) -1) { + fprintf(stderr, " TYPE"); + zend_dump_type_info(r->type_mask, NULL, 0); + return; + } + if (r->range.underflow && r->range.overflow) { return; } @@ -791,7 +797,7 @@ static void zend_dump_block_header(const zend_cfg *cfg, const zend_op_array *op_ fprintf(stderr, " = Pi("); zend_dump_ssa_var(op_array, ssa, p->sources[0], 0, p->var); fprintf(stderr, " &"); - zend_dump_pi_range(op_array, ssa, &p->constraint); + zend_dump_pi_constraint(op_array, ssa, &p->constraint); fprintf(stderr, ")\n"); } p = p->next; @@ -853,6 +859,9 @@ void zend_dump_op_array(const zend_op_array *op_array, uint32_t dump_flags, cons if (ssa) { fprintf(stderr, ", ssa_vars=%d", ssa->vars_count); } + if (func_flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) { + fprintf(stderr, ", dynamic"); + } if (func_flags & ZEND_FUNC_RECURSIVE) { fprintf(stderr, ", recursive"); if (func_flags & ZEND_FUNC_RECURSIVE_DIRECTLY) { diff --git a/ext/opcache/Optimizer/zend_func_info.h b/ext/opcache/Optimizer/zend_func_info.h index 4b0aadd4ee..8fcf00d26a 100644 --- a/ext/opcache/Optimizer/zend_func_info.h +++ b/ext/opcache/Optimizer/zend_func_info.h @@ -22,7 +22,7 @@ #include "zend_ssa.h" /* func flags */ -#define ZEND_FUNC_TOO_DYNAMIC (1<<0) +#define ZEND_FUNC_INDIRECT_VAR_ACCESS (1<<0) #define ZEND_FUNC_HAS_CALLS (1<<1) #define ZEND_FUNC_VARARG (1<<2) #define ZEND_FUNC_NO_LOOPS (1<<3) diff --git a/ext/opcache/Optimizer/zend_inference.c b/ext/opcache/Optimizer/zend_inference.c index 41bd4eebb0..beec91924c 100644 --- a/ext/opcache/Optimizer/zend_inference.c +++ b/ext/opcache/Optimizer/zend_inference.c @@ -475,7 +475,7 @@ int zend_inference_calc_range(const zend_op_array *op_array, zend_ssa *ssa, int tmp->min = ZEND_LONG_MAX; tmp->max = ZEND_LONG_MIN; tmp->overflow = 0; - if (p->pi >= 0) { + if (p->pi >= 0 && p->constraint.type_mask == (uint32_t) -1) { if (p->constraint.negative) { if (ssa->var_info[p->sources[0]].has_range) { tmp->underflow = ssa->var_info[p->sources[0]].range.underflow; @@ -1814,6 +1814,7 @@ static void zend_infer_ranges_warmup(const zend_op_array *op_array, zend_ssa *ss ssa->var_info[j].has_range && ssa->vars[j].definition_phi && ssa->vars[j].definition_phi->pi >= 0 && + ssa->vars[j].definition_phi->constraint.type_mask == (uint32_t) -1 && ssa->vars[j].definition_phi->constraint.negative && ssa->vars[j].definition_phi->constraint.min_ssa_var < 0 && ssa->vars[j].definition_phi->constraint.min_ssa_var < 0) { @@ -3067,8 +3068,11 @@ static void zend_update_type_info(const zend_op_array *op_array, } break; case ZEND_BIND_GLOBAL: + tmp = (MAY_BE_REF | MAY_BE_ANY); + UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); + break; case ZEND_BIND_STATIC: - tmp = (MAY_BE_REF | MAY_BE_ANY ); + tmp = MAY_BE_ANY | (opline->extended_value ? MAY_BE_REF : (MAY_BE_RC1 | MAY_BE_RCN)); UPDATE_SSA_TYPE(tmp, ssa_ops[i].op1_def); break; case ZEND_SEND_VAR: @@ -3655,6 +3659,9 @@ int zend_infer_types_ex(const zend_op_array *op_array, const zend_script *script zend_ssa_phi *p = ssa_vars[j].definition_phi; if (p->pi >= 0) { tmp = get_ssa_var_info(ssa, p->sources[0]); + if (p->constraint.type_mask != (uint32_t) -1) { + tmp &= p->constraint.type_mask; + } UPDATE_SSA_TYPE(tmp, j); if (ssa_var_info[p->sources[0]].ce) { UPDATE_SSA_OBJ_TYPE(ssa_var_info[p->sources[0]].ce, ssa_var_info[p->sources[0]].is_instanceof, j); @@ -4071,17 +4078,22 @@ int zend_ssa_inference(zend_arena **arena, const zend_op_array *op_array, const } ssa_var_info = ssa->var_info; - for (i = 0; i < op_array->last_var; i++) { - if (!op_array->function_name) { + if (!op_array->function_name) { + for (i = 0; i < op_array->last_var; i++) { ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_REF | MAY_BE_ANY | MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - } else if (i == EX_VAR_TO_NUM(op_array->this_var)) { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; - ssa_var_info[i].ce = op_array->scope; - ssa_var_info[i].is_instanceof = 1; - } else { - ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; + ssa_var_info[i].has_range = 0; + } + } else { + for (i = 0; i < op_array->last_var; i++) { + if (i == EX_VAR_TO_NUM(op_array->this_var)) { + ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_OBJECT; + ssa_var_info[i].ce = op_array->scope; + ssa_var_info[i].is_instanceof = 1; + } else { + ssa_var_info[i].type = MAY_BE_UNDEF | MAY_BE_RCN; + } + ssa_var_info[i].has_range = 0; } - ssa_var_info[i].has_range = 0; } for (i = op_array->last_var; i < ssa->vars_count; i++) { ssa_var_info[i].type = 0; diff --git a/ext/opcache/Optimizer/zend_ssa.c b/ext/opcache/Optimizer/zend_ssa.c index 059550b63d..16d22dd258 100644 --- a/ext/opcache/Optimizer/zend_ssa.c +++ b/ext/opcache/Optimizer/zend_ssa.c @@ -21,6 +21,7 @@ #include "zend_dfg.h" #include "zend_ssa.h" #include "zend_dump.h" +#include "zend_inference.h" static int needs_pi(const zend_op_array *op_array, zend_dfg *dfg, zend_ssa *ssa, int from, int to, int var) /* {{{ */ { @@ -78,6 +79,7 @@ static void pi_range( phi->constraint.range.underflow = underflow; phi->constraint.range.overflow = overflow; phi->constraint.negative = negative ? NEG_INIT : NEG_NONE; + phi->constraint.type_mask = (uint32_t) -1; } /* }}} */ @@ -94,6 +96,27 @@ static inline void pi_range_max(zend_ssa_phi *phi, int var, zend_long val) { pi_range(phi, -1, var, ZEND_LONG_MIN, val, 1, 0, 0); } +static void pi_type_mask(zend_ssa_phi *phi, uint32_t type_mask) { + phi->constraint.type_mask = MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; + phi->constraint.type_mask |= type_mask; + if (type_mask & MAY_BE_NULL) { + phi->constraint.type_mask |= MAY_BE_UNDEF; + } +} +static inline void pi_not_type_mask(zend_ssa_phi *phi, uint32_t type_mask) { + uint32_t relevant = MAY_BE_ANY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + pi_type_mask(phi, ~type_mask & relevant); +} +static inline uint32_t mask_for_type_check(uint32_t type) { + if (type == _IS_BOOL) { + return MAY_BE_TRUE|MAY_BE_FALSE; + } else if (type == IS_ARRAY) { + return MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF; + } else { + return 1 << type; + } +} + /* We can interpret $a + 5 == 0 as $a = 0 - 5, i.e. shift the adjustment to the other operand. * This negated adjustment is what is written into the "adjustment" parameter. */ static int find_adjusted_tmp_var(const zend_op_array *op_array, uint32_t build_flags, zend_op *opline, uint32_t var_num, zend_long *adjustment) @@ -805,6 +828,59 @@ int zend_build_ssa(zend_arena **arena, const zend_op_array *op_array, uint32_t b if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bt, var))) { pi_range_not_equals(pi, -1, 0); } + } else if (opline->op1_type == IS_TMP_VAR && (opline-1)->opcode == ZEND_TYPE_CHECK && + opline->op1.var == (opline-1)->result.var && (opline-1)->op1_type == IS_CV) { + int var = EX_VAR_TO_NUM((opline-1)->op1.var); + uint32_t type = (opline-1)->extended_value; + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bt, var))) { + pi_type_mask(pi, mask_for_type_check(type)); + } + if (type != IS_OBJECT && type != IS_RESOURCE) { + /* is_object() and is_resource() may return false, even though the value is + * an object/resource. */ + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bf, var))) { + pi_not_type_mask(pi, mask_for_type_check(type)); + } + } + } else if (opline->op1_type == IS_TMP_VAR && + ((opline-1)->opcode == ZEND_IS_IDENTICAL + || (opline-1)->opcode == ZEND_IS_NOT_IDENTICAL) && + opline->op1.var == (opline-1)->result.var) { + int var; + zval *val; + uint32_t type_mask; + if ((opline-1)->op1_type == IS_CV && (opline-1)->op2_type == IS_CONST) { + var = EX_VAR_TO_NUM((opline-1)->op1.var); + val = CRT_CONSTANT((opline-1)->op2); + } else if ((opline-1)->op1_type == IS_CONST && (opline-1)->op2_type == IS_CV) { + var = EX_VAR_TO_NUM((opline-1)->op2.var); + val = CRT_CONSTANT((opline-1)->op1); + } else { + continue; + } + + /* We're interested in === null/true/false comparisons here, because they eliminate + * a type in the false-branch. Other === VAL comparisons are unlikely to be useful. */ + if (Z_TYPE_P(val) != IS_NULL && Z_TYPE_P(val) != IS_TRUE && Z_TYPE_P(val) != IS_FALSE) { + continue; + } + + type_mask = _const_op_type(val); + if ((opline-1)->opcode == ZEND_IS_IDENTICAL) { + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bt, var))) { + pi_type_mask(pi, type_mask); + } + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bf, var))) { + pi_not_type_mask(pi, type_mask); + } + } else { + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bf, var))) { + pi_type_mask(pi, type_mask); + } + if ((pi = add_pi(arena, op_array, &dfg, ssa, j, bt, var))) { + pi_not_type_mask(pi, type_mask); + } + } } } diff --git a/ext/opcache/Optimizer/zend_ssa.h b/ext/opcache/Optimizer/zend_ssa.h index 0e1bc84dbc..00d6875dfd 100644 --- a/ext/opcache/Optimizer/zend_ssa.h +++ b/ext/opcache/Optimizer/zend_ssa.h @@ -38,21 +38,22 @@ typedef enum _zend_ssa_negative_lat { } zend_ssa_negative_lat; /* Special kind of SSA Phi function used in eSSA */ -typedef struct _zend_ssa_pi_range { +typedef struct _zend_ssa_pi_constraint { zend_ssa_range range; /* simple range constraint */ int min_var; int max_var; int min_ssa_var; /* ((min_var>0) ? MIN(ssa_var) : 0) + range.min */ int max_ssa_var; /* ((man_var>0) ? MAX(ssa_var) : 0) + range.man */ zend_ssa_negative_lat negative; -} zend_ssa_pi_range; + uint32_t type_mask; /* If -1 this is a range constraint */ +} zend_ssa_pi_constraint; /* SSA Phi - ssa_var = Phi(source0, source1, ...sourceN) */ typedef struct _zend_ssa_phi zend_ssa_phi; struct _zend_ssa_phi { zend_ssa_phi *next; /* next Phi in the same BB */ int pi; /* if >= 0 this is actually a e-SSA Pi */ - zend_ssa_pi_range constraint; /* e-SSA Pi constraint */ + zend_ssa_pi_constraint constraint; /* e-SSA Pi constraint */ int var; /* Original CV, VAR or TMP variable index */ int ssa_var; /* SSA variable index */ int block; /* current BB index */ diff --git a/ext/readline/config.w32 b/ext/readline/config.w32 new file mode 100644 index 0000000000..482c99cc04 --- /dev/null +++ b/ext/readline/config.w32 @@ -0,0 +1,16 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("readline", "Readline support", "yes"); + +if (PHP_READLINE != "no") { + if (CHECK_LIB("edit_a.lib;edit.lib", "readline", PHP_READLINE) && + CHECK_HEADER_ADD_INCLUDE("editline/readline.h", "CFLAGS_READLINE")) { + EXTENSION("readline", "readline.c readline_cli.c"); + ADD_FLAG("CFLAGS_READLINE", "/D HAVE_LIBEDIT"); + ADD_FLAG("CFLAGS_READLINE", "/D HAVE_RL_COMPLETION_MATCHES"); + } else { + WARNING("readline not enabled; libraries and headers not found"); + } +} + diff --git a/ext/readline/php_readline.h b/ext/readline/php_readline.h index 52dabdadeb..e3a0aba676 100644 --- a/ext/readline/php_readline.h +++ b/ext/readline/php_readline.h @@ -22,9 +22,11 @@ #define PHP_READLINE_H #if HAVE_LIBREADLINE || HAVE_LIBEDIT +#ifndef PHP_WIN32 #ifdef ZTS #warning Readline module will *NEVER* be thread-safe #endif +#endif extern zend_module_entry readline_module_entry; #define phpext_readline_ptr &readline_module_entry diff --git a/ext/readline/readline.c b/ext/readline/readline.c index ad9b01a946..0e6f849444 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -251,7 +251,9 @@ PHP_FUNCTION(readline_info) array_init(return_value); add_assoc_string(return_value,"line_buffer",SAFE_STRING(rl_line_buffer)); add_assoc_long(return_value,"point",rl_point); +#ifndef PHP_WIN32 add_assoc_long(return_value,"end",rl_end); +#endif #ifdef HAVE_LIBREADLINE add_assoc_long(return_value,"mark",rl_mark); add_assoc_long(return_value,"done",rl_done); @@ -262,7 +264,9 @@ PHP_FUNCTION(readline_info) #if HAVE_ERASE_EMPTY_LINE add_assoc_long(return_value,"erase_empty_line",rl_erase_empty_line); #endif +#ifndef PHP_WIN32 add_assoc_string(return_value,"library_version",(char *)SAFE_STRING(rl_library_version)); +#endif add_assoc_string(return_value,"readline_name",(char *)SAFE_STRING(rl_readline_name)); add_assoc_long(return_value,"attempted_completion_over",rl_attempted_completion_over); } else { @@ -276,8 +280,10 @@ PHP_FUNCTION(readline_info) RETVAL_STRING(SAFE_STRING(oldstr)); } else if (!strcasecmp(what, "point")) { RETVAL_LONG(rl_point); +#ifndef PHP_WIN32 } else if (!strcasecmp(what, "end")) { RETVAL_LONG(rl_end); +#endif #ifdef HAVE_LIBREADLINE } else if (!strcasecmp(what, "mark")) { RETVAL_LONG(rl_mark); @@ -309,8 +315,10 @@ PHP_FUNCTION(readline_info) } RETVAL_LONG(oldval); #endif +#ifndef PHP_WIN32 } else if (!strcasecmp(what,"library_version")) { RETVAL_STRING((char *)SAFE_STRING(rl_library_version)); +#endif } else if (!strcasecmp(what, "readline_name")) { oldstr = (char*)rl_readline_name; if (value) { diff --git a/ext/readline/readline_cli.c b/ext/readline/readline_cli.c index 0cdf9f4ae8..6f4e47d42b 100644 --- a/ext/readline/readline_cli.c +++ b/ext/readline/readline_cli.c @@ -19,6 +19,10 @@ /* $Id$ */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "php.h" #ifndef HAVE_RL_COMPLETION_MATCHES @@ -63,7 +67,7 @@ #include "sapi/cli/cli.h" #include "readline_cli.h" -#ifdef COMPILE_DL_READLINE +#if defined(COMPILE_DL_READLINE) && !defined(PHP_WIN32) #include <dlfcn.h> #endif @@ -598,9 +602,15 @@ static int readline_shell_run(void) /* {{{ */ zend_execute_scripts(ZEND_REQUIRE, NULL, 1, prepend_file_p); } +#ifndef PHP_WIN32 history_file = tilde_expand("~/.php_history"); +#else + spprintf(&history_file, MAX_PATH, "%s/.php_history", getenv("USERPROFILE")); +#endif rl_attempted_completion_function = cli_code_completion; +#ifndef PHP_WIN32 rl_special_prefixes = "$"; +#endif read_history(history_file); EG(exit_status) = 0; @@ -686,13 +696,33 @@ static int readline_shell_run(void) /* {{{ */ php_last_char = '\0'; } +#ifdef PHP_WIN32 + efree(history_file); +#else free(history_file); +#endif efree(code); zend_string_release(prompt); return EG(exit_status); } /* }}} */ +#ifdef PHP_WIN32 +typedef cli_shell_callbacks_t *(__cdecl *get_cli_shell_callbacks)(void); +#define GET_SHELL_CB(cb) \ + do { \ + get_cli_shell_callbacks get_callbacks; \ + HMODULE hMod = GetModuleHandle("php.exe"); \ + (cb) = NULL; \ + if (strlen(sapi_module.name) >= 3 && 0 == strncmp("cli", sapi_module.name, 3)) { \ + get_callbacks = (get_cli_shell_callbacks)GetProcAddress(hMod, "php_cli_get_shell_callbacks"); \ + if (get_callbacks) { \ + (cb) = get_callbacks(); \ + } \ + } \ + } while(0) + +#else /* #ifdef COMPILE_DL_READLINE This dlsym() is always used as even the CGI SAPI is linked against "CLI"-only @@ -711,6 +741,7 @@ this extension sharedto offer compatibility. /*#else #define GET_SHELL_CB(cb) (cb) = php_cli_get_shell_callbacks() #endif*/ +#endif PHP_MINIT_FUNCTION(cli_readline) { @@ -755,7 +786,11 @@ PHP_MINFO_FUNCTION(cli_readline) { php_info_print_table_start(); php_info_print_table_header(2, "Readline Support", "enabled"); +#ifdef PHP_WIN32 + php_info_print_table_row(2, "Readline library", "WinEditLine"); +#else php_info_print_table_row(2, "Readline library", (rl_library_version ? rl_library_version : "Unknown")); +#endif php_info_print_table_end(); DISPLAY_INI_ENTRIES(); diff --git a/ext/readline/tests/libedit_info_001-win32.phpt b/ext/readline/tests/libedit_info_001-win32.phpt new file mode 100644 index 0000000000..5d43921c60 --- /dev/null +++ b/ext/readline/tests/libedit_info_001-win32.phpt @@ -0,0 +1,42 @@ +--TEST-- +readline_info(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline")) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php + +var_dump(readline_info()); +var_dump(readline_info(1)); +var_dump(readline_info(1,1)); +var_dump(readline_info('line_buffer')); +var_dump(readline_info('readline_name')); +var_dump(readline_info('readline_name', 1)); +var_dump(readline_info('readline_name')); +var_dump(readline_info('attempted_completion_over',1)); +var_dump(readline_info('attempted_completion_over')); + +?> +--EXPECTF-- +array(4) { + ["line_buffer"]=> + string(0) "" + ["point"]=> + int(0) + ["readline_name"]=> + string(0) "" + ["attempted_completion_over"]=> + int(0) +} +NULL +NULL +string(0) "" +string(0) "" +string(0) "" +string(1) "1" +int(0) +int(1) diff --git a/ext/readline/tests/libedit_info_001.phpt b/ext/readline/tests/libedit_info_001.phpt index 1d79f4ad0c..33dc144add 100644 --- a/ext/readline/tests/libedit_info_001.phpt +++ b/ext/readline/tests/libedit_info_001.phpt @@ -3,6 +3,9 @@ readline_info(): Basic test --SKIPIF-- <?php if (!extension_loaded("readline")) die("skip"); if (READLINE_LIB != "libedit") die("skip libedit only"); +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip not for windows'); +} ?> --FILE-- <?php diff --git a/ext/readline/tests/libedit_write_history_001-win32.phpt b/ext/readline/tests/libedit_write_history_001-win32.phpt new file mode 100644 index 0000000000..28af4cbfdd --- /dev/null +++ b/ext/readline/tests/libedit_write_history_001-win32.phpt @@ -0,0 +1,29 @@ +--TEST-- +readline_write_history(): Basic test +--SKIPIF-- +<?php if (!extension_loaded("readline") || !function_exists('readline_add_history')) die("skip"); +if (READLINE_LIB != "libedit") die("skip libedit only"); +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php + +$name = tempnam(sys_get_temp_dir(), 'readline.tmp'); + +readline_add_history('foo'); +readline_add_history(''); +readline_add_history(1); +readline_add_history(NULL); +readline_write_history($name); + +var_dump(file_get_contents($name)); + +unlink($name); + +?> +--EXPECT-- +string(6) "foo +1 +" diff --git a/ext/readline/tests/libedit_write_history_001.phpt b/ext/readline/tests/libedit_write_history_001.phpt index e9b6dbee8d..14c3282e6d 100644 --- a/ext/readline/tests/libedit_write_history_001.phpt +++ b/ext/readline/tests/libedit_write_history_001.phpt @@ -3,6 +3,9 @@ readline_write_history(): Basic test --SKIPIF-- <?php if (!extension_loaded("readline") || !function_exists('readline_add_history')) die("skip"); if (READLINE_LIB != "libedit") die("skip libedit only"); +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip not for windows'); +} ?> --FILE-- <?php diff --git a/ext/session/mod_user.c b/ext/session/mod_user.c index e6f162855a..c7c09ff781 100644 --- a/ext/session/mod_user.c +++ b/ext/session/mod_user.c @@ -85,7 +85,16 @@ PS_OPEN_FUNC(user) ZVAL_STRING(&args[0], (char*)save_path); ZVAL_STRING(&args[1], (char*)session_name); - ps_call_handler(&PSF(open), 2, args, &retval); + zend_try { + ps_call_handler(&PSF(open), 2, args, &retval); + } zend_catch { + PS(session_status) = php_session_none; + if (!Z_ISUNDEF(retval)) { + zval_ptr_dtor(&retval); + } + zend_bailout(); + } zend_end_try(); + PS(mod_user_implemented) = 1; FINISH; diff --git a/ext/session/mod_user_class.c b/ext/session/mod_user_class.c index 59b44f5f6f..a774d4bf9c 100644 --- a/ext/session/mod_user_class.c +++ b/ext/session/mod_user_class.c @@ -22,6 +22,10 @@ #include "php_session.h" #define PS_SANITY_CHECK \ + if (PS(session_status) != php_session_active) { \ + php_error_docref(NULL, E_WARNING, "Session is not active"); \ + RETURN_FALSE; \ + } \ if (PS(default_mod) == NULL) { \ php_error_docref(NULL, E_CORE_ERROR, "Cannot call default session handler"); \ RETURN_FALSE; \ @@ -40,6 +44,7 @@ PHP_METHOD(SessionHandler, open) { char *save_path = NULL, *session_name = NULL; size_t save_path_len, session_name_len; + int ret; PS_SANITY_CHECK; @@ -48,7 +53,15 @@ PHP_METHOD(SessionHandler, open) } PS(mod_user_is_open) = 1; - RETVAL_BOOL(SUCCESS == PS(default_mod)->s_open(&PS(mod_data), save_path, session_name)); + + zend_try { + ret = PS(default_mod)->s_open(&PS(mod_data), save_path, session_name); + } zend_catch { + PS(session_status) = php_session_none; + zend_bailout(); + } zend_end_try(); + + RETVAL_BOOL(SUCCESS == ret); } /* }}} */ @@ -56,6 +69,8 @@ PHP_METHOD(SessionHandler, open) Wraps the old close handler */ PHP_METHOD(SessionHandler, close) { + int ret; + PS_SANITY_CHECK_IS_OPEN; // don't return on failure, since not closing the default handler @@ -63,7 +78,15 @@ PHP_METHOD(SessionHandler, close) zend_parse_parameters_none(); PS(mod_user_is_open) = 0; - RETVAL_BOOL(SUCCESS == PS(default_mod)->s_close(&PS(mod_data))); + + zend_try { + ret = PS(default_mod)->s_close(&PS(mod_data)); + } zend_catch { + PS(session_status) = php_session_none; + zend_bailout(); + } zend_end_try(); + + RETVAL_BOOL(SUCCESS == ret); } /* }}} */ diff --git a/ext/session/session.c b/ext/session/session.c index f5a399b75f..22a7ec125d 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -103,6 +103,7 @@ static void php_session_abort(void); static inline void php_rinit_session_globals(void) /* {{{ */ { /* Do NOT init PS(mod_user_names) here! */ + /* TODO: These could be moved to MINIT and removed. These should be initialized by php_rshutdown_session_globals() always when execution is finished. */ PS(id) = NULL; PS(session_status) = php_session_none; PS(mod_data) = NULL; @@ -130,10 +131,15 @@ static inline void php_rshutdown_session_globals(void) /* {{{ */ zend_string_release(PS(id)); PS(id) = NULL; } + if (PS(session_vars)) { zend_string_release(PS(session_vars)); PS(session_vars) = NULL; } + + /* User save handlers may end up directly here by misuse, bugs in user script, etc. */ + /* Set session status to prevent error while restoring save handler INI value. */ + PS(session_status) = php_session_none; } /* }}} */ @@ -522,7 +528,10 @@ static void php_session_initialize(void) /* {{{ */ } /* If there is no ID, use session module to create one */ - if (!PS(id)) { + if (!PS(id) || !ZSTR_VAL(PS(id))[0]) { + if (PS(id)) { + zend_string_release(PS(id)); + } PS(id) = PS(mod)->s_create_sid(&PS(mod_data)); if (!PS(id)) { php_session_abort(); @@ -602,11 +611,16 @@ static void php_session_save_current_state(int write) /* {{{ */ } if ((ret == FAILURE) && !EG(exception)) { - php_error_docref(NULL, E_WARNING, "Failed to write session data (%s). Please " - "verify that the current setting of session.save_path " - "is correct (%s)", - PS(mod)->s_name, - PS(save_path)); + if (!PS(mod_user_implemented)) { + php_error_docref(NULL, E_WARNING, "Failed to write session data (%s). Please " + "verify that the current setting of session.save_path " + "is correct (%s)", + PS(mod)->s_name, + PS(save_path)); + } else { + php_error_docref(NULL, E_WARNING, "Failed to write session data using user " + "defined save handler. (session.save_path: %s)", PS(save_path)); + } } } } @@ -1107,7 +1121,7 @@ static ps_serializer ps_serializers[MAX_SERIALIZERS + 1] = { PHPAPI int php_session_register_serializer(const char *name, zend_string *(*encode)(PS_SERIALIZER_ENCODE_ARGS), int (*decode)(PS_SERIALIZER_DECODE_ARGS)) /* {{{ */ { - int ret = -1; + int ret = FAILURE; int i; for (i = 0; i < MAX_SERIALIZERS; i++) { @@ -1116,7 +1130,7 @@ PHPAPI int php_session_register_serializer(const char *name, zend_string *(*enco ps_serializers[i].encode = encode; ps_serializers[i].decode = decode; ps_serializers[i + 1].name = NULL; - ret = 0; + ret = SUCCESS; break; } } @@ -1138,13 +1152,13 @@ static ps_module *ps_modules[MAX_MODULES + 1] = { PHPAPI int php_session_register_module(ps_module *ptr) /* {{{ */ { - int ret = -1; + int ret = FAILURE; int i; for (i = 0; i < MAX_MODULES; i++) { if (!ps_modules[i]) { ps_modules[i] = ptr; - ret = 0; + ret = SUCCESS; break; } } @@ -1659,8 +1673,8 @@ PHPAPI void php_session_start(void) /* {{{ */ static void php_session_flush(int write) /* {{{ */ { if (PS(session_status) == php_session_active) { - PS(session_status) = php_session_none; php_session_save_current_state(write); + PS(session_status) = php_session_none; } } /* }}} */ @@ -1668,10 +1682,10 @@ static void php_session_flush(int write) /* {{{ */ static void php_session_abort(void) /* {{{ */ { if (PS(session_status) == php_session_active) { - PS(session_status) = php_session_none; if (PS(mod_data) || PS(mod_user_implemented)) { PS(mod)->s_close(&PS(mod_data)); } + PS(session_status) = php_session_none; } } /* }}} */ @@ -2046,13 +2060,13 @@ static PHP_FUNCTION(session_regenerate_id) return; } - if (SG(headers_sent) && PS(use_cookies)) { - php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - headers already sent"); + if (PS(session_status) != php_session_active) { + php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - session is not active"); RETURN_FALSE; } - if (PS(session_status) != php_session_active) { - php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - session is not active"); + if (SG(headers_sent) && PS(use_cookies)) { + php_error_docref(NULL, E_WARNING, "Cannot regenerate session id - headers already sent"); RETURN_FALSE; } @@ -2104,6 +2118,7 @@ static PHP_FUNCTION(session_regenerate_id) zend_string_release(PS(id)); PS(id) = PS(mod)->s_create_sid(&PS(mod_data)); if (!PS(id)) { + PS(mod)->s_close(&PS(mod_data)); PS(session_status) = php_session_none; php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create session ID by collision: %s (path: %s)", PS(mod)->s_name, PS(save_path)); RETURN_FALSE; @@ -2111,6 +2126,7 @@ static PHP_FUNCTION(session_regenerate_id) } /* Read is required to make new session data at this point. */ if (PS(mod)->s_read(&PS(mod_data), PS(id), &data, PS(gc_maxlifetime)) == FAILURE) { + PS(mod)->s_close(&PS(mod_data)); PS(session_status) = php_session_none; php_error_docref(NULL, E_RECOVERABLE_ERROR, "Failed to create(read) session ID: %s (path: %s)", PS(mod)->s_name, PS(save_path)); RETURN_FALSE; @@ -2282,11 +2298,6 @@ static PHP_FUNCTION(session_start) RETURN_FALSE; } - if (PS(id) && !(ZSTR_LEN(PS(id)))) { - php_error_docref(NULL, E_WARNING, "Cannot start session with empty session ID"); - RETURN_FALSE; - } - /* set options */ if (options) { ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), num_idx, str_idx, value) { diff --git a/ext/session/tests/bug55688.phpt b/ext/session/tests/bug55688.phpt index 8db48384af..b073dc3c5c 100644 --- a/ext/session/tests/bug55688.phpt +++ b/ext/session/tests/bug55688.phpt @@ -12,4 +12,4 @@ $x = new SessionHandler; $x->gc(1); ?> --EXPECTF-- -Warning: SessionHandler::gc(): Parent session handler is not open in %s on line %d +Warning: SessionHandler::gc(): Session is not active in %s on line %d diff --git a/ext/session/tests/bug60634.phpt b/ext/session/tests/bug60634.phpt index 86dcb11526..b2f5076287 100644 --- a/ext/session/tests/bug60634.phpt +++ b/ext/session/tests/bug60634.phpt @@ -39,8 +39,17 @@ session_start(); session_write_close(); echo "um, hi\n"; +/* +FIXME: Since session module try to write/close session data in +RSHUTDOWN, write() is executed twices. This is caused by undefined +function error and zend_bailout(). Current session module codes +depends on this behavior. These codes should be modified to remove +multiple write(). +*/ + ?> --EXPECTF-- write: goodbye cruel world +write: goodbye cruel world close: goodbye cruel world diff --git a/ext/session/tests/bug60634_error_1.phpt b/ext/session/tests/bug60634_error_1.phpt index d0733f5a5a..fa76ff522a 100644 --- a/ext/session/tests/bug60634_error_1.phpt +++ b/ext/session/tests/bug60634_error_1.phpt @@ -41,6 +41,11 @@ session_start(); session_write_close(); echo "um, hi\n"; +/* +FIXME: Something wrong. It should try to close after error, otherwise session +may keep "open" state. +*/ + ?> --EXPECTF-- write: goodbye cruel world @@ -51,3 +56,4 @@ Stack trace: #1 %s(%d): session_write_close() #2 {main} thrown in %s on line %d + diff --git a/ext/session/tests/bug67972.phpt b/ext/session/tests/bug67972.phpt index 63ed3a95b8..92c3044ac5 100644 --- a/ext/session/tests/bug67972.phpt +++ b/ext/session/tests/bug67972.phpt @@ -7,4 +7,5 @@ Bug #67972: SessionHandler Invalid memory read create_sid() (new SessionHandler)->create_sid(); --EXPECTF-- -Fatal error: SessionHandler::create_sid(): Cannot call default session handler in %s on line %d +Warning: SessionHandler::create_sid(): Session is not active in %s on line %d + diff --git a/ext/session/tests/bug68063.phpt b/ext/session/tests/bug68063.phpt index d3da470d06..ec3a70d156 100644 --- a/ext/session/tests/bug68063.phpt +++ b/ext/session/tests/bug68063.phpt @@ -3,18 +3,22 @@ Bug #68063 (Empty session IDs do still start sessions) --SKIPIF-- <?php include('skipif.inc'); ?> --INI-- +session.use_strict_mode=0 +session.hash_function=1 +session.hash_bits_per_character=4 --FILE-- <?php +// Empty session ID may happen by browser bugs + // Could also be set with a cookie like "PHPSESSID=; path=/" session_id(''); -// Will still start the session and return true +// Start the session with empty string should result in new session ID var_dump(session_start()); -// Returns an empty string +// Returns newly created session ID var_dump(session_id()); ?> --EXPECTF-- -Warning: session_start(): Cannot start session with empty session ID in %s on line %d -bool(false) -string(0) "" +bool(true) +string(40) "%s" diff --git a/ext/session/tests/bug69111.phpt b/ext/session/tests/bug69111.phpt new file mode 100644 index 0000000000..f5def0ed35 --- /dev/null +++ b/ext/session/tests/bug69111.phpt @@ -0,0 +1,36 @@ +--TEST-- +Bug #69111 (Crash in SessionHandler::read()) +--INI-- +session.save_path= +session.save_handler=files +session.name=PHPSESSID +--SKIPIF-- +<?php include('skipif.inc'); ?> +--FILE-- +<?php +$sh = new SessionHandler; +session_set_save_handler($sh); + +$savePath = ini_get('session.save_path'); +$sessionName = ini_get('session.name'); + +// session_start(); // Uncommenting this makes it not crash when reading the session (see below), but it will not return any data. + +$sh->open($savePath, $sessionName); +$sh->write("foo", "bar"); +$sh->read($id); +$sh->gc(1245); +$sh->close(); +?> +--EXPECTF-- +Warning: SessionHandler::open(): Session is not active in %s on line 10 + +Warning: SessionHandler::write(): Session is not active in %s on line 11 + +Notice: Undefined variable: id in %s on line 12 + +Warning: SessionHandler::read(): Session is not active in %s on line 12 + +Warning: SessionHandler::gc(): Session is not active in %s on line 13 + +Warning: SessionHandler::close(): Session is not active in %s on line 14
\ No newline at end of file diff --git a/ext/session/tests/bug70133.phpt b/ext/session/tests/bug70133.phpt new file mode 100644 index 0000000000..3e019e483b --- /dev/null +++ b/ext/session/tests/bug70133.phpt @@ -0,0 +1,41 @@ +--TEST-- +Bug #70133 (Extended SessionHandler::read is ignoring $session_id when calling parent) +--SKIPIF-- +<?php include('skipif.inc'); ?> +--INI-- +session.save_handler=files +session.save_path= +session.use_strict_mode=0 +--FILE-- +<?php + +class CustomReadHandler extends \SessionHandler { + + public function read($session_id) { + return parent::read('mycustomsession'); + } +} + +ob_start(); + +session_set_save_handler(new CustomReadHandler(), true); + +session_id('mycustomsession'); +session_start(); +$_SESSION['foo'] = 'hoge'; +var_dump(session_id()); +session_commit(); + +session_id('otherid'); +session_start(); +var_dump($_SESSION); +var_dump(session_id()); + +?> +--EXPECT-- +string(15) "mycustomsession" +array(1) { + ["foo"]=> + string(4) "hoge" +} +string(7) "otherid" diff --git a/ext/session/tests/sessionhandler_open_001.phpt b/ext/session/tests/sessionhandler_open_001.phpt index 6ade9e00a5..e6e913a6a5 100644 --- a/ext/session/tests/sessionhandler_open_001.phpt +++ b/ext/session/tests/sessionhandler_open_001.phpt @@ -16,4 +16,11 @@ print "Done!\n"; ?> --EXPECTF-- +Warning: SessionHandler::open(): Session is not active in %s on line 5 + +Warning: SessionHandler::open(): Session is not active in %s on line 6 + +Warning: SessionHandler::open(): Session is not active in %s on line 7 + +Warning: SessionHandler::open(): Session is not active in %s on line 8 Done! diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 49fc72d68f..ee41ff908f 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -2135,7 +2135,7 @@ static void soap_error_handler(int error_num, const char *error_filename, const _old_http_response_code = SG(sapi_headers).http_response_code; _old_http_status_line = SG(sapi_headers).http_status_line; - if (!SOAP_GLOBAL(use_soap_error_handler) || !EG(objects_store).object_buckets) { + if (!PG(modules_activated) || !SOAP_GLOBAL(use_soap_error_handler) || !EG(objects_store).object_buckets) { call_old_error_handler(error_num, error_filename, error_lineno, format, args); return; } diff --git a/ext/sockets/tests/socket_clear_error-win32.phpt b/ext/sockets/tests/socket_clear_error-win32.phpt new file mode 100644 index 0000000000..3a0b1ea162 --- /dev/null +++ b/ext/sockets/tests/socket_clear_error-win32.phpt @@ -0,0 +1,32 @@ +--TEST-- +void socket_clear_error ([ resource $socket ] ) ; +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao paulo - br +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +$socketConn = socket_connect($socket, "127.0.0.1", 21248); +var_dump(socket_last_error($socket)); +socket_clear_error($socket); +var_dump(socket_last_error($socket)); +?> +--CLEAN-- +<?php +socket_close($socket); +unset($socket); +unset($socketConn); +?> +--EXPECTF-- +Warning: socket_connect(): unable to connect [%d]: No connection could be made because the target machine actively refused it. + in %s on line %d +int(%d) +int(%d) diff --git a/ext/sockets/tests/socket_clear_error.phpt b/ext/sockets/tests/socket_clear_error.phpt index af9acaa9bf..273f7a0ca8 100644 --- a/ext/sockets/tests/socket_clear_error.phpt +++ b/ext/sockets/tests/socket_clear_error.phpt @@ -7,6 +7,9 @@ marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao p if (!extension_loaded('sockets')) { die('SKIP sockets extension not available.'); } +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip windows only test'); +} ?> --FILE-- <?php diff --git a/ext/sockets/tests/socket_send.phpt b/ext/sockets/tests/socket_send.phpt index 1411868c4b..ceeb397979 100644 --- a/ext/sockets/tests/socket_send.phpt +++ b/ext/sockets/tests/socket_send.phpt @@ -7,6 +7,9 @@ marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao p if (!extension_loaded('sockets')) { die('SKIP sockets extension not available.'); } +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip not for windows'); +} ?> --FILE-- <?php diff --git a/ext/sockets/tests/socket_send_win32.phpt b/ext/sockets/tests/socket_send_win32.phpt new file mode 100644 index 0000000000..04a985c781 --- /dev/null +++ b/ext/sockets/tests/socket_send_win32.phpt @@ -0,0 +1,43 @@ +--TEST-- +int socket_send ( resource $socket , string $buf , int $len , int $flags ); +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao paulo - br +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php +$port = 80; +$host = "yahoo.com"; +$stringSocket = "send_socket_to_connected_socket"; +$stringSocketLenght = strlen($stringSocket); + +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +$socketConn = socket_connect($socket, $host, $port); + +if(socket_send($socket, $stringSocket, $stringSocketLenght, MSG_OOB)===$stringSocketLenght){ + print("okey\n"); +} + +if(socket_send($socket, $stringSocket, $stringSocketLenght, MSG_DONTROUTE)===$stringSocketLenght){ + print("okey\n"); +} +?> +<?php +socket_close($socket); +unset($port); +unset($host); +unset($stringSocket); +unset($stringSocketLenght); +unset($socket); +unset($socketConn); +?> +--EXPECTF-- +okey +okey diff --git a/ext/sockets/tests/socket_shutdown-win32.phpt b/ext/sockets/tests/socket_shutdown-win32.phpt new file mode 100644 index 0000000000..6280e61044 --- /dev/null +++ b/ext/sockets/tests/socket_shutdown-win32.phpt @@ -0,0 +1,59 @@ +--TEST-- +bool socket_shutdown ( resource $socket [, int $how = 2 ] ) ; +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao paulo - br +--SKIPIF-- +<?php +if (!extension_loaded('sockets')) { + die('SKIP sockets extension not available.'); +} +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php +$host = "yahoo.com"; +$port = 80; + +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +$socketConn = socket_connect($socket, $host, $port); +var_dump(socket_shutdown($socket,0)); +socket_close($socket); + +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +$socketConn = socket_connect($socket, $host, $port); +var_dump(socket_shutdown($socket,1)); +socket_close($socket); + +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +$socketConn = socket_connect($socket, $host, $port); +var_dump(socket_shutdown($socket,2)); +socket_close($socket); + +$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); +var_dump(socket_shutdown($socket,0)); + +$socketConn = socket_connect($socket, $host, $port); +var_dump(socket_shutdown($socket,-1)); +socket_close($socket); +?> +--CLEAN-- +<?php +unset($host); +unset($port); +unset($socket); +unset($socketConn); +?> +--EXPECTF-- +bool(true) +bool(true) +bool(true) + +Warning: socket_shutdown(): unable to shutdown socket [%d]: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied. + in %s on line %d +bool(false) + +Warning: socket_shutdown(): unable to shutdown socket [%d]: An invalid argument was supplied. + in %s on line %d +bool(false) diff --git a/ext/sockets/tests/socket_shutdown.phpt b/ext/sockets/tests/socket_shutdown.phpt index 09f5ac73fc..77cbc8f32c 100644 --- a/ext/sockets/tests/socket_shutdown.phpt +++ b/ext/sockets/tests/socket_shutdown.phpt @@ -7,6 +7,9 @@ marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao p if (!extension_loaded('sockets')) { die('SKIP sockets extension not available.'); } +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip not for windows'); +} ?> --FILE-- <?php diff --git a/ext/standard/math.c b/ext/standard/math.c index 7ea8dc1199..ebfee8ead8 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -146,6 +146,7 @@ PHPAPI double _php_math_round(double value, int places, int mode) { return value; } + places = places < INT_MIN+1 ? INT_MIN+1 : places; precision_places = 14 - php_intlog10abs(value); f1 = php_intpow10(abs(places)); @@ -154,8 +155,10 @@ PHPAPI double _php_math_round(double value, int places, int mode) { the requested places BUT is small enough to make sure a non-zero value is returned, pre-round the result to the precision */ if (precision_places > places && precision_places - places < 15) { - f2 = php_intpow10(abs(precision_places)); - if (precision_places >= 0) { + int64_t use_precision = precision_places < INT_MIN+1 ? INT_MIN+1 : precision_places; + + f2 = php_intpow10(abs((int)use_precision)); + if (use_precision >= 0) { tmp_value = value * f2; } else { tmp_value = value / f2; @@ -163,8 +166,11 @@ PHPAPI double _php_math_round(double value, int places, int mode) { /* preround the result (tmp_value will always be something * 1e14, thus never larger than 1e15 here) */ tmp_value = php_round_helper(tmp_value, mode); + + use_precision = places - precision_places; + use_precision = use_precision < INT_MIN+1 ? INT_MIN+1 : use_precision; /* now correctly move the decimal point */ - f2 = php_intpow10(abs(places - precision_places)); + f2 = php_intpow10(abs((int)use_precision)); /* because places < precision_places */ tmp_value = tmp_value / f2; } else { diff --git a/ext/standard/tests/streams/stream_socket_enable_crypto-win32.phpt b/ext/standard/tests/streams/stream_socket_enable_crypto-win32.phpt new file mode 100644 index 0000000000..2f78f4a4b5 --- /dev/null +++ b/ext/standard/tests/streams/stream_socket_enable_crypto-win32.phpt @@ -0,0 +1,69 @@ +--TEST-- +mixed stream_socket_enable_crypto(resource $stream , bool $enable [, int $crypto_type [, resource $session_stream ]] ) ; +--CREDITS-- +marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao paulo - br +--SKIPIF-- +<?php +if (phpversion() < "5.3.0") { die('SKIP php version so lower.'); } +if (!extension_loaded('openssl')) { die('ext/openssl required'); } +if(substr(PHP_OS, 0, 3) != 'WIN' ) { + die('skip windows only test'); +} +?> +--FILE-- +<?php +$serverUri = "tcp://127.0.0.1:31854"; +$sock = stream_socket_server($serverUri, $errno, $errstr); + +if (is_resource($sock)) { + var_dump(stream_socket_enable_crypto($sock, false)); + var_dump(stream_socket_enable_crypto($sock, true)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv2_CLIENT)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv3_CLIENT)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv2_SERVER)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv3_SERVER)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_SSLv23_SERVER)); + var_dump(stream_socket_enable_crypto($sock, true, STREAM_CRYPTO_METHOD_TLS_SERVER)); +} else { + die("Test stream_socket_enable_crypto has failed; Unable to connect: {$errstr} ({$errno})"); +} +?> +--CLEAN-- +<?php +unset($serverUri); +unset($sock); +unset($errno); +unset($errstr); +?> +--EXPECTF-- +bool(false) + +Warning: stream_socket_enable_crypto(): When enabling encryption you must specify the crypto type in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSLv2 unavailable in the OpenSSL library against which PHP is linked in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied. + in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) + +Warning: stream_socket_enable_crypto(): SSL/TLS already set-up for this stream in %s on line %d +bool(false) diff --git a/ext/standard/tests/streams/stream_socket_enable_crypto.phpt b/ext/standard/tests/streams/stream_socket_enable_crypto.phpt index 47d6c62893..e316096525 100644 --- a/ext/standard/tests/streams/stream_socket_enable_crypto.phpt +++ b/ext/standard/tests/streams/stream_socket_enable_crypto.phpt @@ -6,6 +6,9 @@ marcosptf - <marcosptf@yahoo.com.br> - #phparty7 - @phpsp - novatec/2015 - sao p <?php if (phpversion() < "5.3.0") { die('SKIP php version so lower.'); } if (!extension_loaded('openssl')) { die('ext/openssl required'); } +if(substr(PHP_OS, 0, 3) == 'WIN' ) { + die('skip not for windows'); +} ?> --FILE-- <?php diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index d9d6e76a8d..4e092cb0ea 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -35,6 +35,7 @@ #ifdef PHP_WIN32 # include "win32/time.h" # include "win32/signal.h" +# include "win32/winutil.h" # include <process.h> #endif @@ -224,8 +225,10 @@ static php_cgi_globals_struct php_cgi_globals; #ifdef PHP_WIN32 #define WIN32_MAX_SPAWN_CHILDREN 64 -HANDLE win32_kid_cgi_ps[WIN32_MAX_SPAWN_CHILDREN]; -int win32_kids; +HANDLE kid_cgi_ps[WIN32_MAX_SPAWN_CHILDREN]; +int kids; +HANDLE job = NULL; +JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { 0 }; #endif #ifndef HAVE_ATTRIBUTE_WEAK @@ -1436,16 +1439,20 @@ void fastcgi_cleanup(int signal) #else BOOL fastcgi_cleanup(DWORD sig) { - int i = win32_kids; + int i = kids; while (0 < i--) { - if (NULL == win32_kid_cgi_ps[i]) { + if (NULL == kid_cgi_ps[i]) { continue; } - TerminateProcess(win32_kid_cgi_ps[i], 0); - CloseHandle(win32_kid_cgi_ps[i]); - win32_kid_cgi_ps[i] = NULL; + TerminateProcess(kid_cgi_ps[i], 0); + CloseHandle(kid_cgi_ps[i]); + kid_cgi_ps[i] = NULL; + } + + if (job) { + CloseHandle(job); } parent = 0; @@ -2109,35 +2116,54 @@ consult the installation file that came with this distribution, or visit \n\ char my_name[MAX_PATH] = {0}; int i; - ZeroMemory(&win32_kid_cgi_ps, sizeof(win32_kid_cgi_ps)); - win32_kids = children < WIN32_MAX_SPAWN_CHILDREN ? children : WIN32_MAX_SPAWN_CHILDREN; + ZeroMemory(&kid_cgi_ps, sizeof(kid_cgi_ps)); + kids = children < WIN32_MAX_SPAWN_CHILDREN ? children : WIN32_MAX_SPAWN_CHILDREN; SetConsoleCtrlHandler(fastcgi_cleanup, TRUE); - SetEnvironmentVariable("PHP_FCGI_CHILDREN", NULL); /* kids will inherit the env, don't let them spawn */ + /* kids will inherit the env, don't let them spawn */ + SetEnvironmentVariable("PHP_FCGI_CHILDREN", NULL); GetModuleFileName(NULL, my_name, MAX_PATH); cmd_line = my_name; + job = CreateJobObject(NULL, NULL); + if (!job) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to create job object: [0x%08lx]: %s\n", err, err_text); + + goto parent_out; + } + + job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info))) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to configure job object: [0x%08lx]: %s\n", err, err_text); + } + while (parent) { - i = win32_kids; + i = kids; while (0 < i--) { DWORD status; - if (NULL != win32_kid_cgi_ps[i]) { - if(!GetExitCodeProcess(win32_kid_cgi_ps[i], &status) || status != STILL_ACTIVE) { - CloseHandle(win32_kid_cgi_ps[i]); - win32_kid_cgi_ps[i] = NULL; + if (NULL != kid_cgi_ps[i]) { + if(!GetExitCodeProcess(kid_cgi_ps[i], &status) || status != STILL_ACTIVE) { + CloseHandle(kid_cgi_ps[i]); + kid_cgi_ps[i] = NULL; } } } - i = win32_kids; + i = kids; while (0 < i--) { PROCESS_INFORMATION pi; STARTUPINFO si; - if (NULL != win32_kid_cgi_ps[i]) { + if (NULL != kid_cgi_ps[i]) { continue; } @@ -2151,31 +2177,30 @@ consult the installation file that came with this distribution, or visit \n\ si.hStdError = INVALID_HANDLE_VALUE; if (CreateProcess(NULL, cmd_line, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { - win32_kid_cgi_ps[i] = pi.hProcess; + kid_cgi_ps[i] = pi.hProcess; + if (!AssignProcessToJobObject(job, pi.hProcess)) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to assign child process to job object: [0x%08lx]: %s\n", err, err_text); + } CloseHandle(pi.hThread); } else { DWORD err = GetLastError(); - char *err_text; - - win32_kid_cgi_ps[i] = NULL; - - (void)FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY, - NULL, - err, - LANG_NEUTRAL, - (LPTSTR)&err_text, - 0, - NULL); - + char *err_text = php_win32_error_to_msg(err); + + kid_cgi_ps[i] = NULL; + fprintf(stderr, "unable to spawn: [0x%08lx]: %s\n", err, err_text); } } - WaitForMultipleObjects(win32_kids, win32_kid_cgi_ps, FALSE, INFINITE); + WaitForMultipleObjects(kids, kid_cgi_ps, FALSE, INFINITE); } snprintf(kid_buf, 16, "%d", children); - SetEnvironmentVariable("PHP_FCGI_CHILDREN", kid_buf); /* restore my env */ + /* restore my env */ + SetEnvironmentVariable("PHP_FCGI_CHILDREN", kid_buf); goto parent_out; } else { diff --git a/sapi/cli/config.w32 b/sapi/cli/config.w32 index 664394c8a6..c6409b59df 100644 --- a/sapi/cli/config.w32 +++ b/sapi/cli/config.w32 @@ -12,6 +12,11 @@ if (PHP_CLI == "yes") { ADD_FLAG("CFLAGS_CLI", "/D PHP_WIN32_DEBUG_HEAP"); } ADD_FLAG("LDFLAGS_CLI", "/stack:67108864"); + + if (CHECK_LIB("edit_a.lib;edit.lib", "cli", PHP_CLI) && + CHECK_HEADER_ADD_INCLUDE("editline/readline.h", "CFLAGS_CLI")) { + ADD_FLAG("CFLAGS_CLI", "/D HAVE_LIBEDIT"); + } } if (PHP_CLI_WIN32 == "yes") { diff --git a/sapi/cli/tests/cli_process_title_windows.phpt b/sapi/cli/tests/cli_process_title_windows.phpt index 12eb80756d..4e81b4c634 100644 --- a/sapi/cli/tests/cli_process_title_windows.phpt +++ b/sapi/cli/tests/cli_process_title_windows.phpt @@ -21,7 +21,7 @@ if (shell_exec('PowerShell -Help') === NULL) // cli_set_process_title(). We're only making the API calls to ensure there are // no warnings/errors. -$is_windows8 = false; +$is_windows8_or_above = false; $ps_output = shell_exec("PowerShell -NoProfile \"(Get-Host).UI.RawUI.WindowTitle\""); if ($ps_output === null) { @@ -31,8 +31,8 @@ if ($ps_output === null) $ps_output = trim($ps_output); $end_title_windows8 = ": Windows PowerShell"; -if (($ps_output == "Windows PowerShell") || (strlen($ps_output) > strlen($end_title_windows8) && substr($ps_output,-strlen($end_title_windows8)) === $end_title_windows8)) - $is_windows8 = true; +if (($ps_output == "Windows PowerShell") || (strlen($ps_output) > strlen($end_title_windows8) && substr($ps_output,-strlen($end_title_windows8)) === $end_title_windows8) || PHP_WINDOWS_VERSION_MAJOR >= 10) + $is_windows8_or_above = true; echo "*** Testing setting the process title ***\n"; @@ -42,7 +42,7 @@ $pid = getmypid(); if (cli_set_process_title($original_title) === true) echo "Successfully set title\n"; -if ($is_windows8) +if ($is_windows8_or_above) { $loaded_title = $original_title; } @@ -82,4 +82,4 @@ else *** Testing setting the process title *** Successfully set title Successfully verified title using get-process -Successfully verified title using get
\ No newline at end of file +Successfully verified title using get diff --git a/win32/build/confutils.js b/win32/build/confutils.js index c2852cfd43..82b7fbc7b2 100644 --- a/win32/build/confutils.js +++ b/win32/build/confutils.js @@ -2645,6 +2645,15 @@ function toolset_setup_common_cflags() if (VCVERS >= 1900) { ADD_FLAG('CFLAGS', "/guard:cf"); } + if (VCVERS >= 1800) { + if (PHP_PGI != "yes" && PHP_PGO != "yes") { + ADD_FLAG('CFLAGS', "/Zc:inline"); + } + /* We enable /opt:icf only with the debug pack, so /Gw only makes sense there, too. */ + if (PHP_DEBUG_PACK == "yes") { + ADD_FLAG('CFLAGS', "/Gw"); + } + } } } else if (CLANG_TOOLSET) { |
