# By Adam Harvey (2) and others
# Via Adam Harvey (2) and others
* 'master' of https://git.php.net/repository/php-src:
  Implement variadic function syntax
  Added function opcache_compile_file() to load PHP scripts into cache without execution.
  Fixed issue #135 (segfault in interned strings if initial memory is too low)
  Fix typo: HTTP_ROW_POST_DATA → HTTP_RAW_POST_DATA.
  Make message and format arguments const char * to avoid build warning about invalid cast.
  Copy dba_*() keys before converting to string.
This commit is contained in:
Christopher Jones 2013-09-26 09:57:36 -07:00
commit a3b0fa0d04
50 changed files with 3365 additions and 2630 deletions

2
NEWS
View File

@ -14,6 +14,8 @@ PHP NEWS
. Reduced POST data memory usage by 200-300%. Removed INI setting
always_populate_raw_post_data and the $HTTP_RAW_POST_DATA global
variable. (Mike)
. Implemented dedicated syntax for variadic functions
(RFC: https://wiki.php.net/rfc/variadics). (Nikita)
- cURL:
. Implemented FR #65646 (re-enable CURLOPT_FOLLOWLOCATION with open_basedir

View File

@ -26,7 +26,7 @@ PHP X.Y UPGRADE NOTES
<?php
global $HTTP_RAW_POST_DATA;
if (!isset($HTTP_RAW_POST_DATA)) {
$HTTP_ROW_POST_DATA = file_get_contents("php://input");
$HTTP_RAW_POST_DATA = file_get_contents("php://input");
}
?>
@ -34,8 +34,10 @@ PHP X.Y UPGRADE NOTES
2. New Features
========================================
- Core:
The php://input stream is now re-usable and can be used concurrently with
- Added dedicated syntax for variadic functions.
(https://wiki.php.net/rfc/variadics)
- The php://input stream is now re-usable and can be used concurrently with
enable_post_data_reading=0.
========================================

View File

@ -6,6 +6,7 @@ UPGRADE NOTES - PHP X.Y
a. Addition of do_operation and compare object handlers
b. return_value_ptr now always available, RETVAL_ZVAL_FAST macros
c. POST data handling
d. Arginfo changes
2. Build system changes
a. Unix build system changes
@ -68,6 +69,47 @@ UPGRADE NOTES - PHP X.Y
The recommended way to access raw POST data is to open and use a php://input
stream wrapper. It is safe to be used concurrently and more than once.
d. Arginfo changes
The pass_rest_by_reference argument of the ZEND_BEGIN_ARG_INFO and
ZEND_BEGIN_ARG_INFO_EX() is no longer used. The value passed to it is ignored.
Instead a variadic argument is created using ZEND_ARG_VARIADIC_INFO():
ZEND_ARG_VARIADIC_INFO(0, name) /* pass rest by value */
ZEND_ARG_VARIADIC_INFO(1, name) /* pass rest by reference */
ZEND_ARG_VARIADIC_INFO(ZEND_SEND_PREFER_REF, name)
/* pass rest by prefer-ref */
ZEND_ARG_VARIADIC_INFO() should only be used for the last argument.
The following changes were applied to the zend_arg_info struct:
typedef struct _zend_arg_info {
const char *class_name;
zend_uint class_name_len;
zend_uchar type_hint;
+ zend_uchar pass_by_reference;
zend_bool allow_null;
- zend_bool pass_by_reference;
+ zend_bool is_variadic;
} zend_arg_info;
The following changes were applied to the zend_internal_function_info struct:
typedef struct _zend_internal_function_info {
zend_uint required_num_args;
zend_uchar _type_hint;
zend_bool return_reference;
- zend_bool pass_rest_by_reference;
+ zend_bool _allow_null;
+ zend_bool _is_variadic;
} zend_internal_function_info;
The CHECK_ARG_SEND_TYPE(), ARG_MUST_BE_SENT_BY_REF(),
ARG_SHOULD_BE_SENT_BY_REF() and ARG_MAY_BE_SENT_BY_REF() macros now assume
that the argument passed to them is a zend_function* and that it is non-NULL.
========================
2. Build system changes
========================

View File

@ -0,0 +1,17 @@
--TEST--
It's possible to add additional optional arguments with matching signature
--FILE--
<?php
interface DB {
public function query($query, string ...$params);
}
class MySQL implements DB {
public function query($query, string $extraParam = null, string ...$params) { }
}
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -0,0 +1,16 @@
--TEST--
Additional optional parameters must have a matching prototype
--FILE--
<?php
interface DB {
public function query($query, string ...$params);
}
class MySQL implements DB {
public function query($query, int $extraParam = null, string ...$params) { }
}
?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, string ...$params) in %s on line %d

View File

@ -0,0 +1,57 @@
--TEST--
Basic variadic function
--FILE--
<?php
function test1(... $args) {
var_dump($args);
}
test1();
test1(1);
test1(1, 2, 3);
function test2($arg1, $arg2, ...$args) {
var_dump($arg1, $arg2, $args);
}
test2(1, 2);
test2(1, 2, 3);
test2(1, 2, 3, 4, 5);
?>
--EXPECT--
array(0) {
}
array(1) {
[0]=>
int(1)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
int(1)
int(2)
array(0) {
}
int(1)
int(2)
array(1) {
[0]=>
int(3)
}
int(1)
int(2)
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
int(5)
}

View File

@ -0,0 +1,24 @@
--TEST--
Variadic arguments with by-reference passing
--FILE--
<?php
function test(&... $args) {
$i = 0;
foreach ($args as &$arg) {
$arg = $i++;
}
}
test();
test($a);
var_dump($a);
test($b, $c, $d);
var_dump($b, $c, $d);
?>
--EXPECT--
int(0)
int(0)
int(1)
int(2)

View File

@ -0,0 +1,12 @@
--TEST--
By-ref variadics enforce the reference
--FILE--
<?php
function test(&... $args) { }
test(1);
?>
--EXPECTF--
Fatal error: Only variables can be passed by reference in %s on line %d

View File

@ -0,0 +1,10 @@
--TEST--
Variadic argument cannot have a default value
--FILE--
<?php
function test(...$args = 123) {}
?>
--EXPECTF--
Fatal error: Variadic parameter cannot have a default value in %s on line %d

View File

@ -0,0 +1,16 @@
--TEST--
It's not possible to turn a variadic function into a non-variadic one
--FILE--
<?php
interface DB {
public function query($query, ...$params);
}
class MySQL implements DB {
public function query($query, $params) { }
}
?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, ...$params) in %s on line %d

View File

@ -0,0 +1,10 @@
--TEST--
Only the last argument can be variadic
--FILE--
<?php
function test($foo, ...$bar, $baz) {}
?>
--EXPECTF--
Fatal error: Only the last parameter can be variadic in %s on line %d

View File

@ -0,0 +1,49 @@
--TEST--
Optional parameter before variadic parameter
--FILE--
<?php
function fn($reqParam, $optParam = null, ...$params) {
var_dump($reqParam, $optParam, $params);
}
fn(1);
fn(1, 2);
fn(1, 2, 3);
fn(1, 2, 3, 4);
fn(1, 2, 3, 4, 5);
?>
--EXPECT--
int(1)
NULL
array(0) {
}
int(1)
int(2)
array(0) {
}
int(1)
int(2)
array(1) {
[0]=>
int(3)
}
int(1)
int(2)
array(2) {
[0]=>
int(3)
[1]=>
int(4)
}
int(1)
int(2)
array(3) {
[0]=>
int(3)
[1]=>
int(4)
[2]=>
int(5)
}

View File

@ -0,0 +1,20 @@
--TEST--
It's not possible to remove required parameter before a variadic parameter
--FILE--
<?php
/* Theoretically this should be valid because it weakens the constraint, but
* PHP does not allow this (for non-variadics), so I'm not allowing it here, too,
* to stay consistent. */
interface DB {
public function query($query, ...$params);
}
class MySQL implements DB {
public function query(...$params) { }
}
?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, ...$params) in %s on line %d

View File

@ -0,0 +1,36 @@
--TEST--
Variadic arguments enforce typehints
--FILE--
<?php
function test(array... $args) {
var_dump($args);
}
test();
test([0], [1], [2]);
test([0], [1], 2);
?>
--EXPECTF--
array(0) {
}
array(3) {
[0]=>
array(1) {
[0]=>
int(0)
}
[1]=>
array(1) {
[0]=>
int(1)
}
[2]=>
array(1) {
[0]=>
int(2)
}
}
Catchable fatal error: Argument 3 passed to test() must be of the type array, integer given, called in %s on line %d

View File

@ -0,0 +1,33 @@
--TEST--
Error suppression for typehints on variadic arguments works
--FILE--
<?php
function test(array... $args) {
var_dump($args);
}
set_error_handler(function($errno, $errstr) {
var_dump($errstr);
return true;
});
test([0], [1], 2);
?>
--EXPECTF--
string(%d) "Argument 3 passed to test() must be of the type array, integer given, called in %s on line %d and defined"
array(3) {
[0]=>
array(1) {
[0]=>
int(0)
}
[1]=>
array(1) {
[0]=>
int(1)
}
[2]=>
int(2)
}

View File

@ -0,0 +1,16 @@
--TEST--
Variadic arguments must have compatible passing modes
--FILE--
<?php
interface DB {
public function query($query, &...$params);
}
class MySQL implements DB {
public function query($query, ...$params) { }
}
?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, &...$params) in %s on line %d

View File

@ -0,0 +1,16 @@
--TEST--
Typehints for variadic arguments have to be compatible
--FILE--
<?php
interface DB {
public function query($query, string ...$params);
}
class MySQL implements DB {
public function query($query, int ...$params) { }
}
?>
--EXPECTF--
Fatal error: Declaration of MySQL::query() must be compatible with DB::query($query, string ...$params) in %s on line %d

View File

@ -0,0 +1,17 @@
--TEST--
A non-variadic function can be turned into a variadic one
--FILE--
<?php
interface DB {
public function query($query);
}
class MySQL implements DB {
public function query($query, ...$params) { }
}
?>
===DONE===
--EXPECT--
===DONE===

View File

@ -2090,16 +2090,12 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio
} else {
internal_function->required_num_args = info->required_num_args;
}
if (info->pass_rest_by_reference) {
if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) {
internal_function->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF;
} else {
internal_function->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE;
}
}
if (info->return_reference) {
internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
}
if (ptr->arg_info[ptr->num_args].is_variadic) {
internal_function->fn_flags |= ZEND_ACC_VARIADIC;
}
} else {
internal_function->arg_info = NULL;
internal_function->num_args = 0;

View File

@ -98,16 +98,18 @@ typedef struct _zend_fcall_info_cache {
#define ZEND_FE_END { NULL, NULL, NULL, 0, 0 }
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, 0, pass_by_ref},
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, 0, pass_by_ref},
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, allow_null, pass_by_ref},
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, allow_null, pass_by_ref},
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, allow_null, pass_by_ref},
#define ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, return_reference, required_num_args) \
#define ZEND_ARG_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_PASS_INFO(pass_by_ref) { NULL, 0, NULL, 0, 0, pass_by_ref, 0, 0 },
#define ZEND_ARG_OBJ_INFO(pass_by_ref, name, classname, allow_null) { #name, sizeof(#name)-1, #classname, sizeof(#classname)-1, IS_OBJECT, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_ARRAY_INFO(pass_by_ref, name, allow_null) { #name, sizeof(#name)-1, NULL, 0, IS_ARRAY, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_TYPE_INFO(pass_by_ref, name, type_hint, allow_null) { #name, sizeof(#name)-1, NULL, 0, type_hint, pass_by_ref, allow_null, 0 },
#define ZEND_ARG_VARIADIC_INFO(pass_by_ref, name) { #name, sizeof(#name)-1, NULL, 0, 0, pass_by_ref, 0, 1 },
#define ZEND_BEGIN_ARG_INFO_EX(name, _unused, return_reference, required_num_args) \
static const zend_arg_info name[] = { \
{ NULL, 0, NULL, required_num_args, 0, return_reference, pass_rest_by_reference},
#define ZEND_BEGIN_ARG_INFO(name, pass_rest_by_reference) \
ZEND_BEGIN_ARG_INFO_EX(name, pass_rest_by_reference, ZEND_RETURN_VALUE, -1)
{ NULL, 0, NULL, required_num_args, 0, return_reference, 0, 0 },
#define ZEND_BEGIN_ARG_INFO(name, _unused) \
ZEND_BEGIN_ARG_INFO_EX(name, 0, ZEND_RETURN_VALUE, -1)
#define ZEND_END_ARG_INFO() };
/* Name macros */

View File

@ -1822,7 +1822,7 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
}
/* }}} */
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference TSRMLS_DC) /* {{{ */
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_uchar pass_by_reference, zend_bool is_variadic TSRMLS_DC) /* {{{ */
{
zend_op *opline;
zend_arg_info *cur_arg_info;
@ -1846,6 +1846,19 @@ void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, con
}
}
if (CG(active_op_array)->fn_flags & ZEND_ACC_VARIADIC) {
zend_error(E_COMPILE_ERROR, "Only the last parameter can be variadic");
}
if (is_variadic) {
if (op == ZEND_RECV_INIT) {
zend_error(E_COMPILE_ERROR, "Variadic parameter cannot have a default value");
}
op = ZEND_RECV_VARIADIC;
CG(active_op_array)->fn_flags |= ZEND_ACC_VARIADIC;
}
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
CG(active_op_array)->num_args++;
opline->opcode = op;
@ -1854,16 +1867,19 @@ void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, con
if (op == ZEND_RECV_INIT) {
SET_NODE(opline->op2, initialization);
} else {
CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
SET_UNUSED(opline->op2);
if (!is_variadic) {
CG(active_op_array)->required_num_args = CG(active_op_array)->num_args;
}
}
CG(active_op_array)->arg_info = erealloc(CG(active_op_array)->arg_info, sizeof(zend_arg_info)*(CG(active_op_array)->num_args));
cur_arg_info = &CG(active_op_array)->arg_info[CG(active_op_array)->num_args-1];
cur_arg_info->name = zend_new_interned_string(estrndup(Z_STRVAL(varname->u.constant), Z_STRLEN(varname->u.constant)), Z_STRLEN(varname->u.constant) + 1, 1 TSRMLS_CC);
cur_arg_info->name_len = Z_STRLEN(varname->u.constant);
cur_arg_info->type_hint = 0;
cur_arg_info->allow_null = 1;
cur_arg_info->pass_by_reference = pass_by_reference;
cur_arg_info->allow_null = 1;
cur_arg_info->is_variadic = is_variadic;
cur_arg_info->class_name = NULL;
cur_arg_info->class_name_len = 0;
@ -3083,7 +3099,7 @@ static void do_inherit_method(zend_function *function) /* {{{ */
static zend_bool zend_do_perform_implementation_check(const zend_function *fe, const zend_function *proto TSRMLS_DC) /* {{{ */
{
zend_uint i;
zend_uint i, num_args;
/* If it's a user function then arg_info == NULL means we don't have any parameters but
* we still need to do the arg number checks. We are only willing to ignore this for internal
@ -3113,48 +3129,66 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
return 0;
}
if (fe->common.type != ZEND_USER_FUNCTION
&& (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) != 0
&& (fe->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) == 0) {
return 0;
}
/* by-ref constraints on return values are covariant */
if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
&& !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
return 0;
}
for (i=0; i < proto->common.num_args; i++) {
if (ZEND_LOG_XOR(fe->common.arg_info[i].class_name, proto->common.arg_info[i].class_name)) {
if ((proto->common.fn_flags & ZEND_ACC_VARIADIC)
&& !(fe->common.fn_flags & ZEND_ACC_VARIADIC)) {
return 0;
}
/* For variadic functions any additional (optional) arguments that were added must be
* checked against the signature of the variadic argument, so in this case we have to
* go through all the parameters of the function and not just those present in the
* prototype. */
num_args = proto->common.num_args;
if ((fe->common.fn_flags & ZEND_ACC_VARIADIC)
&& fe->common.num_args > proto->common.num_args) {
num_args = fe->common.num_args;
}
for (i = 0; i < num_args; i++) {
zend_arg_info *fe_arg_info = &fe->common.arg_info[i];
zend_arg_info *proto_arg_info;
if (i < proto->common.num_args) {
proto_arg_info = &proto->common.arg_info[i];
} else {
proto_arg_info = &proto->common.arg_info[proto->common.num_args-1];
}
if (ZEND_LOG_XOR(fe_arg_info->class_name, proto_arg_info->class_name)) {
/* Only one has a type hint and the other one doesn't */
return 0;
}
if (fe->common.arg_info[i].class_name) {
if (fe_arg_info->class_name) {
const char *fe_class_name, *proto_class_name;
zend_uint fe_class_name_len, proto_class_name_len;
if (!strcasecmp(fe->common.arg_info[i].class_name, "parent") && proto->common.scope) {
if (!strcasecmp(fe_arg_info->class_name, "parent") && proto->common.scope) {
fe_class_name = proto->common.scope->name;
fe_class_name_len = proto->common.scope->name_length;
} else if (!strcasecmp(fe->common.arg_info[i].class_name, "self") && fe->common.scope) {
} else if (!strcasecmp(fe_arg_info->class_name, "self") && fe->common.scope) {
fe_class_name = fe->common.scope->name;
fe_class_name_len = fe->common.scope->name_length;
} else {
fe_class_name = fe->common.arg_info[i].class_name;
fe_class_name_len = fe->common.arg_info[i].class_name_len;
fe_class_name = fe_arg_info->class_name;
fe_class_name_len = fe_arg_info->class_name_len;
}
if (!strcasecmp(proto->common.arg_info[i].class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
if (!strcasecmp(proto_arg_info->class_name, "parent") && proto->common.scope && proto->common.scope->parent) {
proto_class_name = proto->common.scope->parent->name;
proto_class_name_len = proto->common.scope->parent->name_length;
} else if (!strcasecmp(proto->common.arg_info[i].class_name, "self") && proto->common.scope) {
} else if (!strcasecmp(proto_arg_info->class_name, "self") && proto->common.scope) {
proto_class_name = proto->common.scope->name;
proto_class_name_len = proto->common.scope->name_length;
} else {
proto_class_name = proto->common.arg_info[i].class_name;
proto_class_name_len = proto->common.arg_info[i].class_name_len;
proto_class_name = proto_arg_info->class_name;
proto_class_name_len = proto_arg_info->class_name_len;
}
if (strcasecmp(fe_class_name, proto_class_name)!=0) {
@ -3181,24 +3215,17 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
}
}
}
if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
if (fe_arg_info->type_hint != proto_arg_info->type_hint) {
/* Incompatible type hint */
return 0;
}
/* by-ref constraints on arguments are invariant */
if (fe->common.arg_info[i].pass_by_reference != proto->common.arg_info[i].pass_by_reference) {
if (fe_arg_info->pass_by_reference != proto_arg_info->pass_by_reference) {
return 0;
}
}
if (proto->common.fn_flags & ZEND_ACC_PASS_REST_BY_REFERENCE) {
for (i=proto->common.num_args; i < fe->common.num_args; i++) {
if (!fe->common.arg_info[i].pass_by_reference) {
return 0;
}
}
}
return 1;
}
/* }}} */
@ -3271,6 +3298,13 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
if (arg_info->pass_by_reference) {
*(offset++) = '&';
}
if (arg_info->is_variadic) {
*(offset++) = '.';
*(offset++) = '.';
*(offset++) = '.';
}
*(offset++) = '$';
if (arg_info->name) {
@ -3286,7 +3320,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
idx /= 10;
} while (idx > 0);
}
if (i >= required) {
if (i >= required && !arg_info->is_variadic) {
*(offset++) = ' ';
*(offset++) = '=';
*(offset++) = ' ';

View File

@ -207,8 +207,7 @@ typedef struct _zend_try_catch_element {
/* disable inline caching */
#define ZEND_ACC_NEVER_CACHE 0x400000
#define ZEND_ACC_PASS_REST_BY_REFERENCE 0x1000000
#define ZEND_ACC_PASS_REST_PREFER_REF 0x2000000
#define ZEND_ACC_VARIADIC 0x1000000
#define ZEND_ACC_RETURN_REFERENCE 0x4000000
#define ZEND_ACC_DONE_PASS_TWO 0x8000000
@ -234,8 +233,9 @@ typedef struct _zend_arg_info {
const char *class_name;
zend_uint class_name_len;
zend_uchar type_hint;
zend_uchar pass_by_reference;
zend_bool allow_null;
zend_bool pass_by_reference;
zend_bool is_variadic;
} zend_arg_info;
/* the following structure repeats the layout of zend_arg_info,
@ -249,7 +249,8 @@ typedef struct _zend_internal_function_info {
zend_uint required_num_args;
zend_uchar _type_hint;
zend_bool return_reference;
zend_bool pass_rest_by_reference;
zend_bool _allow_null;
zend_bool _is_variadic;
} zend_internal_function_info;
typedef struct _zend_compiled_variable {
@ -500,7 +501,7 @@ void zend_do_add_variable(znode *result, const znode *op1, const znode *op2 TSRM
int zend_do_verify_access_types(const znode *current_access_type, const znode *new_modifier);
void zend_do_begin_function_declaration(znode *function_token, znode *function_name, int is_method, int return_reference, znode *fn_flags_znode TSRMLS_DC);
void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_bool pass_by_reference TSRMLS_DC);
void zend_do_receive_arg(zend_uchar op, znode *varname, const znode *offset, const znode *initialization, znode *class_type, zend_bool pass_by_reference, zend_bool is_variadic TSRMLS_DC);
int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace TSRMLS_DC);
void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC);
void zend_do_clone(znode *result, const znode *expr TSRMLS_DC);
@ -817,21 +818,21 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC);
#define ZEND_SEND_BY_REF 1
#define ZEND_SEND_PREFER_REF 2
#define CHECK_ARG_SEND_TYPE(zf, arg_num, m1, m2) \
((zf) && \
((((zend_function*)(zf))->common.arg_info && \
arg_num <= ((zend_function*)(zf))->common.num_args) ? \
(((zend_function *)(zf))->common.arg_info[arg_num-1].pass_by_reference & (m1)) : \
(((zend_function *)(zf))->common.fn_flags & (m2))))
#define CHECK_ARG_SEND_TYPE(zf, arg_num, m) \
((zf)->common.arg_info && \
(arg_num <= (zf)->common.num_args \
? ((zf)->common.arg_info[arg_num-1].pass_by_reference & (m)) \
: ((zf)->common.fn_flags & ZEND_ACC_VARIADIC) \
? ((zf)->common.arg_info[(zf)->common.num_args-1].pass_by_reference & (m)) : 0))
#define ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF, ZEND_ACC_PASS_REST_BY_REFERENCE)
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF)
#define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF, ZEND_ACC_PASS_REST_BY_REFERENCE|ZEND_ACC_PASS_REST_PREFER_REF)
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)
#define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_PREFER_REF, ZEND_ACC_PASS_REST_PREFER_REF)
CHECK_ARG_SEND_TYPE(zf, arg_num, ZEND_SEND_PREFER_REF)
#define ZEND_RETURN_VAL 0
#define ZEND_RETURN_REF 1

View File

@ -560,7 +560,7 @@ ZEND_METHOD(exception, getPrevious)
RETURN_ZVAL(previous, 1, 0);
}
int zend_spprintf(char **message, int max_len, char *format, ...) /* {{{ */
int zend_spprintf(char **message, int max_len, const char *format, ...) /* {{{ */
{
va_list arg;
int len;
@ -732,7 +732,7 @@ ZEND_API zend_class_entry *zend_get_error_exception(TSRMLS_D) /* {{{ */
}
/* }}} */
ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, char *message, long code TSRMLS_DC) /* {{{ */
ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, const char *message, long code TSRMLS_DC) /* {{{ */
{
zval *ex;
@ -760,7 +760,7 @@ ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, char *messa
}
/* }}} */
ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, char *format, ...) /* {{{ */
ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, const char *format, ...) /* {{{ */
{
va_list arg;
char *message;
@ -775,7 +775,7 @@ ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long cod
}
/* }}} */
ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, char *message, long code, int severity TSRMLS_DC) /* {{{ */
ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, const char *message, long code, int severity TSRMLS_DC) /* {{{ */
{
zval *ex = zend_throw_exception(exception_ce, message, code TSRMLS_CC);
zend_update_property_long(default_exception_ce, ex, "severity", sizeof("severity")-1, severity TSRMLS_CC);

View File

@ -40,12 +40,12 @@ ZEND_API void zend_register_default_classes(TSRMLS_D);
/* exception_ce NULL or zend_exception_get_default() or a derived class
* message NULL or the message of the exception */
ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, char *message, long code TSRMLS_DC);
ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, char *format, ...);
ZEND_API zval * zend_throw_exception(zend_class_entry *exception_ce, const char *message, long code TSRMLS_DC);
ZEND_API zval * zend_throw_exception_ex(zend_class_entry *exception_ce, long code TSRMLS_DC, const char *format, ...);
ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC);
ZEND_API void zend_clear_exception(TSRMLS_D);
ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, char *message, long code, int severity TSRMLS_DC);
ZEND_API zval * zend_throw_error_exception(zend_class_entry *exception_ce, const char *message, long code, int severity TSRMLS_DC);
extern ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
@ -53,7 +53,7 @@ extern ZEND_API void (*zend_throw_exception_hook)(zval *ex TSRMLS_DC);
ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC);
/* do not export, in php it's available thru spprintf directly */
int zend_spprintf(char **message, int max_len, char *format, ...);
int zend_spprintf(char **message, int max_len, const char *format, ...);
END_EXTERN_C()

View File

@ -616,12 +616,17 @@ static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zva
char *need_msg;
zend_class_entry *ce;
if (!zf->common.arg_info
|| arg_num>zf->common.num_args) {
if (!zf->common.arg_info) {
return 1;
}
cur_arg_info = &zf->common.arg_info[arg_num-1];
if (arg_num <= zf->common.num_args) {
cur_arg_info = &zf->common.arg_info[arg_num-1];
} else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
cur_arg_info = &zf->common.arg_info[zf->common.num_args-1];
} else {
return 1;
}
if (cur_arg_info->class_name) {
const char *class_name;

View File

@ -212,6 +212,7 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
%token T_NS_C "__NAMESPACE__ (T_NS_C)"
%token T_DIR "__DIR__ (T_DIR)"
%token T_NS_SEPARATOR "\\ (T_NS_SEPARATOR)"
%token T_ELLIPSIS "... (T_ELLIPSIS)"
%% /* Rules */
@ -371,10 +372,14 @@ class_declaration_statement:
;
is_reference:
/* empty */ { $$.op_type = ZEND_RETURN_VAL; }
| '&' { $$.op_type = ZEND_RETURN_REF; }
/* empty */ { $$.op_type = 0; }
| '&' { $$.op_type = 1; }
;
is_variadic:
/* empty */ { $$.op_type = 0; }
| T_ELLIPSIS { $$.op_type = 1; }
;
unticked_function_declaration_statement:
function is_reference T_STRING { zend_do_begin_function_declaration(&$1, &$3, 0, $2.op_type, NULL TSRMLS_CC); }
@ -523,14 +528,14 @@ parameter_list:
non_empty_parameter_list:
optional_class_type T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$2, &$$, NULL, &$1, 0 TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$3, &$$, NULL, &$1, 1 TSRMLS_CC); }
| optional_class_type '&' T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$3, &$$, &$5, &$1, 1 TSRMLS_CC); }
| optional_class_type T_VARIABLE '=' static_scalar { $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$2, &$$, &$4, &$1, 0 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$3, 0 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$5, &$$, NULL, &$3, 1 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type '&' T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$5, &$$, &$7, &$3, 1 TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type T_VARIABLE '=' static_scalar { $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$3, 0 TSRMLS_CC); }
optional_class_type is_reference is_variadic T_VARIABLE
{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV, &$4, &$$, NULL, &$1, $2.op_type, $3.op_type TSRMLS_CC); }
| optional_class_type is_reference is_variadic T_VARIABLE '=' static_scalar
{ $$.op_type = IS_UNUSED; $$.u.op.num=1; zend_do_receive_arg(ZEND_RECV_INIT, &$4, &$$, &$6, &$1, $2.op_type, $3.op_type TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type is_reference is_variadic T_VARIABLE
{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV, &$6, &$$, NULL, &$3, $4.op_type, $5.op_type TSRMLS_CC); }
| non_empty_parameter_list ',' optional_class_type is_reference is_variadic T_VARIABLE '=' static_scalar
{ $$=$1; $$.u.op.num++; zend_do_receive_arg(ZEND_RECV_INIT, &$6, &$$, &$8, &$3, $4.op_type, $5.op_type TSRMLS_CC); }
;

File diff suppressed because it is too large Load Diff

View File

@ -1011,7 +1011,6 @@ NEWLINE ("\r"|"\n"|"\r\n")
/* compute yyleng before each rule */
<!*> := yyleng = YYCURSOR - SCNG(yy_text);
<ST_IN_SCRIPTING>"exit" {
return T_EXIT;
}
@ -1204,6 +1203,10 @@ NEWLINE ("\r"|"\n"|"\r\n")
return T_NS_SEPARATOR;
}
<ST_IN_SCRIPTING>"..." {
return T_ELLIPSIS;
}
<ST_IN_SCRIPTING>"new" {
return T_NEW;
}

View File

@ -3279,6 +3279,37 @@ ZEND_VM_HANDLER(64, ZEND_RECV_INIT, ANY, CONST)
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, ANY, ANY)
{
USE_OPLINE
zend_uint arg_num = opline->op1.num;
zend_uint arg_count = zend_vm_stack_get_args_count(TSRMLS_C);
zval **var_ptr, *params;
SAVE_OPLINE();
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
Z_DELREF_PP(var_ptr);
MAKE_STD_ZVAL(params);
*var_ptr = params;
if (arg_num <= arg_count) {
array_init_size(params, arg_count - arg_num + 1);
} else {
array_init(params);
}
for (; arg_num <= arg_count; ++arg_num) {
zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
Z_ADDREF_PP(param);
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
ZEND_VM_HANDLER(52, ZEND_BOOL, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE

View File

@ -742,6 +742,37 @@ static int ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_uint arg_num = opline->op1.num;
zend_uint arg_count = zend_vm_stack_get_args_count(TSRMLS_C);
zval **var_ptr, *params;
SAVE_OPLINE();
var_ptr = _get_zval_ptr_ptr_cv_BP_VAR_W(execute_data, opline->result.var TSRMLS_CC);
Z_DELREF_PP(var_ptr);
MAKE_STD_ZVAL(params);
*var_ptr = params;
if (arg_num <= arg_count) {
array_init_size(params, arg_count - arg_num + 1);
} else {
array_init(params);
}
for (; arg_num <= arg_count; ++arg_num) {
zval **param = zend_vm_stack_get_arg(arg_num TSRMLS_CC);
zend_verify_arg_type((zend_function *) EG(active_op_array), arg_num, *param, opline->extended_value TSRMLS_CC);
zend_hash_next_index_insert(Z_ARRVAL_P(params), param, sizeof(zval *), NULL);
Z_ADDREF_PP(param);
}
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}
static int ZEND_FASTCALL ZEND_NEW_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
@ -44895,6 +44926,31 @@ void zend_init_opcodes_handlers(void)
ZEND_FAST_RET_SPEC_HANDLER,
ZEND_FAST_RET_SPEC_HANDLER,
ZEND_FAST_RET_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_RECV_VARIADIC_SPEC_HANDLER,
ZEND_NULL_HANDLER
};
zend_opcode_handlers = (opcode_handler_t*)labels;

View File

@ -164,3 +164,4 @@
#define ZEND_GENERATOR_RETURN 161
#define ZEND_FAST_CALL 162
#define ZEND_FAST_RET 163
#define ZEND_RECV_VARIADIC 164

View File

@ -226,12 +226,17 @@ static size_t php_dba_make_key(zval *key, char **key_str, char **key_free TSRMLS
*key_free = *key_str;
return len;
} else {
*key_free = NULL;
zval tmp = *key;
int len;
convert_to_string(key);
*key_str = Z_STRVAL_P(key);
zval_copy_ctor(&tmp);
convert_to_string(&tmp);
return Z_STRLEN_P(key);
*key_free = *key_str = estrndup(Z_STRVAL(tmp), Z_STRLEN(tmp));
len = Z_STRLEN(tmp);
zval_dtor(&tmp);
return len;
}
}
/* }}} */
@ -297,6 +302,14 @@ static size_t php_dba_make_key(zval *key, char **key_str, char **key_free TSRMLS
RETURN_FALSE; \
}
/* the same check, but with a call to DBA_ID_DONE before returning */
#define DBA_WRITE_CHECK_WITH_ID \
if(info->mode != DBA_WRITER && info->mode != DBA_TRUNC && info->mode != DBA_CREAT) { \
php_error_docref(NULL TSRMLS_CC, E_WARNING, "You cannot perform a modification to a database without proper access"); \
DBA_ID_DONE; \
RETURN_FALSE; \
}
/* }}} */
/* {{{ globals */
@ -557,7 +570,7 @@ static void php_dba_update(INTERNAL_FUNCTION_PARAMETERS, int mode)
DBA_FETCH_RESOURCE(info, &id);
DBA_WRITE_CHECK;
DBA_WRITE_CHECK_WITH_ID;
if (info->hnd->update(info, key_str, key_len, val, val_len, mode TSRMLS_CC) == SUCCESS) {
DBA_ID_DONE;
@ -1110,7 +1123,7 @@ PHP_FUNCTION(dba_delete)
{
DBA_ID_GET2;
DBA_WRITE_CHECK;
DBA_WRITE_CHECK_WITH_ID;
if(info->hnd->delete(info, key_str, key_len TSRMLS_CC) == SUCCESS)
{

View File

@ -0,0 +1,38 @@
--TEST--
Bug #65708 (dba functions cast $key param to string in-place, bypassing copy on write)
--SKIPIF--
<?php
require_once(dirname(__FILE__) .'/skipif.inc');
?>
--FILE--
<?php
error_reporting(E_ALL);
require_once(dirname(__FILE__) .'/test.inc');
$db = dba_popen($db_filename, 'c');
$key = 1;
$copy = $key;
echo gettype($key)."\n";
echo gettype($copy)."\n";
dba_exists($key, $db);
echo gettype($key)."\n";
echo gettype($copy)."\n";
dba_close($db);
?>
--CLEAN--
<?php
require(dirname(__FILE__) .'/clean.inc');
?>
--EXPECT--
integer
integer
integer
integer

View File

@ -402,10 +402,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_kana, 0, 0, 1)
ZEND_ARG_INFO(0, encoding)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 1, 0, 3)
ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_convert_variables, 0, 0, 3)
ZEND_ARG_INFO(0, to)
ZEND_ARG_INFO(0, from)
ZEND_ARG_INFO(1, ...)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mb_encode_numericentity, 0, 0, 2)

View File

@ -43,23 +43,28 @@
#define MYSQLI_ZEND_ARG_OBJ_INFO_STMT() ZEND_ARG_INFO(0, stmt)
#endif
ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_result, 1)
ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_result, 0)
MYSQLI_ZEND_ARG_OBJ_INFO_STMT()
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_param, 1)
ZEND_BEGIN_ARG_INFO(arginfo_mysqli_stmt_bind_param, 0)
MYSQLI_ZEND_ARG_OBJ_INFO_STMT()
ZEND_ARG_INFO(0, types)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_result, 1)
ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_result, 0)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_param, 1)
ZEND_BEGIN_ARG_INFO(arginfo_class_mysqli_stmt_bind_param, 0)
ZEND_ARG_INFO(0, types)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(all_args_force_by_ref, 1)
ZEND_BEGIN_ARG_INFO(all_args_force_by_ref, 0)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_mysqli_poll, 0, 0, 4)

View File

@ -1899,7 +1899,7 @@ next_target_znz:
#endif
/* Find a set of variables which are used outside of the block where they are
* defined. We won't apply some optimization patterns for sush variables. */
* defined. We won't apply some optimization patterns for such variables. */
static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *used_ext)
{
zend_code_block *next_block = block->next;
@ -1931,6 +1931,7 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *
if (RESULT_USED(opline)) {
if (!defined_here[VAR_NUM(ZEND_RESULT(opline).var)] && !used_ext[VAR_NUM(ZEND_RESULT(opline).var)] &&
(opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT ||
opline->opcode == ZEND_RECV_VARIADIC ||
(opline->opcode == ZEND_OP_DATA && ZEND_RESULT_TYPE(opline) == IS_TMP_VAR) ||
opline->opcode == ZEND_ADD_ARRAY_ELEMENT)) {
/* these opcodes use the result as argument */
@ -2015,6 +2016,7 @@ static void zend_t_usage(zend_code_block *block, zend_op_array *op_array, char *
if (opline->opcode == ZEND_RECV ||
opline->opcode == ZEND_RECV_INIT ||
opline->opcode == ZEND_RECV_VARIADIC ||
opline->opcode == ZEND_ADD_ARRAY_ELEMENT) {
if (ZEND_OP1_TYPE(opline) == IS_VAR || ZEND_OP1_TYPE(opline) == IS_TMP_VAR) {
usage[VAR_NUM(ZEND_RESULT(opline).var)] = 1;

View File

@ -1450,7 +1450,7 @@ static zend_persistent_script *compile_and_cache_file(zend_file_handle *file_han
}
/* zend_compile() replacement */
static zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC)
{
zend_persistent_script *persistent_script = NULL;
char *key = NULL;
@ -2411,14 +2411,14 @@ static inline int accel_find_sapi(TSRMLS_D)
return FAILURE;
}
static void zend_accel_init_shm(TSRMLS_D)
static int zend_accel_init_shm(TSRMLS_D)
{
zend_shared_alloc_lock(TSRMLS_C);
accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
if (!accel_shared_globals) {
zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
return;
return FAILURE;
}
ZSMMG(app_shared_globals) = accel_shared_globals;
@ -2433,7 +2433,8 @@ static void zend_accel_init_shm(TSRMLS_D)
ZCSG(interned_strings).arBuckets = zend_shared_alloc(ZCSG(interned_strings).nTableSize * sizeof(Bucket *));
ZCSG(interned_strings_start) = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
if (!ZCSG(interned_strings).arBuckets || !ZCSG(interned_strings_start)) {
zend_error(E_ERROR, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
zend_accel_error(ACCEL_LOG_FATAL, ACCELERATOR_PRODUCT_NAME " cannot allocate buffer for interned strings");
return FAILURE;
}
ZCSG(interned_strings_end) = ZCSG(interned_strings_start) + (ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
ZCSG(interned_strings_top) = ZCSG(interned_strings_start);
@ -2472,6 +2473,8 @@ static void zend_accel_init_shm(TSRMLS_D)
ZCSG(restart_in_progress) = 0;
zend_shared_alloc_unlock(TSRMLS_C);
return SUCCESS;
}
static void accel_globals_ctor(zend_accel_globals *accel_globals TSRMLS_DC)
@ -2529,7 +2532,10 @@ static int accel_startup(zend_extension *extension)
/********************************************/
switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
case ALLOC_SUCCESS:
zend_accel_init_shm(TSRMLS_C);
if (zend_accel_init_shm(TSRMLS_C) == FAILURE) {
accel_startup_ok = 0;
return FAILURE;
}
break;
case ALLOC_FAILURE:
accel_startup_ok = 0;

View File

@ -326,6 +326,7 @@ int accelerator_shm_read_lock(TSRMLS_D);
void accelerator_shm_read_unlock(TSRMLS_D);
char *accel_make_persistent_key_ex(zend_file_handle *file_handle, int path_length, int *key_len TSRMLS_DC);
zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type TSRMLS_DC);
#if !defined(ZEND_DECLARE_INHERITED_CLASS_DELAYED)
# define ZEND_DECLARE_INHERITED_CLASS_DELAYED 145

View File

@ -48,6 +48,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_get_status, 0, 0, 0)
ZEND_ARG_INFO(0, fetch_scripts)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_compile_file, 0, 0, 1)
ZEND_ARG_INFO(0, file)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_opcache_invalidate, 0, 0, 1)
ZEND_ARG_INFO(0, script)
ZEND_ARG_INFO(0, force)
@ -59,12 +63,14 @@ static ZEND_FUNCTION(opcache_invalidate);
/* Private functions */
static ZEND_FUNCTION(opcache_get_status);
static ZEND_FUNCTION(opcache_compile_file);
static ZEND_FUNCTION(opcache_get_configuration);
static zend_function_entry accel_functions[] = {
/* User functions */
ZEND_FE(opcache_reset, arginfo_opcache_none)
ZEND_FE(opcache_invalidate, arginfo_opcache_invalidate)
ZEND_FE(opcache_compile_file, arginfo_opcache_compile_file)
/* Private functions */
ZEND_FE(opcache_get_configuration, arginfo_opcache_none)
ZEND_FE(opcache_get_status, arginfo_opcache_get_status)
@ -709,3 +715,44 @@ static ZEND_FUNCTION(opcache_invalidate)
RETURN_FALSE;
}
}
static ZEND_FUNCTION(opcache_compile_file)
{
char *script_name;
int script_name_len;
zend_file_handle handle;
zend_op_array *op_array = NULL;
zend_execute_data *orig_execute_data = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &script_name, &script_name_len) == FAILURE) {
return;
}
if (!ZCG(enabled) || !accel_startup_ok || !ZCSG(accelerator_enabled)) {
zend_error(E_NOTICE, ACCELERATOR_PRODUCT_NAME " seems to be disabled, can't compile file");
RETURN_FALSE;
}
handle.filename = script_name;
handle.free_filename = 0;
handle.opened_path = NULL;
handle.type = ZEND_HANDLE_FILENAME;
orig_execute_data = EG(current_execute_data);
zend_try {
op_array = persistent_compile_file(&handle, ZEND_INCLUDE TSRMLS_CC);
} zend_catch {
EG(current_execute_data) = orig_execute_data;
zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME " could not compile file %s" TSRMLS_CC, handle.filename);
} zend_end_try();
if(op_array != NULL) {
destroy_op_array(op_array TSRMLS_CC);
efree(op_array);
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
zend_destroy_file_handle(&handle TSRMLS_CC);
}

View File

@ -1328,16 +1328,12 @@ int pdo_hash_methods(pdo_dbh_t *dbh, int kind TSRMLS_DC)
} else {
ifunc->required_num_args = info->required_num_args;
}
if (info->pass_rest_by_reference) {
if (info->pass_rest_by_reference == ZEND_SEND_PREFER_REF) {
ifunc->fn_flags |= ZEND_ACC_PASS_REST_PREFER_REF;
} else {
ifunc->fn_flags |= ZEND_ACC_PASS_REST_BY_REFERENCE;
}
}
if (info->return_reference) {
ifunc->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
}
if (funcs->arg_info[funcs->num_args].is_variadic) {
ifunc->fn_flags |= ZEND_ACC_VARIADIC;
}
} else {
ifunc->arg_info = NULL;
ifunc->num_args = 0;

View File

@ -681,8 +681,8 @@ static zend_op* _get_recv_op(zend_op_array *op_array, zend_uint offset)
++offset;
while (op < end) {
if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
&& op->op1.num == (long)offset)
if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
|| op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == (long)offset)
{
return op;
}
@ -715,6 +715,9 @@ static void _parameter_string(string *str, zend_function *fptr, struct _zend_arg
if (arg_info->pass_by_reference) {
string_write(str, "&", sizeof("&")-1);
}
if (arg_info->is_variadic) {
string_write(str, "...", sizeof("...")-1);
}
if (arg_info->name) {
string_printf(str, "$%s", arg_info->name);
} else {
@ -2652,6 +2655,22 @@ ZEND_METHOD(reflection_parameter, getDefaultValueConstantName)
}
/* }}} */
/* {{{ proto public bool ReflectionParameter::isVariadic()
Returns whether this parameter is a variadic parameter */
ZEND_METHOD(reflection_parameter, isVariadic)
{
reflection_object *intern;
parameter_reference *param;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
GET_REFLECTION_OBJECT_PTR(param);
RETVAL_BOOL(param->arg_info->is_variadic);
}
/* }}} */
/* {{{ proto public static mixed ReflectionMethod::export(mixed class, string name [, bool return]) throws ReflectionException
Exports a reflection object. Returns the output if TRUE is specified for return, printing it otherwise. */
ZEND_METHOD(reflection_method, export)
@ -3095,6 +3114,14 @@ ZEND_METHOD(reflection_function, isGenerator)
}
/* }}} */
/* {{{ proto public bool ReflectionFunction::isVariadic()
Returns whether this function is variadic */
ZEND_METHOD(reflection_function, isVariadic)
{
_function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
}
/* }}} */
/* {{{ proto public bool ReflectionFunction::inNamespace()
Returns whether this function is defined in namespace */
ZEND_METHOD(reflection_function, inNamespace)
@ -5720,6 +5747,7 @@ static const zend_function_entry reflection_function_abstract_functions[] = {
ZEND_ME(reflection_function, isInternal, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, isUserDefined, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, isGenerator, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, isVariadic, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getClosureThis, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getClosureScopeClass, arginfo_reflection__void, 0)
ZEND_ME(reflection_function, getDocComment, arginfo_reflection__void, 0)
@ -6022,6 +6050,7 @@ static const zend_function_entry reflection_parameter_functions[] = {
ZEND_ME(reflection_parameter, getDefaultValue, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, isDefaultValueConstant, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, getDefaultValueConstantName, arginfo_reflection__void, 0)
ZEND_ME(reflection_parameter, isVariadic, arginfo_reflection__void, 0)
PHP_FE_END
};

View File

@ -0,0 +1,18 @@
--TEST--
ReflectionFunction::isVariadic()
--FILE--
<?php
function test1($args) {}
function test2(...$args) {}
function test3($arg, ...$args) {}
var_dump((new ReflectionFunction('test1'))->isVariadic());
var_dump((new ReflectionFunction('test2'))->isVariadic());
var_dump((new ReflectionFunction('test3'))->isVariadic());
?>
--EXPECT--
bool(false)
bool(true)
bool(true)

View File

@ -61,6 +61,10 @@ Name: SORT_REGULAR_or_SORT_NUMERIC_or_SORT_STRING
Is passed by reference: yes
Can be passed by value: yes
Name: more_array_and_sort_options
Is passed by reference: yes
Can be passed by value: yes
=> sort:
Name: arg

View File

@ -0,0 +1,24 @@
--TEST--
ReflectionParameter::isVariadic()
--FILE--
<?php
function test1($args) {}
function test2(...$args) {}
function test3($arg, ...$args) {}
$r1 = new ReflectionFunction('test1');
$r2 = new ReflectionFunction('test2');
$r3 = new ReflectionFunction('test3');
var_dump($r1->getParameters()[0]->isVariadic());
var_dump($r2->getParameters()[0]->isVariadic());
var_dump($r3->getParameters()[0]->isVariadic());
var_dump($r3->getParameters()[1]->isVariadic());
?>
--EXPECT--
bool(false)
bool(true)
bool(false)
bool(true)

View File

@ -4,7 +4,7 @@ ReflectionParameter::__toString()
Stefan Koopmanschap <stefan@stefankoopmanschap.nl>
--FILE--
<?php
function ReflectionParameterTest($test, $test2 = null) {
function ReflectionParameterTest($test, $test2 = null, ...$test3) {
echo $test;
}
$reflect = new ReflectionFunction('ReflectionParameterTest');
@ -17,4 +17,5 @@ foreach($params as $key => $value) {
--EXPECT--
Parameter #0 [ <required> $test ]
Parameter #1 [ <optional> $test2 = NULL ]
Parameter #2 [ <optional> ...$test3 ]
==DONE==

View File

@ -2938,8 +2938,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fgetss, 0, 0, 0)
ZEND_ARG_INFO(0, allowable_tags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 1, 0, 1)
ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fscanf, 0, 0, 1)
ZEND_ARG_INFO(0, format)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_file_object_fwrite, 0, 0, 1)

View File

@ -4,7 +4,7 @@ SPL: Allow valid extension of SplFileObject::fscanf
<?php
class A extends SplFileObject {
public function fscanf($format) {
public function fscanf($format, &...$vars) {
}
}

View File

@ -1890,7 +1890,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3stmt_bindvalue, 0, 0, 2)
ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_sqlite3stmt_construct, 1)
ZEND_BEGIN_ARG_INFO_EX(arginfo_sqlite3stmt_construct, 0, 0, 1)
ZEND_ARG_INFO(0, sqlite3)
ZEND_END_ARG_INFO()

View File

@ -288,11 +288,11 @@ ZEND_BEGIN_ARG_INFO(arginfo_reset, 0)
ZEND_ARG_INFO(1, arg)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_current, ZEND_SEND_PREFER_REF)
ZEND_BEGIN_ARG_INFO(arginfo_current, 0)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_key, ZEND_SEND_PREFER_REF)
ZEND_BEGIN_ARG_INFO(arginfo_key, 0)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arg)
ZEND_END_ARG_INFO()
@ -564,13 +564,14 @@ ZEND_BEGIN_ARG_INFO(arginfo_array_udiff_uassoc, 0)
ZEND_ARG_INFO(0, callback_key_comp_func)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_multisort, ZEND_SEND_PREFER_REF, 0, 1)
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_multisort, 0, 0, 1)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arr1) /* ARRAY_INFO(0, arg1, 0) */
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, SORT_ASC_or_SORT_DESC)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, SORT_REGULAR_or_SORT_NUMERIC_or_SORT_STRING)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, arr2)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, SORT_ASC_or_SORT_DESC)
ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, SORT_REGULAR_or_SORT_NUMERIC_or_SORT_STRING)
ZEND_ARG_VARIADIC_INFO(ZEND_SEND_PREFER_REF, more_array_and_sort_options)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_array_rand, 0, 0, 1)
@ -1139,10 +1140,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_fgetss, 0, 0, 1)
ZEND_ARG_INFO(0, allowable_tags)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_fscanf, 1, 0, 2)
ZEND_BEGIN_ARG_INFO_EX(arginfo_fscanf, 0, 0, 2)
ZEND_ARG_INFO(0, stream)
ZEND_ARG_INFO(0, format)
ZEND_ARG_INFO(1, ...)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_fwrite, 0, 0, 2)
@ -2450,10 +2451,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_str_pad, 0, 0, 2)
ZEND_ARG_INFO(0, pad_type)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_sscanf, 1, 0, 2)
ZEND_BEGIN_ARG_INFO_EX(arginfo_sscanf, 0, 0, 2)
ZEND_ARG_INFO(0, str)
ZEND_ARG_INFO(0, format)
ZEND_ARG_INFO(1, ...)
ZEND_ARG_VARIADIC_INFO(1, vars)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO(arginfo_str_rot13, 0)

View File

@ -38,6 +38,7 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
REGISTER_LONG_CONSTANT("T_LOGICAL_XOR", T_LOGICAL_XOR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_LOGICAL_AND", T_LOGICAL_AND, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_PRINT", T_PRINT, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_YIELD", T_YIELD, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_SR_EQUAL", T_SR_EQUAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_SL_EQUAL", T_SL_EQUAL, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_XOR_EQUAL", T_XOR_EQUAL, CONST_CS | CONST_PERSISTENT);
@ -108,7 +109,6 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
REGISTER_LONG_CONSTANT("T_FUNCTION", T_FUNCTION, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_CONST", T_CONST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_RETURN", T_RETURN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_YIELD", T_YIELD, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_TRY", T_TRY, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_CATCH", T_CATCH, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_FINALLY", T_FINALLY, CONST_CS | CONST_PERSISTENT);
@ -158,6 +158,7 @@ void tokenizer_register_constants(INIT_FUNC_ARGS) {
REGISTER_LONG_CONSTANT("T_NS_C", T_NS_C, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_DIR", T_DIR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_NS_SEPARATOR", T_NS_SEPARATOR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_ELLIPSIS", T_ELLIPSIS, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("T_DOUBLE_COLON", T_PAAMAYIM_NEKUDOTAYIM, CONST_CS | CONST_PERSISTENT);
}
@ -174,6 +175,7 @@ char *get_token_type_name(int token_type)
case T_LOGICAL_XOR: return "T_LOGICAL_XOR";
case T_LOGICAL_AND: return "T_LOGICAL_AND";
case T_PRINT: return "T_PRINT";
case T_YIELD: return "T_YIELD";
case T_SR_EQUAL: return "T_SR_EQUAL";
case T_SL_EQUAL: return "T_SL_EQUAL";
case T_XOR_EQUAL: return "T_XOR_EQUAL";
@ -244,7 +246,6 @@ char *get_token_type_name(int token_type)
case T_FUNCTION: return "T_FUNCTION";
case T_CONST: return "T_CONST";
case T_RETURN: return "T_RETURN";
case T_YIELD: return "T_YIELD";
case T_TRY: return "T_TRY";
case T_CATCH: return "T_CATCH";
case T_FINALLY: return "T_FINALLY";
@ -294,6 +295,7 @@ char *get_token_type_name(int token_type)
case T_NS_C: return "T_NS_C";
case T_DIR: return "T_DIR";
case T_NS_SEPARATOR: return "T_NS_SEPARATOR";
case T_ELLIPSIS: return "T_ELLIPSIS";
}
return "UNKNOWN";