diff --git a/TSRM/tsrm_win32.c b/TSRM/tsrm_win32.c index 1fe2a47a87c24..4c8fc9d19aa9a 100644 --- a/TSRM/tsrm_win32.c +++ b/TSRM/tsrm_win32.c @@ -636,7 +636,7 @@ TSRM_API int shmget(key_t key, size_t size, int flags) {/*{{{*/ shm_pair *shm; char shm_segment[sizeof(SEGMENT_PREFIX INT_MIN_AS_STRING)]; - HANDLE shm_handle = NULL, info_handle = NULL; + HANDLE shm_handle = NULL; BOOL created = FALSE; if (key != IPC_PRIVATE) { diff --git a/UPGRADING b/UPGRADING index 9df115d1e735e..c35d9477af899 100644 --- a/UPGRADING +++ b/UPGRADING @@ -155,7 +155,7 @@ PHP 8.5 UPGRADE NOTES - Session: . session_start is stricter in regard of the option argument. - it throws a ValueError if the whole is not a hashmap or + It throws a ValueError if the whole is not a hashmap or a TypeError if read_on_close value is not a valid type compatible with int. @@ -170,7 +170,7 @@ PHP 8.5 UPGRADE NOTES . socket_create_listen, socket_bind and socket_sendto throw a ValueError if the port is lower than 0 or greater than 65535, also if any of the hints array entry is indexes numerically. - . socket_addrinfo_lookup throw a TypeError if any of the hints + . socket_addrinfo_lookup throws a TypeError if any of the hints values cannot be cast to a int and can throw a ValueError if any of these values overflow. . socket_set_option with MCAST_LEAVE_GROUP/MCAST_LEAVE_SOURCE_GROUP diff --git a/Zend/zend_operators.h b/Zend/zend_operators.h index 7ed441965ed5c..db86345b69968 100644 --- a/Zend/zend_operators.h +++ b/Zend/zend_operators.h @@ -777,11 +777,13 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL * have read the values of op1 and op2. */ + zend_long sum = (zend_long) ((zend_ulong) Z_LVAL_P(op1) + (zend_ulong) Z_LVAL_P(op2)); + if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) == (Z_LVAL_P(op2) & LONG_SIGN_MASK) - && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != ((Z_LVAL_P(op1) + Z_LVAL_P(op2)) & LONG_SIGN_MASK))) { + && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (sum & LONG_SIGN_MASK))) { ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) + (double) Z_LVAL_P(op2)); } else { - ZVAL_LONG(result, Z_LVAL_P(op1) + Z_LVAL_P(op2)); + ZVAL_LONG(result, sum); } #endif } @@ -873,11 +875,19 @@ overflow: ZEND_ATTRIBUTE_COLD_LABEL ZVAL_LONG(result, llresult); } #else - ZVAL_LONG(result, Z_LVAL_P(op1) - Z_LVAL_P(op2)); + /* + * 'result' may alias with op1 or op2, so we need to + * ensure that 'result' is not updated until after we + * have read the values of op1 and op2. + */ + + zend_long sub = (zend_long) ((zend_ulong) Z_LVAL_P(op1) - (zend_ulong) Z_LVAL_P(op2)); if (UNEXPECTED((Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(op2) & LONG_SIGN_MASK) - && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (Z_LVAL_P(result) & LONG_SIGN_MASK))) { + && (Z_LVAL_P(op1) & LONG_SIGN_MASK) != (sub & LONG_SIGN_MASK))) { ZVAL_DOUBLE(result, (double) Z_LVAL_P(op1) - (double) Z_LVAL_P(op2)); + } else { + ZVAL_LONG(result, sub); } #endif } diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 5a177457a4492..af980b7b86f2a 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -249,7 +249,6 @@ static void function_dtor(zval *zv) static PHP_FUNCTION(com_method_handler) { zval *object = getThis(); - zend_string *method = EX(func)->common.function_name; zval *args = NULL; php_com_dotnet_object *obj = CDNO_FETCH(object); int nargs; diff --git a/ext/gd/gd.c b/ext/gd/gd.c index c5f7b65ce4c8b..b712861830bc9 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -1409,7 +1409,8 @@ gdImagePtr _php_image_create_from_string(zend_string *data, const char *tn, gdIm gdImagePtr im; gdIOCtx *io_ctx; - io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(data), ZSTR_VAL(data), 0); + ZEND_ASSERT(ZSTR_LEN(data) <= INT_MAX); /* checked in imagecreatefromstring() */ + io_ctx = gdNewDynamicCtxEx((int) ZSTR_LEN(data), ZSTR_VAL(data), 0); if (!io_ctx) { return NULL; @@ -1439,6 +1440,10 @@ PHP_FUNCTION(imagecreatefromstring) Z_PARAM_STR(data) ZEND_PARSE_PARAMETERS_END(); + if (ZSTR_LEN(data) > INT_MAX) { + zend_argument_value_error(1, "is too long"); + } + imtype = _php_image_type(data); switch (imtype) { @@ -1562,17 +1567,23 @@ static void _php_image_create_from(INTERNAL_FUNCTION_PARAMETERS, int image_type, buff = php_stream_copy_to_mem(stream, PHP_STREAM_COPY_ALL, 0); if (!buff) { - php_error_docref(NULL, E_WARNING,"Cannot read image data"); + php_error_docref(NULL, E_WARNING, "Cannot read image data"); + goto out_err; + } + + if (ZSTR_LEN(buff) > INT_MAX) { + zend_string_release_ex(buff, 0); + php_error_docref(NULL, E_WARNING, "Cannot read images with more than %d bytes", INT_MAX); goto out_err; } /* needs to be malloc (persistent) - GD will free() it later */ pstr = pestrndup(ZSTR_VAL(buff), ZSTR_LEN(buff), 1); - io_ctx = gdNewDynamicCtxEx(ZSTR_LEN(buff), pstr, 0); + io_ctx = gdNewDynamicCtxEx((int) ZSTR_LEN(buff), pstr, 0); if (!io_ctx) { pefree(pstr, 1); zend_string_release_ex(buff, 0); - php_error_docref(NULL, E_WARNING,"Cannot allocate GD IO context"); + php_error_docref(NULL, E_WARNING, "Cannot allocate GD IO context"); goto out_err; } @@ -1796,7 +1807,7 @@ static void _php_image_output(INTERNAL_FUNCTION_PARAMETERS, int image_type, cons fflush(fp); fclose(fp); } else { - int b; + size_t b; FILE *tmp; char buf[4096]; zend_string *path; @@ -2983,7 +2994,8 @@ static void php_imagechar(INTERNAL_FUNCTION_PARAMETERS, int mode) zend_long X, Y, COL; zend_string *C; gdImagePtr im; - int ch = 0, col, x, y, i, l = 0; + int ch = 0, col, x, y, i; + size_t l = 0; unsigned char *str = NULL; zend_object *font_obj = NULL; zend_long font_int = 0; @@ -4337,7 +4349,9 @@ static void _php_image_output_putc(struct gdIOCtx *ctx, int c) /* {{{ */ static int _php_image_output_putbuf(struct gdIOCtx *ctx, const void* buf, int l) /* {{{ */ { - return php_write((void *)buf, l); + size_t written = php_write((void *)buf, l); + ZEND_ASSERT(written <= INT_MAX); /* since l <= INT_MAX */ + return (int) written; } /* }}} */ static void _php_image_output_ctxfree(struct gdIOCtx *ctx) /* {{{ */ diff --git a/ext/mbstring/mbstring.c b/ext/mbstring/mbstring.c index f1edfe5536df8..90792c3e4bb96 100644 --- a/ext/mbstring/mbstring.c +++ b/ext/mbstring/mbstring.c @@ -3348,7 +3348,8 @@ try_next_encoding:; } for (size_t i = 0; i < length; i++) { - array[i].demerits = (uint64_t) (array[i].demerits * array[i].multiplier); + double demerits = array[i].demerits * (double) array[i].multiplier; + array[i].demerits = demerits < (double) UINT64_MAX ? (uint64_t) demerits : UINT64_MAX; } return length; diff --git a/ext/mbstring/tests/gh17503.phpt b/ext/mbstring/tests/gh17503.phpt new file mode 100644 index 0000000000000..92a2cf39cb10f --- /dev/null +++ b/ext/mbstring/tests/gh17503.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-17503 (Undefined float conversion in mb_convert_variables) +--EXTENSIONS-- +mbstring +--FILE-- +"); +var_dump(mb_convert_variables("ASCII", ["UTF-8", "UTF-16"], $a)); +?> +--EXPECT-- +string(5) "UTF-8" diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 2158438aea03c..aee2afa7a513d 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -10053,9 +10053,9 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen func = call_info->callee_func; } if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && !JIT_G(current_frame)->call->func) { + && (!JIT_G(current_frame) + || !JIT_G(current_frame)->call + || !JIT_G(current_frame)->call->func)) { call_info = NULL; func = NULL; /* megamorphic call from trait */ } } diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index e4b3ad3017e0d..d1bc2bdbd77cf 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1872,7 +1872,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin if (!(orig_op1_type & IS_TRACE_PACKED)) { zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; - if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type) + && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { info->type |= MAY_BE_PACKED_GUARD; info->type &= ~MAY_BE_ARRAY_PACKED; } @@ -1881,7 +1882,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin && val_type != IS_UNDEF) { zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; - if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type) + && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { info->type |= MAY_BE_PACKED_GUARD; info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH); } @@ -1965,7 +1967,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; - if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type) + && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { info->type |= MAY_BE_PACKED_GUARD; if (orig_op1_type & IS_TRACE_PACKED) { info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH); @@ -2067,7 +2070,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; - if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type) + && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { info->type |= MAY_BE_PACKED_GUARD; if (orig_op1_type & IS_TRACE_PACKED) { info->type &= ~(MAY_BE_ARRAY_NUMERIC_HASH|MAY_BE_ARRAY_STRING_HASH); @@ -2097,7 +2101,8 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin zend_ssa_var_info *info = &tssa->var_info[tssa->ops[idx].op1_use]; - if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type)) { + if (MAY_BE_PACKED(info->type) && MAY_BE_HASH(info->type) + && (info->type & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { info->type |= MAY_BE_PACKED_GUARD; info->type &= ~MAY_BE_ARRAY_PACKED; } @@ -4236,10 +4241,13 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par if ((info & MAY_BE_PACKED_GUARD) != 0 && (trace_buffer->stop == ZEND_JIT_TRACE_STOP_LOOP || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_CALL - || trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) + || (trace_buffer->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET + && EX_VAR_TO_NUM((opline-1)->result.var) == i)) && (ssa->vars[i].use_chain != -1 || (ssa->vars[i].phi_use_chain && !(ssa->var_info[ssa->vars[i].phi_use_chain->ssa_var].type & MAY_BE_PACKED_GUARD)))) { + ZEND_ASSERT(STACK_TYPE(stack, i) == IS_ARRAY); + if (!zend_jit_packed_guard(&ctx, opline, EX_NUM_TO_VAR(i), info)) { goto jit_failure; } diff --git a/ext/opcache/tests/jit/gh17577.phpt b/ext/opcache/tests/jit/gh17577.phpt new file mode 100644 index 0000000000000..2eac2d05e432d --- /dev/null +++ b/ext/opcache/tests/jit/gh17577.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-17577 (JIT packed type guard crash) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit_buffer_size=16M +opcache.jit_hot_func=1 +--FILE-- + +--EXPECTF-- +Warning: Trying to access array offset on int in %s on line %d + +Warning: Trying to access array offset on int in %s on line %d + +Warning: Trying to access array offset on int in %s on line %d diff --git a/ext/opcache/tests/jit/gh17654.phpt b/ext/opcache/tests/jit/gh17654.phpt new file mode 100644 index 0000000000000..59d9205b37f2a --- /dev/null +++ b/ext/opcache/tests/jit/gh17654.phpt @@ -0,0 +1,38 @@ +--TEST-- +GH-17654 (Multiple classes using same trait causes function JIT crash) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1214 +opcache.jit_buffer_size=16M +--FILE-- +addUnit("test2"); + (new Test)->addUnit("test"); +} + +main(); +?> +--EXPECT-- +string(5) "test2" +string(4) "test" diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 10af61fa2b08f..677e76f6caf74 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -24,7 +24,6 @@ #include "php.h" #include "php_ini.h" -#include "ext/standard/info.h" #include "php_pdo.h" #include "php_pdo_driver.h" #include "php_pdo_int.h" @@ -36,7 +35,7 @@ #include "zend_observer.h" #include "zend_extensions.h" -static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value); +static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value, uint32_t value_arg_num); void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error) { @@ -513,7 +512,7 @@ PDO_API void php_pdo_internal_construct_driver(INTERNAL_FUNCTION_PARAMETERS, zen ZVAL_DEREF(attr_value); /* TODO: Should the constructor fail when the attribute cannot be set? */ - pdo_dbh_attribute_set(dbh, long_key, attr_value); + pdo_dbh_attribute_set(dbh, long_key, attr_value, 3); } ZEND_HASH_FOREACH_END(); } @@ -659,8 +658,6 @@ PHP_METHOD(PDO, prepare) /* give it a reference to me */ GC_ADDREF(&dbh_obj->std); stmt->database_object_handle = &dbh_obj->std; - /* we haven't created a lazy object yet */ - ZVAL_UNDEF(&stmt->lazy_object_ref); if (dbh->methods->preparer(dbh, statement, stmt, options)) { if (Z_TYPE(ctor_args) == IS_ARRAY) { @@ -779,7 +776,7 @@ PHP_METHOD(PDO, inTransaction) } /* }}} */ -PDO_API bool pdo_get_long_param(zend_long *lval, zval *value) +PDO_API bool pdo_get_long_param(zend_long *lval, const zval *value) { switch (Z_TYPE_P(value)) { case IS_LONG: @@ -797,7 +794,7 @@ PDO_API bool pdo_get_long_param(zend_long *lval, zval *value) return false; } } -PDO_API bool pdo_get_bool_param(bool *bval, zval *value) +PDO_API bool pdo_get_bool_param(bool *bval, const zval *value) { switch (Z_TYPE_P(value)) { case IS_TRUE: @@ -817,7 +814,7 @@ PDO_API bool pdo_get_bool_param(bool *bval, zval *value) } /* Return false on failure, true otherwise */ -static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* {{{ */ +static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value, uint32_t value_arg_num) /* {{{ */ { zend_long lval; bool bval; @@ -834,7 +831,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / dbh->error_mode = lval; return true; default: - zend_value_error("Error mode must be one of the PDO::ERRMODE_* constants"); + zend_argument_value_error(value_arg_num, "Error mode must be one of the PDO::ERRMODE_* constants"); return false; } return false; @@ -850,7 +847,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / dbh->desired_case = lval; return true; default: - zend_value_error("Case folding mode must be one of the PDO::CASE_* constants"); + zend_argument_value_error(value_arg_num, "Case folding mode must be one of the PDO::CASE_* constants"); return false; } return false; @@ -868,7 +865,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / zval *tmp; if ((tmp = zend_hash_index_find(Z_ARRVAL_P(value), 0)) != NULL && Z_TYPE_P(tmp) == IS_LONG) { if (Z_LVAL_P(tmp) == PDO_FETCH_INTO || Z_LVAL_P(tmp) == PDO_FETCH_CLASS) { - zend_value_error("PDO::FETCH_INTO and PDO::FETCH_CLASS cannot be set as the default fetch mode"); + zend_argument_value_error(value_arg_num, "PDO::FETCH_INTO and PDO::FETCH_CLASS cannot be set as the default fetch mode"); return false; } } @@ -879,7 +876,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / } } if (lval == PDO_FETCH_USE_DEFAULT) { - zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants"); + zend_argument_value_error(value_arg_num, "Fetch mode must be a bitmask of PDO::FETCH_* constants"); return false; } dbh->default_fetch_type = lval; @@ -909,25 +906,25 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / return false; } if (Z_TYPE_P(value) != IS_ARRAY) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given", + zend_argument_type_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS value must be of type array, %s given", zend_zval_value_name(value)); return false; } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL) { - zend_value_error("PDO::ATTR_STATEMENT_CLASS value must be an array with the format " + zend_argument_value_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS value must be an array with the format " "array(classname, constructor_args)"); return false; } if (Z_TYPE_P(item) != IS_STRING || (pce = zend_lookup_class(Z_STR_P(item))) == NULL) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be a valid class"); + zend_argument_type_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS class must be a valid class"); return false; } if (!instanceof_function(pce, pdo_dbstmt_ce)) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement"); + zend_argument_type_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement"); return false; } if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) { - zend_type_error("User-supplied statement class cannot have a public constructor"); + zend_argument_type_error(value_arg_num, "User-supplied statement class cannot have a public constructor"); return false; } dbh->def_stmt_ce = pce; @@ -937,7 +934,7 @@ static bool pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) / } if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) { if (Z_TYPE_P(item) != IS_ARRAY) { - zend_type_error("PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", + zend_argument_type_error(value_arg_num, "PDO::ATTR_STATEMENT_CLASS constructor_args must be of type ?array, %s given", zend_zval_value_name(value)); return false; } @@ -983,7 +980,7 @@ PHP_METHOD(PDO, setAttribute) PDO_DBH_CLEAR_ERR(); PDO_CONSTRUCT_CHECK; - RETURN_BOOL(pdo_dbh_attribute_set(dbh, attr, value)); + RETURN_BOOL(pdo_dbh_attribute_set(dbh, attr, value, 2)); } /* }}} */ @@ -1225,8 +1222,6 @@ PHP_METHOD(PDO, query) /* give it a reference to me */ GC_ADDREF(&dbh_obj->std); stmt->database_object_handle = &dbh_obj->std; - /* we haven't created a lazy object yet */ - ZVAL_UNDEF(&stmt->lazy_object_ref); if (dbh->methods->preparer(dbh, statement, stmt, NULL)) { PDO_STMT_CLEAR_ERR(); diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 0b779f6562781..b2b4984ef8177 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -206,17 +206,17 @@ PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count) stmt->column_count = new_count; } -static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */ +static void pdo_get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */ { - if (Z_ISUNDEF(stmt->lazy_object_ref)) { + if (stmt->lazy_object_ref == NULL) { pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), pdo_row_ce); row->stmt = stmt; zend_object_std_init(&row->std, pdo_row_ce); - ZVAL_OBJ(&stmt->lazy_object_ref, &row->std); + stmt->lazy_object_ref = &row->std; GC_ADDREF(&stmt->std); GC_DELREF(&row->std); } - ZVAL_COPY(return_value, &stmt->lazy_object_ref); + ZVAL_OBJ_COPY(return_value, stmt->lazy_object_ref); } /* }}} */ @@ -685,7 +685,7 @@ static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type h } if (how == PDO_FETCH_LAZY) { - get_lazy_object(stmt, return_value); + pdo_get_lazy_object(stmt, return_value); return true; } @@ -2369,16 +2369,16 @@ static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name return NULL; } -void pdo_row_free_storage(zend_object *std) +static void pdo_row_free_storage(zend_object *std) { pdo_row_t *row = php_pdo_row_fetch_object(std); if (row->stmt) { - ZVAL_UNDEF(&row->stmt->lazy_object_ref); + row->stmt->lazy_object_ref = NULL; OBJ_RELEASE(&row->stmt->std); } } -zend_object *pdo_row_new(zend_class_entry *ce) +static zend_object *pdo_row_new(zend_class_entry *ce) { pdo_row_t *row = zend_object_alloc(sizeof(pdo_row_t), ce); zend_object_std_init(&row->std, ce); diff --git a/ext/pdo/php_pdo_driver.h b/ext/pdo/php_pdo_driver.h index a57a17bb81a4a..f232241b51248 100644 --- a/ext/pdo/php_pdo_driver.h +++ b/ext/pdo/php_pdo_driver.h @@ -609,7 +609,7 @@ struct _pdo_stmt_t { /* for lazy fetches, we always return the same lazy object handle. * Let's keep it here. */ - zval lazy_object_ref; + zend_object *lazy_object_ref; pdo_dbh_t *dbh; /* we want to keep the dbh alive while we live, so we own a reference */ @@ -698,8 +698,8 @@ PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count); PDO_API void php_pdo_internal_construct_driver(INTERNAL_FUNCTION_PARAMETERS, zend_object *current_object, zend_class_entry *called_scope, zval *new_zval_object); /* Normalization for fetching long param for driver attributes */ -PDO_API bool pdo_get_long_param(zend_long *lval, zval *value); -PDO_API bool pdo_get_bool_param(bool *bval, zval *value); +PDO_API bool pdo_get_long_param(zend_long *lval, const zval *value); +PDO_API bool pdo_get_bool_param(bool *bval, const zval *value); PDO_API void pdo_throw_exception(unsigned int driver_errcode, char *driver_errmsg, pdo_error_type *pdo_error); diff --git a/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index 13c2e3d9431b4..e8befe9f819a3 100644 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -42,10 +42,8 @@ bool pdo_stmt_describe_columns(pdo_stmt_t *stmt); bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num, zval *args, uint32_t variadic_num_args); -extern zend_object *pdo_row_new(zend_class_entry *ce); extern const zend_function_entry pdo_row_functions[]; extern zend_class_entry *pdo_row_ce; -void pdo_row_free_storage(zend_object *std); extern zend_object_handlers pdo_row_object_handlers; zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object); diff --git a/ext/pdo/tests/bug_44159.phpt b/ext/pdo/tests/bug_44159.phpt index 9d6b2876a15ef..1784324875edc 100644 --- a/ext/pdo/tests/bug_44159.phpt +++ b/ext/pdo/tests/bug_44159.phpt @@ -40,9 +40,9 @@ foreach ($attrs as $attr) { ?> --EXPECT-- -TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, null given -TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, int given -TypeError: PDO::ATTR_STATEMENT_CLASS value must be of type array, string given +TypeError: PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS value must be of type array, null given +TypeError: PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS value must be of type array, int given +TypeError: PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS value must be of type array, string given TypeError: Attribute value must be of type bool for selected attribute, null given bool(true) TypeError: Attribute value must be of type bool for selected attribute, string given diff --git a/ext/pdo/tests/pdo_027.phpt b/ext/pdo/tests/pdo_027.phpt index a18f9b83c6ac5..6bb350f0c133b 100644 --- a/ext/pdo/tests/pdo_027.phpt +++ b/ext/pdo/tests/pdo_027.phpt @@ -19,7 +19,13 @@ $db->exec('create table test027 (id int, name varchar(10))'); $db->exec("INSERT INTO test027 (id,name) VALUES(1,'test1')"); $db->exec("INSERT INTO test027 (id,name) VALUES(2,'test2')"); -foreach ($db->query("SELECT * FROM test027", PDO::FETCH_LAZY) as $v) { +$alias = null; +$r = $db->query("SELECT * FROM test027", PDO::FETCH_LAZY); +var_dump($r); +foreach ($r as $v) { + var_dump($alias === $v); + var_dump($v); + $alias = $v; echo "lazy: " . $v->id.$v->name."\n"; } echo "End\n"; @@ -31,6 +37,28 @@ $db = PDOTest::factory(); PDOTest::dropTableIfExists($db, "test027"); ?> --EXPECT-- +object(PDOStatement)#2 (1) { + ["queryString"]=> + string(21) "SELECT * FROM test027" +} +bool(false) +object(PDORow)#4 (3) { + ["queryString"]=> + string(21) "SELECT * FROM test027" + ["id"]=> + string(1) "1" + ["name"]=> + string(5) "test1" +} lazy: 1test1 +bool(true) +object(PDORow)#4 (3) { + ["queryString"]=> + string(21) "SELECT * FROM test027" + ["id"]=> + string(1) "2" + ["name"]=> + string(5) "test2" +} lazy: 2test2 End diff --git a/ext/pdo/tests/pdo_fetch_lazy_as_default.phpt b/ext/pdo/tests/pdo_fetch_lazy_as_default.phpt new file mode 100644 index 0000000000000..578d758bfb34c --- /dev/null +++ b/ext/pdo/tests/pdo_fetch_lazy_as_default.phpt @@ -0,0 +1,90 @@ +--TEST-- +PDO Common: PDO::FETCH_LAZY set via PDOStatement::setFetchMode() +--DESCRIPTION-- +This test uses an EXPECT section because we want to know the object handlers +--EXTENSIONS-- +pdo +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE pdo_fetch_lazy_as_default_changed(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), grp VARCHAR(10))'); +// Firebird does not allow inserting multiple rows with INSERT INTO +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (1, 'A', 'alpha', 'Group1')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (2, 'B', 'beta', 'Group1')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (3, 'C', 'gamma', 'Group2')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (4, 'D', 'delta', 'Group2')"); + +function to_upper_with_log(string $str): string { + echo __FUNCTION__, '(', var_export($str, true), ')', PHP_EOL; + return strtoupper($str); +} + +$pdoQuery = $db->prepare('SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed'); +$pdoQuery->execute(); +$pdoQuery->setFetchMode(PDO::FETCH_LAZY); + +class Test { + public $val1; + public $val2; +} +$o = new Test(); + +var_dump($pdoQuery->fetch()); +var_dump($pdoQuery->fetchObject(Test::class)); +var_dump($pdoQuery->fetch()); +$pdoQuery->setFetchMode(PDO::FETCH_INTO, $o); +var_dump($pdoQuery->fetch()); +var_dump($o); + +?> +--CLEAN-- + +--EXPECT-- +object(PDORow)#4 (3) { + ["queryString"]=> + string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed" + ["val2"]=> + string(5) "alpha" + ["val1"]=> + string(1) "A" +} +object(Test)#4 (2) { + ["val1"]=> + string(1) "B" + ["val2"]=> + string(4) "beta" +} +object(PDORow)#4 (3) { + ["queryString"]=> + string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed" + ["val2"]=> + string(5) "gamma" + ["val1"]=> + string(1) "C" +} +object(Test)#3 (2) { + ["val1"]=> + string(1) "D" + ["val2"]=> + string(5) "delta" +} +object(Test)#3 (2) { + ["val1"]=> + string(1) "D" + ["val2"]=> + string(5) "delta" +} diff --git a/ext/pdo/tests/pdo_fetch_lazy_as_not_default.phpt b/ext/pdo/tests/pdo_fetch_lazy_as_not_default.phpt new file mode 100644 index 0000000000000..ca11119c636e5 --- /dev/null +++ b/ext/pdo/tests/pdo_fetch_lazy_as_not_default.phpt @@ -0,0 +1,89 @@ +--TEST-- +PDO Common: PDO::FETCH_LAZY when FETCH_INTO set via PDOStatement::setFetchMode() +--DESCRIPTION-- +This test uses an EXPECT section because we want to know the object handlers +--EXTENSIONS-- +pdo +--SKIPIF-- + +--FILE-- +exec('CREATE TABLE pdo_fetch_lazy_as_default_changed(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10), grp VARCHAR(10))'); +// Firebird does not allow inserting multiple rows with INSERT INTO +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (1, 'A', 'alpha', 'Group1')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (2, 'B', 'beta', 'Group1')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (3, 'C', 'gamma', 'Group2')"); +$db->exec("INSERT INTO pdo_fetch_lazy_as_default_changed VALUES (4, 'D', 'delta', 'Group2')"); + +function to_upper_with_log(string $str): string { + echo __FUNCTION__, '(', var_export($str, true), ')', PHP_EOL; + return strtoupper($str); +} + +$pdoQuery = $db->prepare('SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed'); +$pdoQuery->execute(); + +class Test { + public $val1; + public $val2; +} +$o = new Test(); + +$pdoQuery->setFetchMode(PDO::FETCH_INTO, $o); + +var_dump($pdoQuery->fetch()); +var_dump($pdoQuery->fetch(PDO::FETCH_LAZY)); +var_dump($pdoQuery->fetch()); + +$another_obj = new stdClass(); +var_dump($another_obj); + +var_dump($pdoQuery->fetch(PDO::FETCH_LAZY)); + +?> +--CLEAN-- + +--EXPECT-- +object(Test)#3 (2) { + ["val1"]=> + string(1) "A" + ["val2"]=> + string(5) "alpha" +} +object(PDORow)#4 (3) { + ["queryString"]=> + string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed" + ["val2"]=> + string(4) "beta" + ["val1"]=> + string(1) "B" +} +object(Test)#3 (2) { + ["val1"]=> + string(1) "C" + ["val2"]=> + string(5) "gamma" +} +object(stdClass)#4 (0) { +} +object(PDORow)#5 (3) { + ["queryString"]=> + string(56) "SELECT val2, val1 FROM pdo_fetch_lazy_as_default_changed" + ["val2"]=> + string(5) "delta" + ["val1"]=> + string(1) "D" +} diff --git a/ext/pdo/tests/pdo_query_fetch_lazy001.phpt b/ext/pdo/tests/pdo_query_fetch_lazy001.phpt new file mode 100644 index 0000000000000..cec5e9f6d6c93 --- /dev/null +++ b/ext/pdo/tests/pdo_query_fetch_lazy001.phpt @@ -0,0 +1,37 @@ +--TEST-- +PDO Common: PDO::query() with PDO::FETCH_LAZY unused result +--EXTENSIONS-- +pdo +--SKIPIF-- + +--FILE-- +exec('create table pdo_query_fetch_lazy_001 (id int, name varchar(10))'); +$db->exec("INSERT INTO pdo_query_fetch_lazy_001 (id,name) VALUES(1,'test1')"); +$db->exec("INSERT INTO pdo_query_fetch_lazy_001 (id,name) VALUES(2,'test2')"); + +$r = $db->query("SELECT * FROM pdo_query_fetch_lazy_001", PDO::FETCH_LAZY); +var_dump($r); +echo "End\n"; +?> +--CLEAN-- + +--EXPECT-- +object(PDOStatement)#2 (1) { + ["queryString"]=> + string(38) "SELECT * FROM pdo_query_fetch_lazy_001" +} +End diff --git a/ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt b/ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt index df5f6c99d3483..95fcb16824c0f 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_attr_errmode.phpt @@ -158,7 +158,7 @@ error_reporting=E_ALL TypeError: Attribute value must be of type int for selected attribute, array given TypeError: Attribute value must be of type int for selected attribute, stdClass given TypeError: Attribute value must be of type int for selected attribute, string given -ValueError: Error mode must be one of the PDO::ERRMODE_* constants +ValueError: PDO::setAttribute(): Argument #2 ($value) Error mode must be one of the PDO::ERRMODE_* constants Warning: PDO::query(): SQLSTATE[42000]: Syntax error or access violation: %d You have an error in your SQL syntax; check the manual that corresponds to your %s server version for the right syntax to use near '%s' at line %d in %s on line %d diff --git a/ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt b/ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt index a22af1cbdefb1..c932d14288d15 100644 --- a/ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt +++ b/ext/pdo_mysql/tests/pdo_mysql_attr_statement_class.phpt @@ -136,11 +136,11 @@ array(1) { [0]=> string(12) "PDOStatement" } -PDO::ATTR_STATEMENT_CLASS value must be of type array, string given -PDO::ATTR_STATEMENT_CLASS class must be a valid class -PDO::ATTR_STATEMENT_CLASS class must be a valid class -PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement -TypeError: User-supplied statement class cannot have a public constructor +PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS value must be of type array, string given +PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS class must be a valid class +PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS class must be a valid class +PDO::setAttribute(): Argument #2 ($value) PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement +TypeError: PDO::setAttribute(): Argument #2 ($value) User-supplied statement class cannot have a public constructor array(2) { [0]=> string(12) "mystatement4" diff --git a/ext/pdo_odbc/odbc_stmt.c b/ext/pdo_odbc/odbc_stmt.c index 95840ec7f5391..cd7ee7f9ebe98 100644 --- a/ext/pdo_odbc/odbc_stmt.c +++ b/ext/pdo_odbc/odbc_stmt.c @@ -88,12 +88,11 @@ static int pdo_odbc_utf82ucs2(pdo_stmt_t *stmt, int is_unicode, const char *buf, return PDO_ODBC_CONV_NOT_REQUIRED; } -static int pdo_odbc_ucs22utf8(pdo_stmt_t *stmt, int is_unicode, zval *result) +static int pdo_odbc_ucs22utf8(int is_unicode, zval *result) { #ifdef PHP_WIN32 ZEND_ASSERT(Z_TYPE_P(result) == IS_STRING); if (is_unicode && Z_STRLEN_P(result) != 0) { - pdo_odbc_stmt *S = (pdo_odbc_stmt*)stmt->driver_data; DWORD ret; ret = WideCharToMultiByte(CP_UTF8, 0, (LPCWSTR) Z_STRVAL_P(result), Z_STRLEN_P(result)/sizeof(WCHAR), NULL, 0, NULL, NULL); @@ -502,7 +501,7 @@ static int odbc_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *p if (P->len >= 0) { ZVAL_STRINGL(parameter, P->outbuf, P->len); - switch (pdo_odbc_ucs22utf8(stmt, P->is_unicode, parameter)) { + switch (pdo_odbc_ucs22utf8(P->is_unicode, parameter)) { case PDO_ODBC_CONV_FAIL: /* something fishy, but allow it to come back as binary */ case PDO_ODBC_CONV_NOT_REQUIRED: @@ -751,7 +750,7 @@ static int odbc_stmt_get_col(pdo_stmt_t *stmt, int colno, zval *result, enum pdo } unicode_conv: - switch (pdo_odbc_ucs22utf8(stmt, C->is_unicode, result)) { + switch (pdo_odbc_ucs22utf8(C->is_unicode, result)) { case PDO_ODBC_CONV_FAIL: /* oh well. They can have the binary version of it */ case PDO_ODBC_CONV_NOT_REQUIRED: diff --git a/ext/phar/tests/zip/033.phpt b/ext/phar/tests/zip/033.phpt index de4ba2b71f027..cf5ccd9a51050 100644 --- a/ext/phar/tests/zip/033.phpt +++ b/ext/phar/tests/zip/033.phpt @@ -5,6 +5,12 @@ phar --INI-- phar.readonly=0 phar.require_hash=0 +--SKIPIF-- + --FILE-- ExceptionRecord; - CONTEXT *xc = xp->ContextRecord; switch (xr->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: diff --git a/win32/sendmail.c b/win32/sendmail.c index c5215bf35c6f8..80dff3f390772 100644 --- a/win32/sendmail.c +++ b/win32/sendmail.c @@ -111,6 +111,15 @@ static char *ErrorMessages[] = #define PHP_WIN32_MAIL_DOT_PATTERN "\n." #define PHP_WIN32_MAIL_DOT_REPLACE "\n.." +static int SendText(char *RPath, const char *Subject, const char *mailTo, char *mailCc, char *mailBcc, const char *data, + const char *headers, char *headers_lc, char **error_message); +static int MailConnect(); +static int PostHeader(char *RPath, const char *Subject, const char *mailTo, char *xheaders); +static int Post(LPCSTR msg); +static int Ack(char **server_response); +static unsigned long GetAddr(LPSTR szHost); +static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString); + /* This function is meant to unify the headers passed to to mail() * This means, use PCRE to transform single occurrences of \n or \r in \r\n * As a second step we also eliminate all \r\n occurrences which are: @@ -195,8 +204,6 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message, } if (headers) { - char *pos = NULL; - /* Use PCRE to trim the header into the right format */ if (NULL == (headers_trim = php_win32_mail_trim_header(headers))) { *error = W32_SM_PCRE_ERROR; diff --git a/win32/sendmail.h b/win32/sendmail.h index 486482c0c0c7b..e6096f789eb78 100644 --- a/win32/sendmail.h +++ b/win32/sendmail.h @@ -36,14 +36,5 @@ PHPAPI int TSendMail(const char *host, int *error, char **error_message, const char *headers, const char *Subject, const char *mailTo, const char *data, char *mailCc, char *mailBcc, char *mailRPath); PHPAPI void TSMClose(void); -static int SendText(char *RPath, const char *Subject, const char *mailTo, char *mailCc, char *mailBcc, const char *data, - const char *headers, char *headers_lc, char **error_message); PHPAPI char *GetSMErrorText(int index); - -static int MailConnect(); -static int PostHeader(char *RPath, const char *Subject, const char *mailTo, char *xheaders); -static int Post(LPCSTR msg); -static int Ack(char **server_response); -static unsigned long GetAddr(LPSTR szHost); -static int FormatEmailAddress(char* Buf, char* EmailAddress, char* FormatString); #endif /* sendmail_h */