1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2016-01-02 17:56:11 +08:00
| Copyright ( c ) 1998 - 2016 Zend Technologies Ltd . ( http : //www.zend.com) |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license , |
2002-10-25 02:04:12 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2001-12-11 23:16:21 +08:00
| http : //www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
2015-08-31 16:38:16 +08:00
| Dmitry Stogov < dmitry @ zend . com > |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2003-02-01 09:49:15 +08:00
/* $Id$ */
2000-02-10 05:48:16 +08:00
# define ZEND_INTENSIVE_DEBUGGING 0
1999-07-16 22:58:16 +08:00
1999-04-08 02:10:10 +08:00
# include <stdio.h>
# include <signal.h>
# include "zend.h"
# include "zend_compile.h"
# include "zend_execute.h"
# include "zend_API.h"
# include "zend_ptr_stack.h"
# include "zend_constants.h"
# include "zend_extensions.h"
2002-11-20 01:51:30 +08:00
# include "zend_ini.h"
2004-02-12 18:38:14 +08:00
# include "zend_exceptions.h"
2006-05-10 07:53:23 +08:00
# include "zend_interfaces.h"
2008-07-14 17:49:03 +08:00
# include "zend_closures.h"
2012-05-20 20:45:01 +08:00
# include "zend_generators.h"
2004-09-24 05:43:32 +08:00
# include "zend_vm.h"
2010-04-24 21:32:30 +08:00
# include "zend_dtrace.h"
2014-09-19 06:01:05 +08:00
# include "zend_inheritance.h"
2016-03-18 03:00:27 +08:00
# include "zend_type_info.h"
2004-09-24 05:43:32 +08:00
2006-05-15 23:31:27 +08:00
/* Virtual current working directory support */
2013-10-17 15:43:52 +08:00
# include "zend_virtual_cwd.h"
2006-05-15 23:31:27 +08:00
2004-10-23 05:42:14 +08:00
# define _CONST_CODE 0
# define _TMP_CODE 1
# define _VAR_CODE 2
# define _UNUSED_CODE 3
# define _CV_CODE 4
2015-03-14 03:25:10 +08:00
typedef int ( ZEND_FASTCALL * incdec_t ) ( zval * ) ;
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
# define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type)
# define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type)
2015-09-09 08:18:52 +08:00
# define get_zval_ptr_r(op_type, node, ex, should_free) _get_zval_ptr_r(op_type, node, ex, should_free)
# define get_zval_ptr_r_deref(op_type, node, ex, should_free) _get_zval_ptr_r_deref(op_type, node, ex, should_free)
2015-03-17 23:53:19 +08:00
# define get_zval_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_undef(op_type, node, ex, should_free, type)
2014-12-14 06:06:14 +08:00
# define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
# define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type)
# define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type)
2015-06-05 06:53:32 +08:00
# define get_obj_zval_ptr_undef(op_type, node, ex, should_free, type) _get_obj_zval_ptr_undef(op_type, node, ex, should_free, type)
2014-12-14 06:06:14 +08:00
# define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type)
1999-04-08 02:10:10 +08:00
/* Prototypes */
2014-12-14 06:06:14 +08:00
static void zend_extension_statement_handler ( const zend_extension * extension , zend_op_array * op_array ) ;
static void zend_extension_fcall_begin_handler ( const zend_extension * extension , zend_op_array * op_array ) ;
static void zend_extension_fcall_end_handler ( const zend_extension * extension , zend_op_array * op_array ) ;
1999-04-08 02:10:10 +08:00
2016-02-05 22:23:23 +08:00
# define RETURN_VALUE_USED(opline) ((opline)->result_type != IS_UNUSED)
1999-12-21 23:55:46 +08:00
2014-07-11 04:32:18 +08:00
static ZEND_FUNCTION ( pass )
{
}
static const zend_internal_function zend_pass_function = {
ZEND_INTERNAL_FUNCTION , /* type */
2015-04-23 02:46:13 +08:00
{ 0 , 0 , 0 } , /* arg_flags */
2014-08-28 02:45:27 +08:00
0 , /* fn_flags */
2014-07-11 04:32:18 +08:00
NULL , /* name */
NULL , /* scope */
NULL , /* prototype */
0 , /* num_args */
0 , /* required_num_args */
NULL , /* arg_info */
ZEND_FN ( pass ) , /* handler */
NULL /* module */
} ;
2010-04-20 19:16:39 +08:00
# undef zval_ptr_dtor
2014-12-14 06:06:14 +08:00
# define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC)
2010-04-20 19:16:39 +08:00
2014-08-27 23:10:29 +08:00
# define READY_TO_DESTROY(zv) \
2015-08-23 10:40:28 +08:00
( UNEXPECTED ( zv ) & & Z_REFCOUNTED_P ( zv ) & & Z_REFCOUNT_P ( zv ) = = 1 )
2014-08-27 23:10:29 +08:00
2015-12-23 20:56:49 +08:00
# define EXTRACT_ZVAL_PTR(zv) do { \
2015-07-17 15:55:34 +08:00
zval * __zv = ( zv ) ; \
2015-08-19 17:21:14 +08:00
if ( EXPECTED ( Z_TYPE_P ( __zv ) = = IS_INDIRECT ) ) { \
2015-12-23 20:56:49 +08:00
ZVAL_COPY ( __zv , Z_INDIRECT_P ( __zv ) ) ; \
2015-07-17 15:55:34 +08:00
} \
} while ( 0 )
2007-12-14 22:14:50 +08:00
2004-08-20 04:03:06 +08:00
# define FREE_OP(should_free) \
2014-11-18 14:05:48 +08:00
if ( should_free ) { \
zval_ptr_dtor_nogc ( should_free ) ; \
2004-08-20 04:03:06 +08:00
}
2015-03-09 20:57:15 +08:00
# define FREE_UNFETCHED_OP(type, var) \
if ( ( type ) & ( IS_TMP_VAR | IS_VAR ) ) { \
zval_ptr_dtor_nogc ( EX_VAR ( var ) ) ; \
}
2004-08-20 04:03:06 +08:00
# define FREE_OP_VAR_PTR(should_free) \
2014-11-18 14:05:48 +08:00
if ( should_free ) { \
zval_ptr_dtor_nogc ( should_free ) ; \
2004-08-20 04:03:06 +08:00
}
2014-08-08 17:47:34 +08:00
# define CV_DEF_OF(i) (EX(func)->op_array.vars[i])
2004-10-05 03:54:35 +08:00
2015-03-07 20:07:18 +08:00
# define ZEND_VM_MAIN_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
# define ZEND_VM_GENERATOR_STACK_PAGE_SLOTS (256)
2014-10-10 00:29:02 +08:00
2015-03-07 20:07:18 +08:00
# define ZEND_VM_STACK_PAGE_SLOTS(gen) ((gen) ? ZEND_VM_GENERATOR_STACK_PAGE_SLOTS : ZEND_VM_MAIN_STACK_PAGE_SLOTS)
2014-10-10 00:29:02 +08:00
2015-03-07 20:07:18 +08:00
# define ZEND_VM_STACK_PAGE_SIZE(gen) (ZEND_VM_STACK_PAGE_SLOTS(gen) * sizeof(zval))
2014-10-10 00:29:02 +08:00
2015-03-07 20:07:18 +08:00
# define ZEND_VM_STACK_FREE_PAGE_SIZE(gen) \
( ( ZEND_VM_STACK_PAGE_SLOTS ( gen ) - ZEND_VM_STACK_HEADER_SLOTS ) * sizeof ( zval ) )
# define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(gen, size) \
2015-06-21 00:28:51 +08:00
( ( ( size ) + ( ZEND_VM_STACK_FREE_PAGE_SIZE ( gen ) - 1 ) ) & ~ ( ZEND_VM_STACK_PAGE_SIZE ( gen ) - 1 ) )
2014-10-10 00:29:02 +08:00
static zend_always_inline zend_vm_stack zend_vm_stack_new_page ( size_t size , zend_vm_stack prev ) {
zend_vm_stack page = ( zend_vm_stack ) emalloc ( size ) ;
2015-12-11 02:17:24 +08:00
page - > top = ZEND_VM_STACK_ELEMENTS ( page ) ;
2014-10-10 00:29:02 +08:00
page - > end = ( zval * ) ( ( char * ) page + size ) ;
page - > prev = prev ;
return page ;
}
2014-12-14 06:06:14 +08:00
ZEND_API void zend_vm_stack_init ( void )
2014-10-10 00:29:02 +08:00
{
2015-03-07 20:07:18 +08:00
EG ( vm_stack ) = zend_vm_stack_new_page ( ZEND_VM_STACK_PAGE_SIZE ( 0 /* main stack */ ) , NULL ) ;
2014-10-10 00:29:02 +08:00
EG ( vm_stack ) - > top + + ;
EG ( vm_stack_top ) = EG ( vm_stack ) - > top ;
EG ( vm_stack_end ) = EG ( vm_stack ) - > end ;
}
2014-12-14 06:06:14 +08:00
ZEND_API void zend_vm_stack_destroy ( void )
2014-10-10 00:29:02 +08:00
{
zend_vm_stack stack = EG ( vm_stack ) ;
while ( stack ! = NULL ) {
zend_vm_stack p = stack - > prev ;
efree ( stack ) ;
stack = p ;
}
}
2014-12-14 06:06:14 +08:00
ZEND_API void * zend_vm_stack_extend ( size_t size )
2014-10-10 00:29:02 +08:00
{
2015-03-07 20:07:18 +08:00
zend_vm_stack stack ;
void * ptr ;
2014-10-10 00:29:02 +08:00
2015-03-07 20:07:18 +08:00
stack = EG ( vm_stack ) ;
stack - > top = EG ( vm_stack_top ) ;
2014-10-10 00:29:02 +08:00
EG ( vm_stack ) = stack = zend_vm_stack_new_page (
2015-03-07 20:07:18 +08:00
EXPECTED ( size < ZEND_VM_STACK_FREE_PAGE_SIZE ( 0 ) ) ?
ZEND_VM_STACK_PAGE_SIZE ( 0 ) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE ( 0 , size ) ,
2014-10-10 00:29:02 +08:00
stack ) ;
ptr = stack - > top ;
EG ( vm_stack_top ) = ( void * ) ( ( ( char * ) ptr ) + size ) ;
EG ( vm_stack_end ) = stack - > end ;
return ptr ;
}
2014-08-26 01:28:33 +08:00
ZEND_API zval * zend_get_compiled_variable_value ( const zend_execute_data * execute_data , uint32_t var )
2005-01-22 10:29:18 +08:00
{
2014-03-27 20:00:25 +08:00
return EX_VAR ( var ) ;
2005-01-22 10:29:18 +08:00
}
2014-11-18 14:05:48 +08:00
static zend_always_inline zval * _get_zval_ptr_tmp ( uint32_t var , const zend_execute_data * execute_data , zend_free_op * should_free )
2005-06-14 01:50:07 +08:00
{
2014-03-04 16:27:50 +08:00
zval * ret = EX_VAR ( var ) ;
2014-11-18 14:05:48 +08:00
* should_free = ret ;
2014-05-29 17:17:33 +08:00
ZEND_ASSERT ( Z_TYPE_P ( ret ) ! = IS_REFERENCE ) ;
2014-03-04 16:27:50 +08:00
return ret ;
2005-06-14 01:50:07 +08:00
}
2014-11-18 14:05:48 +08:00
static zend_always_inline zval * _get_zval_ptr_var ( uint32_t var , const zend_execute_data * execute_data , zend_free_op * should_free )
2005-03-24 05:05:56 +08:00
{
2014-02-18 20:27:38 +08:00
zval * ret = EX_VAR ( var ) ;
2014-11-18 14:05:48 +08:00
* should_free = ret ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-11-18 14:05:48 +08:00
static zend_always_inline zval * _get_zval_ptr_var_deref ( uint32_t var , const zend_execute_data * execute_data , zend_free_op * should_free )
2014-02-18 20:27:38 +08:00
{
zval * ret = EX_VAR ( var ) ;
2014-11-18 14:05:48 +08:00
* should_free = ret ;
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
2009-03-11 20:14:34 +08:00
}
2005-03-24 05:05:56 +08:00
2015-09-09 08:18:52 +08:00
static zend_never_inline ZEND_COLD void zval_undefined_cv ( uint32_t var , const zend_execute_data * execute_data )
{
zend_string * cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
zend_error ( E_NOTICE , " Undefined variable: %s " , ZSTR_VAL ( cv ) ) ;
}
2014-12-14 06:06:14 +08:00
static zend_never_inline zval * _get_zval_cv_lookup ( zval * ptr , uint32_t var , int type , const zend_execute_data * execute_data )
2009-03-11 20:14:34 +08:00
{
2014-02-19 05:12:05 +08:00
switch ( type ) {
case BP_VAR_R :
case BP_VAR_UNSET :
2015-09-09 08:18:52 +08:00
zval_undefined_cv ( var , execute_data ) ;
2014-02-19 05:12:05 +08:00
/* break missing intentionally */
case BP_VAR_IS :
2014-03-26 22:07:31 +08:00
ptr = & EG ( uninitialized_zval ) ;
break ;
2014-02-19 05:12:05 +08:00
case BP_VAR_RW :
2015-09-09 08:18:52 +08:00
zval_undefined_cv ( var , execute_data ) ;
2014-02-19 05:12:05 +08:00
/* break missing intentionally */
case BP_VAR_W :
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
2014-02-19 05:12:05 +08:00
break ;
}
2014-03-26 22:07:31 +08:00
return ptr ;
2005-03-24 05:05:56 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_R ( zval * ptr , uint32_t var , const zend_execute_data * execute_data )
2010-04-20 19:16:39 +08:00
{
2015-09-09 08:18:52 +08:00
zval_undefined_cv ( var , execute_data ) ;
2014-02-19 05:12:05 +08:00
return & EG ( uninitialized_zval ) ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_UNSET ( zval * ptr , uint32_t var , const zend_execute_data * execute_data )
2010-04-20 19:16:39 +08:00
{
2015-09-09 08:18:52 +08:00
zval_undefined_cv ( var , execute_data ) ;
2014-02-19 05:12:05 +08:00
return & EG ( uninitialized_zval ) ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_RW ( zval * ptr , uint32_t var , const zend_execute_data * execute_data )
2010-04-20 19:16:39 +08:00
{
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
2015-09-09 08:18:52 +08:00
zval_undefined_cv ( var , execute_data ) ;
2014-03-26 22:07:31 +08:00
return ptr ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_W ( zval * ptr , uint32_t var , const zend_execute_data * execute_data )
2010-04-20 19:16:39 +08:00
{
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
return ptr ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv ( const zend_execute_data * execute_data , uint32_t var , int type )
2004-10-05 03:54:35 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2006-05-10 07:53:23 +08:00
2014-02-10 14:04:30 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup ( ret , var , type , execute_data ) ;
2004-10-05 03:54:35 +08:00
}
2014-02-10 14:04:30 +08:00
return ret ;
2004-10-05 03:54:35 +08:00
}
2015-03-17 23:53:19 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_undef ( const zend_execute_data * execute_data , uint32_t var )
{
return EX_VAR ( var ) ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref ( const zend_execute_data * execute_data , uint32_t var , int type )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup ( ret , var , type , execute_data ) ;
2014-02-19 05:12:05 +08:00
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_R ( const zend_execute_data * execute_data , uint32_t var )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2010-04-20 19:16:39 +08:00
2014-02-10 14:04:30 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_R ( ret , var , execute_data ) ;
2010-04-20 19:16:39 +08:00
}
2014-02-10 14:04:30 +08:00
return ret ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_R ( const zend_execute_data * execute_data , uint32_t var )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_R ( ret , var , execute_data ) ;
2014-02-19 05:12:05 +08:00
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_UNSET ( const zend_execute_data * execute_data , uint32_t var )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2010-04-20 19:16:39 +08:00
2014-02-10 14:04:30 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_UNSET ( ret , var , execute_data ) ;
2010-04-20 19:16:39 +08:00
}
2014-02-10 14:04:30 +08:00
return ret ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_UNSET ( const zend_execute_data * execute_data , uint32_t var )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_UNSET ( ret , var , execute_data ) ;
2014-02-19 05:12:05 +08:00
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_IS ( const zend_execute_data * execute_data , uint32_t var )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2010-04-20 19:16:39 +08:00
2014-02-10 14:04:30 +08:00
return ret ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_IS ( const zend_execute_data * execute_data , uint32_t var )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_RW ( const zend_execute_data * execute_data , uint32_t var )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2010-04-20 19:16:39 +08:00
2014-02-10 14:04:30 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_RW ( ret , var , execute_data ) ;
2010-04-20 19:16:39 +08:00
}
2014-02-10 14:04:30 +08:00
return ret ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_RW ( const zend_execute_data * execute_data , uint32_t var )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_RW ( ret , var , execute_data ) ;
2014-02-19 05:12:05 +08:00
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_W ( const zend_execute_data * execute_data , uint32_t var )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2010-04-20 19:16:39 +08:00
2014-03-27 15:19:34 +08:00
if ( Z_TYPE_P ( ret ) = = IS_UNDEF ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_W ( ret , var , execute_data ) ;
2010-04-20 19:16:39 +08:00
}
2014-02-10 14:04:30 +08:00
return ret ;
2010-04-20 19:16:39 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_undef_BP_VAR_W ( const zend_execute_data * execute_data , uint32_t var )
2014-04-04 18:36:34 +08:00
{
return EX_VAR ( var ) ;
}
2015-03-17 23:53:19 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_undef_BP_VAR_RW ( const zend_execute_data * execute_data , uint32_t var )
{
return EX_VAR ( var ) ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_W ( const zend_execute_data * execute_data , uint32_t var )
2014-02-18 20:27:38 +08:00
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
2014-03-27 15:19:34 +08:00
if ( Z_TYPE_P ( ret ) = = IS_UNDEF ) {
2014-12-14 06:06:14 +08:00
return _get_zval_cv_lookup_BP_VAR_W ( ret , var , execute_data ) ;
2014-02-19 05:12:05 +08:00
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
2004-09-24 05:43:32 +08:00
{
2014-12-09 20:15:24 +08:00
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
2014-12-09 08:03:38 +08:00
return _get_zval_ptr_tmp ( node . var , execute_data , should_free ) ;
2014-12-09 20:15:24 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
2014-12-09 08:03:38 +08:00
return _get_zval_ptr_var ( node . var , execute_data , should_free ) ;
2014-12-09 20:15:24 +08:00
}
2015-01-03 17:22:58 +08:00
} else {
2014-12-09 20:15:24 +08:00
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
2014-12-12 15:19:41 +08:00
return EX_CONSTANT ( node ) ;
2015-03-13 01:39:04 +08:00
} else if ( op_type = = IS_CV ) {
2014-12-14 06:06:14 +08:00
return _get_zval_ptr_cv ( execute_data , node . var , type ) ;
2015-03-13 01:39:04 +08:00
} else {
return NULL ;
2014-12-09 20:15:24 +08:00
}
2005-06-14 01:50:07 +08:00
}
2004-09-24 05:43:32 +08:00
}
2015-09-09 08:18:52 +08:00
static zend_always_inline zval * _get_zval_ptr_r ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free )
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
return _get_zval_ptr_tmp ( node . var , execute_data , should_free ) ;
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
return _get_zval_ptr_var ( node . var , execute_data , should_free ) ;
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
return EX_CONSTANT ( node ) ;
} else if ( op_type = = IS_CV ) {
return _get_zval_ptr_cv_BP_VAR_R ( execute_data , node . var ) ;
} else {
return NULL ;
}
}
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * _get_zval_ptr_deref ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
2014-02-18 20:27:38 +08:00
{
2014-12-09 20:15:24 +08:00
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
2014-12-09 08:03:38 +08:00
return _get_zval_ptr_tmp ( node . var , execute_data , should_free ) ;
2014-12-09 20:15:24 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
2014-12-09 08:03:38 +08:00
return _get_zval_ptr_var_deref ( node . var , execute_data , should_free ) ;
2014-12-09 20:15:24 +08:00
}
2015-01-03 17:22:58 +08:00
} else {
2014-12-09 20:15:24 +08:00
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
2014-12-12 15:19:41 +08:00
return EX_CONSTANT ( node ) ;
2015-03-13 01:39:04 +08:00
} else if ( op_type = = IS_CV ) {
2014-12-14 06:06:14 +08:00
return _get_zval_ptr_cv_deref ( execute_data , node . var , type ) ;
2015-03-13 01:39:04 +08:00
} else {
return NULL ;
2014-12-09 20:15:24 +08:00
}
2014-02-18 20:27:38 +08:00
}
}
2015-09-09 08:18:52 +08:00
static zend_always_inline zval * _get_zval_ptr_r_deref ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free )
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
return _get_zval_ptr_tmp ( node . var , execute_data , should_free ) ;
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
return _get_zval_ptr_var_deref ( node . var , execute_data , should_free ) ;
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
return EX_CONSTANT ( node ) ;
} else if ( op_type = = IS_CV ) {
return _get_zval_ptr_cv_deref_BP_VAR_R ( execute_data , node . var ) ;
} else {
return NULL ;
}
}
}
2015-03-17 23:53:19 +08:00
static zend_always_inline zval * _get_zval_ptr_undef ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
return _get_zval_ptr_tmp ( node . var , execute_data , should_free ) ;
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
return _get_zval_ptr_var ( node . var , execute_data , should_free ) ;
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
return EX_CONSTANT ( node ) ;
} else if ( op_type = = IS_CV ) {
return _get_zval_ptr_cv_undef ( execute_data , node . var ) ;
} else {
return NULL ;
}
}
}
2014-11-18 14:05:48 +08:00
static zend_always_inline zval * _get_zval_ptr_ptr_var ( uint32_t var , const zend_execute_data * execute_data , zend_free_op * should_free )
2004-09-24 05:43:32 +08:00
{
2014-03-04 16:27:50 +08:00
zval * ret = EX_VAR ( var ) ;
2005-06-14 01:50:07 +08:00
2014-03-04 20:32:40 +08:00
if ( EXPECTED ( Z_TYPE_P ( ret ) = = IS_INDIRECT ) ) {
2014-11-18 14:05:48 +08:00
* should_free = NULL ;
2014-11-17 13:36:14 +08:00
ret = Z_INDIRECT_P ( ret ) ;
2015-02-04 22:56:14 +08:00
} else {
2015-08-19 17:21:14 +08:00
* should_free = ret ;
2002-03-10 21:42:37 +08:00
}
2014-11-17 13:36:14 +08:00
return ret ;
2004-09-24 05:43:32 +08:00
}
2014-12-14 06:06:14 +08:00
static inline zval * _get_zval_ptr_ptr ( int op_type , znode_op node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
2014-04-17 06:12:06 +08:00
{
if ( op_type = = IS_CV ) {
2014-11-18 14:05:48 +08:00
* should_free = NULL ;
2014-12-14 06:06:14 +08:00
return _get_zval_ptr_cv ( execute_data , node . var , type ) ;
2014-04-17 06:12:06 +08:00
} else /* if (op_type == IS_VAR) */ {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
2014-12-09 08:03:38 +08:00
return _get_zval_ptr_ptr_var ( node . var , execute_data , should_free ) ;
2014-04-17 06:12:06 +08:00
}
}
2014-11-18 14:05:48 +08:00
static zend_always_inline zval * _get_obj_zval_ptr_unused ( zend_execute_data * execute_data )
2015-04-01 20:54:03 +08:00
{
return & EX ( This ) ;
2004-09-24 05:43:32 +08:00
}
1999-12-23 02:10:38 +08:00
2014-12-14 06:06:14 +08:00
static inline zval * _get_obj_zval_ptr ( int op_type , znode_op op , zend_execute_data * execute_data , zend_free_op * should_free , int type )
2005-06-14 01:50:07 +08:00
{
2010-04-20 18:57:45 +08:00
if ( op_type = = IS_UNUSED ) {
2015-04-01 20:54:03 +08:00
* should_free = NULL ;
return & EX ( This ) ;
2005-06-14 01:50:07 +08:00
}
2012-12-04 14:14:39 +08:00
return get_zval_ptr ( op_type , op , execute_data , should_free , type ) ;
2005-06-14 01:50:07 +08:00
}
2015-06-05 06:53:32 +08:00
static inline zval * _get_obj_zval_ptr_undef ( int op_type , znode_op op , zend_execute_data * execute_data , zend_free_op * should_free , int type )
{
if ( op_type = = IS_UNUSED ) {
* should_free = NULL ;
return & EX ( This ) ;
}
return get_zval_ptr_undef ( op_type , op , execute_data , should_free , type ) ;
}
2014-12-14 06:06:14 +08:00
static inline zval * _get_obj_zval_ptr_ptr ( int op_type , znode_op node , zend_execute_data * execute_data , zend_free_op * should_free , int type )
2014-04-17 06:12:06 +08:00
{
if ( op_type = = IS_UNUSED ) {
2015-04-01 20:54:03 +08:00
* should_free = NULL ;
return & EX ( This ) ;
2014-04-17 06:12:06 +08:00
}
return get_zval_ptr_ptr ( op_type , node , execute_data , should_free , type ) ;
}
2014-12-14 06:06:14 +08:00
static inline void zend_assign_to_variable_reference ( zval * variable_ptr , zval * value_ptr )
2001-06-22 05:17:10 +08:00
{
2015-05-13 17:55:42 +08:00
zend_reference * ref ;
2015-04-29 04:57:21 +08:00
if ( EXPECTED ( ! Z_ISREF_P ( value_ptr ) ) ) {
ZVAL_NEW_REF ( value_ptr , value_ptr ) ;
2015-05-13 17:55:42 +08:00
} else if ( UNEXPECTED ( variable_ptr = = value_ptr ) ) {
return ;
2015-04-29 04:57:21 +08:00
}
2014-10-06 04:58:40 +08:00
2015-05-13 17:55:42 +08:00
ref = Z_REF_P ( value_ptr ) ;
GC_REFCOUNT ( ref ) + + ;
zval_ptr_dtor ( variable_ptr ) ;
ZVAL_REF ( variable_ptr , ref ) ;
2001-06-22 05:17:10 +08:00
}
2007-07-19 23:29:30 +08:00
/* this should modify object only if it's empty */
2015-02-26 04:20:47 +08:00
static inline int make_real_object ( zval * object )
2002-03-11 05:02:00 +08:00
{
2014-04-04 06:52:53 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( object ) ! = IS_OBJECT ) ) {
2015-02-26 04:20:47 +08:00
if ( EXPECTED ( Z_TYPE_P ( object ) < = IS_FALSE ) ) {
/* nothing to destroy */
} else if ( EXPECTED ( ( Z_TYPE_P ( object ) = = IS_STRING & & Z_STRLEN_P ( object ) = = 0 ) ) ) {
2014-06-05 20:04:11 +08:00
zval_ptr_dtor_nogc ( object ) ;
2014-12-09 17:17:55 +08:00
} else {
return 0 ;
2014-03-14 02:56:18 +08:00
}
2015-02-26 04:20:47 +08:00
object_init ( object ) ;
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
2002-03-10 21:42:37 +08:00
}
2014-12-09 17:17:55 +08:00
return 1 ;
2002-03-10 21:42:37 +08:00
}
2002-10-17 02:06:36 +08:00
2015-08-12 00:11:21 +08:00
static char * zend_verify_internal_arg_class_kind ( const zend_internal_arg_info * cur_arg_info , char * * class_name , zend_class_entry * * pce )
2006-05-26 08:36:13 +08:00
{
2014-05-02 23:01:36 +08:00
zend_string * key ;
ALLOCA_FLAG ( use_heap ) ;
2015-06-29 21:44:54 +08:00
ZSTR_ALLOCA_INIT ( key , cur_arg_info - > class_name , strlen ( cur_arg_info - > class_name ) , use_heap ) ;
2014-12-14 06:06:14 +08:00
* pce = zend_fetch_class ( key , ( ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ;
2015-06-29 21:44:54 +08:00
ZSTR_ALLOCA_FREE ( key , use_heap ) ;
2014-05-02 23:01:36 +08:00
2015-06-30 18:59:27 +08:00
* class_name = ( * pce ) ? ZSTR_VAL ( ( * pce ) - > name ) : ( char * ) cur_arg_info - > class_name ;
2006-10-02 19:09:52 +08:00
if ( * pce & & ( * pce ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2006-05-26 08:36:13 +08:00
return " implement interface " ;
} else {
return " be an instance of " ;
}
}
2015-06-17 17:07:43 +08:00
static zend_always_inline zend_class_entry * zend_verify_arg_class_kind ( const zend_arg_info * cur_arg_info )
2014-12-03 21:56:09 +08:00
{
2015-06-17 17:07:43 +08:00
return zend_fetch_class ( cur_arg_info - > class_name , ( ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ;
2014-12-03 21:56:09 +08:00
}
2015-08-19 19:40:56 +08:00
static ZEND_COLD void zend_verify_arg_error ( const zend_function * zf , uint32_t arg_num , const char * need_msg , const char * need_kind , const char * given_msg , const char * given_kind , zval * arg )
2006-05-26 08:36:13 +08:00
{
zend_execute_data * ptr = EG ( current_execute_data ) - > prev_execute_data ;
2015-06-30 18:59:27 +08:00
const char * fname = ZSTR_VAL ( zf - > common . function_name ) ;
2014-02-10 14:04:30 +08:00
const char * fsep ;
2010-10-15 05:33:10 +08:00
const char * fclass ;
2006-05-26 08:36:13 +08:00
if ( zf - > common . scope ) {
fsep = " :: " ;
2015-06-30 18:59:27 +08:00
fclass = ZSTR_VAL ( zf - > common . scope - > name ) ;
2006-05-26 08:36:13 +08:00
} else {
fsep = " " ;
fclass = " " ;
}
2014-11-27 17:52:31 +08:00
if ( zf - > common . type = = ZEND_USER_FUNCTION ) {
if ( ptr & & ptr - > func & & ZEND_USER_CODE ( ptr - > func - > common . type ) ) {
2015-03-20 16:10:29 +08:00
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d " ,
arg_num , fclass , fsep , fname , need_msg , need_kind , given_msg , given_kind ,
2015-06-30 18:59:27 +08:00
ZSTR_VAL ( ptr - > func - > op_array . filename ) , ptr - > opline - > lineno ) ;
2014-11-27 17:52:31 +08:00
} else {
2015-03-19 00:23:09 +08:00
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s, %s%s given " , arg_num , fclass , fsep , fname , need_msg , need_kind , given_msg , given_kind ) ;
2014-11-27 17:52:31 +08:00
}
2006-05-26 08:36:13 +08:00
} else {
2015-03-19 00:23:09 +08:00
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s, %s%s given " , arg_num , fclass , fsep , fname , need_msg , need_kind , given_msg , given_kind ) ;
2006-05-26 08:36:13 +08:00
}
}
2014-12-14 06:06:14 +08:00
static int is_null_constant ( zval * default_value )
2014-11-25 23:09:08 +08:00
{
2014-11-25 23:12:30 +08:00
if ( Z_CONSTANT_P ( default_value ) ) {
zval constant ;
2014-11-25 23:09:08 +08:00
2014-11-25 23:12:30 +08:00
ZVAL_COPY_VALUE ( & constant , default_value ) ;
2015-04-02 07:05:25 +08:00
if ( UNEXPECTED ( zval_update_constant_ex ( & constant , 0 , NULL ) ! = SUCCESS ) ) {
return 0 ;
}
2014-11-25 23:09:08 +08:00
if ( Z_TYPE ( constant ) = = IS_NULL ) {
return 1 ;
}
zval_dtor ( & constant ) ;
}
return 0 ;
}
2015-03-20 21:04:04 +08:00
static zend_bool zend_verify_weak_scalar_type_hint ( zend_uchar type_hint , zval * arg )
2014-12-29 21:49:12 +08:00
{
switch ( type_hint ) {
case _IS_BOOL : {
zend_bool dest ;
2015-03-21 04:18:52 +08:00
if ( ! zend_parse_arg_bool_weak ( arg , & dest ) ) {
2014-12-29 21:49:12 +08:00
return 0 ;
}
zval_ptr_dtor ( arg ) ;
ZVAL_BOOL ( arg , dest ) ;
return 1 ;
}
case IS_LONG : {
zend_long dest ;
2015-03-21 04:18:52 +08:00
if ( ! zend_parse_arg_long_weak ( arg , & dest ) ) {
2014-12-29 21:49:12 +08:00
return 0 ;
}
zval_ptr_dtor ( arg ) ;
ZVAL_LONG ( arg , dest ) ;
return 1 ;
}
case IS_DOUBLE : {
double dest ;
2015-03-21 04:18:52 +08:00
if ( ! zend_parse_arg_double_weak ( arg , & dest ) ) {
2014-12-29 21:49:12 +08:00
return 0 ;
}
zval_ptr_dtor ( arg ) ;
ZVAL_DOUBLE ( arg , dest ) ;
return 1 ;
}
case IS_STRING : {
zend_string * dest ;
2015-02-10 23:51:16 +08:00
/* on success "arg" is converted to IS_STRING */
2015-03-21 04:18:52 +08:00
if ( ! zend_parse_arg_str_weak ( arg , & dest ) ) {
2014-12-29 21:49:12 +08:00
return 0 ;
}
return 1 ;
}
default :
return 0 ;
}
}
2015-03-20 21:04:04 +08:00
static zend_bool zend_verify_scalar_type_hint ( zend_uchar type_hint , zval * arg , zend_bool strict )
2015-03-20 01:51:24 +08:00
{
2015-03-20 21:04:04 +08:00
if ( UNEXPECTED ( strict ) ) {
2015-03-21 04:18:52 +08:00
/* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
2015-03-20 21:04:04 +08:00
if ( type_hint ! = IS_DOUBLE | | Z_TYPE_P ( arg ) ! = IS_LONG ) {
return 0 ;
2015-03-20 01:51:24 +08:00
}
2015-03-20 21:04:04 +08:00
} else if ( UNEXPECTED ( Z_TYPE_P ( arg ) = = IS_NULL ) ) {
2015-03-20 22:26:38 +08:00
/* NULL may be accepted only by nullable hints (this is already checked) */
2015-03-20 21:04:04 +08:00
return 0 ;
2015-03-20 01:51:24 +08:00
}
2015-03-20 21:04:04 +08:00
return zend_verify_weak_scalar_type_hint ( type_hint , arg ) ;
2015-03-20 01:51:24 +08:00
}
2015-09-08 22:20:52 +08:00
static int zend_verify_internal_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg )
2014-12-03 21:56:09 +08:00
{
zend_internal_arg_info * cur_arg_info ;
2015-03-20 21:04:04 +08:00
char * need_msg , * class_name ;
2014-12-03 21:56:09 +08:00
zend_class_entry * ce ;
if ( EXPECTED ( arg_num < = zf - > internal_function . num_args ) ) {
cur_arg_info = & zf - > internal_function . arg_info [ arg_num - 1 ] ;
} else if ( zf - > internal_function . fn_flags & ZEND_ACC_VARIADIC ) {
2014-12-22 21:44:39 +08:00
cur_arg_info = & zf - > internal_function . arg_info [ zf - > internal_function . num_args ] ;
2014-12-03 21:56:09 +08:00
} else {
2015-09-08 22:20:52 +08:00
return 1 ;
2014-12-03 21:56:09 +08:00
}
2015-03-20 21:04:04 +08:00
if ( cur_arg_info - > type_hint ) {
2014-12-03 21:56:09 +08:00
ZVAL_DEREF ( arg ) ;
2015-03-20 21:04:04 +08:00
if ( EXPECTED ( cur_arg_info - > type_hint = = Z_TYPE_P ( arg ) ) ) {
if ( cur_arg_info - > class_name ) {
need_msg = zend_verify_internal_arg_class_kind ( ( zend_internal_arg_info * ) cur_arg_info , & class_name , & ce ) ;
if ( ! ce | | ! instanceof_function ( Z_OBJCE_P ( arg ) , ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , need_msg , class_name , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( arg ) - > name ) , arg ) ;
2015-09-08 22:20:52 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
}
2014-12-03 21:56:09 +08:00
}
} else if ( Z_TYPE_P ( arg ) ! = IS_NULL | | ! cur_arg_info - > allow_null ) {
2015-03-20 21:04:04 +08:00
if ( cur_arg_info - > class_name ) {
need_msg = zend_verify_internal_arg_class_kind ( ( zend_internal_arg_info * ) cur_arg_info , & class_name , & ce ) ;
zend_verify_arg_error ( zf , arg_num , need_msg , class_name , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-09-08 22:20:52 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
} else if ( cur_arg_info - > type_hint = = IS_CALLABLE ) {
if ( ! zend_is_callable ( arg , IS_CALLABLE_CHECK_SILENT , NULL ) ) {
zend_verify_arg_error ( zf , arg_num , " be callable " , " " , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-09-08 22:20:52 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
}
} else if ( cur_arg_info - > type_hint = = _IS_BOOL & &
EXPECTED ( Z_TYPE_P ( arg ) = = IS_FALSE | | Z_TYPE_P ( arg ) = = IS_TRUE ) ) {
/* pass */
} else if ( UNEXPECTED ( ! zend_verify_scalar_type_hint ( cur_arg_info - > type_hint , arg , ZEND_CALL_USES_STRICT_TYPES ( EG ( current_execute_data ) ) ) ) ) {
zend_verify_arg_error ( zf , arg_num , " be of the type " , zend_get_type_by_const ( cur_arg_info - > type_hint ) , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-09-08 22:20:52 +08:00
return 0 ;
2014-12-03 21:56:09 +08:00
}
}
}
2015-09-08 22:20:52 +08:00
return 1 ;
2014-12-03 21:56:09 +08:00
}
2015-06-17 17:07:43 +08:00
static zend_always_inline int zend_verify_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg , zval * default_value , void * * cache_slot )
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
{
zend_arg_info * cur_arg_info ;
2015-06-17 17:07:43 +08:00
char * need_msg ;
2006-05-22 02:10:31 +08:00
zend_class_entry * ce ;
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
2014-04-04 18:36:34 +08:00
if ( EXPECTED ( arg_num < = zf - > common . num_args ) ) {
2013-09-27 00:39:17 +08:00
cur_arg_info = & zf - > common . arg_info [ arg_num - 1 ] ;
2015-06-17 17:07:43 +08:00
} else if ( UNEXPECTED ( zf - > common . fn_flags & ZEND_ACC_VARIADIC ) ) {
2014-12-22 21:44:39 +08:00
cur_arg_info = & zf - > common . arg_info [ zf - > common . num_args ] ;
2013-09-27 00:39:17 +08:00
} else {
2015-04-29 04:57:21 +08:00
return 1 ;
2013-09-27 00:39:17 +08:00
}
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
2015-03-20 21:04:04 +08:00
if ( cur_arg_info - > type_hint ) {
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( arg ) ;
2015-03-20 21:04:04 +08:00
if ( EXPECTED ( cur_arg_info - > type_hint = = Z_TYPE_P ( arg ) ) ) {
if ( cur_arg_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( cur_arg_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , " be an instance of " , ZSTR_VAL ( cur_arg_info - > class_name ) , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( arg ) - > name ) , arg ) ;
2015-06-17 17:07:43 +08:00
return 0 ;
}
* cache_slot = ( void * ) ce ;
}
if ( UNEXPECTED ( ! instanceof_function ( Z_OBJCE_P ( arg ) , ce ) ) ) {
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , need_msg , ZSTR_VAL ( ce - > name ) , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( arg ) - > name ) , arg ) ;
2015-04-29 04:57:21 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
}
2006-05-22 02:10:31 +08:00
}
2014-12-14 06:06:14 +08:00
} else if ( Z_TYPE_P ( arg ) ! = IS_NULL | | ! ( cur_arg_info - > allow_null | | ( default_value & & is_null_constant ( default_value ) ) ) ) {
2015-03-20 21:04:04 +08:00
if ( cur_arg_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( cur_arg_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-21 07:35:22 +08:00
if ( Z_TYPE_P ( arg ) = = IS_OBJECT ) {
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , " be an instance of " , ZSTR_VAL ( cur_arg_info - > class_name ) , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( arg ) - > name ) , arg ) ;
2015-06-21 07:35:22 +08:00
} else {
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , " be an instance of " , ZSTR_VAL ( cur_arg_info - > class_name ) , " " , zend_zval_type_name ( arg ) , arg ) ;
2015-06-21 07:35:22 +08:00
}
2015-06-17 17:07:43 +08:00
return 0 ;
}
* cache_slot = ( void * ) ce ;
}
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , need_msg , ZSTR_VAL ( ce - > name ) , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-04-29 04:57:21 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
} else if ( cur_arg_info - > type_hint = = IS_CALLABLE ) {
if ( ! zend_is_callable ( arg , IS_CALLABLE_CHECK_SILENT , NULL ) ) {
zend_verify_arg_error ( zf , arg_num , " be callable " , " " , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-04-29 04:57:21 +08:00
return 0 ;
2015-03-20 21:04:04 +08:00
}
} else if ( cur_arg_info - > type_hint = = _IS_BOOL & &
EXPECTED ( Z_TYPE_P ( arg ) = = IS_FALSE | | Z_TYPE_P ( arg ) = = IS_TRUE ) ) {
/* pass */
} else if ( UNEXPECTED ( ! zend_verify_scalar_type_hint ( cur_arg_info - > type_hint , arg , ZEND_ARG_USES_STRICT_TYPES ( ) ) ) ) {
zend_verify_arg_error ( zf , arg_num , " be of the type " , zend_get_type_by_const ( cur_arg_info - > type_hint ) , zend_zval_type_name ( arg ) , " " , arg ) ;
2015-04-29 04:57:21 +08:00
return 0 ;
2014-06-05 22:42:17 +08:00
}
2010-05-21 03:18:35 +08:00
}
2005-05-26 21:46:17 +08:00
}
2015-04-29 04:57:21 +08:00
return 1 ;
2014-04-04 18:36:34 +08:00
}
2015-06-17 17:07:43 +08:00
static zend_always_inline int zend_verify_missing_arg_type ( zend_function * zf , uint32_t arg_num , void * * cache_slot )
2014-04-04 18:36:34 +08:00
{
zend_arg_info * cur_arg_info ;
char * need_msg ;
zend_class_entry * ce ;
if ( EXPECTED ( arg_num < = zf - > common . num_args ) ) {
cur_arg_info = & zf - > common . arg_info [ arg_num - 1 ] ;
2015-06-17 17:07:43 +08:00
} else if ( UNEXPECTED ( zf - > common . fn_flags & ZEND_ACC_VARIADIC ) ) {
2014-12-22 21:44:39 +08:00
cur_arg_info = & zf - > common . arg_info [ zf - > common . num_args ] ;
2014-04-04 18:36:34 +08:00
} else {
return 1 ;
}
2015-03-20 21:04:04 +08:00
if ( cur_arg_info - > type_hint ) {
if ( cur_arg_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( cur_arg_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , " be an instance of " , ZSTR_VAL ( cur_arg_info - > class_name ) , " none " , " " , NULL ) ;
2015-06-17 17:07:43 +08:00
return 0 ;
}
* cache_slot = ( void * ) ce ;
}
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_arg_error ( zf , arg_num , need_msg , ZSTR_VAL ( ce - > name ) , " none " , " " , NULL ) ;
2014-06-05 22:42:17 +08:00
} else if ( cur_arg_info - > type_hint = = IS_CALLABLE ) {
2015-03-19 00:23:09 +08:00
zend_verify_arg_error ( zf , arg_num , " be callable " , " " , " none " , " " , NULL ) ;
2014-06-05 22:42:17 +08:00
} else {
2015-03-19 00:23:09 +08:00
zend_verify_arg_error ( zf , arg_num , " be of the type " , zend_get_type_by_const ( cur_arg_info - > type_hint ) , " none " , " " , NULL ) ;
2014-04-04 18:36:34 +08:00
}
2014-09-10 17:02:01 +08:00
return 0 ;
2014-04-04 18:36:34 +08:00
}
2014-09-10 17:02:01 +08:00
return 1 ;
2014-04-04 18:36:34 +08:00
}
2015-10-13 17:40:58 +08:00
static ZEND_COLD void zend_verify_missing_arg ( zend_execute_data * execute_data , uint32_t arg_num , void * * cache_slot )
2014-04-04 18:36:34 +08:00
{
2014-06-27 03:51:14 +08:00
if ( EXPECTED ( ! ( EX ( func ) - > common . fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) ) | |
2015-08-19 19:40:56 +08:00
UNEXPECTED ( zend_verify_missing_arg_type ( EX ( func ) , arg_num , cache_slot ) ) ) {
2015-06-30 18:59:27 +08:00
const char * class_name = EX ( func ) - > common . scope ? ZSTR_VAL ( EX ( func ) - > common . scope - > name ) : " " ;
2014-06-27 03:51:14 +08:00
const char * space = EX ( func ) - > common . scope ? " :: " : " " ;
2015-06-30 18:59:27 +08:00
const char * func_name = EX ( func ) - > common . function_name ? ZSTR_VAL ( EX ( func ) - > common . function_name ) : " main " ;
2014-04-04 18:36:34 +08:00
zend_execute_data * ptr = EX ( prev_execute_data ) ;
2014-06-27 17:02:49 +08:00
if ( ptr & & ptr - > func & & ZEND_USER_CODE ( ptr - > func - > common . type ) ) {
2015-06-30 18:59:27 +08:00
zend_error ( E_WARNING , " Missing argument %u for %s%s%s(), called in %s on line %d and defined " , arg_num , class_name , space , func_name , ZSTR_VAL ( ptr - > func - > op_array . filename ) , ptr - > opline - > lineno ) ;
2014-04-04 18:36:34 +08:00
} else {
zend_error ( E_WARNING , " Missing argument %u for %s%s%s() " , arg_num , class_name , space , func_name ) ;
}
}
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
}
2015-08-19 19:40:56 +08:00
static ZEND_COLD void zend_verify_return_error ( const zend_function * zf , const char * need_msg , const char * need_kind , const char * returned_msg , const char * returned_kind )
2015-01-09 04:40:36 +08:00
{
2015-06-30 18:59:27 +08:00
const char * fname = ZSTR_VAL ( zf - > common . function_name ) ;
2015-01-09 04:40:36 +08:00
const char * fsep ;
const char * fclass ;
if ( zf - > common . scope ) {
fsep = " :: " ;
2015-06-30 18:59:27 +08:00
fclass = ZSTR_VAL ( zf - > common . scope - > name ) ;
2015-01-09 04:40:36 +08:00
} else {
fsep = " " ;
fclass = " " ;
}
2015-09-23 13:04:33 +08:00
zend_type_error ( " Return value of %s%s%s() must %s%s, %s%s returned " ,
fclass , fsep , fname , need_msg , need_kind , returned_msg , returned_kind ) ;
2015-03-19 03:22:21 +08:00
}
2015-08-19 19:40:56 +08:00
static ZEND_COLD void zend_verify_internal_return_error ( const zend_function * zf , const char * need_msg , const char * need_kind , const char * returned_msg , const char * returned_kind )
2015-01-09 04:40:36 +08:00
{
2015-06-30 18:59:27 +08:00
const char * fname = ZSTR_VAL ( zf - > common . function_name ) ;
2015-01-09 04:40:36 +08:00
const char * fsep ;
const char * fclass ;
if ( zf - > common . scope ) {
fsep = " :: " ;
2015-06-30 18:59:27 +08:00
fclass = ZSTR_VAL ( zf - > common . scope - > name ) ;
2015-01-09 04:40:36 +08:00
} else {
fsep = " " ;
fclass = " " ;
}
2015-04-01 18:32:23 +08:00
zend_error_noreturn ( E_CORE_ERROR , " Return value of %s%s%s() must %s%s, %s%s returned " ,
2015-01-09 04:40:36 +08:00
fclass , fsep , fname , need_msg , need_kind , returned_msg , returned_kind ) ;
}
2015-10-15 02:15:32 +08:00
static ZEND_COLD void zend_verify_void_return_error ( const zend_function * zf , const char * returned_msg , const char * returned_kind )
{
const char * fname = ZSTR_VAL ( zf - > common . function_name ) ;
const char * fsep ;
const char * fclass ;
if ( zf - > common . scope ) {
fsep = " :: " ;
fclass = ZSTR_VAL ( zf - > common . scope - > name ) ;
} else {
fsep = " " ;
fclass = " " ;
}
zend_type_error ( " %s%s%s() must not return a value, %s%s returned " ,
fclass , fsep , fname , returned_msg , returned_kind ) ;
}
2015-02-05 16:01:07 +08:00
# if ZEND_DEBUG
2015-03-20 21:04:04 +08:00
static int zend_verify_internal_return_type ( zend_function * zf , zval * ret )
2015-02-05 16:01:07 +08:00
{
zend_arg_info * ret_info = zf - > common . arg_info - 1 ;
2015-03-20 21:04:04 +08:00
char * need_msg , * class_name ;
2015-02-05 16:01:07 +08:00
zend_class_entry * ce ;
2015-03-20 21:04:04 +08:00
if ( ret_info - > type_hint ) {
if ( EXPECTED ( ret_info - > type_hint = = Z_TYPE_P ( ret ) ) ) {
if ( ret_info - > class_name ) {
need_msg = zend_verify_internal_arg_class_kind ( ( zend_internal_arg_info * ) ret_info , & class_name , & ce ) ;
if ( ! ce | | ! instanceof_function ( Z_OBJCE_P ( ret ) , ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_internal_return_error ( zf , need_msg , class_name , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( ret ) - > name ) ) ;
2015-03-20 21:04:04 +08:00
return 0 ;
}
2015-02-05 16:01:07 +08:00
}
} else if ( Z_TYPE_P ( ret ) ! = IS_NULL | | ! ret_info - > allow_null ) {
2015-03-20 21:04:04 +08:00
if ( ret_info - > class_name ) {
need_msg = zend_verify_internal_arg_class_kind ( ( zend_internal_arg_info * ) ret_info , & class_name , & ce ) ;
zend_verify_internal_return_error ( zf , need_msg , class_name , zend_zval_type_name ( ret ) , " " ) ;
} else if ( ret_info - > type_hint = = IS_CALLABLE ) {
if ( ! zend_is_callable ( ret , IS_CALLABLE_CHECK_SILENT , NULL ) & & ( Z_TYPE_P ( ret ) ! = IS_NULL | | ! ret_info - > allow_null ) ) {
zend_verify_internal_return_error ( zf , " be callable " , " " , zend_zval_type_name ( ret ) , " " ) ;
return 0 ;
}
} else if ( ret_info - > type_hint = = _IS_BOOL & &
EXPECTED ( Z_TYPE_P ( ret ) = = IS_FALSE | | Z_TYPE_P ( ret ) = = IS_TRUE ) ) {
/* pass */
2015-10-15 02:15:32 +08:00
} else if ( ret_info - > type_hint = = IS_VOID ) {
zend_verify_void_return_error ( zf , zend_zval_type_name ( ret ) , " " ) ;
2015-03-20 21:04:04 +08:00
} else {
/* Use strict check to verify return value of internal function */
zend_verify_internal_return_error ( zf , " be of the type " , zend_get_type_by_const ( ret_info - > type_hint ) , zend_zval_type_name ( ret ) , " " ) ;
2015-02-05 16:01:07 +08:00
return 0 ;
}
}
}
return 1 ;
}
# endif
2015-06-17 17:07:43 +08:00
static zend_always_inline void zend_verify_return_type ( zend_function * zf , zval * ret , void * * cache_slot )
2015-01-09 04:40:36 +08:00
{
zend_arg_info * ret_info = zf - > common . arg_info - 1 ;
2015-06-17 17:07:43 +08:00
char * need_msg ;
2015-01-09 04:40:36 +08:00
zend_class_entry * ce ;
2015-03-20 21:04:04 +08:00
if ( ret_info - > type_hint ) {
if ( EXPECTED ( ret_info - > type_hint = = Z_TYPE_P ( ret ) ) ) {
if ( ret_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( ret_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , " be an instance of " , ZSTR_VAL ( ret_info - > class_name ) , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( ret ) - > name ) ) ;
2015-06-17 17:07:43 +08:00
return ;
}
* cache_slot = ( void * ) ce ;
}
if ( UNEXPECTED ( ! instanceof_function ( Z_OBJCE_P ( ret ) , ce ) ) ) {
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , need_msg , ZSTR_VAL ( ce - > name ) , " instance of " , ZSTR_VAL ( Z_OBJCE_P ( ret ) - > name ) ) ;
2015-03-20 21:04:04 +08:00
}
2015-01-09 04:40:36 +08:00
}
} else if ( Z_TYPE_P ( ret ) ! = IS_NULL | | ! ret_info - > allow_null ) {
2015-03-20 21:04:04 +08:00
if ( ret_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( ret_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , " be an instance of " , ZSTR_VAL ( ret_info - > class_name ) , zend_zval_type_name ( ret ) , " " ) ;
2015-06-17 17:07:43 +08:00
return ;
}
* cache_slot = ( void * ) ce ;
}
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , need_msg , ZSTR_VAL ( ce - > name ) , zend_zval_type_name ( ret ) , " " ) ;
2015-03-20 21:04:04 +08:00
} else if ( ret_info - > type_hint = = IS_CALLABLE ) {
if ( ! zend_is_callable ( ret , IS_CALLABLE_CHECK_SILENT , NULL ) ) {
zend_verify_return_error ( zf , " be callable " , " " , zend_zval_type_name ( ret ) , " " ) ;
}
} else if ( ret_info - > type_hint = = _IS_BOOL & &
EXPECTED ( Z_TYPE_P ( ret ) = = IS_FALSE | | Z_TYPE_P ( ret ) = = IS_TRUE ) ) {
/* pass */
2015-10-15 02:15:32 +08:00
/* There would be a check here for the IS_VOID type hint, which
* would trigger an error because a value had been returned .
* However , zend_compile . c already does a compile - time check
* that bans ` return . . . ; ` within a void function . Thus we can skip
* this part of the runtime check for non - internal functions .
*/
2015-03-20 21:04:04 +08:00
} else if ( UNEXPECTED ( ! zend_verify_scalar_type_hint ( ret_info - > type_hint , ret , ZEND_RET_USES_STRICT_TYPES ( ) ) ) ) {
zend_verify_return_error ( zf , " be of the type " , zend_get_type_by_const ( ret_info - > type_hint ) , zend_zval_type_name ( ret ) , " " ) ;
2015-01-09 04:40:36 +08:00
}
}
}
}
2015-08-19 19:40:56 +08:00
static ZEND_COLD int zend_verify_missing_return_type ( zend_function * zf , void * * cache_slot )
2015-01-09 04:40:36 +08:00
{
zend_arg_info * ret_info = zf - > common . arg_info - 1 ;
char * need_msg ;
zend_class_entry * ce ;
2015-10-15 02:15:32 +08:00
if ( ret_info - > type_hint & & EXPECTED ( ret_info - > type_hint ! = IS_VOID ) ) {
2015-03-20 21:04:04 +08:00
if ( ret_info - > class_name ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
ce = ( zend_class_entry * ) * cache_slot ;
} else {
ce = zend_verify_arg_class_kind ( ret_info ) ;
if ( UNEXPECTED ( ! ce ) ) {
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , " be an instance of " , ZSTR_VAL ( ret_info - > class_name ) , " none " , " " ) ;
2015-06-17 17:07:43 +08:00
return 0 ;
}
* cache_slot = ( void * ) ce ;
}
need_msg =
( ce - > ce_flags & ZEND_ACC_INTERFACE ) ?
" implement interface " : " be an instance of " ;
2015-06-30 18:59:27 +08:00
zend_verify_return_error ( zf , need_msg , ZSTR_VAL ( ce - > name ) , " none " , " " ) ;
2015-03-20 21:04:04 +08:00
return 0 ;
2015-01-09 04:40:36 +08:00
} else if ( ret_info - > type_hint = = IS_CALLABLE ) {
2015-03-19 00:23:09 +08:00
zend_verify_return_error ( zf , " be callable " , " " , " none " , " " ) ;
2015-01-09 04:40:36 +08:00
} else {
2015-03-19 00:23:09 +08:00
zend_verify_return_error ( zf , " be of the type " , zend_get_type_by_const ( ret_info - > type_hint ) , " none " , " " ) ;
2015-01-09 04:40:36 +08:00
}
return 0 ;
}
return 1 ;
}
2015-03-03 08:28:31 +08:00
static zend_never_inline void zend_assign_to_object_dim ( zval * retval , zval * object , zval * property_name , int value_type , znode_op value_op , const zend_execute_data * execute_data )
2014-12-09 05:10:23 +08:00
{
zend_free_op free_value ;
zval * value = get_zval_ptr_deref ( value_type , value_op , execute_data , & free_value , BP_VAR_R ) ;
/* Note: property_name in this case is really the array index! */
if ( ! Z_OBJ_HT_P ( object ) - > write_dimension ) {
2015-07-08 01:10:22 +08:00
zend_throw_error ( NULL , " Cannot use object as array " ) ;
2015-04-01 19:50:09 +08:00
FREE_OP ( free_value ) ;
return ;
2014-12-09 05:10:23 +08:00
}
2014-11-25 04:19:24 +08:00
2014-12-09 05:10:23 +08:00
/* separate our value if necessary */
if ( value_type = = IS_CONST ) {
2016-04-06 01:09:14 +08:00
if ( UNEXPECTED ( Z_REFCOUNTED_P ( value ) ) ) {
Z_ADDREF_P ( value ) ;
2014-12-09 05:10:23 +08:00
}
2002-03-10 21:42:37 +08:00
}
2006-05-10 07:53:23 +08:00
2014-12-14 06:06:14 +08:00
Z_OBJ_HT_P ( object ) - > write_dimension ( object , property_name , value ) ;
2014-12-09 05:10:23 +08:00
2015-04-15 18:34:23 +08:00
if ( retval & & EXPECTED ( ! EG ( exception ) ) ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY ( retval , value ) ;
2002-03-10 21:42:37 +08:00
}
2015-04-15 18:34:23 +08:00
if ( value_type = = IS_CONST ) {
zval_ptr_dtor_nogc ( value ) ;
} else {
2014-09-23 21:21:29 +08:00
FREE_OP ( free_value ) ;
}
2002-03-10 21:42:37 +08:00
}
2015-03-14 02:10:09 +08:00
static zend_never_inline void zend_binary_assign_op_obj_dim ( zval * object , zval * property , zval * value , zval * retval , binary_op_type binary_op )
2014-12-09 20:15:24 +08:00
{
zval * z ;
2015-01-26 16:25:05 +08:00
zval rv , res ;
2014-12-09 20:15:24 +08:00
if ( Z_OBJ_HT_P ( object ) - > read_dimension & &
2014-12-14 06:06:14 +08:00
( z = Z_OBJ_HT_P ( object ) - > read_dimension ( object , property , BP_VAR_R , & rv ) ) ! = NULL ) {
2014-12-09 20:15:24 +08:00
if ( Z_TYPE_P ( z ) = = IS_OBJECT & & Z_OBJ_HT_P ( z ) - > get ) {
2015-04-15 04:15:38 +08:00
zval rv2 ;
zval * value = Z_OBJ_HT_P ( z ) - > get ( z , & rv2 ) ;
2014-12-09 20:15:24 +08:00
2015-04-15 04:15:38 +08:00
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
2014-12-09 20:15:24 +08:00
}
ZVAL_COPY_VALUE ( z , value ) ;
}
2015-01-26 16:25:05 +08:00
binary_op ( & res , Z_ISREF_P ( z ) ? Z_REFVAL_P ( z ) : z , value ) ;
Z_OBJ_HT_P ( object ) - > write_dimension ( object , property , & res ) ;
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
}
2014-12-09 20:15:24 +08:00
if ( retval ) {
2015-01-26 16:25:05 +08:00
ZVAL_COPY ( retval , & res ) ;
2014-12-09 20:15:24 +08:00
}
2015-01-26 16:25:05 +08:00
zval_ptr_dtor ( & res ) ;
2014-12-09 20:15:24 +08:00
} else {
zend_error ( E_WARNING , " Attempt to assign property of non-object " ) ;
if ( retval ) {
ZVAL_NULL ( retval ) ;
}
}
}
2014-12-14 06:06:14 +08:00
static void zend_assign_to_string_offset ( zval * str , zend_long offset , zval * value , zval * result )
2014-09-07 06:54:47 +08:00
{
2014-04-04 06:52:53 +08:00
zend_string * old_str ;
2016-02-12 07:01:59 +08:00
zend_uchar c ;
size_t string_len ;
1999-04-08 02:10:10 +08:00
2015-07-22 04:16:08 +08:00
if ( offset < ( zend_long ) ( - Z_STRLEN_P ( str ) ) ) {
2016-02-12 07:01:59 +08:00
/* Error on negative offset */
2014-09-07 06:54:47 +08:00
zend_error ( E_WARNING , " Illegal string offset: " ZEND_LONG_FMT , offset ) ;
2014-08-26 01:24:55 +08:00
zend_string_release ( Z_STR_P ( str ) ) ;
2014-04-04 06:52:53 +08:00
if ( result ) {
ZVAL_NULL ( result ) ;
}
return ;
2014-02-10 14:04:30 +08:00
}
2016-02-12 07:01:59 +08:00
if ( Z_TYPE_P ( value ) ! = IS_STRING ) {
/* Convert to string, just the time to pick the 1st byte */
zend_string * tmp = zval_get_string ( value ) ;
string_len = ZSTR_LEN ( tmp ) ;
c = ( zend_uchar ) ZSTR_VAL ( tmp ) [ 0 ] ;
zend_string_release ( tmp ) ;
} else {
string_len = Z_STRLEN_P ( value ) ;
c = ( zend_uchar ) Z_STRVAL_P ( value ) [ 0 ] ;
}
if ( string_len = = 0 ) {
/* Error on empty input string */
zend_error ( E_WARNING , " Cannot assign an empty string to a string offset " ) ;
zend_string_release ( Z_STR_P ( str ) ) ;
if ( result ) {
ZVAL_NULL ( result ) ;
}
return ;
}
2015-07-22 04:16:08 +08:00
if ( offset < 0 ) { /* Handle negative offset */
offset + = ( zend_long ) Z_STRLEN_P ( str ) ;
}
2014-04-04 06:52:53 +08:00
old_str = Z_STR_P ( str ) ;
2014-09-16 15:28:49 +08:00
if ( ( size_t ) offset > = Z_STRLEN_P ( str ) ) {
2016-02-12 07:01:59 +08:00
/* Extend string if needed */
2014-09-07 06:54:47 +08:00
zend_long old_len = Z_STRLEN_P ( str ) ;
2015-03-20 07:02:42 +08:00
Z_STR_P ( str ) = zend_string_extend ( Z_STR_P ( str ) , offset + 1 , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO_P ( str ) = IS_STRING_EX ;
2014-02-28 21:39:08 +08:00
memset ( Z_STRVAL_P ( str ) + old_len , ' ' , offset - old_len ) ;
Z_STRVAL_P ( str ) [ offset + 1 ] = 0 ;
2014-09-19 19:41:01 +08:00
} else if ( ! Z_REFCOUNTED_P ( str ) ) {
2014-08-26 01:24:55 +08:00
Z_STR_P ( str ) = zend_string_init ( Z_STRVAL_P ( str ) , Z_STRLEN_P ( str ) , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO_P ( str ) = IS_STRING_EX ;
2014-02-10 14:04:30 +08:00
}
1999-04-08 02:10:10 +08:00
2016-02-12 07:01:59 +08:00
Z_STRVAL_P ( str ) [ offset ] = c ;
2014-04-04 06:52:53 +08:00
2014-08-26 01:24:55 +08:00
zend_string_release ( old_str ) ;
2014-04-04 06:52:53 +08:00
if ( result ) {
2016-02-12 07:01:59 +08:00
/* Return the new character */
2014-04-04 06:52:53 +08:00
if ( CG ( one_char_string ) [ c ] ) {
2014-08-26 01:28:33 +08:00
ZVAL_INTERNED_STR ( result , CG ( one_char_string ) [ c ] ) ;
2014-04-04 06:52:53 +08:00
} else {
2014-08-26 01:24:55 +08:00
ZVAL_NEW_STR ( result , zend_string_init ( Z_STRVAL_P ( str ) + offset , 1 , 0 ) ) ;
2014-04-04 06:52:53 +08:00
}
}
2007-12-14 22:14:50 +08:00
}
1999-04-08 02:10:10 +08:00
2015-06-03 23:44:25 +08:00
static zend_never_inline void zend_post_incdec_overloaded_property ( zval * object , zval * property , void * * cache_slot , int inc , zval * result )
{
if ( Z_OBJ_HT_P ( object ) - > read_property & & Z_OBJ_HT_P ( object ) - > write_property ) {
zval rv , obj ;
zval * z ;
zval z_copy ;
ZVAL_OBJ ( & obj , Z_OBJ_P ( object ) ) ;
Z_ADDREF ( obj ) ;
z = Z_OBJ_HT ( obj ) - > read_property ( & obj , property , BP_VAR_R , cache_slot , & rv ) ;
if ( UNEXPECTED ( EG ( exception ) ) ) {
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
return ;
}
if ( UNEXPECTED ( Z_TYPE_P ( z ) = = IS_OBJECT ) & & Z_OBJ_HT_P ( z ) - > get ) {
zval rv2 ;
zval * value = Z_OBJ_HT_P ( z ) - > get ( z , & rv2 ) ;
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
}
ZVAL_COPY_VALUE ( z , value ) ;
}
2015-08-10 17:12:33 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( z ) = = IS_REFERENCE ) ) {
ZVAL_COPY ( result , Z_REFVAL_P ( z ) ) ;
} else {
ZVAL_COPY ( result , z ) ;
}
ZVAL_DUP ( & z_copy , result ) ;
2015-06-03 23:44:25 +08:00
if ( inc ) {
increment_function ( & z_copy ) ;
} else {
decrement_function ( & z_copy ) ;
}
Z_OBJ_HT ( obj ) - > write_property ( & obj , property , & z_copy , cache_slot ) ;
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
zval_ptr_dtor ( & z_copy ) ;
zval_ptr_dtor ( z ) ;
} else {
zend_error ( E_WARNING , " Attempt to increment/decrement property of non-object " ) ;
ZVAL_NULL ( result ) ;
}
}
static zend_never_inline void zend_pre_incdec_overloaded_property ( zval * object , zval * property , void * * cache_slot , int inc , zval * result )
{
zval rv ;
if ( Z_OBJ_HT_P ( object ) - > read_property & & Z_OBJ_HT_P ( object ) - > write_property ) {
zval * z , obj ;
ZVAL_OBJ ( & obj , Z_OBJ_P ( object ) ) ;
Z_ADDREF ( obj ) ;
z = Z_OBJ_HT ( obj ) - > read_property ( & obj , property , BP_VAR_R , cache_slot , & rv ) ;
if ( UNEXPECTED ( EG ( exception ) ) ) {
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
return ;
}
if ( UNEXPECTED ( Z_TYPE_P ( z ) = = IS_OBJECT ) & & Z_OBJ_HT_P ( z ) - > get ) {
zval rv2 ;
zval * value = Z_OBJ_HT_P ( z ) - > get ( z , & rv2 ) ;
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
}
ZVAL_COPY_VALUE ( z , value ) ;
}
ZVAL_DEREF ( z ) ;
SEPARATE_ZVAL_NOREF ( z ) ;
if ( inc ) {
increment_function ( z ) ;
} else {
decrement_function ( z ) ;
}
if ( UNEXPECTED ( result ) ) {
ZVAL_COPY ( result , z ) ;
}
Z_OBJ_HT ( obj ) - > write_property ( & obj , property , z , cache_slot ) ;
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
zval_ptr_dtor ( z ) ;
} else {
zend_error ( E_WARNING , " Attempt to increment/decrement property of non-object " ) ;
if ( UNEXPECTED ( result ) ) {
ZVAL_NULL ( result ) ;
}
}
}
static zend_never_inline void zend_assign_op_overloaded_property ( zval * object , zval * property , void * * cache_slot , zval * value , binary_op_type binary_op , zval * result )
{
zval * z ;
zval rv , obj ;
zval * zptr ;
ZVAL_OBJ ( & obj , Z_OBJ_P ( object ) ) ;
Z_ADDREF ( obj ) ;
2015-10-01 22:33:30 +08:00
if ( EXPECTED ( Z_OBJ_HT ( obj ) - > read_property ) ) {
z = Z_OBJ_HT ( obj ) - > read_property ( & obj , property , BP_VAR_R , cache_slot , & rv ) ;
2015-06-03 23:44:25 +08:00
if ( UNEXPECTED ( EG ( exception ) ) ) {
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
return ;
}
if ( Z_TYPE_P ( z ) = = IS_OBJECT & & Z_OBJ_HT_P ( z ) - > get ) {
zval rv2 ;
zval * value = Z_OBJ_HT_P ( z ) - > get ( z , & rv2 ) ;
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
}
ZVAL_COPY_VALUE ( z , value ) ;
}
zptr = z ;
ZVAL_DEREF ( z ) ;
SEPARATE_ZVAL_NOREF ( z ) ;
binary_op ( z , z , value ) ;
Z_OBJ_HT ( obj ) - > write_property ( & obj , property , z , cache_slot ) ;
if ( UNEXPECTED ( result ) ) {
ZVAL_COPY ( result , z ) ;
}
zval_ptr_dtor ( zptr ) ;
} else {
zend_error ( E_WARNING , " Attempt to assign property of non-object " ) ;
if ( UNEXPECTED ( result ) ) {
ZVAL_NULL ( result ) ;
}
}
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
}
1999-04-08 02:10:10 +08:00
/* Utility Functions for Extensions */
2014-12-14 06:06:14 +08:00
static void zend_extension_statement_handler ( const zend_extension * extension , zend_op_array * op_array )
1999-04-08 02:10:10 +08:00
{
if ( extension - > statement_handler ) {
extension - > statement_handler ( op_array ) ;
}
}
2014-12-14 06:06:14 +08:00
static void zend_extension_fcall_begin_handler ( const zend_extension * extension , zend_op_array * op_array )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_begin_handler ) {
extension - > fcall_begin_handler ( op_array ) ;
}
}
2014-12-14 06:06:14 +08:00
static void zend_extension_fcall_end_handler ( const zend_extension * extension , zend_op_array * op_array )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_end_handler ) {
extension - > fcall_end_handler ( op_array ) ;
}
}
2014-12-14 06:06:14 +08:00
static zend_always_inline HashTable * zend_get_target_symbol_table ( zend_execute_data * execute_data , int fetch_type )
1999-04-08 02:10:10 +08:00
{
2014-04-08 04:38:54 +08:00
HashTable * ht ;
2015-01-03 17:22:58 +08:00
if ( EXPECTED ( fetch_type = = ZEND_FETCH_GLOBAL_LOCK ) | |
2014-04-08 04:38:54 +08:00
EXPECTED ( fetch_type = = ZEND_FETCH_GLOBAL ) ) {
2015-02-14 03:20:39 +08:00
ht = & EG ( symbol_table ) ;
2014-04-08 04:38:54 +08:00
} else {
ZEND_ASSERT ( fetch_type = = ZEND_FETCH_LOCAL ) ;
2014-07-04 21:03:44 +08:00
if ( ! EX ( symbol_table ) ) {
2014-12-14 06:06:14 +08:00
zend_rebuild_symbol_table ( ) ;
2014-04-08 04:38:54 +08:00
}
2015-02-14 03:20:39 +08:00
ht = EX ( symbol_table ) ;
1999-04-08 02:10:10 +08:00
}
2014-04-08 04:38:54 +08:00
return ht ;
2002-02-05 03:29:56 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zval * zend_fetch_dimension_address_inner ( HashTable * ht , const zval * dim , int dim_type , int type )
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval * retval ;
zend_string * offset_key ;
2014-08-26 01:24:55 +08:00
zend_ulong hval ;
1999-04-08 02:10:10 +08:00
2014-12-05 18:45:03 +08:00
try_again :
2014-08-26 01:24:55 +08:00
if ( EXPECTED ( Z_TYPE_P ( dim ) = = IS_LONG ) ) {
hval = Z_LVAL_P ( dim ) ;
2014-04-05 05:56:51 +08:00
num_index :
retval = zend_hash_index_find ( ht , hval ) ;
if ( retval = = NULL ) {
switch ( type ) {
case BP_VAR_R :
2015-06-09 14:56:34 +08:00
zend_error ( E_NOTICE , " Undefined offset: " ZEND_LONG_FMT , hval ) ;
2014-04-05 05:56:51 +08:00
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
2015-06-09 14:56:34 +08:00
zend_error ( E_NOTICE , " Undefined offset: " ZEND_LONG_FMT , hval ) ;
2015-10-08 04:47:09 +08:00
retval = zend_hash_index_update ( ht , hval , & EG ( uninitialized_zval ) ) ;
break ;
2014-04-05 05:56:51 +08:00
case BP_VAR_W :
2014-05-27 04:38:58 +08:00
retval = zend_hash_index_add_new ( ht , hval , & EG ( uninitialized_zval ) ) ;
2014-04-05 05:56:51 +08:00
break ;
2011-03-16 13:41:50 +08:00
}
2016-03-10 14:58:10 +08:00
}
2014-04-05 05:56:51 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( dim ) = = IS_STRING ) ) {
offset_key = Z_STR_P ( dim ) ;
if ( dim_type ! = IS_CONST ) {
2014-06-03 17:10:42 +08:00
if ( ZEND_HANDLE_NUMERIC ( offset_key , hval ) ) {
goto num_index ;
}
2014-04-05 05:56:51 +08:00
}
str_index :
retval = zend_hash_find ( ht , offset_key ) ;
if ( retval ) {
/* support for $GLOBALS[...] */
if ( UNEXPECTED ( Z_TYPE_P ( retval ) = = IS_INDIRECT ) ) {
retval = Z_INDIRECT_P ( retval ) ;
if ( UNEXPECTED ( Z_TYPE_P ( retval ) = = IS_UNDEF ) ) {
switch ( type ) {
case BP_VAR_R :
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Undefined index: %s " , ZSTR_VAL ( offset_key ) ) ;
2014-04-05 05:56:51 +08:00
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Undefined index: %s " , ZSTR_VAL ( offset_key ) ) ;
2014-04-05 05:56:51 +08:00
/* break missing intentionally */
case BP_VAR_W :
ZVAL_NULL ( retval ) ;
break ;
2014-03-26 22:07:31 +08:00
}
}
2016-03-10 14:58:10 +08:00
}
2015-01-03 17:22:58 +08:00
} else {
2014-04-05 05:56:51 +08:00
switch ( type ) {
case BP_VAR_R :
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Undefined index: %s " , ZSTR_VAL ( offset_key ) ) ;
2014-04-05 05:56:51 +08:00
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Undefined index: %s " , ZSTR_VAL ( offset_key ) ) ;
2015-10-08 04:47:09 +08:00
retval = zend_hash_update ( ht , offset_key , & EG ( uninitialized_zval ) ) ;
break ;
2014-04-05 05:56:51 +08:00
case BP_VAR_W :
2014-05-26 21:16:16 +08:00
retval = zend_hash_add_new ( ht , offset_key , & EG ( uninitialized_zval ) ) ;
2014-04-05 05:56:51 +08:00
break ;
1999-04-08 02:10:10 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else {
switch ( Z_TYPE_P ( dim ) ) {
case IS_NULL :
2015-06-29 21:44:54 +08:00
offset_key = ZSTR_EMPTY_ALLOC ( ) ;
2014-04-05 05:56:51 +08:00
goto str_index ;
case IS_DOUBLE :
2014-08-26 01:24:55 +08:00
hval = zend_dval_to_lval ( Z_DVAL_P ( dim ) ) ;
2014-04-05 05:56:51 +08:00
goto num_index ;
case IS_RESOURCE :
2015-03-15 16:47:25 +08:00
zend_error ( E_NOTICE , " Resource ID#%pd used as offset, casting to integer (%pd) " , Z_RES_HANDLE_P ( dim ) , Z_RES_HANDLE_P ( dim ) ) ;
2014-04-05 05:56:51 +08:00
hval = Z_RES_HANDLE_P ( dim ) ;
goto num_index ;
2014-04-30 22:32:42 +08:00
case IS_FALSE :
hval = 0 ;
goto num_index ;
case IS_TRUE :
hval = 1 ;
2014-04-05 05:56:51 +08:00
goto num_index ;
2014-12-05 18:45:03 +08:00
case IS_REFERENCE :
dim = Z_REFVAL_P ( dim ) ;
goto try_again ;
2014-04-05 05:56:51 +08:00
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
retval = ( type = = BP_VAR_W | | type = = BP_VAR_RW ) ?
2016-01-28 23:00:06 +08:00
NULL : & EG ( uninitialized_zval ) ;
2014-04-05 05:56:51 +08:00
}
1999-04-08 02:10:10 +08:00
}
return retval ;
}
2014-12-14 06:06:14 +08:00
static zend_never_inline zend_long zend_check_string_offset ( zval * dim , int type )
2014-10-21 23:30:43 +08:00
{
zend_long offset ;
2014-12-05 18:45:03 +08:00
try_again :
2014-10-21 23:30:43 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( dim ) ! = IS_LONG ) ) {
switch ( Z_TYPE_P ( dim ) ) {
case IS_STRING :
if ( IS_LONG = = is_numeric_string ( Z_STRVAL_P ( dim ) , Z_STRLEN_P ( dim ) , NULL , NULL , - 1 ) ) {
break ;
}
if ( type ! = BP_VAR_UNSET ) {
zend_error ( E_WARNING , " Illegal string offset '%s' " , Z_STRVAL_P ( dim ) ) ;
}
break ;
case IS_DOUBLE :
case IS_NULL :
case IS_FALSE :
case IS_TRUE :
zend_error ( E_NOTICE , " String offset cast occurred " ) ;
break ;
2014-12-05 18:45:03 +08:00
case IS_REFERENCE :
dim = Z_REFVAL_P ( dim ) ;
goto try_again ;
2014-10-21 23:30:43 +08:00
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
break ;
}
offset = zval_get_long ( dim ) ;
} else {
offset = Z_LVAL_P ( dim ) ;
}
return offset ;
}
2015-12-24 21:03:31 +08:00
static zend_never_inline ZEND_COLD void zend_wrong_string_offset ( void )
2015-12-23 18:52:15 +08:00
{
const char * msg = NULL ;
const zend_op * opline = EG ( current_execute_data ) - > opline ;
const zend_op * end ;
uint32_t var ;
switch ( opline - > opcode ) {
case ZEND_ASSIGN_ADD :
case ZEND_ASSIGN_SUB :
case ZEND_ASSIGN_MUL :
case ZEND_ASSIGN_DIV :
case ZEND_ASSIGN_MOD :
case ZEND_ASSIGN_SL :
case ZEND_ASSIGN_SR :
case ZEND_ASSIGN_CONCAT :
case ZEND_ASSIGN_BW_OR :
case ZEND_ASSIGN_BW_AND :
case ZEND_ASSIGN_BW_XOR :
case ZEND_ASSIGN_POW :
msg = " Cannot use assign-op operators with string offsets " ;
break ;
case ZEND_FETCH_DIM_W :
case ZEND_FETCH_DIM_RW :
case ZEND_FETCH_DIM_FUNC_ARG :
case ZEND_FETCH_DIM_UNSET :
/* TODO: Encode the "reason" into opline->extended_value??? */
var = opline - > result . var ;
opline + + ;
end = EG ( current_execute_data ) - > func - > op_array . opcodes +
EG ( current_execute_data ) - > func - > op_array . last ;
while ( opline < end ) {
if ( opline - > op1_type = = IS_VAR & & opline - > op1 . var = = var ) {
switch ( opline - > opcode ) {
case ZEND_ASSIGN_ADD :
case ZEND_ASSIGN_SUB :
case ZEND_ASSIGN_MUL :
case ZEND_ASSIGN_DIV :
case ZEND_ASSIGN_MOD :
case ZEND_ASSIGN_SL :
case ZEND_ASSIGN_SR :
case ZEND_ASSIGN_CONCAT :
case ZEND_ASSIGN_BW_OR :
case ZEND_ASSIGN_BW_AND :
case ZEND_ASSIGN_BW_XOR :
case ZEND_ASSIGN_POW :
if ( opline - > extended_value = = ZEND_ASSIGN_OBJ ) {
msg = " Cannot use string offset as an object " ;
} else if ( opline - > extended_value = = ZEND_ASSIGN_DIM ) {
msg = " Cannot use string offset as an array " ;
} else {
msg = " Cannot use assign-op operators with string offsets " ;
}
break ;
case ZEND_PRE_INC_OBJ :
case ZEND_PRE_DEC_OBJ :
case ZEND_POST_INC_OBJ :
case ZEND_POST_DEC_OBJ :
case ZEND_PRE_INC :
case ZEND_PRE_DEC :
case ZEND_POST_INC :
case ZEND_POST_DEC :
msg = " Cannot increment/decrement string offsets " ;
break ;
case ZEND_FETCH_DIM_W :
case ZEND_FETCH_DIM_RW :
case ZEND_FETCH_DIM_FUNC_ARG :
case ZEND_FETCH_DIM_UNSET :
case ZEND_ASSIGN_DIM :
msg = " Cannot use string offset as an array " ;
break ;
case ZEND_FETCH_OBJ_W :
case ZEND_FETCH_OBJ_RW :
case ZEND_FETCH_OBJ_FUNC_ARG :
case ZEND_FETCH_OBJ_UNSET :
case ZEND_ASSIGN_OBJ :
msg = " Cannot use string offset as an object " ;
break ;
case ZEND_ASSIGN_REF :
case ZEND_ADD_ARRAY_ELEMENT :
case ZEND_INIT_ARRAY :
msg = " Cannot create references to/from string offsets " ;
break ;
case ZEND_RETURN_BY_REF :
msg = " Cannot return string offsets by reference " ;
break ;
case ZEND_UNSET_DIM :
case ZEND_UNSET_OBJ :
msg = " Cannot unset string offsets " ;
break ;
case ZEND_YIELD :
msg = " Cannot yield string offsets by reference " ;
break ;
case ZEND_SEND_REF :
case ZEND_SEND_VAR_EX :
msg = " Only variables can be passed by reference " ;
break ;
EMPTY_SWITCH_DEFAULT_CASE ( ) ;
}
break ;
}
if ( opline - > op2_type = = IS_VAR & & opline - > op2 . var = = var ) {
ZEND_ASSERT ( opline - > opcode = = ZEND_ASSIGN_REF ) ;
msg = " Cannot create references to/from string offsets " ;
break ;
}
}
break ;
EMPTY_SWITCH_DEFAULT_CASE ( ) ;
}
ZEND_ASSERT ( msg ! = NULL ) ;
zend_throw_error ( NULL , msg ) ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline zend_long zend_fetch_string_offset ( zval * container , zval * dim , int type )
2014-10-21 23:30:43 +08:00
{
2014-12-14 06:06:14 +08:00
zend_long offset = zend_check_string_offset ( dim , type ) ;
2014-10-21 23:30:43 +08:00
if ( Z_REFCOUNTED_P ( container ) ) {
if ( Z_REFCOUNT_P ( container ) > 1 ) {
Z_DELREF_P ( container ) ;
zval_copy_ctor_func ( container ) ;
}
Z_ADDREF_P ( container ) ;
}
return offset ;
}
2014-12-14 06:06:14 +08:00
static zend_always_inline void zend_fetch_dimension_address ( zval * result , zval * container , zval * dim , int dim_type , int type )
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval * retval ;
1999-04-08 02:10:10 +08:00
2014-04-05 05:56:51 +08:00
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
2015-06-01 22:22:04 +08:00
try_array :
2014-06-05 20:04:11 +08:00
SEPARATE_ARRAY ( container ) ;
2007-11-20 19:01:28 +08:00
fetch_from_array :
2014-04-05 05:56:51 +08:00
if ( dim = = NULL ) {
retval = zend_hash_next_index_insert ( Z_ARRVAL_P ( container ) , & EG ( uninitialized_zval ) ) ;
2014-09-22 17:18:49 +08:00
if ( UNEXPECTED ( retval = = NULL ) ) {
2014-04-05 05:56:51 +08:00
zend_error ( E_WARNING , " Cannot add element to the array as the next element is already occupied " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
return ;
2014-04-04 23:01:53 +08:00
}
2014-04-05 05:56:51 +08:00
} else {
2014-12-14 06:06:14 +08:00
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type ) ;
2016-01-28 23:00:06 +08:00
if ( UNEXPECTED ( ! retval ) ) {
ZVAL_ERROR ( result ) ;
return ;
}
2014-04-05 05:56:51 +08:00
}
2014-09-22 21:52:38 +08:00
ZVAL_INDIRECT ( result , retval ) ;
2015-06-01 22:22:04 +08:00
return ;
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_REFERENCE ) ) {
container = Z_REFVAL_P ( container ) ;
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
goto try_array ;
}
}
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
2014-08-26 01:24:55 +08:00
if ( type ! = BP_VAR_UNSET & & UNEXPECTED ( Z_STRLEN_P ( container ) = = 0 ) ) {
2014-09-23 21:21:29 +08:00
zval_ptr_dtor_nogc ( container ) ;
2014-06-09 19:41:29 +08:00
convert_to_array :
ZVAL_NEW_ARR ( container ) ;
zend_hash_init ( Z_ARRVAL_P ( container ) , 8 , NULL , ZVAL_PTR_DTOR , 0 ) ;
2014-04-05 05:56:51 +08:00
goto fetch_from_array ;
}
2014-09-07 06:54:47 +08:00
2015-04-01 19:50:09 +08:00
if ( dim = = NULL ) {
2015-07-08 01:10:22 +08:00
zend_throw_error ( NULL , " [] operator not supported for strings " ) ;
2015-04-01 19:50:09 +08:00
} else {
zend_check_string_offset ( dim , type ) ;
2015-12-23 18:52:15 +08:00
zend_wrong_string_offset ( ) ;
2015-04-01 19:50:09 +08:00
}
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-04-05 05:56:51 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
if ( ! Z_OBJ_HT_P ( container ) - > read_dimension ) {
2015-07-08 01:10:22 +08:00
zend_throw_error ( NULL , " Cannot use object as array " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-04-05 05:56:51 +08:00
} else {
2014-12-14 06:06:14 +08:00
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result ) ;
2014-04-05 05:56:51 +08:00
2014-04-10 03:49:58 +08:00
if ( UNEXPECTED ( retval = = & EG ( uninitialized_zval ) ) ) {
2014-07-09 17:30:47 +08:00
zend_class_entry * ce = Z_OBJCE_P ( container ) ;
2014-04-10 03:49:58 +08:00
ZVAL_NULL ( result ) ;
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Indirect modification of overloaded element of %s has no effect " , ZSTR_VAL ( ce - > name ) ) ;
2014-09-22 17:18:49 +08:00
} else if ( EXPECTED ( retval & & Z_TYPE_P ( retval ) ! = IS_UNDEF ) ) {
2014-04-05 05:56:51 +08:00
if ( ! Z_ISREF_P ( retval ) ) {
if ( Z_REFCOUNTED_P ( retval ) & &
Z_REFCOUNT_P ( retval ) > 1 ) {
if ( Z_TYPE_P ( retval ) ! = IS_OBJECT ) {
Z_DELREF_P ( retval ) ;
ZVAL_DUP ( result , retval ) ;
retval = result ;
2014-04-04 23:01:53 +08:00
} else {
2015-08-18 21:46:02 +08:00
ZVAL_COPY_VALUE ( result , retval ) ;
2014-04-05 05:56:51 +08:00
retval = result ;
2014-04-04 23:01:53 +08:00
}
2014-02-27 19:40:13 +08:00
}
2014-04-05 05:56:51 +08:00
if ( Z_TYPE_P ( retval ) ! = IS_OBJECT ) {
zend_class_entry * ce = Z_OBJCE_P ( container ) ;
2015-06-30 18:59:27 +08:00
zend_error ( E_NOTICE , " Indirect modification of overloaded element of %s has no effect " , ZSTR_VAL ( ce - > name ) ) ;
2014-04-05 05:56:51 +08:00
}
2015-08-23 11:40:49 +08:00
} else if ( UNEXPECTED ( Z_REFCOUNT_P ( retval ) = = 1 ) ) {
ZVAL_UNREF ( retval ) ;
2014-04-05 05:56:51 +08:00
}
if ( result ! = retval ) {
2014-09-22 21:52:38 +08:00
ZVAL_INDIRECT ( result , retval ) ;
2005-06-03 19:16:19 +08:00
}
2007-12-14 22:14:50 +08:00
} else {
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2007-12-14 22:14:50 +08:00
}
2014-04-05 05:56:51 +08:00
}
2014-12-09 05:10:23 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( container ) < = IS_FALSE ) ) {
2016-01-28 23:00:06 +08:00
if ( type ! = BP_VAR_UNSET ) {
2014-04-05 05:56:51 +08:00
goto convert_to_array ;
} else {
/* for read-mode only */
ZVAL_NULL ( result ) ;
}
2016-02-01 16:12:28 +08:00
} else if ( EXPECTED ( Z_ISERROR_P ( container ) ) ) {
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-04-05 05:56:51 +08:00
} else {
if ( type = = BP_VAR_UNSET ) {
zend_error ( E_WARNING , " Cannot unset offset in a non-array variable " ) ;
ZVAL_NULL ( result ) ;
} else {
zend_error ( E_WARNING , " Cannot use a scalar value as an array " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
}
}
2014-12-14 06:06:14 +08:00
static zend_never_inline void zend_fetch_dimension_address_W ( zval * result , zval * container_ptr , zval * dim , int dim_type )
2007-12-14 22:14:50 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_W ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2014-12-14 06:06:14 +08:00
static zend_never_inline void zend_fetch_dimension_address_RW ( zval * result , zval * container_ptr , zval * dim , int dim_type )
2014-04-05 05:56:51 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_RW ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2014-12-14 06:06:14 +08:00
static zend_never_inline void zend_fetch_dimension_address_UNSET ( zval * result , zval * container_ptr , zval * dim , int dim_type )
2014-04-05 05:56:51 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_UNSET ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2014-12-14 06:06:14 +08:00
static zend_always_inline void zend_fetch_dimension_address_read ( zval * result , zval * container , zval * dim , int dim_type , int type )
2014-04-05 05:56:51 +08:00
{
zval * retval ;
2010-07-16 21:38:09 +08:00
2014-04-05 05:56:51 +08:00
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
2015-06-01 22:22:04 +08:00
try_array :
2014-12-14 06:06:14 +08:00
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type ) ;
2014-04-05 05:56:51 +08:00
ZVAL_COPY ( result , retval ) ;
2015-06-01 22:22:04 +08:00
return ;
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_REFERENCE ) ) {
container = Z_REFVAL_P ( container ) ;
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
goto try_array ;
}
}
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
2014-08-26 01:24:55 +08:00
zend_long offset ;
2014-04-05 05:56:51 +08:00
2014-12-08 23:11:14 +08:00
try_string_offset :
2014-08-26 01:24:55 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( dim ) ! = IS_LONG ) ) {
2016-03-10 15:09:51 +08:00
switch ( Z_TYPE_P ( dim ) ) {
2014-08-26 01:24:55 +08:00
/* case IS_LONG: */
2014-04-05 05:56:51 +08:00
case IS_STRING :
2014-08-26 01:24:55 +08:00
if ( IS_LONG = = is_numeric_string ( Z_STRVAL_P ( dim ) , Z_STRLEN_P ( dim ) , NULL , NULL , - 1 ) ) {
2014-04-05 05:56:51 +08:00
break ;
}
2015-06-20 21:09:58 +08:00
if ( type = = BP_VAR_IS ) {
ZVAL_NULL ( result ) ;
return ;
2011-02-14 16:46:53 +08:00
}
2015-06-20 21:09:58 +08:00
zend_error ( E_WARNING , " Illegal string offset '%s' " , Z_STRVAL_P ( dim ) ) ;
2014-04-05 05:56:51 +08:00
break ;
case IS_DOUBLE :
case IS_NULL :
2014-04-30 22:32:42 +08:00
case IS_FALSE :
case IS_TRUE :
2014-04-05 05:56:51 +08:00
if ( type ! = BP_VAR_IS ) {
zend_error ( E_NOTICE , " String offset cast occurred " ) ;
2014-04-01 22:06:50 +08:00
}
2014-04-05 05:56:51 +08:00
break ;
2014-12-05 18:45:03 +08:00
case IS_REFERENCE :
dim = Z_REFVAL_P ( dim ) ;
2014-12-08 23:11:14 +08:00
goto try_string_offset ;
2014-04-05 05:56:51 +08:00
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
break ;
2007-12-14 22:14:50 +08:00
}
2014-08-26 01:24:55 +08:00
offset = zval_get_long ( dim ) ;
2014-06-05 20:04:11 +08:00
} else {
2014-08-26 01:24:55 +08:00
offset = Z_LVAL_P ( dim ) ;
2014-04-05 05:56:51 +08:00
}
2015-07-22 04:16:08 +08:00
if ( UNEXPECTED ( Z_STRLEN_P ( container ) < ( size_t ) ( ( offset < 0 ) ? - offset : ( offset + 1 ) ) ) ) {
2014-04-05 05:56:51 +08:00
if ( type ! = BP_VAR_IS ) {
2014-09-03 21:57:28 +08:00
zend_error ( E_NOTICE , " Uninitialized string offset: %pd " , offset ) ;
2015-06-20 21:09:58 +08:00
ZVAL_EMPTY_STRING ( result ) ;
} else {
ZVAL_NULL ( result ) ;
2014-04-05 05:56:51 +08:00
}
} else {
2015-07-22 04:16:08 +08:00
zend_uchar c ;
zend_long real_offset ;
real_offset = ( UNEXPECTED ( offset < 0 ) ) /* Handle negative offset */
? ( zend_long ) Z_STRLEN_P ( container ) + offset : offset ;
c = ( zend_uchar ) Z_STRVAL_P ( container ) [ real_offset ] ;
2014-04-05 05:56:51 +08:00
if ( CG ( one_char_string ) [ c ] ) {
2014-08-26 01:28:33 +08:00
ZVAL_INTERNED_STR ( result , CG ( one_char_string ) [ c ] ) ;
2007-12-14 22:14:50 +08:00
} else {
2015-07-22 04:16:08 +08:00
ZVAL_NEW_STR ( result , zend_string_init ( Z_STRVAL_P ( container ) + real_offset , 1 , 0 ) ) ;
2014-04-05 05:56:51 +08:00
}
}
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
if ( ! Z_OBJ_HT_P ( container ) - > read_dimension ) {
2015-07-08 01:10:22 +08:00
zend_throw_error ( NULL , " Cannot use object as array " ) ;
2015-04-01 19:50:09 +08:00
ZVAL_NULL ( result ) ;
2014-04-05 05:56:51 +08:00
} else {
2014-12-14 06:06:14 +08:00
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result ) ;
2014-04-05 05:56:51 +08:00
2014-10-03 18:35:05 +08:00
ZEND_ASSERT ( result ! = NULL ) ;
if ( retval ) {
if ( result ! = retval ) {
ZVAL_COPY ( result , retval ) ;
2007-12-14 22:14:50 +08:00
}
2014-10-03 18:35:05 +08:00
} else {
ZVAL_NULL ( result ) ;
1999-04-08 02:10:10 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else {
ZVAL_NULL ( result ) ;
1999-04-08 02:10:10 +08:00
}
}
2014-12-14 06:06:14 +08:00
static zend_never_inline void zend_fetch_dimension_address_read_R ( zval * result , zval * container , zval * dim , int dim_type )
2014-04-05 05:56:51 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_R ) ;
2014-04-05 05:56:51 +08:00
}
2014-12-14 06:06:14 +08:00
static zend_never_inline void zend_fetch_dimension_address_read_IS ( zval * result , zval * container , zval * dim , int dim_type )
2014-04-05 05:56:51 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_IS ) ;
2014-04-05 05:56:51 +08:00
}
2014-12-14 06:06:14 +08:00
ZEND_API void zend_fetch_dimension_by_zval ( zval * result , zval * container , zval * dim )
2014-08-04 17:56:27 +08:00
{
2014-12-14 06:06:14 +08:00
zend_fetch_dimension_address_read_R ( result , container , dim , IS_TMP_VAR ) ;
2014-08-04 17:56:27 +08:00
}
2006-05-10 07:53:23 +08:00
2014-12-14 06:06:14 +08:00
static zend_always_inline void zend_fetch_property_address ( zval * result , zval * container , uint32_t container_op_type , zval * prop_ptr , uint32_t prop_op_type , void * * cache_slot , int type )
1999-04-08 02:10:10 +08:00
{
2014-12-09 06:09:44 +08:00
if ( container_op_type ! = IS_UNUSED & & UNEXPECTED ( Z_TYPE_P ( container ) ! = IS_OBJECT ) ) {
do {
2016-02-01 16:12:28 +08:00
if ( container_op_type = = IS_VAR & & UNEXPECTED ( Z_ISERROR_P ( container ) ) ) {
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-10-10 20:36:12 +08:00
return ;
}
2006-05-10 07:53:23 +08:00
2014-12-09 06:09:44 +08:00
if ( Z_ISREF_P ( container ) ) {
container = Z_REFVAL_P ( container ) ;
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
break ;
}
}
2014-10-10 20:36:12 +08:00
/* this should modify object only if it's empty */
if ( type ! = BP_VAR_UNSET & &
2014-12-09 05:10:23 +08:00
EXPECTED ( Z_TYPE_P ( container ) < = IS_FALSE | |
( Z_TYPE_P ( container ) = = IS_STRING & & Z_STRLEN_P ( container ) = = 0 ) ) ) {
2014-10-10 20:36:12 +08:00
zval_ptr_dtor_nogc ( container ) ;
object_init ( container ) ;
} else {
zend_error ( E_WARNING , " Attempt to modify property of non-object " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2014-10-10 20:36:12 +08:00
return ;
}
2014-12-09 06:09:44 +08:00
} while ( 0 ) ;
1999-04-08 02:10:10 +08:00
}
2014-11-06 19:50:03 +08:00
if ( prop_op_type = = IS_CONST & &
EXPECTED ( Z_OBJCE_P ( container ) = = CACHED_PTR_EX ( cache_slot ) ) ) {
2015-01-13 16:33:00 +08:00
uint32_t prop_offset = ( uint32_t ) ( intptr_t ) CACHED_PTR_EX ( cache_slot + 1 ) ;
2014-11-06 19:50:03 +08:00
zend_object * zobj = Z_OBJ_P ( container ) ;
zval * retval ;
2015-02-26 04:20:47 +08:00
if ( EXPECTED ( prop_offset ! = ( uint32_t ) ZEND_DYNAMIC_PROPERTY_OFFSET ) ) {
2015-01-13 16:33:00 +08:00
retval = OBJ_PROP ( zobj , prop_offset ) ;
2014-11-06 19:50:03 +08:00
if ( EXPECTED ( Z_TYPE_P ( retval ) ! = IS_UNDEF ) ) {
ZVAL_INDIRECT ( result , retval ) ;
return ;
}
} else if ( EXPECTED ( zobj - > properties ! = NULL ) ) {
2015-12-09 21:07:59 +08:00
if ( UNEXPECTED ( GC_REFCOUNT ( zobj - > properties ) > 1 ) ) {
if ( EXPECTED ( ! ( GC_FLAGS ( zobj - > properties ) & IS_ARRAY_IMMUTABLE ) ) ) {
GC_REFCOUNT ( zobj - > properties ) - - ;
}
zobj - > properties = zend_array_dup ( zobj - > properties ) ;
}
2014-11-06 19:50:03 +08:00
retval = zend_hash_find ( zobj - > properties , Z_STR_P ( prop_ptr ) ) ;
if ( EXPECTED ( retval ) ) {
ZVAL_INDIRECT ( result , retval ) ;
return ;
}
}
}
2014-09-22 17:18:49 +08:00
if ( EXPECTED ( Z_OBJ_HT_P ( container ) - > get_property_ptr_ptr ) ) {
2014-12-14 06:06:14 +08:00
zval * ptr = Z_OBJ_HT_P ( container ) - > get_property_ptr_ptr ( container , prop_ptr , type , cache_slot ) ;
2014-02-10 14:04:30 +08:00
if ( NULL = = ptr ) {
2015-10-01 22:33:30 +08:00
if ( EXPECTED ( Z_OBJ_HT_P ( container ) - > read_property ) ) {
ptr = Z_OBJ_HT_P ( container ) - > read_property ( container , prop_ptr , type , cache_slot , result ) ;
2014-02-27 19:40:13 +08:00
if ( ptr ! = result ) {
2014-09-22 21:52:38 +08:00
ZVAL_INDIRECT ( result , ptr ) ;
2015-08-23 11:40:49 +08:00
} else if ( UNEXPECTED ( Z_ISREF_P ( ptr ) & & Z_REFCOUNT_P ( ptr ) = = 1 ) ) {
ZVAL_UNREF ( ptr ) ;
2014-02-27 19:40:13 +08:00
}
2005-01-18 17:05:39 +08:00
} else {
2015-07-08 01:10:22 +08:00
zend_throw_error ( NULL , " Cannot access undefined property for object with overloaded property access " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2005-01-18 17:05:39 +08:00
}
2008-01-24 01:55:55 +08:00
} else {
2014-09-22 21:52:38 +08:00
ZVAL_INDIRECT ( result , ptr ) ;
2002-02-07 22:08:43 +08:00
}
2014-09-22 17:18:49 +08:00
} else if ( EXPECTED ( Z_OBJ_HT_P ( container ) - > read_property ) ) {
2014-12-14 06:06:14 +08:00
zval * ptr = Z_OBJ_HT_P ( container ) - > read_property ( container , prop_ptr , type , cache_slot , result ) ;
2014-02-27 19:40:13 +08:00
if ( ptr ! = result ) {
2014-09-22 21:52:38 +08:00
ZVAL_INDIRECT ( result , ptr ) ;
2015-08-23 11:40:49 +08:00
} else if ( UNEXPECTED ( Z_ISREF_P ( ptr ) & & Z_REFCOUNT_P ( ptr ) = = 1 ) ) {
ZVAL_UNREF ( ptr ) ;
2014-02-27 19:40:13 +08:00
}
2004-09-24 05:43:32 +08:00
} else {
zend_error ( E_WARNING , " This object doesn't support property references " ) ;
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2001-05-03 03:51:33 +08:00
}
1999-04-08 02:10:10 +08:00
}
2000-02-10 05:48:16 +08:00
# if ZEND_INTENSIVE_DEBUGGING
2014-05-25 18:32:35 +08:00
# define CHECK_SYMBOL_TABLES() \
2014-12-14 06:06:14 +08:00
zend_hash_apply ( & EG ( symbol_table ) , zend_check_symbol ) ; \
2014-07-04 22:03:45 +08:00
if ( & EG ( symbol_table ) ! = EX ( symbol_table ) ) { \
2014-12-14 06:06:14 +08:00
zend_hash_apply ( EX ( symbol_table ) , zend_check_symbol ) ; \
2000-02-10 05:48:16 +08:00
}
2014-12-14 06:06:14 +08:00
static int zend_check_symbol ( zval * pz )
2000-02-10 05:48:16 +08:00
{
2014-05-25 18:32:35 +08:00
if ( Z_TYPE_P ( pz ) = = IS_INDIRECT ) {
pz = Z_INDIRECT_P ( pz ) ;
}
if ( Z_TYPE_P ( pz ) > 10 ) {
2014-03-11 14:23:14 +08:00
fprintf ( stderr , " Warning! %x has invalid type! \n " , * pz ) ;
2010-01-25 22:47:19 +08:00
/* See http://support.microsoft.com/kb/190351 */
2015-07-05 00:55:22 +08:00
# ifdef ZEND_WIN32
2010-01-25 22:47:19 +08:00
fflush ( stderr ) ;
# endif
2014-05-25 18:32:35 +08:00
} else if ( Z_TYPE_P ( pz ) = = IS_ARRAY ) {
2014-12-14 06:06:14 +08:00
zend_hash_apply ( Z_ARRVAL_P ( pz ) , zend_check_symbol ) ;
2014-05-25 18:32:35 +08:00
} else if ( Z_TYPE_P ( pz ) = = IS_OBJECT ) {
2002-02-07 22:08:43 +08:00
/* OBJ-TBI - doesn't support new object model! */
2014-12-14 06:06:14 +08:00
zend_hash_apply ( Z_OBJPROP_P ( pz ) , zend_check_symbol ) ;
2000-02-10 05:48:16 +08:00
}
return 0 ;
}
# else
# define CHECK_SYMBOL_TABLES()
# endif
2014-12-14 06:06:14 +08:00
ZEND_API void execute_internal ( zend_execute_data * execute_data , zval * return_value )
2003-01-12 00:12:44 +08:00
{
2014-12-14 06:06:14 +08:00
execute_data - > func - > internal_function . handler ( execute_data , return_value ) ;
2003-01-12 00:12:44 +08:00
}
2014-12-14 06:06:14 +08:00
ZEND_API void zend_clean_and_cache_symbol_table ( zend_array * symbol_table ) /* { { { */
2012-05-28 12:43:18 +08:00
{
if ( EG ( symtable_cache_ptr ) > = EG ( symtable_cache_limit ) ) {
2015-02-14 03:20:39 +08:00
zend_array_destroy ( symbol_table ) ;
2012-05-28 12:43:18 +08:00
} else {
/* clean before putting into the cache, since clean
could call dtors , which could use cached hash */
2015-02-14 03:20:39 +08:00
zend_symtable_clean ( symbol_table ) ;
2012-05-28 12:43:18 +08:00
* ( + + EG ( symtable_cache_ptr ) ) = symbol_table ;
}
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_always_inline void i_free_compiled_variables ( zend_execute_data * execute_data ) /* { { { */
2012-05-28 12:43:18 +08:00
{
2015-04-16 19:46:54 +08:00
zval * cv = EX_VAR_NUM ( 0 ) ;
zval * end = cv + EX ( func ) - > op_array . last_var ;
while ( EXPECTED ( cv ! = end ) ) {
2015-04-17 02:45:40 +08:00
if ( Z_REFCOUNTED_P ( cv ) ) {
if ( ! Z_DELREF_P ( cv ) ) {
zend_refcounted * r = Z_COUNTED_P ( cv ) ;
ZVAL_NULL ( cv ) ;
zval_dtor_func_for_ptr ( r ) ;
} else {
GC_ZVAL_CHECK_POSSIBLE_ROOT ( cv ) ;
}
}
2015-04-16 19:46:54 +08:00
cv + + ;
}
2012-12-05 17:23:37 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
void zend_free_compiled_variables ( zend_execute_data * execute_data ) /* { { { */
2012-12-05 17:23:37 +08:00
{
2014-12-14 06:06:14 +08:00
i_free_compiled_variables ( execute_data ) ;
2012-05-28 12:43:18 +08:00
}
/* }}} */
2015-03-17 00:48:29 +08:00
# ifdef ZEND_WIN32
# define ZEND_VM_INTERRUPT_CHECK() do { \
if ( EG ( timed_out ) ) { \
zend_timeout ( 0 ) ; \
} \
} while ( 0 )
# else
# define ZEND_VM_INTERRUPT_CHECK() do { \
} while ( 0 )
# endif
2013-02-19 12:56:02 +08:00
/*
2012-12-04 14:42:19 +08:00
* Stack Frame Layout ( the whole stack frame is allocated at once )
2013-02-19 12:56:02 +08:00
* = = = = = = = = = = = = = = = = = =
2012-12-04 14:42:19 +08:00
*
* + = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +
2014-06-27 03:51:14 +08:00
* EG ( current_execute_data ) - > | zend_execute_data |
2012-12-04 14:42:19 +08:00
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-06-27 03:51:14 +08:00
* EX_CV_NUM ( 0 ) - - - - - - - - - > | VAR [ 0 ] = ARG [ 1 ] |
2014-02-10 14:04:30 +08:00
* | . . . |
2014-06-27 16:25:36 +08:00
* | VAR [ op_array - > num_args - 1 ] = ARG [ N ] |
* | . . . |
2014-02-10 14:04:30 +08:00
* | VAR [ op_array - > last_var - 1 ] |
2014-06-27 16:25:36 +08:00
* | VAR [ op_array - > last_var ] = TMP [ 0 ] |
2012-12-04 14:42:19 +08:00
* | . . . |
2014-02-18 05:41:23 +08:00
* | VAR [ op_array - > last_var + op_array - > T - 1 ] |
2014-06-27 16:25:36 +08:00
* | ARG [ N + 1 ] ( extra_args ) |
* | . . . |
2012-12-04 14:42:19 +08:00
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2015-02-25 15:37:21 +08:00
static zend_always_inline void i_init_func_execute_data ( zend_execute_data * execute_data , zend_op_array * op_array , zval * return_value , int check_this ) /* { { { */
2014-07-04 22:03:45 +08:00
{
2014-09-17 20:17:58 +08:00
uint32_t first_extra_arg , num_args ;
2014-07-04 22:03:45 +08:00
ZEND_ASSERT ( EX ( func ) = = ( zend_function * ) op_array ) ;
2014-07-08 01:33:09 +08:00
EX ( opline ) = op_array - > opcodes ;
2014-09-17 20:17:58 +08:00
EX ( call ) = NULL ;
EX ( return_value ) = return_value ;
2014-07-04 22:03:45 +08:00
2014-09-17 20:17:58 +08:00
/* Handle arguments */
2014-07-04 22:03:45 +08:00
first_extra_arg = op_array - > num_args ;
2014-11-28 15:28:49 +08:00
num_args = EX_NUM_ARGS ( ) ;
2014-09-17 20:17:58 +08:00
if ( UNEXPECTED ( num_args > first_extra_arg ) ) {
2016-01-28 16:41:15 +08:00
if ( EXPECTED ( ! ( op_array - > fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE ) ) ) {
zval * end , * src , * dst ;
uint32_t type_flags = 0 ;
2014-07-04 22:03:45 +08:00
2016-01-28 16:41:15 +08:00
if ( EXPECTED ( ( op_array - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) = = 0 ) ) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX ( opline ) + = first_extra_arg ;
}
2014-07-04 22:03:45 +08:00
2016-01-28 16:41:15 +08:00
/* move extra args into separate array after all CV and TMP vars */
end = EX_VAR_NUM ( first_extra_arg - 1 ) ;
src = end + ( num_args - first_extra_arg ) ;
dst = src + ( op_array - > last_var + op_array - > T - first_extra_arg ) ;
if ( EXPECTED ( src ! = dst ) ) {
do {
type_flags | = Z_TYPE_INFO_P ( src ) ;
ZVAL_COPY_VALUE ( dst , src ) ;
ZVAL_UNDEF ( src ) ;
src - - ;
dst - - ;
} while ( src ! = end ) ;
} else {
do {
type_flags | = Z_TYPE_INFO_P ( src ) ;
src - - ;
} while ( src ! = end ) ;
}
ZEND_ADD_CALL_FLAG ( execute_data , ( ( type_flags > > Z_TYPE_FLAGS_SHIFT ) & IS_TYPE_REFCOUNTED ) ) ;
2014-07-04 22:03:45 +08:00
}
2014-09-17 20:17:58 +08:00
} else if ( EXPECTED ( ( op_array - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) = = 0 ) ) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX ( opline ) + = num_args ;
}
/* Initialize CV variables (skip arguments) */
2014-10-13 17:49:10 +08:00
if ( EXPECTED ( ( int ) num_args < op_array - > last_var ) ) {
2014-09-17 20:17:58 +08:00
zval * var = EX_VAR_NUM ( num_args ) ;
zval * end = EX_VAR_NUM ( op_array - > last_var ) ;
do {
ZVAL_UNDEF ( var ) ;
var + + ;
} while ( var ! = end ) ;
}
2014-07-04 22:03:45 +08:00
2016-04-01 21:17:49 +08:00
if ( check_this & & op_array - > this_var ! = ( uint32_t ) - 1 & & EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
2014-10-03 23:32:46 +08:00
ZVAL_OBJ ( EX_VAR ( op_array - > this_var ) , Z_OBJ ( EX ( This ) ) ) ;
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) + + ;
2014-07-04 22:03:45 +08:00
}
2014-12-12 15:19:41 +08:00
EX_LOAD_RUN_TIME_CACHE ( op_array ) ;
EX_LOAD_LITERALS ( op_array ) ;
2014-07-04 22:03:45 +08:00
EG ( current_execute_data ) = execute_data ;
2015-03-17 00:48:29 +08:00
ZEND_VM_INTERRUPT_CHECK ( ) ;
2014-07-04 22:03:45 +08:00
}
2014-07-08 17:53:13 +08:00
/* }}} */
2014-07-04 22:03:45 +08:00
2016-04-05 05:01:00 +08:00
static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache ( zend_op_array * op_array ) /* { { { */
{
ZEND_ASSERT ( op_array - > run_time_cache = = NULL ) ;
op_array - > run_time_cache = zend_arena_alloc ( & CG ( arena ) , op_array - > cache_size ) ;
memset ( op_array - > run_time_cache , 0 , op_array - > cache_size ) ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_always_inline void i_init_code_execute_data ( zend_execute_data * execute_data , zend_op_array * op_array , zval * return_value ) /* { { { */
2014-07-04 22:03:45 +08:00
{
ZEND_ASSERT ( EX ( func ) = = ( zend_function * ) op_array ) ;
2014-08-26 05:45:02 +08:00
EX ( opline ) = op_array - > opcodes ;
2014-09-17 20:17:58 +08:00
EX ( call ) = NULL ;
EX ( return_value ) = return_value ;
2014-07-04 22:03:45 +08:00
2016-04-01 21:17:49 +08:00
if ( UNEXPECTED ( op_array - > this_var ! = ( uint32_t ) - 1 ) & & EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
2014-10-06 05:38:59 +08:00
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) + + ;
2015-09-24 04:16:30 +08:00
if ( ! zend_hash_str_add ( EX ( symbol_table ) , " this " , sizeof ( " this " ) - 1 , & EX ( This ) ) ) {
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) - - ;
}
2014-10-06 05:38:59 +08:00
}
2015-09-24 04:16:30 +08:00
zend_attach_symbol_table ( execute_data ) ;
2015-09-20 05:22:07 +08:00
if ( ! op_array - > run_time_cache ) {
2015-02-25 06:52:35 +08:00
op_array - > run_time_cache = emalloc ( op_array - > cache_size ) ;
memset ( op_array - > run_time_cache , 0 , op_array - > cache_size ) ;
2014-07-04 22:03:45 +08:00
}
2014-12-12 15:19:41 +08:00
EX_LOAD_RUN_TIME_CACHE ( op_array ) ;
EX_LOAD_LITERALS ( op_array ) ;
2014-07-04 22:03:45 +08:00
EG ( current_execute_data ) = execute_data ;
2015-03-17 00:48:29 +08:00
ZEND_VM_INTERRUPT_CHECK ( ) ;
2014-07-04 22:03:45 +08:00
}
2014-07-08 17:53:13 +08:00
/* }}} */
2014-07-04 22:03:45 +08:00
2014-12-14 06:06:14 +08:00
static zend_always_inline void i_init_execute_data ( zend_execute_data * execute_data , zend_op_array * op_array , zval * return_value ) /* { { { */
2012-12-04 14:42:19 +08:00
{
2014-06-27 03:51:14 +08:00
ZEND_ASSERT ( EX ( func ) = = ( zend_function * ) op_array ) ;
2012-12-04 14:42:19 +08:00
2014-08-26 05:45:02 +08:00
EX ( opline ) = op_array - > opcodes ;
2014-09-17 20:17:58 +08:00
EX ( call ) = NULL ;
EX ( return_value ) = return_value ;
2012-12-04 14:42:19 +08:00
2014-06-27 03:51:14 +08:00
if ( UNEXPECTED ( EX ( symbol_table ) ! = NULL ) ) {
2016-04-01 21:17:49 +08:00
if ( UNEXPECTED ( op_array - > this_var ! = ( uint32_t ) - 1 ) & & EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
2015-09-24 04:16:30 +08:00
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) + + ;
if ( ! zend_hash_str_add ( EX ( symbol_table ) , " this " , sizeof ( " this " ) - 1 , & EX ( This ) ) ) {
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) - - ;
}
}
2014-04-18 17:46:36 +08:00
zend_attach_symbol_table ( execute_data ) ;
2014-04-24 19:53:20 +08:00
} else {
2014-09-17 20:17:58 +08:00
uint32_t first_extra_arg , num_args ;
2015-01-03 17:22:58 +08:00
2014-09-17 20:17:58 +08:00
/* Handle arguments */
first_extra_arg = op_array - > num_args ;
2014-11-28 15:28:49 +08:00
num_args = EX_NUM_ARGS ( ) ;
2014-09-17 20:17:58 +08:00
if ( UNEXPECTED ( num_args > first_extra_arg ) ) {
2016-01-28 16:41:15 +08:00
if ( EXPECTED ( ! ( op_array - > fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE ) ) ) {
zval * end , * src , * dst ;
uint32_t type_flags = 0 ;
2014-06-27 03:51:14 +08:00
2016-01-28 16:41:15 +08:00
if ( EXPECTED ( ( op_array - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) = = 0 ) ) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX ( opline ) + = first_extra_arg ;
}
2014-04-24 19:53:20 +08:00
2016-01-28 16:41:15 +08:00
/* move extra args into separate array after all CV and TMP vars */
end = EX_VAR_NUM ( first_extra_arg - 1 ) ;
src = end + ( num_args - first_extra_arg ) ;
dst = src + ( op_array - > last_var + op_array - > T - first_extra_arg ) ;
if ( EXPECTED ( src ! = dst ) ) {
do {
type_flags | = Z_TYPE_INFO_P ( src ) ;
ZVAL_COPY_VALUE ( dst , src ) ;
ZVAL_UNDEF ( src ) ;
src - - ;
dst - - ;
} while ( src ! = end ) ;
} else {
do {
type_flags | = Z_TYPE_INFO_P ( src ) ;
src - - ;
} while ( src ! = end ) ;
}
ZEND_ADD_CALL_FLAG ( execute_data , ( ( type_flags > > Z_TYPE_FLAGS_SHIFT ) & IS_TYPE_REFCOUNTED ) ) ;
2014-04-24 19:53:20 +08:00
}
2014-09-17 20:17:58 +08:00
} else if ( EXPECTED ( ( op_array - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) = = 0 ) ) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
EX ( opline ) + = num_args ;
}
/* Initialize CV variables (skip arguments) */
2014-10-13 17:49:10 +08:00
if ( EXPECTED ( ( int ) num_args < op_array - > last_var ) ) {
2014-09-17 20:17:58 +08:00
zval * var = EX_VAR_NUM ( num_args ) ;
zval * end = EX_VAR_NUM ( op_array - > last_var ) ;
do {
ZVAL_UNDEF ( var ) ;
var + + ;
} while ( var ! = end ) ;
}
2014-03-26 22:07:31 +08:00
2016-04-01 21:17:49 +08:00
if ( op_array - > this_var ! = ( uint32_t ) - 1 & & EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
2015-09-24 04:16:30 +08:00
ZVAL_OBJ ( EX_VAR ( op_array - > this_var ) , Z_OBJ ( EX ( This ) ) ) ;
GC_REFCOUNT ( Z_OBJ ( EX ( This ) ) ) + + ;
}
2012-12-04 14:42:19 +08:00
}
2014-12-13 02:57:12 +08:00
if ( ! op_array - > run_time_cache ) {
2014-06-18 06:47:01 +08:00
if ( op_array - > function_name ) {
2015-02-25 06:52:35 +08:00
op_array - > run_time_cache = zend_arena_alloc ( & CG ( arena ) , op_array - > cache_size ) ;
2014-06-18 06:47:01 +08:00
} else {
2015-02-25 06:52:35 +08:00
op_array - > run_time_cache = emalloc ( op_array - > cache_size ) ;
2014-06-18 06:47:01 +08:00
}
2015-02-25 06:52:35 +08:00
memset ( op_array - > run_time_cache , 0 , op_array - > cache_size ) ;
2014-04-24 19:53:20 +08:00
}
2014-12-12 15:19:41 +08:00
EX_LOAD_RUN_TIME_CACHE ( op_array ) ;
EX_LOAD_LITERALS ( op_array ) ;
2012-12-04 14:42:19 +08:00
2014-04-24 19:53:20 +08:00
EG ( current_execute_data ) = execute_data ;
2015-03-17 00:48:29 +08:00
ZEND_VM_INTERRUPT_CHECK ( ) ;
2014-06-27 03:51:14 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API zend_execute_data * zend_create_generator_execute_data ( zend_execute_data * call , zend_op_array * op_array , zval * return_value ) /* { { { */
2014-06-27 03:51:14 +08:00
{
/*
* Normally the execute_data is allocated on the VM stack ( because it does
* not actually do any allocation and thus is faster ) . For generators
* though this behavior would be suboptimal , because the ( rather large )
* structure would have to be copied back and forth every time execution is
* suspended or resumed . That ' s why for generators the execution context
* is allocated using a separate VM stack , thus allowing to save and
* restore it simply by replacing a pointer .
*/
zend_execute_data * execute_data ;
2014-11-28 15:28:49 +08:00
uint32_t num_args = ZEND_CALL_NUM_ARGS ( call ) ;
2014-09-29 23:41:00 +08:00
size_t stack_size = ( ZEND_CALL_FRAME_SLOT + MAX ( op_array - > last_var + op_array - > T , num_args ) ) * sizeof ( zval ) ;
2015-05-07 21:28:23 +08:00
uint32_t call_info ;
2014-06-27 03:51:14 +08:00
2014-10-10 00:29:02 +08:00
EG ( vm_stack ) = zend_vm_stack_new_page (
2015-03-07 20:07:18 +08:00
EXPECTED ( stack_size < ZEND_VM_STACK_FREE_PAGE_SIZE ( 1 ) ) ?
ZEND_VM_STACK_PAGE_SIZE ( 1 ) :
ZEND_VM_STACK_PAGE_ALIGNED_SIZE ( 1 , stack_size ) ,
2014-09-29 23:41:00 +08:00
NULL ) ;
2014-10-10 00:29:02 +08:00
EG ( vm_stack_top ) = EG ( vm_stack ) - > top ;
EG ( vm_stack_end ) = EG ( vm_stack ) - > end ;
2014-06-27 03:51:14 +08:00
2015-05-12 20:56:42 +08:00
call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | ( ZEND_CALL_INFO ( call ) & ( ZEND_CALL_CLOSURE | ZEND_CALL_RELEASE_THIS ) ) ;
2014-06-27 03:51:14 +08:00
execute_data = zend_vm_stack_push_call_frame (
2015-05-07 21:28:23 +08:00
call_info ,
2014-06-27 03:51:14 +08:00
( zend_function * ) op_array ,
num_args ,
2016-04-01 21:17:49 +08:00
Z_TYPE ( call - > This ) ! = IS_OBJECT ? Z_CE ( call - > This ) : NULL ,
Z_TYPE ( call - > This ) = = IS_OBJECT ? Z_OBJ ( call - > This ) : NULL ) ;
2015-04-15 22:02:21 +08:00
EX ( prev_execute_data ) = NULL ;
2014-11-28 15:28:49 +08:00
EX_NUM_ARGS ( ) = num_args ;
2014-06-27 03:51:14 +08:00
/* copy arguments */
if ( num_args > 0 ) {
2014-07-07 19:50:44 +08:00
zval * arg_src = ZEND_CALL_ARG ( call , 1 ) ;
2014-06-27 03:51:14 +08:00
zval * arg_dst = ZEND_CALL_ARG ( execute_data , 1 ) ;
2015-04-29 00:11:45 +08:00
zval * end = arg_src + num_args ;
2014-06-27 03:51:14 +08:00
2015-04-29 00:11:45 +08:00
do {
ZVAL_COPY_VALUE ( arg_dst , arg_src ) ;
arg_src + + ;
arg_dst + + ;
} while ( arg_src ! = end ) ;
2014-06-27 03:51:14 +08:00
}
2014-07-08 16:17:52 +08:00
EX ( symbol_table ) = NULL ;
2016-04-05 05:01:00 +08:00
if ( UNEXPECTED ( ! op_array - > run_time_cache ) ) {
init_func_run_time_cache ( op_array ) ;
}
2015-02-25 15:37:21 +08:00
i_init_func_execute_data ( execute_data , op_array , return_value , 1 ) ;
2012-12-04 14:42:19 +08:00
return execute_data ;
}
/* }}} */
2014-12-14 06:06:14 +08:00
ZEND_API void zend_init_execute_data ( zend_execute_data * execute_data , zend_op_array * op_array , zval * return_value ) /* { { { */
2012-12-05 17:23:37 +08:00
{
2014-06-27 03:51:14 +08:00
EX ( prev_execute_data ) = EG ( current_execute_data ) ;
2014-12-14 06:06:14 +08:00
i_init_execute_data ( execute_data , op_array , return_value ) ;
2012-12-05 17:23:37 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch ( const zend_op * opline , zend_execute_data * call ) /* { { { */
2013-08-29 17:35:11 +08:00
{
2014-08-26 01:28:33 +08:00
uint32_t arg_num = opline - > extended_value & ZEND_FETCH_ARG_MASK ;
2016-02-27 02:44:28 +08:00
if ( EXPECTED ( arg_num < = MAX_ARG_FLAG_NUM ) ) {
return QUICK_ARG_SHOULD_BE_SENT_BY_REF ( call - > func , arg_num ) ;
}
2014-06-24 06:17:16 +08:00
return ARG_SHOULD_BE_SENT_BY_REF ( call - > func , arg_num ) ;
2013-08-29 17:35:11 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_execute_data * zend_vm_stack_copy_call_frame ( zend_execute_data * call , uint32_t passed_args , uint32_t additional_args ) /* { { { */
2014-01-18 19:30:44 +08:00
{
2014-06-27 03:51:14 +08:00
zend_execute_data * new_call ;
2014-10-10 00:29:02 +08:00
int used_stack = ( EG ( vm_stack_top ) - ( zval * ) call ) + additional_args ;
2015-01-03 17:22:58 +08:00
2014-06-27 03:51:14 +08:00
/* copy call frame into new stack segment */
2014-12-14 06:06:14 +08:00
new_call = zend_vm_stack_extend ( used_stack * sizeof ( zval ) ) ;
2014-06-27 03:51:14 +08:00
* new_call = * call ;
2016-04-01 21:17:49 +08:00
ZEND_ADD_CALL_FLAG ( new_call , ZEND_CALL_ALLOCATED ) ;
2015-06-21 00:28:51 +08:00
2014-06-27 03:51:14 +08:00
if ( passed_args ) {
zval * src = ZEND_CALL_ARG ( call , 1 ) ;
zval * dst = ZEND_CALL_ARG ( new_call , 1 ) ;
do {
ZVAL_COPY_VALUE ( dst , src ) ;
passed_args - - ;
src + + ;
dst + + ;
} while ( passed_args ) ;
}
2014-01-18 19:30:44 +08:00
2014-06-27 03:51:14 +08:00
/* delete old call_frame from previous stack segment */
2014-10-10 00:29:02 +08:00
EG ( vm_stack ) - > prev - > top = ( zval * ) call ;
2014-01-18 19:30:44 +08:00
2014-06-27 03:51:14 +08:00
/* delete previous stack segment if it becames empty */
2015-12-11 02:17:24 +08:00
if ( UNEXPECTED ( EG ( vm_stack ) - > prev - > top = = ZEND_VM_STACK_ELEMENTS ( EG ( vm_stack ) - > prev ) ) ) {
2014-10-10 00:29:02 +08:00
zend_vm_stack r = EG ( vm_stack ) - > prev ;
2014-06-27 03:51:14 +08:00
2014-10-10 00:29:02 +08:00
EG ( vm_stack ) - > prev = r - > prev ;
2014-06-27 03:51:14 +08:00
efree ( r ) ;
2014-01-18 19:30:44 +08:00
}
2014-06-27 03:51:14 +08:00
2014-06-24 06:17:16 +08:00
return new_call ;
2014-01-18 19:30:44 +08:00
}
/* }}} */
2014-12-14 06:06:14 +08:00
static zend_always_inline void zend_vm_stack_extend_call_frame ( zend_execute_data * * call , uint32_t passed_args , uint32_t additional_args ) /* { { { */
2014-01-18 19:30:44 +08:00
{
2015-02-26 04:20:47 +08:00
if ( EXPECTED ( ( uint32_t ) ( EG ( vm_stack_end ) - EG ( vm_stack_top ) ) > additional_args ) ) {
2014-10-10 00:29:02 +08:00
EG ( vm_stack_top ) + = additional_args ;
2014-06-27 03:51:14 +08:00
} else {
2014-12-14 06:06:14 +08:00
* call = zend_vm_stack_copy_call_frame ( * call , passed_args , additional_args ) ;
2014-01-18 19:30:44 +08:00
}
}
/* }}} */
2015-02-20 19:59:56 +08:00
static zend_always_inline zend_generator * zend_get_running_generator ( zend_execute_data * execute_data ) /* { { { */
{
/* The generator object is stored in EX(return_value) */
zend_generator * generator = ( zend_generator * ) EX ( return_value ) ;
/* However control may currently be delegated to another generator.
* That ' s the one we ' re interested in . */
2015-03-07 07:28:12 +08:00
return generator ;
2015-02-20 19:59:56 +08:00
}
/* }}} */
2015-11-10 15:10:39 +08:00
static void cleanup_unfinished_calls ( zend_execute_data * execute_data , uint32_t op_num ) /* { { { */
2015-06-21 00:35:27 +08:00
{
if ( UNEXPECTED ( EX ( call ) ) ) {
zend_execute_data * call = EX ( call ) ;
zend_op * opline = EX ( func ) - > op_array . opcodes + op_num ;
int level ;
int do_exit ;
2015-07-24 15:49:01 +08:00
if ( UNEXPECTED ( opline - > opcode = = ZEND_INIT_FCALL | |
opline - > opcode = = ZEND_INIT_FCALL_BY_NAME | |
opline - > opcode = = ZEND_INIT_DYNAMIC_CALL | |
opline - > opcode = = ZEND_INIT_METHOD_CALL | |
opline - > opcode = = ZEND_INIT_STATIC_METHOD_CALL ) ) {
ZEND_ASSERT ( op_num ) ;
opline - - ;
}
2015-06-21 00:35:27 +08:00
do {
/* If the exception was thrown during a function call there might be
* arguments pushed to the stack that have to be dtor ' ed . */
/* find the number of actually passed arguments */
level = 0 ;
do_exit = 0 ;
do {
switch ( opline - > opcode ) {
case ZEND_DO_FCALL :
case ZEND_DO_ICALL :
case ZEND_DO_UCALL :
case ZEND_DO_FCALL_BY_NAME :
level + + ;
break ;
case ZEND_INIT_FCALL :
case ZEND_INIT_FCALL_BY_NAME :
case ZEND_INIT_NS_FCALL_BY_NAME :
case ZEND_INIT_DYNAMIC_CALL :
case ZEND_INIT_USER_CALL :
case ZEND_INIT_METHOD_CALL :
case ZEND_INIT_STATIC_METHOD_CALL :
case ZEND_NEW :
if ( level = = 0 ) {
ZEND_CALL_NUM_ARGS ( call ) = 0 ;
do_exit = 1 ;
}
level - - ;
break ;
case ZEND_SEND_VAL :
case ZEND_SEND_VAL_EX :
case ZEND_SEND_VAR :
case ZEND_SEND_VAR_EX :
case ZEND_SEND_REF :
case ZEND_SEND_VAR_NO_REF :
case ZEND_SEND_USER :
if ( level = = 0 ) {
ZEND_CALL_NUM_ARGS ( call ) = opline - > op2 . num ;
do_exit = 1 ;
}
break ;
case ZEND_SEND_ARRAY :
case ZEND_SEND_UNPACK :
if ( level = = 0 ) {
do_exit = 1 ;
}
break ;
}
if ( ! do_exit ) {
opline - - ;
}
} while ( ! do_exit ) ;
if ( call - > prev_execute_data ) {
/* skip current call region */
level = 0 ;
do_exit = 0 ;
do {
switch ( opline - > opcode ) {
case ZEND_DO_FCALL :
case ZEND_DO_ICALL :
case ZEND_DO_UCALL :
case ZEND_DO_FCALL_BY_NAME :
level + + ;
break ;
case ZEND_INIT_FCALL :
case ZEND_INIT_FCALL_BY_NAME :
case ZEND_INIT_NS_FCALL_BY_NAME :
case ZEND_INIT_DYNAMIC_CALL :
case ZEND_INIT_USER_CALL :
case ZEND_INIT_METHOD_CALL :
case ZEND_INIT_STATIC_METHOD_CALL :
case ZEND_NEW :
if ( level = = 0 ) {
do_exit = 1 ;
}
level - - ;
break ;
}
opline - - ;
} while ( ! do_exit ) ;
}
zend_vm_stack_free_args ( EX ( call ) ) ;
if ( ZEND_CALL_INFO ( call ) & ZEND_CALL_RELEASE_THIS ) {
if ( ZEND_CALL_INFO ( call ) & ZEND_CALL_CTOR ) {
2016-02-12 03:42:49 +08:00
GC_REFCOUNT ( Z_OBJ ( call - > This ) ) - - ;
2015-06-21 00:35:27 +08:00
if ( GC_REFCOUNT ( Z_OBJ ( call - > This ) ) = = 1 ) {
zend_object_store_ctor_failed ( Z_OBJ ( call - > This ) ) ;
}
}
OBJ_RELEASE ( Z_OBJ ( call - > This ) ) ;
}
2015-06-26 11:10:58 +08:00
if ( call - > func - > common . fn_flags & ZEND_ACC_CLOSURE ) {
2015-06-27 02:39:56 +08:00
zend_object_release ( ( zend_object * ) call - > func - > common . prototype ) ;
2015-07-07 18:19:57 +08:00
} else if ( call - > func - > common . fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE ) {
2015-06-21 00:35:27 +08:00
zend_string_release ( call - > func - > common . function_name ) ;
zend_free_trampoline ( call - > func ) ;
}
EX ( call ) = call - > prev_execute_data ;
zend_vm_stack_free_call_frame ( call ) ;
call = EX ( call ) ;
} while ( call ) ;
}
2015-11-10 15:10:39 +08:00
}
/* }}} */
static void cleanup_live_vars ( zend_execute_data * execute_data , uint32_t op_num , uint32_t catch_op_num ) /* { { { */
{
int i ;
2015-07-10 08:31:52 +08:00
2015-11-11 16:12:44 +08:00
for ( i = 0 ; i < EX ( func ) - > op_array . last_live_range ; i + + ) {
const zend_live_range * range = & EX ( func ) - > op_array . live_range [ i ] ;
if ( range - > start > op_num ) {
2015-07-10 08:31:52 +08:00
/* further blocks will not be relevant... */
break ;
2015-11-11 16:12:44 +08:00
} else if ( op_num < range - > end ) {
2015-11-11 02:48:03 +08:00
if ( ! catch_op_num | | catch_op_num > = range - > end ) {
2015-11-13 20:35:07 +08:00
uint32_t kind = range - > var & ZEND_LIVE_MASK ;
uint32_t var_num = range - > var & ~ ZEND_LIVE_MASK ;
2015-11-11 02:48:03 +08:00
zval * var = EX_VAR ( var_num ) ;
2015-11-13 20:35:07 +08:00
if ( kind = = ZEND_LIVE_TMPVAR ) {
2015-11-11 02:48:03 +08:00
zval_ptr_dtor_nogc ( var ) ;
2015-11-13 20:35:07 +08:00
} else if ( kind = = ZEND_LIVE_LOOP ) {
2015-07-10 08:31:52 +08:00
if ( Z_TYPE_P ( var ) ! = IS_ARRAY & & Z_FE_ITER_P ( var ) ! = ( uint32_t ) - 1 ) {
zend_hash_iterator_del ( Z_FE_ITER_P ( var ) ) ;
}
zval_ptr_dtor_nogc ( var ) ;
2015-11-13 20:35:07 +08:00
} else if ( kind = = ZEND_LIVE_ROPE ) {
2015-11-11 02:48:03 +08:00
zend_string * * rope = ( zend_string * * ) var ;
2015-07-10 08:31:52 +08:00
zend_op * last = EX ( func ) - > op_array . opcodes + op_num ;
while ( ( last - > opcode ! = ZEND_ROPE_ADD & & last - > opcode ! = ZEND_ROPE_INIT )
2015-11-11 02:48:03 +08:00
| | last - > result . var ! = var_num ) {
2015-07-10 08:31:52 +08:00
ZEND_ASSERT ( last > = EX ( func ) - > op_array . opcodes ) ;
last - - ;
}
if ( last - > opcode = = ZEND_ROPE_INIT ) {
zend_string_release ( * rope ) ;
} else {
int j = last - > extended_value ;
do {
zend_string_release ( rope [ j ] ) ;
} while ( j - - ) ;
}
2015-11-13 20:35:07 +08:00
} else if ( kind = = ZEND_LIVE_SILENCE ) {
2015-07-10 08:31:52 +08:00
/* restore previous error_reporting value */
2015-11-11 02:48:03 +08:00
if ( ! EG ( error_reporting ) & & Z_LVAL_P ( var ) ! = 0 ) {
EG ( error_reporting ) = Z_LVAL_P ( var ) ;
2015-07-10 08:31:52 +08:00
}
}
}
}
}
2015-06-21 00:35:27 +08:00
}
/* }}} */
void zend_cleanup_unfinished_execution ( zend_execute_data * execute_data , uint32_t op_num , uint32_t catch_op_num ) {
2015-11-10 15:10:39 +08:00
cleanup_unfinished_calls ( execute_data , op_num ) ;
cleanup_live_vars ( execute_data , op_num , catch_op_num ) ;
2015-06-21 00:35:27 +08:00
}
2016-03-18 03:00:27 +08:00
static void zend_swap_operands ( zend_op * op ) /* { { { */
{
znode_op tmp ;
zend_uchar tmp_type ;
tmp = op - > op1 ;
tmp_type = op - > op1_type ;
op - > op1 = op - > op2 ;
op - > op1_type = op - > op2_type ;
op - > op2 = tmp ;
op - > op2_type = tmp_type ;
}
/* }}} */
2016-04-12 19:41:06 +08:00
static zend_never_inline zend_execute_data * zend_init_dynamic_call_string ( zend_string * function , uint32_t num_args ) /* { { { */
{
zend_function * fbc ;
zval * func ;
zend_class_entry * called_scope ;
zend_string * lcname ;
const char * colon ;
if ( ( colon = zend_memrchr ( ZSTR_VAL ( function ) , ' : ' , ZSTR_LEN ( function ) ) ) ! = NULL & &
colon > ZSTR_VAL ( function ) & &
* ( colon - 1 ) = = ' : '
) {
zend_string * mname ;
size_t cname_length = colon - ZSTR_VAL ( function ) - 1 ;
size_t mname_length = ZSTR_LEN ( function ) - cname_length - ( sizeof ( " :: " ) - 1 ) ;
lcname = zend_string_init ( ZSTR_VAL ( function ) , cname_length , 0 ) ;
called_scope = zend_fetch_class_by_name ( lcname , NULL , ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION ) ;
if ( UNEXPECTED ( called_scope = = NULL ) ) {
zend_string_release ( lcname ) ;
return NULL ;
}
mname = zend_string_init ( ZSTR_VAL ( function ) + ( cname_length + sizeof ( " :: " ) - 1 ) , mname_length , 0 ) ;
if ( called_scope - > get_static_method ) {
fbc = called_scope - > get_static_method ( called_scope , mname ) ;
} else {
fbc = zend_std_get_static_method ( called_scope , mname , NULL ) ;
}
if ( UNEXPECTED ( fbc = = NULL ) ) {
if ( EXPECTED ( ! EG ( exception ) ) ) {
zend_throw_error ( NULL , " Call to undefined method %s::%s() " , ZSTR_VAL ( called_scope - > name ) , ZSTR_VAL ( mname ) ) ;
}
zend_string_release ( lcname ) ;
zend_string_release ( mname ) ;
return NULL ;
}
zend_string_release ( lcname ) ;
zend_string_release ( mname ) ;
if ( UNEXPECTED ( ! ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ) ) {
if ( fbc - > common . fn_flags & ZEND_ACC_ALLOW_STATIC ) {
zend_error ( E_DEPRECATED ,
" Non-static method %s::%s() should not be called statically " ,
ZSTR_VAL ( fbc - > common . scope - > name ) , ZSTR_VAL ( fbc - > common . function_name ) ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
return NULL ;
}
} else {
zend_throw_error (
zend_ce_error ,
" Non-static method %s::%s() cannot be called statically " ,
ZSTR_VAL ( fbc - > common . scope - > name ) , ZSTR_VAL ( fbc - > common . function_name ) ) ;
return NULL ;
}
}
} else {
if ( ZSTR_VAL ( function ) [ 0 ] = = ' \\ ' ) {
lcname = zend_string_alloc ( ZSTR_LEN ( function ) - 1 , 0 ) ;
zend_str_tolower_copy ( ZSTR_VAL ( lcname ) , ZSTR_VAL ( function ) + 1 , ZSTR_LEN ( function ) - 1 ) ;
} else {
lcname = zend_string_tolower ( function ) ;
}
if ( UNEXPECTED ( ( func = zend_hash_find ( EG ( function_table ) , lcname ) ) = = NULL ) ) {
zend_throw_error ( NULL , " Call to undefined function %s() " , ZSTR_VAL ( function ) ) ;
zend_string_release ( lcname ) ;
return NULL ;
}
zend_string_release ( lcname ) ;
fbc = Z_FUNC_P ( func ) ;
called_scope = NULL ;
}
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! fbc - > op_array . run_time_cache ) ) {
init_func_run_time_cache ( & fbc - > op_array ) ;
}
return zend_vm_stack_push_call_frame ( ZEND_CALL_NESTED_FUNCTION ,
fbc , num_args , called_scope , NULL ) ;
}
/* }}} */
static zend_never_inline zend_execute_data * zend_init_dynamic_call_object ( zval * function , uint32_t num_args ) /* { { { */
{
zend_function * fbc ;
zend_class_entry * called_scope ;
zend_object * object ;
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION ;
if ( EXPECTED ( Z_OBJ_HANDLER_P ( function , get_closure ) ) & &
EXPECTED ( Z_OBJ_HANDLER_P ( function , get_closure ) ( function , & called_scope , & fbc , & object ) = = SUCCESS ) ) {
if ( fbc - > common . fn_flags & ZEND_ACC_CLOSURE ) {
/* Delay closure destruction until its invocation */
ZEND_ASSERT ( GC_TYPE ( ( zend_object * ) fbc - > common . prototype ) = = IS_OBJECT ) ;
GC_REFCOUNT ( ( zend_object * ) fbc - > common . prototype ) + + ;
call_info | = ZEND_CALL_CLOSURE ;
} else if ( object ) {
call_info | = ZEND_CALL_RELEASE_THIS ;
GC_REFCOUNT ( object ) + + ; /* For $this pointer */
}
} else {
zend_throw_error ( NULL , " Function name must be a string " ) ;
return NULL ;
}
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! fbc - > op_array . run_time_cache ) ) {
init_func_run_time_cache ( & fbc - > op_array ) ;
}
return zend_vm_stack_push_call_frame ( call_info ,
fbc , num_args , called_scope , object ) ;
}
/* }}} */
static zend_never_inline zend_execute_data * zend_init_dynamic_call_array ( zend_array * function , uint32_t num_args ) /* { { { */
{
zend_function * fbc ;
zend_class_entry * called_scope ;
zend_object * object ;
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION ;
if ( zend_hash_num_elements ( function ) = = 2 ) {
zval * obj ;
zval * method ;
obj = zend_hash_index_find ( function , 0 ) ;
method = zend_hash_index_find ( function , 1 ) ;
if ( UNEXPECTED ( ! obj ) | | UNEXPECTED ( ! method ) ) {
zend_throw_error ( NULL , " Array callback has to contain indices 0 and 1 " ) ;
return NULL ;
}
ZVAL_DEREF ( obj ) ;
if ( UNEXPECTED ( Z_TYPE_P ( obj ) ! = IS_STRING ) & & UNEXPECTED ( Z_TYPE_P ( obj ) ! = IS_OBJECT ) ) {
zend_throw_error ( NULL , " First array member is not a valid class name or object " ) ;
return NULL ;
}
ZVAL_DEREF ( method ) ;
if ( UNEXPECTED ( Z_TYPE_P ( method ) ! = IS_STRING ) ) {
zend_throw_error ( NULL , " Second array member is not a valid method " ) ;
return NULL ;
}
if ( Z_TYPE_P ( obj ) = = IS_STRING ) {
object = NULL ;
called_scope = zend_fetch_class_by_name ( Z_STR_P ( obj ) , NULL , ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION ) ;
if ( UNEXPECTED ( called_scope = = NULL ) ) {
return NULL ;
}
if ( called_scope - > get_static_method ) {
fbc = called_scope - > get_static_method ( called_scope , Z_STR_P ( method ) ) ;
} else {
fbc = zend_std_get_static_method ( called_scope , Z_STR_P ( method ) , NULL ) ;
}
if ( UNEXPECTED ( fbc = = NULL ) ) {
if ( EXPECTED ( ! EG ( exception ) ) ) {
zend_throw_error ( NULL , " Call to undefined method %s::%s() " , ZSTR_VAL ( called_scope - > name ) , Z_STRVAL_P ( method ) ) ;
}
return NULL ;
}
if ( ! ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ) {
if ( fbc - > common . fn_flags & ZEND_ACC_ALLOW_STATIC ) {
zend_error ( E_DEPRECATED ,
" Non-static method %s::%s() should not be called statically " ,
ZSTR_VAL ( fbc - > common . scope - > name ) , ZSTR_VAL ( fbc - > common . function_name ) ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
return NULL ;
}
} else {
zend_throw_error (
zend_ce_error ,
" Non-static method %s::%s() cannot be called statically " ,
ZSTR_VAL ( fbc - > common . scope - > name ) , ZSTR_VAL ( fbc - > common . function_name ) ) ;
return NULL ;
}
}
} else {
called_scope = Z_OBJCE_P ( obj ) ;
object = Z_OBJ_P ( obj ) ;
fbc = Z_OBJ_HT_P ( obj ) - > get_method ( & object , Z_STR_P ( method ) , NULL ) ;
if ( UNEXPECTED ( fbc = = NULL ) ) {
if ( EXPECTED ( ! EG ( exception ) ) ) {
zend_throw_error ( NULL , " Call to undefined method %s::%s() " , ZSTR_VAL ( object - > ce - > name ) , Z_STRVAL_P ( method ) ) ;
}
return NULL ;
}
if ( ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ! = 0 ) {
object = NULL ;
} else {
call_info | = ZEND_CALL_RELEASE_THIS ;
GC_REFCOUNT ( object ) + + ; /* For $this pointer */
}
}
} else {
zend_throw_error ( NULL , " Function name must be a string " ) ;
return NULL ;
}
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! fbc - > op_array . run_time_cache ) ) {
init_func_run_time_cache ( & fbc - > op_array ) ;
}
return zend_vm_stack_push_call_frame ( call_info ,
fbc , num_args , called_scope , object ) ;
}
/* }}} */
2015-03-17 18:51:02 +08:00
# ifdef HAVE_GCC_GLOBAL_REGS
2015-03-18 07:15:49 +08:00
# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
2015-03-13 08:28:21 +08:00
# define ZEND_VM_FP_GLOBAL_REG "%esi"
# define ZEND_VM_IP_GLOBAL_REG "%edi"
2015-03-18 07:15:49 +08:00
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
2015-03-13 08:28:21 +08:00
# define ZEND_VM_FP_GLOBAL_REG "%r14"
# define ZEND_VM_IP_GLOBAL_REG "%r15"
2015-03-18 21:15:00 +08:00
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
2015-08-11 00:12:11 +08:00
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
2015-03-18 21:15:00 +08:00
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
2015-03-13 08:28:21 +08:00
# endif
# endif
2015-07-08 23:33:58 +08:00
# define ZEND_VM_NEXT_OPCODE_EX(check_exception, skip) \
2012-12-05 17:23:37 +08:00
CHECK_SYMBOL_TABLES ( ) \
2015-07-08 23:33:58 +08:00
if ( check_exception ) { \
OPLINE = EX ( opline ) + ( skip ) ; \
} else { \
OPLINE = opline + ( skip ) ; \
} \
2012-12-05 17:23:37 +08:00
ZEND_VM_CONTINUE ( )
2015-07-08 23:33:58 +08:00
# define ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION() \
ZEND_VM_NEXT_OPCODE_EX ( 1 , 1 )
# define ZEND_VM_NEXT_OPCODE() \
ZEND_VM_NEXT_OPCODE_EX ( 0 , 1 )
2015-03-17 00:48:29 +08:00
# define ZEND_VM_SET_NEXT_OPCODE(new_op) \
2012-12-05 17:23:37 +08:00
CHECK_SYMBOL_TABLES ( ) \
OPLINE = new_op
2015-03-17 00:48:29 +08:00
# define ZEND_VM_SET_OPCODE(new_op) \
CHECK_SYMBOL_TABLES ( ) \
OPLINE = new_op ; \
ZEND_VM_INTERRUPT_CHECK ( )
2014-04-30 15:23:19 +08:00
# define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
2014-12-12 15:19:41 +08:00
ZEND_VM_SET_OPCODE ( ZEND_OFFSET_TO_OPLINE ( opline , offset ) )
2014-04-30 15:23:19 +08:00
2012-12-05 17:23:37 +08:00
# define ZEND_VM_JMP(new_op) \
if ( EXPECTED ( ! EG ( exception ) ) ) { \
ZEND_VM_SET_OPCODE ( new_op ) ; \
} else { \
LOAD_OPLINE ( ) ; \
} \
ZEND_VM_CONTINUE ( )
# define ZEND_VM_INC_OPCODE() \
OPLINE + +
2015-04-29 05:40:43 +08:00
2015-04-29 09:17:59 +08:00
# ifndef VM_SMART_OPCODES
# define VM_SMART_OPCODES 1
# endif
# if VM_SMART_OPCODES
# define ZEND_VM_REPEATABLE_OPCODE \
do {
# define ZEND_VM_REPEAT_OPCODE(_opcode) \
2015-04-29 19:20:44 +08:00
} while ( UNEXPECTED ( ( + + opline ) - > opcode = = _opcode ) ) ; \
OPLINE = opline ; \
ZEND_VM_CONTINUE ( )
2015-04-29 09:17:59 +08:00
# define ZEND_VM_SMART_BRANCH(_result, _check) do { \
int __result ; \
if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPZ ) ) { \
2015-06-19 23:03:23 +08:00
__result = ( _result ) ; \
2015-04-29 09:17:59 +08:00
} else if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPNZ ) ) { \
2015-06-19 23:03:23 +08:00
__result = ! ( _result ) ; \
2015-04-29 09:17:59 +08:00
} else { \
break ; \
} \
if ( ( _check ) & & UNEXPECTED ( EG ( exception ) ) ) { \
HANDLE_EXCEPTION ( ) ; \
} \
if ( __result ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
} else { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
} \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
2016-03-11 17:17:03 +08:00
# define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check) do { \
if ( ( _check ) & & UNEXPECTED ( EG ( exception ) ) ) { \
HANDLE_EXCEPTION ( ) ; \
} \
if ( _result ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
} else { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
} \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
# define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check) do { \
if ( ( _check ) & & UNEXPECTED ( EG ( exception ) ) ) { \
HANDLE_EXCEPTION ( ) ; \
} \
if ( ! ( _result ) ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
} else { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
} \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
2015-04-29 09:17:59 +08:00
# else
# define ZEND_VM_REPEATABLE_OPCODE
# define ZEND_VM_REPEAT_OPCODE(_opcode)
# define ZEND_VM_SMART_BRANCH(_result, _check)
2016-03-11 17:17:03 +08:00
# define ZEND_VM_SMART_BRANCH_JMPZ(_result, _check)
# define ZEND_VM_SMART_BRANCH_JMPNZ(_result, _check)
2015-04-29 09:17:59 +08:00
# endif
2015-04-29 05:40:43 +08:00
2012-12-05 17:23:37 +08:00
# ifdef __GNUC__
# define ZEND_VM_GUARD(name) __asm__("#" #name)
# else
# define ZEND_VM_GUARD(name)
# endif
2015-03-17 23:53:19 +08:00
# define GET_OP1_UNDEF_CV(ptr, type) \
_get_zval_cv_lookup_ # # type ( ptr , opline - > op1 . var , execute_data )
# define GET_OP2_UNDEF_CV(ptr, type) \
_get_zval_cv_lookup_ # # type ( ptr , opline - > op2 . var , execute_data )
2012-12-05 17:23:37 +08:00
# include "zend_vm_execute.h"
ZEND_API int zend_set_user_opcode_handler ( zend_uchar opcode , user_opcode_handler_t handler )
{
if ( opcode ! = ZEND_USER_OPCODE ) {
if ( handler = = NULL ) {
/* restore the original handler */
zend_user_opcodes [ opcode ] = opcode ;
} else {
zend_user_opcodes [ opcode ] = ZEND_USER_OPCODE ;
}
zend_user_opcode_handlers [ opcode ] = handler ;
return SUCCESS ;
}
return FAILURE ;
}
ZEND_API user_opcode_handler_t zend_get_user_opcode_handler ( zend_uchar opcode )
{
return zend_user_opcode_handlers [ opcode ] ;
}
2015-08-12 00:11:21 +08:00
ZEND_API zval * zend_get_zval_ptr ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
{
2014-12-09 08:03:38 +08:00
return get_zval_ptr ( op_type , * node , execute_data , should_free , type ) ;
2012-12-05 17:23:37 +08:00
}
2015-08-12 14:52:08 +08:00
ZEND_API void ZEND_FASTCALL zend_check_internal_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg )
2015-08-12 00:11:21 +08:00
{
zend_verify_internal_arg_type ( zf , arg_num , arg ) ;
}
2015-08-12 14:52:08 +08:00
ZEND_API int ZEND_FASTCALL zend_check_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg , zval * default_value , void * * cache_slot )
2015-08-12 00:11:21 +08:00
{
return zend_verify_arg_type ( zf , arg_num , arg , default_value , cache_slot ) ;
}
2015-10-13 17:40:58 +08:00
ZEND_API void ZEND_FASTCALL zend_check_missing_arg ( zend_execute_data * execute_data , uint32_t arg_num , void * * cache_slot )
2015-08-12 00:11:21 +08:00
{
2015-10-13 17:40:58 +08:00
zend_verify_missing_arg ( execute_data , arg_num , cache_slot ) ;
2015-08-12 00:11:21 +08:00
}
2003-02-01 09:49:15 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/