Skip to content

Add array|int and object-of-class|int types to stubs #6081

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -221,15 +221,21 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code,
case ZPP_ERROR_WRONG_CLASS_OR_NULL:
zend_wrong_parameter_class_or_null_error(num, name, arg);
break;
case ZPP_ERROR_WRONG_ARG:
zend_wrong_parameter_type_error(num, expected_type, arg);
break;
case ZPP_ERROR_WRONG_CLASS_OR_STRING:
zend_wrong_parameter_class_or_string_error(num, name, arg);
break;
case ZPP_ERROR_WRONG_CLASS_OR_STRING_OR_NULL:
zend_wrong_parameter_class_or_string_or_null_error(num, name, arg);
break;
case ZPP_ERROR_WRONG_CLASS_OR_LONG:
zend_wrong_parameter_class_or_long_error(num, name, arg);
break;
case ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL:
zend_wrong_parameter_class_or_long_or_null_error(num, name, arg);
break;
case ZPP_ERROR_WRONG_ARG:
zend_wrong_parameter_type_error(num, expected_type, arg);
break;
case ZPP_ERROR_UNEXPECTED_EXTRA_NAMED:
zend_unexpected_extra_named_error();
break;
Expand Down Expand Up @@ -280,6 +286,26 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(u
}
/* }}} */

ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(uint32_t num, const char *name, zval *arg) /* {{{ */
{
if (EG(exception)) {
return;
}

zend_argument_type_error(num, "must be of type %s|int, %s given", name, zend_zval_type_name(arg));
}
/* }}} */

ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */
{
if (EG(exception)) {
return;
}

zend_argument_type_error(num, "must be of type %s|int|null, %s given", name, zend_zval_type_name(arg));
}
/* }}} */

ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_error(uint32_t num, const char *name, zval *arg) /* {{{ */
{
if (EG(exception)) {
Expand Down
114 changes: 109 additions & 5 deletions Zend/zend_API.h
Original file line number Diff line number Diff line change
Expand Up @@ -1209,6 +1209,8 @@ static zend_always_inline zval *zend_try_array_init(zval *zv)
_(Z_EXPECTED_STRING_OR_NULL, "of type ?string") \
_(Z_EXPECTED_ARRAY, "of type array") \
_(Z_EXPECTED_ARRAY_OR_NULL, "of type ?array") \
_(Z_EXPECTED_ARRAY_OR_LONG, "of type array|int") \
_(Z_EXPECTED_ARRAY_OR_LONG_OR_NULL, "of type array|int|null") \
_(Z_EXPECTED_ITERABLE, "of type iterable") \
_(Z_EXPECTED_ITERABLE_OR_NULL, "of type ?iterable") \
_(Z_EXPECTED_FUNC, "a valid callback") \
Expand Down Expand Up @@ -1248,6 +1250,8 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code,
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t num, zend_expected_type expected_type, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_or_null_error(uint32_t num, const char *name, zval *arg);
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, char *error);
Expand All @@ -1261,11 +1265,13 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
#define ZPP_ERROR_WRONG_CALLBACK 2
#define ZPP_ERROR_WRONG_CLASS 3
#define ZPP_ERROR_WRONG_CLASS_OR_NULL 4
#define ZPP_ERROR_WRONG_ARG 5
#define ZPP_ERROR_WRONG_COUNT 6
#define ZPP_ERROR_WRONG_CLASS_OR_STRING 7
#define ZPP_ERROR_WRONG_CLASS_OR_STRING_OR_NULL 8
#define ZPP_ERROR_UNEXPECTED_EXTRA_NAMED 9
#define ZPP_ERROR_WRONG_CLASS_OR_STRING 5
#define ZPP_ERROR_WRONG_CLASS_OR_STRING_OR_NULL 6
#define ZPP_ERROR_WRONG_CLASS_OR_LONG 7
#define ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL 8
#define ZPP_ERROR_WRONG_ARG 9
#define ZPP_ERROR_WRONG_COUNT 10
#define ZPP_ERROR_UNEXPECTED_EXTRA_NAMED 11

#define ZEND_PARSE_PARAMETERS_START_EX(flags, min_num_args, max_num_args) do { \
const int _flags = (flags); \
Expand Down Expand Up @@ -1530,6 +1536,20 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
#define Z_PARAM_ARRAY_HT_OR_NULL(dest) \
Z_PARAM_ARRAY_HT_EX(dest, 1, 0)

#define Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, is_null, allow_null) \
Z_PARAM_PROLOGUE(0, 0); \
if (UNEXPECTED(!zend_parse_arg_array_ht_or_long(_arg, &dest_ht, &dest_long, &is_null, allow_null))) { \
_expected_type = allow_null ? Z_EXPECTED_ARRAY_OR_LONG_OR_NULL : Z_EXPECTED_ARRAY_OR_LONG; \
_error_code = ZPP_ERROR_WRONG_ARG; \
break; \
}

#define Z_PARAM_ARRAY_HT_OR_LONG(dest_ht, dest_long) \
Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, _dummy, 0)

#define Z_PARAM_ARRAY_HT_OR_LONG_OR_NULL(dest_ht, dest_long, is_null) \
Z_PARAM_ARRAY_HT_OR_LONG_EX(dest_ht, dest_long, is_null, 1)

/* old "H" */
#define Z_PARAM_ARRAY_OR_OBJECT_HT_EX2(dest, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
Expand Down Expand Up @@ -1638,6 +1658,44 @@ ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *
#define Z_PARAM_OBJECT_OF_CLASS_OR_NULL(dest, _ce) \
Z_PARAM_OBJECT_OF_CLASS_EX(dest, _ce, 1, 0)

/* The same as Z_PARAM_OBJECT_OF_CLASS_EX2 except that dest is a zend_object rather than a zval */
#define Z_PARAM_OBJ_OF_CLASS_EX2(dest, _ce, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
if (UNEXPECTED(!zend_parse_arg_obj(_arg, &dest, _ce, check_null))) { \
if (_ce) { \
_error = ZSTR_VAL((_ce)->name); \
_error_code = check_null ? ZPP_ERROR_WRONG_CLASS_OR_NULL : ZPP_ERROR_WRONG_CLASS; \
break; \
} else { \
_expected_type = check_null ? Z_EXPECTED_OBJECT_OR_NULL : Z_EXPECTED_OBJECT; \
_error_code = ZPP_ERROR_WRONG_ARG; \
break; \
} \
}

#define Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, check_null, separate) \
Z_PARAM_OBJ_OF_CLASS_EX2(dest, _ce, check_null, separate, separate)

#define Z_PARAM_OBJ_OF_CLASS(dest, _ce) \
Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, 0, 0)

#define Z_PARAM_OBJ_OF_CLASS_OR_NULL(dest, _ce) \
Z_PARAM_OBJ_OF_CLASS_EX(dest, _ce, 1, 0)

#define Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, is_null, allow_null) \
Z_PARAM_PROLOGUE(0, 0); \
if (UNEXPECTED(!zend_parse_arg_obj_or_long(_arg, &dest_obj, _ce, &dest_long, &is_null, allow_null))) { \
_error = ZSTR_VAL((_ce)->name); \
_error_code = allow_null ? ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL : ZPP_ERROR_WRONG_CLASS_OR_LONG; \
break; \
}

#define Z_PARAM_OBJ_OF_CLASS_OR_LONG(dest_obj, _ce, dest_long) \
Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, _dummy, 0)

#define Z_PARAM_OBJ_OF_CLASS_OR_LONG_OR_NULL(dest_obj, _ce, dest_long, is_null) \
Z_PARAM_OBJ_OF_CLASS_OR_LONG_EX(dest_obj, _ce, dest_long, is_null, 1)

/* old "p" */
#define Z_PARAM_PATH_EX2(dest, dest_len, check_null, deref, separate) \
Z_PARAM_PROLOGUE(deref, separate); \
Expand Down Expand Up @@ -1991,6 +2049,29 @@ static zend_always_inline bool zend_parse_arg_array_ht(zval *arg, HashTable **de
return 1;
}

static zend_always_inline bool zend_parse_arg_array_ht_or_long(
zval *arg, HashTable **dest_ht, zend_long *dest_long, zend_bool *is_null, bool allow_null
) {
if (allow_null) {
*is_null = 0;
}

if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY)) {
*dest_ht = Z_ARRVAL_P(arg);
} else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
*dest_ht = NULL;
*dest_long = Z_LVAL_P(arg);
} else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
*dest_ht = NULL;
*is_null = 1;
} else {
*dest_ht = NULL;
return zend_parse_arg_long_slow(arg, dest_long);
}

return 1;
}

static zend_always_inline bool zend_parse_arg_object(zval *arg, zval **dest, zend_class_entry *ce, bool check_null)
{
if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) &&
Expand All @@ -2017,6 +2098,29 @@ static zend_always_inline bool zend_parse_arg_obj(zval *arg, zend_object **dest,
return 1;
}

static zend_always_inline bool zend_parse_arg_obj_or_long(
zval *arg, zend_object **dest_obj, zend_class_entry *ce, zend_long *dest_long, zend_bool *is_null, bool allow_null
) {
if (allow_null) {
*is_null = 0;
}

if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT) && EXPECTED(instanceof_function(Z_OBJCE_P(arg), ce) != 0)) {
*dest_obj = Z_OBJ_P(arg);
} else if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
*dest_obj = NULL;
*dest_long = Z_LVAL_P(arg);
} else if (allow_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
*dest_obj = NULL;
*is_null = 1;
} else {
*dest_obj = NULL;
return zend_parse_arg_long_slow(arg, dest_long);
}

return 1;
}

static zend_always_inline bool zend_parse_arg_resource(zval *arg, zval **dest, bool check_null)
{
if (EXPECTED(Z_TYPE_P(arg) == IS_RESOURCE)) {
Expand Down
35 changes: 25 additions & 10 deletions ext/date/php_date.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "ext/standard/php_math.h"
#include "php_date.h"
#include "zend_interfaces.h"
#include "zend_exceptions.h"
#include "lib/timelib.h"
#include "lib/timelib_private.h"
#ifndef PHP_WIN32
Expand Down Expand Up @@ -4117,13 +4118,11 @@ PHP_METHOD(DatePeriod, __construct)
timelib_time *clone;
zend_error_handling error_handling;

zend_replace_error_handling(EH_THROW, NULL, &error_handling);
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) {
php_error_docref(NULL, E_WARNING, "This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments.");
zend_restore_error_handling(&error_handling);
return;
zend_type_error("DatePeriod::__construct() accepts either (DateTimeInterface, DateInterval, int [, int]) OR (DateTimeInterface, DateInterval, DateTime [, int]) OR (string [, int]) as arguments");
RETURN_THROWS();
}
}
}
Expand All @@ -4132,15 +4131,30 @@ PHP_METHOD(DatePeriod, __construct)
dpobj->current = NULL;

if (isostr) {
zend_replace_error_handling(EH_THROW, zend_ce_value_error, &error_handling);
date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len);
zend_restore_error_handling(&error_handling);
if (EG(exception)) {
RETURN_THROWS();
}

if (dpobj->start == NULL) {
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain a start date.", isostr);
zend_string *func = get_active_function_or_method_name();
zend_value_error("%s(): Argument #1 must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr);
zend_string_release(func);
RETURN_THROWS();
}
if (dpobj->interval == NULL) {
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an interval.", isostr);
zend_string *func = get_active_function_or_method_name();
zend_value_error("%s(): Argument #1 must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr);
zend_string_release(func);
RETURN_THROWS();
}
if (dpobj->end == NULL && recurrences == 0) {
php_error_docref(NULL, E_WARNING, "The ISO interval '%s' did not contain an end date or a recurrence count.", isostr);
zend_string *func = get_active_function_or_method_name();
zend_value_error("%s(): Argument #1 must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr);
zend_string_release(func);
RETURN_THROWS();
}

if (dpobj->start) {
Expand Down Expand Up @@ -4179,7 +4193,10 @@ PHP_METHOD(DatePeriod, __construct)
}

if (dpobj->end == NULL && recurrences < 1) {
php_error_docref(NULL, E_WARNING, "The recurrence count '%d' is invalid. Needs to be > 0", (int) recurrences);
zend_string *func = get_active_function_or_method_name();
zend_value_error("%s(): Recurrence count must be greater than 0", ZSTR_VAL(func));
zend_string_release(func);
RETURN_THROWS();
}

/* options */
Expand All @@ -4189,8 +4206,6 @@ PHP_METHOD(DatePeriod, __construct)
dpobj->recurrences = recurrences + dpobj->include_start_date;

dpobj->initialized = 1;

zend_restore_error_handling(&error_handling);
}
/* }}} */

Expand Down
15 changes: 8 additions & 7 deletions ext/date/tests/DatePeriod_wrong_constructor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ Havard Eide <[email protected]>
date.timezone=UTC
--FILE--
<?php
new DatePeriod();

try {
new DatePeriod();
} catch (TypeError $exception) {
echo $exception->getMessage() . "\n";
}
?>
--EXPECTF--
Fatal error: Uncaught Exception: DatePeriod::__construct(): This constructor accepts either (DateTimeInterface, DateInterval, int) OR (DateTimeInterface, DateInterval, DateTime) OR (string) as arguments. in %s:%d
Stack trace:
#0 %s(%d): DatePeriod->__construct()
#1 {main}
thrown in %s on line %d
--EXPECT--
DatePeriod::__construct() accepts either (DateTimeInterface, DateInterval, int [, int]) OR (DateTimeInterface, DateInterval, DateTime [, int]) OR (string [, int]) as arguments
11 changes: 6 additions & 5 deletions ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ DatePeriod: Test wrong recurrence parameter on __construct
<?php
try {
new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'), 0);
} catch (Exception $exception) {
} catch (ValueError $exception) {
echo $exception->getMessage(), "\n";
}

try {
new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'),-1);
} catch (Exception $exception) {
new DatePeriod(new DateTime('yesterday'), new DateInterval('P1D'), -1);
} catch (ValueError $exception) {
echo $exception->getMessage(), "\n";
}

?>
--EXPECT--
DatePeriod::__construct(): The recurrence count '0' is invalid. Needs to be > 0
DatePeriod::__construct(): The recurrence count '-1' is invalid. Needs to be > 0
DatePeriod::__construct(): Recurrence count must be greater than 0
DatePeriod::__construct(): Recurrence count must be greater than 0
7 changes: 2 additions & 5 deletions ext/date/tests/bug44562.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@ Bug #44562 (Creating instance of DatePeriod crashes)
<?php
date_default_timezone_set('Europe/Oslo');

try
{
try {
$dp = new DatePeriod('2D');
}
catch ( Exception $e )
{
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}

Expand Down
2 changes: 1 addition & 1 deletion ext/date/tests/bug54283.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Bug #54283 (new DatePeriod(NULL) causes crash)

try {
var_dump(new DatePeriod(NULL));
} catch (Exception $e) {
} catch (ValueError $e) {
var_dump($e->getMessage());
}

Expand Down
4 changes: 2 additions & 2 deletions ext/date/tests/date_interval_bad_format_leak.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ try {

try {
$perid = new DatePeriod('P3"D');
} catch (Exception $e) {
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}

try {
new DatePeriod('2008-03-01T12:00:00Z1');
} catch (Exception $e) {
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}

Expand Down
Loading