diff --git a/Zend/zend.c b/Zend/zend.c index 07692db85196..d523b02f64c3 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1815,7 +1815,6 @@ ZEND_API void zend_free_recorded_errors(void) ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format, ...) /* {{{ */ { va_list va; - char *message = NULL; if (!exception_ce) { exception_ce = zend_ce_error; @@ -1827,13 +1826,13 @@ ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const c } va_start(va, format); - zend_vspprintf(&message, 0, format, va); - + zend_string *message = zend_vstrpprintf(0, format, va); //TODO: we can't convert compile-time errors to exceptions yet??? if (EG(current_execute_data) && !CG(in_compilation)) { - zend_throw_exception(exception_ce, message, 0); + const char *format = "%S"; + zend_throw_exception_ex(exception_ce, 0, format, message); } else { - zend_error_noreturn(E_ERROR, "%s", message); + zend_error_noreturn(E_ERROR, "%s", ZSTR_VAL(message)); } efree(message); diff --git a/ext/date/php_date.c b/ext/date/php_date.c index 0e24e4450641..c0a98165400f 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -522,10 +522,11 @@ static timelib_tzinfo *php_date_parse_tzfile_wrapper(const char *formal_tzname, static PHP_INI_MH(OnUpdate_date_timezone) { if (new_value && !timelib_timezone_id_is_valid(ZSTR_VAL(new_value), DATE_TIMEZONEDB)) { + const char *format = "Invalid date.timezone value '%S', using '%s' instead"; php_error_docref( NULL, E_WARNING, - "Invalid date.timezone value '%s', using '%s' instead", - ZSTR_VAL(new_value), + format, + new_value, DATEG(default_timezone) ? DATEG(default_timezone) : "UTC" ); return FAILURE; @@ -2387,7 +2388,7 @@ static void php_date_get_current_time_with_fraction(time_t *sec, suseconds_t *us #endif } -PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, size_t time_str_len, const char *format, zval *timezone_object, int flags) /* {{{ */ +PHPAPI bool php_date_initialize(php_date_obj *dateobj, const zend_string *time_string, const char *format, zval *timezone_object, int flags) /* {{{ */ { timelib_time *now; timelib_tzinfo *tzi = NULL; @@ -2398,6 +2399,13 @@ PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, siz time_t sec; suseconds_t usec; int options = 0; + const char *time_str = ""; + size_t time_str_len = 0; + + if (time_string) { + time_str = ZSTR_VAL(time_string); + time_str_len = ZSTR_LEN(time_string); + } if (dateobj->time) { timelib_time_dtor(dateobj->time); @@ -2421,7 +2429,8 @@ PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, siz /* If called from a constructor throw an exception */ if ((flags & PHP_DATE_INIT_CTOR) && err && err->error_count) { /* spit out the first library error message, at least */ - zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, "Failed to parse time string (%s) at position %d (%c): %s", time_str, + const char *exception_format = "Failed to parse time string (%S) at position %d (%c): %s"; + zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, exception_format, time_string, err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); } if (err && err->error_count) { @@ -2565,17 +2574,16 @@ PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts) PHP_FUNCTION(date_create) { zval *timezone_object = NULL; - char *time_str = NULL; - size_t time_str_len = 0; + zend_string *time_str = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_STRING(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_date, return_value); - if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) { + if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, NULL, timezone_object, 0)) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2586,17 +2594,16 @@ PHP_FUNCTION(date_create) PHP_FUNCTION(date_create_immutable) { zval *timezone_object = NULL; - char *time_str = NULL; - size_t time_str_len = 0; + zend_string *time_str = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_STRING(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); php_date_instantiate(date_ce_immutable, return_value); - if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, NULL, timezone_object, 0)) { + if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, NULL, timezone_object, 0)) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2607,20 +2614,26 @@ PHP_FUNCTION(date_create_immutable) PHP_FUNCTION(date_create_from_format) { zval *timezone_object = NULL; - char *time_str = NULL, *format_str = NULL; - size_t time_str_len = 0, format_str_len = 0; + zend_string *time_str = NULL; + char *format_str = NULL; + size_t format_str_len = 0; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(format_str, format_str_len) - Z_PARAM_PATH(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OPTIONAL Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); + if (UNEXPECTED(zend_str_has_nul_byte(time_str))) { + zend_argument_value_error(2, "must not contain any null bytes"); + RETURN_THROWS(); + } + if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) { RETURN_THROWS(); } - if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) { + if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2631,20 +2644,26 @@ PHP_FUNCTION(date_create_from_format) PHP_FUNCTION(date_create_immutable_from_format) { zval *timezone_object = NULL; - char *time_str = NULL, *format_str = NULL; - size_t time_str_len = 0, format_str_len = 0; + zend_string *time_str = NULL; + char *format_str = NULL; + size_t format_str_len = 0; ZEND_PARSE_PARAMETERS_START(2, 3) Z_PARAM_STRING(format_str, format_str_len) - Z_PARAM_PATH(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OPTIONAL Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); + if (UNEXPECTED(zend_str_has_nul_byte(time_str))) { + zend_argument_value_error(2, "must not contain any null bytes"); + RETURN_THROWS(); + } + if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) { RETURN_THROWS(); } - if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) { + if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) { zval_ptr_dtor(return_value); RETURN_FALSE; } @@ -2655,16 +2674,20 @@ PHP_FUNCTION(date_create_immutable_from_format) PHP_METHOD(DateTime, __construct) { zval *timezone_object = NULL; - char *time_str = NULL; - size_t time_str_len = 0; + zend_string *time_str = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_STRING(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); - php_date_initialize(Z_PHPDATE_P(ZEND_THIS), time_str, time_str_len, NULL, timezone_object, PHP_DATE_INIT_CTOR); + if (time_str && UNEXPECTED(zend_str_has_nul_byte(time_str))) { + zend_argument_value_error(2, "must not contain any null bytes"); + RETURN_THROWS(); + } + + php_date_initialize(Z_PHPDATE_P(ZEND_THIS), time_str, NULL, timezone_object, PHP_DATE_INIT_CTOR); } /* }}} */ @@ -2672,16 +2695,15 @@ PHP_METHOD(DateTime, __construct) PHP_METHOD(DateTimeImmutable, __construct) { zval *timezone_object = NULL; - char *time_str = NULL; - size_t time_str_len = 0; + zend_string *time_str = NULL; ZEND_PARSE_PARAMETERS_START(0, 2) Z_PARAM_OPTIONAL - Z_PARAM_STRING(time_str, time_str_len) + Z_PARAM_STR(time_str) Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone) ZEND_PARSE_PARAMETERS_END(); - php_date_initialize(Z_PHPDATE_P(ZEND_THIS), time_str, time_str_len, NULL, timezone_object, PHP_DATE_INIT_CTOR); + php_date_initialize(Z_PHPDATE_P(ZEND_THIS), time_str, NULL, timezone_object, PHP_DATE_INIT_CTOR); } /* }}} */ @@ -2876,7 +2898,7 @@ static bool php_date_initialize_from_hash(php_date_obj **dateobj, const HashTabl zend_string *tmp = zend_string_concat3( Z_STRVAL_P(z_date), Z_STRLEN_P(z_date), " ", 1, Z_STRVAL_P(z_timezone), Z_STRLEN_P(z_timezone)); - bool ret = php_date_initialize(*dateobj, ZSTR_VAL(tmp), ZSTR_LEN(tmp), NULL, NULL, 0); + bool ret = php_date_initialize(*dateobj, tmp, NULL, NULL, 0); zend_string_release(tmp); return ret; } @@ -2896,7 +2918,7 @@ static bool php_date_initialize_from_hash(php_date_obj **dateobj, const HashTabl tzobj->tzi.tz = tzi; tzobj->initialized = true; - ret = php_date_initialize(*dateobj, Z_STRVAL_P(z_date), Z_STRLEN_P(z_date), NULL, &tmp_obj, 0); + ret = php_date_initialize(*dateobj, Z_STR_P(z_date), NULL, &tmp_obj, 0); zval_ptr_dtor(&tmp_obj); return ret; } @@ -3251,7 +3273,7 @@ PHP_FUNCTION(date_format) } /* }}} */ -static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{{ */ +static bool php_date_modify(zval *object, zend_string *modify) /* {{{ */ { php_date_obj *dateobj; timelib_time *tmp_time; @@ -3264,14 +3286,15 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ return false; } - tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); + tmp_time = timelib_strtotime(ZSTR_VAL(modify), ZSTR_LEN(modify), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); /* update last errors and warnings */ update_errors_warnings(&err); if (err && err->error_count) { + const char *format = "Failed to parse time string (%S) at position %d (%c): %s"; /* spit out the first library error message, at least */ - php_error_docref(NULL, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify, + php_error_docref(NULL, E_WARNING, format, modify, err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); @@ -3336,14 +3359,13 @@ static bool php_date_modify(zval *object, char *modify, size_t modify_len) /* {{ PHP_FUNCTION(date_modify) { zval *object; - char *modify; - size_t modify_len; + zend_string *modify; - if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "Os", &object, date_ce_date, &modify, &modify_len) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "OS", &object, date_ce_date, &modify) == FAILURE) { RETURN_THROWS(); } - if (!php_date_modify(object, modify, modify_len)) { + if (!php_date_modify(object, modify)) { RETURN_FALSE; } @@ -3355,17 +3377,16 @@ PHP_FUNCTION(date_modify) PHP_METHOD(DateTime, modify) { zval *object; - char *modify; - size_t modify_len; + zend_string *modify; zend_error_handling zeh; object = ZEND_THIS; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(modify, modify_len) + Z_PARAM_STR(modify) ZEND_PARSE_PARAMETERS_END(); zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); - if (!php_date_modify(object, modify, modify_len)) { + if (!php_date_modify(object, modify)) { zend_restore_error_handling(&zeh); RETURN_THROWS(); } @@ -3380,19 +3401,18 @@ PHP_METHOD(DateTime, modify) PHP_METHOD(DateTimeImmutable, modify) { zval *object, new_object; - char *modify; - size_t modify_len; + zend_string *modify; zend_error_handling zeh; object = ZEND_THIS; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(modify, modify_len) + Z_PARAM_STR(modify) ZEND_PARSE_PARAMETERS_END(); date_clone_immutable(object, &new_object); zend_replace_error_handling(EH_THROW, date_ce_date_malformed_string_exception, &zeh); - if (!php_date_modify(&new_object, modify, modify_len)) { + if (!php_date_modify(&new_object, modify)) { zval_ptr_dtor(&new_object); zend_restore_error_handling(&zeh); RETURN_THROWS(); @@ -4444,7 +4464,7 @@ PHP_FUNCTION(timezone_location_get) } /* }}} */ -static bool date_interval_initialize(timelib_rel_time **rt, const char *format, size_t format_length) /* {{{ */ +static bool date_interval_initialize(timelib_rel_time **rt, const zend_string *format) /* {{{ */ { timelib_time *b = NULL, *e = NULL; timelib_rel_time *p = NULL; @@ -4452,10 +4472,11 @@ static bool date_interval_initialize(timelib_rel_time **rt, const char *format, bool retval = false; timelib_error_container *errors; - timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors); + timelib_strtointerval(ZSTR_VAL(format), ZSTR_LEN(format), &b, &e, &p, &r, &errors); if (errors->error_count > 0) { - zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Unknown or bad format (%s)", format); + const char *exception_format = "Unknown or bad format (%S)"; + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, exception_format, format); retval = false; if (p) { timelib_rel_time_dtor(p); @@ -4471,7 +4492,8 @@ static bool date_interval_initialize(timelib_rel_time **rt, const char *format, *rt = timelib_diff(b, e); retval = true; } else { - zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, "Failed to parse interval (%s)", format); + const char *exception_format = "Failed to parse interval (%S)"; + zend_throw_exception_ex(date_ce_date_malformed_interval_string_exception, 0, exception_format, format); retval = false; } } @@ -4620,7 +4642,12 @@ PHP_METHOD(DateInterval, __construct) Z_PARAM_STR(interval_string) ZEND_PARSE_PARAMETERS_END(); - if (!date_interval_initialize(&reltime, ZSTR_VAL(interval_string), ZSTR_LEN(interval_string))) { + if (UNEXPECTED(zend_str_has_nul_byte(interval_string))) { + zend_argument_value_error(1, "must not contain any null bytes"); + RETURN_THROWS(); + } + + if (!date_interval_initialize(&reltime, interval_string)) { RETURN_THROWS(); } @@ -4642,9 +4669,16 @@ static void php_date_interval_initialize_from_hash(php_interval_obj *intobj, con time = timelib_strtotime(Z_STRVAL_P(date_str), Z_STRLEN_P(date_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if (err->error_count > 0) { + const zend_string *date_string; + if (Z_TYPE_P(date_str) == IS_STRING) { + date_string = Z_STR_P(date_str); + } else { + date_string = ZSTR_EMPTY_ALLOC(); + } + const char *format = "Unknown or bad format (%S) at position %d (%c) while unserializing: %s"; zend_throw_error(NULL, - "Unknown or bad format (%s) at position %d (%c) while unserializing: %s", - Z_STRVAL_P(date_str), + format, + date_string, err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); timelib_time_dtor(time); @@ -4890,7 +4924,8 @@ PHP_FUNCTION(date_interval_create_from_date_string) time = timelib_strtotime(ZSTR_VAL(time_str), ZSTR_LEN(time_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if (err->error_count > 0) { - php_error_docref(NULL, E_WARNING, "Unknown or bad format (%s) at position %d (%c): %s", ZSTR_VAL(time_str), + const char *format = "Unknown or bad format (%S) at position %d (%c): %s"; + php_error_docref(NULL, E_WARNING, format, time_str, err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); RETVAL_FALSE; goto cleanup; @@ -4924,7 +4959,8 @@ PHP_METHOD(DateInterval, createFromDateString) time = timelib_strtotime(ZSTR_VAL(time_str), ZSTR_LEN(time_str), &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper); if (err->error_count > 0) { - zend_throw_error(date_ce_date_malformed_interval_string_exception, "Unknown or bad format (%s) at position %d (%c): %s", ZSTR_VAL(time_str), + const char *format = "Unknown or bad format (%S) at position %d (%c): %s"; + zend_throw_exception_ex( date_ce_date_malformed_interval_string_exception, 0, format, time_str, err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); goto cleanup; } @@ -5030,7 +5066,7 @@ PHP_FUNCTION(date_interval_format) } /* }}} */ -static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, zend_long *recurrences, const char *format, size_t format_length) /* {{{ */ +static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib_rel_time **d, zend_long *recurrences, const zend_string *format) /* {{{ */ { timelib_time *b = NULL, *e = NULL; timelib_rel_time *p = NULL; @@ -5038,11 +5074,12 @@ static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib timelib_error_container *errors; bool retval = false; - timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors); + timelib_strtointerval(ZSTR_VAL(format), ZSTR_LEN(format), &b, &e, &p, &r, &errors); if (errors->error_count > 0) { retval = false; - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "Unknown or bad format (%s)", format); + const char *exception_format = "Unknown or bad format (%S)"; + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, exception_format, format); if (b) { timelib_time_dtor(b); } @@ -5063,27 +5100,27 @@ static bool date_period_initialize(timelib_time **st, timelib_time **et, timelib return retval; } /* }}} */ -static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_entry* base_ce, const char *isostr, size_t isostr_len, zend_long *recurrences) +static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_entry* base_ce, const zend_string *isostr, zend_long *recurrences) { - if (!date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), recurrences, isostr, isostr_len)) { + if (!date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), recurrences, isostr)) { return false; } if (dpobj->start == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), ZSTR_VAL(isostr)); zend_string_release(func); return false; } if (dpobj->interval == NULL) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), ZSTR_VAL(isostr)); zend_string_release(func); return false; } if (dpobj->end == NULL && *recurrences == 0) { zend_string *func = get_active_function_or_method_name(); - zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr); + zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), ZSTR_VAL(isostr)); zend_string_release(func); return false; } @@ -5135,11 +5172,10 @@ PHP_METHOD(DatePeriod, createFromISO8601String) { php_period_obj *dpobj; zend_long recurrences = 0, options = 0; - char *isostr = NULL; - size_t isostr_len = 0; + zend_string *isostr = NULL; ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(isostr, isostr_len) + Z_PARAM_STR(isostr) Z_PARAM_OPTIONAL Z_PARAM_LONG(options) ZEND_PARSE_PARAMETERS_END(); @@ -5151,7 +5187,7 @@ PHP_METHOD(DatePeriod, createFromISO8601String) dpobj->current = NULL; - if (!date_period_init_iso8601_string(dpobj, date_ce_immutable, isostr, isostr_len, &recurrences)) { + if (!date_period_init_iso8601_string(dpobj, date_ce_immutable, isostr, &recurrences)) { RETURN_THROWS(); } @@ -5184,19 +5220,23 @@ PHP_METHOD(DatePeriod, __construct) php_date_obj *dateobj; zval *start, *end = NULL, *interval; zend_long recurrences = 0, options = 0; - char *isostr = NULL; - size_t isostr_len = 0; + zend_string *isostr = NULL; timelib_time *clone; if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) { if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) { - if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "s|l", &isostr, &isostr_len, &options) == FAILURE) { + if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "S|l", &isostr, &options) == FAILURE) { zend_type_error("DatePeriod::__construct() accepts (DateTimeInterface, DateInterval, int [, int]), or (DateTimeInterface, DateInterval, DateTime [, int]), or (string [, int]) as arguments"); RETURN_THROWS(); } } } + if (isostr && UNEXPECTED(zend_str_has_nul_byte(isostr))) { + zend_argument_value_error(1, "must not contain any null bytes"); + RETURN_THROWS(); + } + dpobj = Z_PHPPERIOD_P(ZEND_THIS); date_period_reset(dpobj); @@ -5207,7 +5247,7 @@ PHP_METHOD(DatePeriod, __construct) RETURN_THROWS(); } - if (!date_period_init_iso8601_string(dpobj, date_ce_date, isostr, isostr_len, &recurrences)) { + if (!date_period_init_iso8601_string(dpobj, date_ce_date, isostr, &recurrences)) { RETURN_THROWS(); } } else { @@ -5451,22 +5491,22 @@ PHP_FUNCTION(timezone_abbreviations_list) /* {{{ Sets the default timezone used by all date/time functions in a script */ PHP_FUNCTION(date_default_timezone_set) { - char *zone; - size_t zone_len; + zend_string *zone; ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_STRING(zone, zone_len) + Z_PARAM_STR(zone) ZEND_PARSE_PARAMETERS_END(); - if (!timelib_timezone_id_is_valid(zone, DATE_TIMEZONEDB)) { - php_error_docref(NULL, E_NOTICE, "Timezone ID '%s' is invalid", zone); + if (!timelib_timezone_id_is_valid(ZSTR_VAL(zone), DATE_TIMEZONEDB)) { + const char *format = "Timezone ID '%S' is invalid"; + php_error_docref(NULL, E_NOTICE, format, zone); RETURN_FALSE; } if (DATEG(timezone)) { efree(DATEG(timezone)); DATEG(timezone) = NULL; } - DATEG(timezone) = estrndup(zone, zone_len); + DATEG(timezone) = estrndup(ZSTR_VAL(zone), ZSTR_LEN(zone)); RETURN_TRUE; } /* }}} */ diff --git a/ext/date/php_date.h b/ext/date/php_date.h index 651cc28225fd..8eb24fca7e36 100644 --- a/ext/date/php_date.h +++ b/ext/date/php_date.h @@ -149,7 +149,7 @@ PHPAPI zend_class_entry *php_date_get_period_ce(void); #define PHP_DATE_INIT_FORMAT 0x02 PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object); -PHPAPI bool php_date_initialize(php_date_obj *dateobj, const char *time_str, size_t time_str_len, const char *format, zval *timezone_object, int flags); +PHPAPI bool php_date_initialize(php_date_obj *dateobj, const zend_string *time_str, const char *format, zval *timezone_object, int flags); PHPAPI void php_date_initialize_from_ts_long(php_date_obj *dateobj, zend_long sec, int usec); PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts); diff --git a/ext/date/tests/22993/dateInterval_create_null_byte.phpt b/ext/date/tests/22993/dateInterval_create_null_byte.phpt new file mode 100644 index 000000000000..44b475e20ba1 --- /dev/null +++ b/ext/date/tests/22993/dateInterval_create_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-22993: DateInterval::createFromDateString() error message with embedded NUL byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +Unknown or bad format (foo%0bar) at position 0 (f): The timezone could not be found in the database diff --git a/ext/date/tests/22993/dateInterval_nul_byte.phpt b/ext/date/tests/22993/dateInterval_nul_byte.phpt new file mode 100644 index 000000000000..64e622eb4c5e --- /dev/null +++ b/ext/date/tests/22993/dateInterval_nul_byte.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-22993: DateInterval error message with embedded NUL byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +Fatal error: Uncaught ValueError: DateInterval::__construct(): Argument #1 ($duration) must not contain any null bytes in %s:%d +Stack trace: +#0 %s(%d): DateInterval->__construct('foo\x00bar') +#1 {main} + thrown in %s on line %d diff --git a/ext/date/tests/22993/dateInterval_unserialize_null_byte.phpt b/ext/date/tests/22993/dateInterval_unserialize_null_byte.phpt new file mode 100644 index 000000000000..c4bb09cd4e7f --- /dev/null +++ b/ext/date/tests/22993/dateInterval_unserialize_null_byte.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-22993: DateInterval unserialize() error message with embedded NUL byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +Unknown or bad format (foo%0bar) at position 0 (f) while unserializing: The timezone could not be found in the database diff --git a/ext/date/tests/22993/datePeriod_create_iso8601_null_byte.phpt b/ext/date/tests/22993/datePeriod_create_iso8601_null_byte.phpt new file mode 100644 index 000000000000..b259baa8995c --- /dev/null +++ b/ext/date/tests/22993/datePeriod_create_iso8601_null_byte.phpt @@ -0,0 +1,15 @@ +--TEST-- +GH-22993: DatePeriod::createFromISO8601String() error message with embedded NUL byte +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECTF-- +Unknown or bad format (foo%0bar) + diff --git a/ext/date/tests/22993/dateTime_modify_embedded_null.phpt b/ext/date/tests/22993/dateTime_modify_embedded_null.phpt new file mode 100644 index 000000000000..900fa4937ddc --- /dev/null +++ b/ext/date/tests/22993/dateTime_modify_embedded_null.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-22993: DateTime::modify() error message with embedded NUL byte +--FILE-- +modify("foo\0bar"); +} catch (DateMalformedStringException $e) { + echo $e->getMessage(), "\n"; +} + +?> +--EXPECTF-- +DateTime::modify(): Failed to parse time string (foo%0bar) at position %s diff --git a/ext/date/tests/22993/date_interval_null_byte.phpt b/ext/date/tests/22993/date_interval_null_byte.phpt new file mode 100644 index 000000000000..53e906c004ba --- /dev/null +++ b/ext/date/tests/22993/date_interval_null_byte.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-22993: date_interval_create_from_date_string() error message with embedded NUL byte +--FILE-- + +--EXPECTF-- +Warning: date_interval_create_from_date_string(): Unknown or bad format (foo%0bar) at position 0 (f): %s diff --git a/ext/date/tests/22993/ini_date_timezone_null_byte.phpt b/ext/date/tests/22993/ini_date_timezone_null_byte.phpt new file mode 100644 index 000000000000..0d98638b190c --- /dev/null +++ b/ext/date/tests/22993/ini_date_timezone_null_byte.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-22993: ini_set() with embedded NUL byte in date.timezone +--FILE-- + +--EXPECTF-- +Warning: ini_set(): Invalid date.timezone value 'foo%0bar', using 'UTC' instead in %s on line %d diff --git a/ext/date/tests/22993/nul-byte-error-message.phpt b/ext/date/tests/22993/nul-byte-error-message.phpt new file mode 100644 index 000000000000..58b04ac11797 --- /dev/null +++ b/ext/date/tests/22993/nul-byte-error-message.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-22993: DateTimeImmutable error message with embedded NUL byte +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECTF-- +Failed to parse time string (foo%0bar) at position 0 (f): The timezone could not be found in the database diff --git a/ext/date/tests/22993/timezone_set_null_byte.phpt b/ext/date/tests/22993/timezone_set_null_byte.phpt new file mode 100644 index 000000000000..491fba088b07 --- /dev/null +++ b/ext/date/tests/22993/timezone_set_null_byte.phpt @@ -0,0 +1,10 @@ +--TEST-- +GH-22993: date_default_timezone_set() notice with embedded NUL byte +--FILE-- + +--EXPECTF-- +Notice: date_default_timezone_set(): Timezone ID 'foo%0bar' is invalid in %s on line %d