1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-01-30 17:23:29 +08:00
| Copyright ( c ) 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
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2018-11-01 23:20:07 +08:00
| Authors : Andi Gutmans < andi @ php . net > |
| Zeev Suraski < zeev @ php . net > |
| Dmitry Stogov < dmitry @ php . net > |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
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
2017-06-16 06:42:49 +08:00
# ifdef HAVE_GCC_GLOBAL_REGS
# if defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(i386)
# define ZEND_VM_FP_GLOBAL_REG "%esi"
# define ZEND_VM_IP_GLOBAL_REG "%edi"
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__x86_64__)
# define ZEND_VM_FP_GLOBAL_REG "%r14"
# define ZEND_VM_IP_GLOBAL_REG "%r15"
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
# elif defined(__IBMC__) && ZEND_GCC_VERSION >= 4002 && defined(__powerpc64__)
# define ZEND_VM_FP_GLOBAL_REG "r28"
# define ZEND_VM_IP_GLOBAL_REG "r29"
2019-04-22 19:29:30 +08:00
# elif defined(__GNUC__) && ZEND_GCC_VERSION >= 4008 && defined(__aarch64__)
# define ZEND_VM_FP_GLOBAL_REG "x27"
# define ZEND_VM_IP_GLOBAL_REG "x28"
2017-06-16 06:42:49 +08:00
# endif
# endif
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
# pragma GCC diagnostic ignored "-Wvolatile-register-var"
register zend_execute_data * volatile execute_data __asm__ ( ZEND_VM_FP_GLOBAL_REG ) ;
# pragma GCC diagnostic warning "-Wvolatile-register-var"
2019-02-12 22:39:02 +08:00
# endif
2019-04-09 06:17:10 +08:00
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-06-16 06:42:49 +08:00
# define EXECUTE_DATA_D void
# define EXECUTE_DATA_C
# define EXECUTE_DATA_DC
# define EXECUTE_DATA_CC
# define NO_EXECUTE_DATA_CC
# else
# define EXECUTE_DATA_D zend_execute_data* execute_data
# define EXECUTE_DATA_C execute_data
# define EXECUTE_DATA_DC , EXECUTE_DATA_D
# define EXECUTE_DATA_CC , EXECUTE_DATA_C
# define NO_EXECUTE_DATA_CC , NULL
2019-02-12 22:39:02 +08:00
# endif
2019-04-09 06:17:10 +08:00
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2019-02-12 22:39:02 +08:00
# define OPLINE_D void
# define OPLINE_C
# define OPLINE_DC
# define OPLINE_CC
# else
2017-10-04 21:53:01 +08:00
# define OPLINE_D const zend_op* opline
# define OPLINE_C opline
# define OPLINE_DC , OPLINE_D
# define OPLINE_CC , OPLINE_C
2017-06-16 06:42:49 +08:00
# endif
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
# pragma GCC diagnostic ignored "-Wvolatile-register-var"
register const zend_op * volatile opline __asm__ ( ZEND_VM_IP_GLOBAL_REG ) ;
# pragma GCC diagnostic warning "-Wvolatile-register-var"
# else
# endif
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
2017-10-04 21:53:01 +08:00
# define get_zval_ptr(op_type, node, should_free, type) _get_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
# define get_zval_ptr_deref(op_type, node, should_free, type) _get_zval_ptr_deref(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
# define get_zval_ptr_undef(op_type, node, should_free, type) _get_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
# define get_op_data_zval_ptr_r(op_type, node, should_free) _get_op_data_zval_ptr_r(op_type, node, should_free EXECUTE_DATA_CC OPLINE_CC)
2017-11-25 05:57:45 +08:00
# define get_op_data_zval_ptr_deref_r(op_type, node, should_free) _get_op_data_zval_ptr_deref_r(op_type, node, should_free EXECUTE_DATA_CC OPLINE_CC)
2017-06-16 06:42:49 +08:00
# define get_zval_ptr_ptr(op_type, node, should_free, type) _get_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
# define get_zval_ptr_ptr_undef(op_type, node, should_free, type) _get_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
2017-10-04 21:53:01 +08:00
# define get_obj_zval_ptr(op_type, node, should_free, type) _get_obj_zval_ptr(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
# define get_obj_zval_ptr_undef(op_type, node, should_free, type) _get_obj_zval_ptr_undef(op_type, node, should_free, type EXECUTE_DATA_CC OPLINE_CC)
2017-06-16 06:42:49 +08:00
# define get_obj_zval_ptr_ptr(op_type, node, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, should_free, type EXECUTE_DATA_CC)
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 )
{
}
2016-05-01 02:46:52 +08:00
ZEND_API const zend_internal_function zend_pass_function = {
2014-07-11 04:32:18 +08:00
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 */
2016-04-29 19:03:33 +08:00
NULL , /* module */
{ NULL , NULL , NULL , NULL } /* reserved */
2014-07-11 04:32:18 +08:00
} ;
2017-12-26 21:50:34 +08:00
# define FREE_VAR_PTR_AND_EXTRACT_RESULT_IF_NECESSARY(free_op, result) do { \
zval * __container_to_free = ( free_op ) ; \
if ( UNEXPECTED ( __container_to_free ) \
& & EXPECTED ( Z_REFCOUNTED_P ( __container_to_free ) ) ) { \
zend_refcounted * __ref = Z_COUNTED_P ( __container_to_free ) ; \
if ( UNEXPECTED ( ! GC_DELREF ( __ref ) ) ) { \
zval * __zv = ( result ) ; \
if ( EXPECTED ( Z_TYPE_P ( __zv ) = = IS_INDIRECT ) ) { \
ZVAL_COPY ( __zv , Z_INDIRECT_P ( __zv ) ) ; \
} \
2018-07-06 19:14:44 +08:00
rc_dtor_func ( __ref ) ; \
2017-12-26 21:50:34 +08:00
} \
} \
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
2017-04-15 18:08:09 +08:00
# define ZEND_VM_STACK_PAGE_SLOTS (16 * 1024) /* should be a power of 2 */
2014-10-10 00:29:02 +08:00
2017-04-15 18:08:09 +08:00
# define ZEND_VM_STACK_PAGE_SIZE (ZEND_VM_STACK_PAGE_SLOTS * sizeof(zval))
2014-10-10 00:29:02 +08:00
2018-12-26 18:09:32 +08:00
# define ZEND_VM_STACK_PAGE_ALIGNED_SIZE(size, page_size) \
2016-08-06 01:51:51 +08:00
( ( ( size ) + ZEND_VM_STACK_HEADER_SLOTS * sizeof ( zval ) \
2018-12-26 18:09:32 +08:00
+ ( ( page_size ) - 1 ) ) & ~ ( ( page_size ) - 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
{
2017-11-22 20:36:09 +08:00
EG ( vm_stack_page_size ) = ZEND_VM_STACK_PAGE_SIZE ;
2017-04-15 18:08:09 +08:00
EG ( vm_stack ) = zend_vm_stack_new_page ( ZEND_VM_STACK_PAGE_SIZE , 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 ;
}
2018-12-26 18:09:32 +08:00
ZEND_API void zend_vm_stack_init_ex ( size_t page_size )
{
/* page_size must be a power of 2 */
ZEND_ASSERT ( page_size > 0 & & ( page_size & ( page_size - 1 ) ) = = 0 ) ;
EG ( vm_stack_page_size ) = page_size ;
EG ( vm_stack ) = zend_vm_stack_new_page ( page_size , NULL ) ;
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 (
2017-11-22 20:36:09 +08:00
EXPECTED ( size < EG ( vm_stack_page_size ) - ( ZEND_VM_STACK_HEADER_SLOTS * sizeof ( zval ) ) ) ?
2018-12-26 18:09:32 +08:00
EG ( vm_stack_page_size ) : ZEND_VM_STACK_PAGE_ALIGNED_SIZE ( size , EG ( vm_stack_page_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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_tmp ( uint32_t var , zend_free_op * should_free EXECUTE_DATA_DC )
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_var ( uint32_t var , zend_free_op * should_free EXECUTE_DATA_DC )
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 ;
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_var_deref ( uint32_t var , zend_free_op * should_free EXECUTE_DATA_DC )
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
2018-12-18 22:34:18 +08:00
static zend_never_inline ZEND_COLD zval * zval_undefined_cv ( uint32_t var EXECUTE_DATA_DC )
2015-09-09 08:18:52 +08:00
{
2018-02-28 18:06:37 +08:00
if ( EXPECTED ( EG ( exception ) = = NULL ) ) {
zend_string * cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
zend_error ( E_NOTICE , " Undefined variable: %s " , ZSTR_VAL ( cv ) ) ;
}
2018-12-18 22:34:18 +08:00
return & EG ( uninitialized_zval ) ;
}
static zend_never_inline ZEND_COLD zval * ZEND_FASTCALL _zval_undefined_op1 ( EXECUTE_DATA_D )
{
return zval_undefined_cv ( EX ( opline ) - > op1 . var EXECUTE_DATA_CC ) ;
}
static zend_never_inline ZEND_COLD zval * ZEND_FASTCALL _zval_undefined_op2 ( EXECUTE_DATA_D )
{
return zval_undefined_cv ( EX ( opline ) - > op2 . var EXECUTE_DATA_CC ) ;
2015-09-09 08:18:52 +08:00
}
2018-12-18 22:34:18 +08:00
# define ZVAL_UNDEFINED_OP1() _zval_undefined_op1(EXECUTE_DATA_C)
# define ZVAL_UNDEFINED_OP2() _zval_undefined_op2(EXECUTE_DATA_C)
2018-07-03 16:07:39 +08:00
static zend_never_inline ZEND_COLD zval * _get_zval_cv_lookup ( zval * ptr , uint32_t var , int type EXECUTE_DATA_DC )
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 :
2018-12-18 22:34:18 +08:00
ptr = zval_undefined_cv ( var EXECUTE_DATA_CC ) ;
break ;
2014-02-19 05:12:05 +08:00
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 :
2017-06-16 06:42:49 +08:00
zval_undefined_cv ( var EXECUTE_DATA_CC ) ;
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv ( uint32_t var , int type EXECUTE_DATA_DC )
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 ) ) {
2018-07-03 16:07:39 +08:00
if ( type = = BP_VAR_W ) {
ZVAL_NULL ( ret ) ;
} else {
return _get_zval_cv_lookup ( ret , var , type EXECUTE_DATA_CC ) ;
}
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref ( uint32_t var , int type EXECUTE_DATA_DC )
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 ) ) {
2018-07-03 16:07:39 +08:00
if ( type = = BP_VAR_W ) {
ZVAL_NULL ( ret ) ;
return ret ;
} else {
return _get_zval_cv_lookup ( ret , var , type EXECUTE_DATA_CC ) ;
}
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 ;
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_R ( uint32_t var EXECUTE_DATA_DC )
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 ) ) {
2018-12-18 22:34:18 +08:00
return zval_undefined_cv ( var EXECUTE_DATA_CC ) ;
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_R ( uint32_t var EXECUTE_DATA_DC )
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 ) ) {
2018-12-18 22:34:18 +08:00
return zval_undefined_cv ( var EXECUTE_DATA_CC ) ;
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 ;
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_IS ( uint32_t var EXECUTE_DATA_DC )
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_RW ( uint32_t var EXECUTE_DATA_DC )
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 ) ) {
2018-12-18 22:34:18 +08:00
ZVAL_NULL ( ret ) ;
zval_undefined_cv ( var EXECUTE_DATA_CC ) ;
return ret ;
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
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_W ( uint32_t var EXECUTE_DATA_DC )
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 ) {
2018-07-03 16:07:39 +08:00
ZVAL_NULL ( ret ) ;
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
}
2017-10-04 21:53:01 +08:00
static zend_always_inline zval * _get_zval_ptr ( int op_type , znode_op node , zend_free_op * should_free , int type EXECUTE_DATA_DC OPLINE_DC )
2004-09-24 05:43:32 +08:00
{
2014-12-09 20:15:24 +08:00
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
2019-07-04 01:19:56 +08:00
if ( ! ZEND_DEBUG | | op_type = = IS_VAR ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_var ( node . var , should_free EXECUTE_DATA_CC ) ;
2019-07-04 01:19:56 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_TMP_VAR ) ;
return _get_zval_ptr_tmp ( node . var , should_free EXECUTE_DATA_CC ) ;
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 ) {
2017-10-04 21:53:01 +08:00
return RT_CONSTANT ( opline , node ) ;
2015-03-13 01:39:04 +08:00
} else if ( op_type = = IS_CV ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_cv ( node . var , type EXECUTE_DATA_CC ) ;
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
}
2017-10-04 21:53:01 +08:00
static zend_always_inline zval * _get_op_data_zval_ptr_r ( int op_type , znode_op node , zend_free_op * should_free EXECUTE_DATA_DC OPLINE_DC )
2015-09-09 08:18:52 +08:00
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
2019-07-04 01:19:56 +08:00
if ( ! ZEND_DEBUG | | op_type = = IS_VAR ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_var ( node . var , should_free EXECUTE_DATA_CC ) ;
2019-07-04 01:19:56 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_TMP_VAR ) ;
return _get_zval_ptr_tmp ( node . var , should_free EXECUTE_DATA_CC ) ;
2015-09-09 08:18:52 +08:00
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
2017-10-04 21:53:01 +08:00
return RT_CONSTANT ( opline + 1 , node ) ;
2015-09-09 08:18:52 +08:00
} else if ( op_type = = IS_CV ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_cv_BP_VAR_R ( node . var EXECUTE_DATA_CC ) ;
2015-09-09 08:18:52 +08:00
} else {
return NULL ;
}
}
}
2019-07-25 02:51:19 +08:00
static zend_always_inline ZEND_ATTRIBUTE_UNUSED zval * _get_zval_ptr_deref ( int op_type , znode_op node , zend_free_op * should_free , int type EXECUTE_DATA_DC OPLINE_DC )
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 ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_tmp ( node . var , should_free EXECUTE_DATA_CC ) ;
2014-12-09 20:15:24 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_var_deref ( node . var , should_free EXECUTE_DATA_CC ) ;
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 ) {
2017-10-04 21:53:01 +08:00
return RT_CONSTANT ( opline , node ) ;
2015-03-13 01:39:04 +08:00
} else if ( op_type = = IS_CV ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_cv_deref ( node . var , type EXECUTE_DATA_CC ) ;
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
}
}
2019-06-12 19:14:08 +08:00
static zend_always_inline ZEND_ATTRIBUTE_UNUSED zval * _get_op_data_zval_ptr_deref_r ( int op_type , znode_op node , zend_free_op * should_free EXECUTE_DATA_DC OPLINE_DC )
2017-11-25 05:57:45 +08:00
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
if ( op_type = = IS_TMP_VAR ) {
return _get_zval_ptr_tmp ( node . var , should_free EXECUTE_DATA_CC ) ;
} else {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
return _get_zval_ptr_var_deref ( node . var , should_free EXECUTE_DATA_CC ) ;
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
return RT_CONSTANT ( opline + 1 , node ) ;
} else if ( op_type = = IS_CV ) {
return _get_zval_ptr_cv_deref_BP_VAR_R ( node . var EXECUTE_DATA_CC ) ;
} else {
return NULL ;
}
}
}
2017-10-04 21:53:01 +08:00
static zend_always_inline zval * _get_zval_ptr_undef ( int op_type , znode_op node , zend_free_op * should_free , int type EXECUTE_DATA_DC OPLINE_DC )
2015-03-17 23:53:19 +08:00
{
if ( op_type & ( IS_TMP_VAR | IS_VAR ) ) {
2019-07-04 01:19:56 +08:00
if ( ! ZEND_DEBUG | | op_type = = IS_VAR ) {
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_var ( node . var , should_free EXECUTE_DATA_CC ) ;
2019-07-04 01:19:56 +08:00
} else {
ZEND_ASSERT ( op_type = = IS_TMP_VAR ) ;
return _get_zval_ptr_tmp ( node . var , should_free EXECUTE_DATA_CC ) ;
2015-03-17 23:53:19 +08:00
}
} else {
* should_free = NULL ;
if ( op_type = = IS_CONST ) {
2017-10-04 21:53:01 +08:00
return RT_CONSTANT ( opline , node ) ;
2015-03-17 23:53:19 +08:00
} else if ( op_type = = IS_CV ) {
2018-07-03 16:07:39 +08:00
return EX_VAR ( node . var ) ;
2015-03-17 23:53:19 +08:00
} else {
return NULL ;
}
}
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * _get_zval_ptr_ptr_var ( uint32_t var , zend_free_op * should_free EXECUTE_DATA_DC )
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
}
2017-06-16 06:42:49 +08:00
static inline zval * _get_zval_ptr_ptr ( int op_type , znode_op node , zend_free_op * should_free , int type EXECUTE_DATA_DC )
2014-04-17 06:12:06 +08:00
{
if ( op_type = = IS_CV ) {
2014-11-18 14:05:48 +08:00
* should_free = NULL ;
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_cv ( node . var , type EXECUTE_DATA_CC ) ;
2014-04-17 06:12:06 +08:00
} else /* if (op_type == IS_VAR) */ {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
2017-06-16 06:42:49 +08:00
return _get_zval_ptr_ptr_var ( node . var , should_free EXECUTE_DATA_CC ) ;
2014-04-17 06:12:06 +08:00
}
}
2019-06-12 19:14:08 +08:00
static inline ZEND_ATTRIBUTE_UNUSED zval * _get_obj_zval_ptr ( int op_type , znode_op op , zend_free_op * should_free , int type EXECUTE_DATA_DC OPLINE_DC )
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
}
2017-06-16 06:42:49 +08:00
return get_zval_ptr ( op_type , op , should_free , type ) ;
2005-06-14 01:50:07 +08:00
}
2019-06-12 19:14:08 +08:00
static inline ZEND_ATTRIBUTE_UNUSED zval * _get_obj_zval_ptr_undef ( int op_type , znode_op op , zend_free_op * should_free , int type EXECUTE_DATA_DC OPLINE_DC )
2015-06-05 06:53:32 +08:00
{
if ( op_type = = IS_UNUSED ) {
* should_free = NULL ;
return & EX ( This ) ;
}
2017-06-16 06:42:49 +08:00
return get_zval_ptr_undef ( op_type , op , should_free , type ) ;
2015-06-05 06:53:32 +08:00
}
2019-06-12 19:14:08 +08:00
static inline ZEND_ATTRIBUTE_UNUSED zval * _get_obj_zval_ptr_ptr ( int op_type , znode_op node , zend_free_op * should_free , int type EXECUTE_DATA_DC )
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
}
2017-06-16 06:42:49 +08:00
return get_zval_ptr_ptr ( op_type , node , should_free , type ) ;
2014-04-17 06:12:06 +08:00
}
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 ) ;
2017-10-27 06:28:58 +08:00
GC_ADDREF ( ref ) ;
2016-09-29 15:56:01 +08:00
if ( Z_REFCOUNTED_P ( variable_ptr ) ) {
zend_refcounted * garbage = Z_COUNTED_P ( variable_ptr ) ;
2017-10-27 06:28:58 +08:00
if ( GC_DELREF ( garbage ) = = 0 ) {
2016-09-29 15:56:01 +08:00
ZVAL_REF ( variable_ptr , ref ) ;
2018-07-06 19:14:44 +08:00
rc_dtor_func ( garbage ) ;
2016-09-29 15:56:01 +08:00
return ;
} else {
2016-10-21 22:47:30 +08:00
gc_check_possible_root ( garbage ) ;
2016-09-29 15:56:01 +08:00
}
}
2015-05-13 17:55:42 +08:00
ZVAL_REF ( variable_ptr , ref ) ;
2001-06-22 05:17:10 +08:00
}
2019-06-06 20:56:42 +08:00
static zend_never_inline zval * zend_assign_to_typed_property_reference ( zend_property_info * prop_info , zval * prop , zval * value_ptr EXECUTE_DATA_DC )
2019-06-06 18:13:09 +08:00
{
if ( ! zend_verify_prop_assignable_by_ref ( prop_info , value_ptr , EX_USES_STRICT_TYPES ( ) ) ) {
return & EG ( uninitialized_zval ) ;
}
if ( Z_ISREF_P ( prop ) ) {
ZEND_REF_DEL_TYPE_SOURCE ( Z_REF_P ( prop ) , prop_info ) ;
}
zend_assign_to_variable_reference ( prop , value_ptr ) ;
ZEND_REF_ADD_TYPE_SOURCE ( Z_REF_P ( prop ) , prop_info ) ;
return prop ;
}
2019-01-16 16:06:19 +08:00
static zend_never_inline ZEND_COLD int zend_wrong_assign_to_variable_reference ( zval * variable_ptr , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
2018-02-21 15:10:04 +08:00
{
zend_error ( E_NOTICE , " Only variables should be assigned by reference " ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
return 0 ;
}
2019-01-16 16:06:19 +08:00
/* Use IS_TMP_VAR instead of IS_VAR to avoid ISREF check */
2019-01-16 19:26:32 +08:00
Z_TRY_ADDREF_P ( value_ptr ) ;
2019-01-16 16:06:19 +08:00
value_ptr = zend_assign_to_variable ( variable_ptr , value_ptr , IS_TMP_VAR , EX_USES_STRICT_TYPES ( ) ) ;
2018-02-21 15:10:04 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , value_ptr ) ;
}
return 1 ;
}
2019-01-07 19:28:51 +08:00
static void zend_format_type ( zend_type type , const char * * part1 , const char * * part2 ) {
* part1 = ZEND_TYPE_ALLOW_NULL ( type ) ? " ? " : " " ;
if ( ZEND_TYPE_IS_CLASS ( type ) ) {
if ( ZEND_TYPE_IS_CE ( type ) ) {
* part2 = ZSTR_VAL ( ZEND_TYPE_CE ( type ) - > name ) ;
} else {
* part2 = ZSTR_VAL ( ZEND_TYPE_NAME ( type ) ) ;
}
} else {
* part2 = zend_get_type_by_const ( ZEND_TYPE_CODE ( type ) ) ;
}
}
static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_prop_error ( zend_property_info * prop , const char * type ) {
const char * prop_type1 , * prop_type2 ;
zend_format_type ( prop - > type , & prop_type1 , & prop_type2 ) ;
zend_type_error (
" Cannot auto-initialize an %s inside property %s::$%s of type %s%s " ,
type ,
ZSTR_VAL ( prop - > ce - > name ) , zend_get_unmangled_property_name ( prop - > name ) ,
prop_type1 , prop_type2
) ;
}
static zend_never_inline ZEND_COLD void zend_throw_auto_init_in_ref_error ( zend_property_info * prop , const char * type ) {
const char * prop_type1 , * prop_type2 ;
zend_format_type ( prop - > type , & prop_type1 , & prop_type2 ) ;
zend_type_error (
" Cannot auto-initialize an %s inside a reference held by property %s::$%s of type %s%s " ,
type ,
ZSTR_VAL ( prop - > ce - > name ) , zend_get_unmangled_property_name ( prop - > name ) ,
prop_type1 , prop_type2
) ;
}
static zend_never_inline ZEND_COLD void zend_throw_access_uninit_prop_by_ref_error (
zend_property_info * prop ) {
zend_throw_error ( NULL ,
" Cannot access uninitialized non-nullable property %s::$%s by reference " ,
ZSTR_VAL ( prop - > ce - > name ) ,
zend_get_unmangled_property_name ( prop - > name ) ) ;
}
2019-06-21 16:43:17 +08:00
static zend_never_inline zend_bool zend_verify_ref_stdClass_assignable ( zend_reference * ref ) ;
static zend_never_inline zend_bool zend_verify_ref_array_assignable ( zend_reference * ref ) ;
2019-01-07 19:28:51 +08:00
2007-07-19 23:29:30 +08:00
/* this should modify object only if it's empty */
2019-01-07 19:28:51 +08:00
static zend_never_inline ZEND_COLD zval * ZEND_FASTCALL make_real_object ( zval * object , zval * property OPLINE_DC EXECUTE_DATA_DC )
2002-03-11 05:02:00 +08:00
{
2018-02-20 22:22:11 +08:00
zend_object * obj ;
2019-01-07 19:28:51 +08:00
zval * ref = NULL ;
if ( Z_ISREF_P ( object ) ) {
ref = object ;
object = Z_REFVAL_P ( object ) ;
}
2018-02-20 22:22:11 +08:00
2019-01-07 19:28:51 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( object ) > IS_FALSE & &
( Z_TYPE_P ( object ) ! = IS_STRING | | Z_STRLEN_P ( object ) ! = 0 ) ) ) {
2018-02-20 22:22:11 +08:00
if ( opline - > op1_type ! = IS_VAR | | EXPECTED ( ! Z_ISERROR_P ( object ) ) ) {
2018-02-21 23:43:38 +08:00
zend_string * tmp_property_name ;
zend_string * property_name = zval_get_tmp_string ( property , & tmp_property_name ) ;
2018-02-20 22:22:11 +08:00
if ( opline - > opcode = = ZEND_PRE_INC_OBJ
| | opline - > opcode = = ZEND_PRE_DEC_OBJ
| | opline - > opcode = = ZEND_POST_INC_OBJ
| | opline - > opcode = = ZEND_POST_DEC_OBJ ) {
zend_error ( E_WARNING , " Attempt to increment/decrement property '%s' of non-object " , ZSTR_VAL ( property_name ) ) ;
2018-02-15 13:06:34 +08:00
} else if ( opline - > opcode = = ZEND_FETCH_OBJ_W
| | opline - > opcode = = ZEND_FETCH_OBJ_RW
2019-02-20 18:53:31 +08:00
| | opline - > opcode = = ZEND_FETCH_OBJ_FUNC_ARG
2018-02-15 13:06:34 +08:00
| | opline - > opcode = = ZEND_ASSIGN_OBJ_REF ) {
zend_error ( E_WARNING , " Attempt to modify property '%s' of non-object " , ZSTR_VAL ( property_name ) ) ;
2018-02-20 22:22:11 +08:00
} else {
2018-02-21 23:43:38 +08:00
zend_error ( E_WARNING , " Attempt to assign property '%s' of non-object " , ZSTR_VAL ( property_name ) ) ;
2018-02-20 22:22:11 +08:00
}
2018-07-27 13:00:14 +08:00
zend_tmp_string_release ( tmp_property_name ) ;
2018-02-20 22:22:11 +08:00
}
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
2014-03-14 02:56:18 +08:00
}
2019-01-07 19:28:51 +08:00
return NULL ;
}
2019-06-21 16:43:17 +08:00
if ( ref & & ZEND_REF_HAS_TYPE_SOURCES ( Z_REF_P ( ref ) ) ) {
if ( UNEXPECTED ( ! zend_verify_ref_stdClass_assignable ( Z_REF_P ( ref ) ) ) ) {
2019-01-07 19:28:51 +08:00
if ( RETURN_VALUE_USED ( opline ) ) {
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
}
return NULL ;
}
2002-03-10 21:42:37 +08:00
}
2019-01-07 19:28:51 +08:00
zval_ptr_dtor_nogc ( object ) ;
2018-02-20 22:22:11 +08:00
object_init ( object ) ;
Z_ADDREF_P ( object ) ;
obj = Z_OBJ_P ( object ) ;
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
if ( GC_REFCOUNT ( obj ) = = 1 ) {
/* the enclosing container was deleted, obj is unreferenced */
OBJ_RELEASE ( obj ) ;
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
}
2019-01-07 19:28:51 +08:00
return NULL ;
2018-02-20 22:22:11 +08:00
}
Z_DELREF_P ( object ) ;
2019-01-07 19:28:51 +08:00
return object ;
2002-03-10 21:42:37 +08:00
}
2002-10-17 02:06:36 +08:00
2016-08-12 02:24:22 +08:00
static ZEND_COLD void zend_verify_type_error_common (
const zend_function * zf , const zend_arg_info * arg_info ,
const zend_class_entry * ce , zval * value ,
const char * * fname , const char * * fsep , const char * * fclass ,
const char * * need_msg , const char * * need_kind , const char * * need_or_null ,
const char * * given_msg , const char * * given_kind )
2006-05-26 08:36:13 +08:00
{
2016-08-12 02:24:22 +08:00
zend_bool is_interface = 0 ;
2016-08-18 02:26:32 +08:00
* fname = ZSTR_VAL ( zf - > common . function_name ) ;
2006-05-26 08:36:13 +08:00
if ( zf - > common . scope ) {
2016-08-12 02:24:22 +08:00
* fsep = " :: " ;
* fclass = ZSTR_VAL ( zf - > common . scope - > name ) ;
2006-05-26 08:36:13 +08:00
} else {
2016-08-12 02:24:22 +08:00
* fsep = " " ;
* fclass = " " ;
}
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( arg_info - > type ) ) {
if ( ce ) {
if ( ce - > ce_flags & ZEND_ACC_INTERFACE ) {
* need_msg = " implement interface " ;
is_interface = 1 ;
2016-08-12 02:24:22 +08:00
} else {
* need_msg = " be an instance of " ;
}
2017-01-13 16:37:46 +08:00
* need_kind = ZSTR_VAL ( ce - > name ) ;
} else {
/* We don't know whether it's a class or interface, assume it's a class */
* need_msg = " be an instance of " ;
* need_kind = ZSTR_VAL ( ZEND_TYPE_NAME ( arg_info - > type ) ) ;
}
} else {
switch ( ZEND_TYPE_CODE ( arg_info - > type ) ) {
2017-06-26 03:43:25 +08:00
case IS_OBJECT :
* need_msg = " be an " ;
* need_kind = " object " ;
break ;
2017-01-13 16:37:46 +08:00
case IS_CALLABLE :
* need_msg = " be callable " ;
* need_kind = " " ;
break ;
case IS_ITERABLE :
* need_msg = " be iterable " ;
* need_kind = " " ;
break ;
default :
* need_msg = " be of the type " ;
* need_kind = zend_get_type_by_const ( ZEND_TYPE_CODE ( arg_info - > type ) ) ;
break ;
}
2006-05-26 08:36:13 +08:00
}
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_ALLOW_NULL ( arg_info - > type ) ) {
2016-08-12 02:24:22 +08:00
* need_or_null = is_interface ? " or be null " : " or null " ;
} else {
* need_or_null = " " ;
}
if ( value ) {
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( arg_info - > type ) & & Z_TYPE_P ( value ) = = IS_OBJECT ) {
2016-08-12 02:24:22 +08:00
* given_msg = " instance of " ;
* given_kind = ZSTR_VAL ( Z_OBJCE_P ( value ) - > name ) ;
} else {
* given_msg = zend_zval_type_name ( value ) ;
* given_kind = " " ;
}
} else {
* given_msg = " none " ;
* given_kind = " " ;
}
}
static ZEND_COLD void zend_verify_arg_error (
const zend_function * zf , const zend_arg_info * arg_info ,
int arg_num , const zend_class_entry * ce , zval * value )
{
zend_execute_data * ptr = EG ( current_execute_data ) - > prev_execute_data ;
const char * fname , * fsep , * fclass ;
const char * need_msg , * need_kind , * need_or_null , * given_msg , * given_kind ;
2016-08-31 03:09:26 +08:00
if ( value ) {
zend_verify_type_error_common (
zf , arg_info , ce , value ,
& fname , & fsep , & fclass , & need_msg , & need_kind , & need_or_null , & given_msg , & given_kind ) ;
if ( zf - > common . type = = ZEND_USER_FUNCTION ) {
if ( ptr & & ptr - > func & & ZEND_USER_CODE ( ptr - > func - > common . type ) ) {
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s%s, %s%s given, called in %s on line %d " ,
arg_num , fclass , fsep , fname , need_msg , need_kind , need_or_null , given_msg , given_kind ,
ZSTR_VAL ( ptr - > func - > op_array . filename ) , ptr - > opline - > lineno ) ;
} else {
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s%s, %s%s given " , arg_num , fclass , fsep , fname , need_msg , need_kind , need_or_null , given_msg , given_kind ) ;
}
2014-11-27 17:52:31 +08:00
} else {
2016-08-08 23:15:59 +08:00
zend_type_error ( " Argument %d passed to %s%s%s() must %s%s%s, %s%s given " , arg_num , fclass , fsep , fname , need_msg , need_kind , need_or_null , given_msg , given_kind ) ;
2014-11-27 17:52:31 +08:00
}
2006-05-26 08:36:13 +08:00
} else {
2016-08-31 03:09:26 +08:00
zend_missing_arg_error ( ptr ) ;
2006-05-26 08:36:13 +08:00
}
}
2016-04-28 09:13:34 +08:00
static int is_null_constant ( zend_class_entry * scope , zval * default_value )
2014-11-25 23:09:08 +08:00
{
2017-10-10 15:11:05 +08:00
if ( Z_TYPE_P ( default_value ) = = IS_CONSTANT_AST ) {
2014-11-25 23:12:30 +08:00
zval constant ;
2014-11-25 23:09:08 +08:00
2016-04-28 09:13:34 +08:00
ZVAL_COPY ( & constant , default_value ) ;
if ( UNEXPECTED ( zval_update_constant_ex ( & constant , scope ) ! = SUCCESS ) ) {
2015-04-02 07:05:25 +08:00
return 0 ;
}
2014-11-25 23:09:08 +08:00
if ( Z_TYPE ( constant ) = = IS_NULL ) {
return 1 ;
}
2017-10-09 17:24:11 +08:00
zval_ptr_dtor_nogc ( & constant ) ;
2014-11-25 23:09:08 +08:00
}
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 */
2018-08-19 12:32:00 +08:00
return zend_parse_arg_str_weak ( arg , & dest ) ;
2014-12-29 21:49:12 +08:00
}
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
}
2019-01-07 19:28:51 +08:00
ZEND_COLD zend_never_inline void zend_verify_property_type_error ( zend_property_info * info , zval * property )
{
const char * prop_type1 , * prop_type2 ;
/* we _may_ land here in case reading already errored and runtime cache thus has not been updated (i.e. it contains a valid but unrelated info) */
if ( EG ( exception ) ) {
return ;
}
// TODO Switch to a more standard error message?
zend_format_type ( info - > type , & prop_type1 , & prop_type2 ) ;
( void ) prop_type1 ;
if ( ZEND_TYPE_IS_CLASS ( info - > type ) ) {
zend_type_error ( " Typed property %s::$%s must be an instance of %s%s, %s used " ,
ZSTR_VAL ( info - > ce - > name ) ,
zend_get_unmangled_property_name ( info - > name ) ,
prop_type2 ,
ZEND_TYPE_ALLOW_NULL ( info - > type ) ? " or null " : " " ,
Z_TYPE_P ( property ) = = IS_OBJECT ? ZSTR_VAL ( Z_OBJCE_P ( property ) - > name ) : zend_get_type_by_const ( Z_TYPE_P ( property ) ) ) ;
} else {
zend_type_error ( " Typed property %s::$%s must be %s%s, %s used " ,
ZSTR_VAL ( info - > ce - > name ) ,
zend_get_unmangled_property_name ( info - > name ) ,
prop_type2 ,
ZEND_TYPE_ALLOW_NULL ( info - > type ) ? " or null " : " " ,
Z_TYPE_P ( property ) = = IS_OBJECT ? ZSTR_VAL ( Z_OBJCE_P ( property ) - > name ) : zend_get_type_by_const ( Z_TYPE_P ( property ) ) ) ;
}
}
static zend_bool zend_resolve_class_type ( zend_type * type , zend_class_entry * self_ce ) {
zend_class_entry * ce ;
zend_string * name = ZEND_TYPE_NAME ( * type ) ;
if ( zend_string_equals_literal_ci ( name , " self " ) ) {
/* We need to explicitly check for this here, to avoid updating the type in the trait and
* later using the wrong " self " when the trait is used in a class . */
if ( UNEXPECTED ( ( self_ce - > ce_flags & ZEND_ACC_TRAIT ) ! = 0 ) ) {
zend_throw_error ( NULL , " Cannot write a%s value to a 'self' typed static property of a trait " , ZEND_TYPE_ALLOW_NULL ( * type ) ? " non-null " : " " ) ;
return 0 ;
}
ce = self_ce ;
} else if ( zend_string_equals_literal_ci ( name , " parent " ) ) {
if ( UNEXPECTED ( ! self_ce - > parent ) ) {
zend_throw_error ( NULL , " Cannot access parent:: when current class scope has no parent " ) ;
return 0 ;
}
ce = self_ce - > parent ;
} else {
ce = zend_lookup_class ( name ) ;
if ( UNEXPECTED ( ! ce ) ) {
return 0 ;
}
}
zend_string_release ( name ) ;
* type = ZEND_TYPE_ENCODE_CE ( ce , ZEND_TYPE_ALLOW_NULL ( * type ) ) ;
return 1 ;
}
static zend_always_inline zend_bool i_zend_check_property_type ( zend_property_info * info , zval * property , zend_bool strict )
{
ZEND_ASSERT ( ! Z_ISREF_P ( property ) ) ;
if ( ZEND_TYPE_IS_CLASS ( info - > type ) ) {
if ( UNEXPECTED ( Z_TYPE_P ( property ) ! = IS_OBJECT ) ) {
return Z_TYPE_P ( property ) = = IS_NULL & & ZEND_TYPE_ALLOW_NULL ( info - > type ) ;
}
if ( UNEXPECTED ( ! ZEND_TYPE_IS_CE ( info - > type ) ) & & UNEXPECTED ( ! zend_resolve_class_type ( & info - > type , info - > ce ) ) ) {
return 0 ;
}
return instanceof_function ( Z_OBJCE_P ( property ) , ZEND_TYPE_CE ( info - > type ) ) ;
}
ZEND_ASSERT ( ZEND_TYPE_CODE ( info - > type ) ! = IS_CALLABLE ) ;
if ( EXPECTED ( ZEND_TYPE_CODE ( info - > type ) = = Z_TYPE_P ( property ) ) ) {
return 1 ;
} else if ( EXPECTED ( Z_TYPE_P ( property ) = = IS_NULL ) ) {
return ZEND_TYPE_ALLOW_NULL ( info - > type ) ;
} else if ( ZEND_TYPE_CODE ( info - > type ) = = _IS_BOOL & & EXPECTED ( Z_TYPE_P ( property ) = = IS_FALSE | | Z_TYPE_P ( property ) = = IS_TRUE ) ) {
return 1 ;
} else if ( ZEND_TYPE_CODE ( info - > type ) = = IS_ITERABLE ) {
return zend_is_iterable ( property ) ;
} else {
return zend_verify_scalar_type_hint ( ZEND_TYPE_CODE ( info - > type ) , property , strict ) ;
}
}
static zend_bool zend_always_inline i_zend_verify_property_type ( zend_property_info * info , zval * property , zend_bool strict )
{
if ( i_zend_check_property_type ( info , property , strict ) ) {
return 1 ;
}
zend_verify_property_type_error ( info , property ) ;
return 0 ;
}
zend_bool zend_never_inline zend_verify_property_type ( zend_property_info * info , zval * property , zend_bool strict ) {
return i_zend_verify_property_type ( info , property , strict ) ;
}
2019-01-16 07:13:43 +08:00
static zend_never_inline zval * zend_assign_to_typed_prop ( zend_property_info * info , zval * property_val , zval * value EXECUTE_DATA_DC )
{
zval tmp ;
ZVAL_DEREF ( value ) ;
ZVAL_COPY ( & tmp , value ) ;
if ( UNEXPECTED ( ! i_zend_verify_property_type ( info , & tmp , EX_USES_STRICT_TYPES ( ) ) ) ) {
zval_ptr_dtor ( & tmp ) ;
return & EG ( uninitialized_zval ) ;
}
return zend_assign_to_variable ( property_val , & tmp , IS_TMP_VAR , EX_USES_STRICT_TYPES ( ) ) ;
}
2016-08-12 02:24:22 +08:00
static zend_always_inline zend_bool zend_check_type (
2017-01-13 16:37:46 +08:00
zend_type type ,
2016-08-12 02:24:22 +08:00
zval * arg , zend_class_entry * * ce , void * * cache_slot ,
2017-01-13 16:37:46 +08:00
zval * default_value , zend_class_entry * scope ,
zend_bool is_return_type )
2016-08-12 02:24:22 +08:00
{
2019-01-07 19:28:51 +08:00
zend_reference * ref = NULL ;
2017-01-13 16:37:46 +08:00
if ( ! ZEND_TYPE_IS_SET ( type ) ) {
2016-08-12 02:24:22 +08:00
return 1 ;
}
2019-01-07 19:28:51 +08:00
if ( UNEXPECTED ( Z_ISREF_P ( arg ) ) ) {
ref = Z_REF_P ( arg ) ;
arg = Z_REFVAL_P ( arg ) ;
}
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( type ) ) {
if ( EXPECTED ( * cache_slot ) ) {
* ce = ( zend_class_entry * ) * cache_slot ;
} else {
* ce = zend_fetch_class ( ZEND_TYPE_NAME ( type ) , ( ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ;
if ( UNEXPECTED ( ! * ce ) ) {
2017-01-14 00:51:12 +08:00
return Z_TYPE_P ( arg ) = = IS_NULL & & ( ZEND_TYPE_ALLOW_NULL ( type ) | | ( default_value & & is_null_constant ( scope , default_value ) ) ) ;
2016-08-12 02:24:22 +08:00
}
2017-01-13 16:37:46 +08:00
* cache_slot = ( void * ) * ce ;
}
if ( EXPECTED ( Z_TYPE_P ( arg ) = = IS_OBJECT ) ) {
return instanceof_function ( Z_OBJCE_P ( arg ) , * ce ) ;
2016-08-12 02:24:22 +08:00
}
2017-08-15 19:46:18 +08:00
return Z_TYPE_P ( arg ) = = IS_NULL & & ( ZEND_TYPE_ALLOW_NULL ( type ) | | ( default_value & & is_null_constant ( scope , default_value ) ) ) ;
2017-01-13 16:37:46 +08:00
} else if ( EXPECTED ( ZEND_TYPE_CODE ( type ) = = Z_TYPE_P ( arg ) ) ) {
2016-08-12 02:24:22 +08:00
return 1 ;
}
2017-01-13 16:37:46 +08:00
if ( Z_TYPE_P ( arg ) = = IS_NULL & & ( ZEND_TYPE_ALLOW_NULL ( type ) | | ( default_value & & is_null_constant ( scope , default_value ) ) ) ) {
2016-08-12 02:24:22 +08:00
/* Null passed to nullable type */
return 1 ;
}
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_CODE ( type ) = = IS_CALLABLE ) {
2016-08-12 02:24:22 +08:00
return zend_is_callable ( arg , IS_CALLABLE_CHECK_SILENT , NULL ) ;
2017-01-13 16:37:46 +08:00
} else if ( ZEND_TYPE_CODE ( type ) = = IS_ITERABLE ) {
2016-08-12 02:24:22 +08:00
return zend_is_iterable ( arg ) ;
2017-01-13 16:37:46 +08:00
} else if ( ZEND_TYPE_CODE ( type ) = = _IS_BOOL & &
2016-08-12 02:24:22 +08:00
EXPECTED ( Z_TYPE_P ( arg ) = = IS_FALSE | | Z_TYPE_P ( arg ) = = IS_TRUE ) ) {
return 1 ;
2019-01-07 19:28:51 +08:00
} else if ( ref & & ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) {
return 0 ; /* we cannot have conversions for typed refs */
2016-08-12 02:24:22 +08:00
} else {
2017-01-13 16:37:46 +08:00
return zend_verify_scalar_type_hint ( ZEND_TYPE_CODE ( type ) , arg ,
2016-08-12 02:24:22 +08:00
is_return_type ? ZEND_RET_USES_STRICT_TYPES ( ) : ZEND_ARG_USES_STRICT_TYPES ( ) ) ;
}
/* Special handling for IS_VOID is not necessary (for return types),
* because this case is already checked at compile - time . */
}
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 ;
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
2018-02-22 16:33:26 +08:00
ce = NULL ;
2017-01-13 16:37:46 +08:00
if ( UNEXPECTED ( ! zend_check_type ( cur_arg_info - > type , arg , & ce , cache_slot , default_value , zf - > common . scope , 0 ) ) ) {
2016-08-12 02:24:22 +08:00
zend_verify_arg_error ( zf , cur_arg_info , arg_num , ce , arg ) ;
2019-04-15 18:18:16 +08:00
return 0 ;
}
return 1 ;
}
static zend_always_inline int zend_verify_recv_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg , zval * default_value , void * * cache_slot )
{
zend_arg_info * cur_arg_info = & zf - > common . arg_info [ arg_num - 1 ] ;
zend_class_entry * ce ;
ZEND_ASSERT ( arg_num < = zf - > common . num_args ) ;
cur_arg_info = & zf - > common . arg_info [ arg_num - 1 ] ;
ce = NULL ;
if ( UNEXPECTED ( ! zend_check_type ( cur_arg_info - > type , arg , & ce , cache_slot , default_value , zf - > common . scope , 0 ) ) ) {
zend_verify_arg_error ( zf , cur_arg_info , arg_num , ce , arg ) ;
return 0 ;
}
return 1 ;
}
static zend_always_inline int zend_verify_variadic_arg_type ( zend_function * zf , uint32_t arg_num , zval * arg , zval * default_value , void * * cache_slot )
{
zend_arg_info * cur_arg_info ;
zend_class_entry * ce ;
ZEND_ASSERT ( arg_num > zf - > common . num_args ) ;
ZEND_ASSERT ( zf - > common . fn_flags & ZEND_ACC_VARIADIC ) ;
cur_arg_info = & zf - > common . arg_info [ zf - > common . num_args ] ;
ce = NULL ;
if ( UNEXPECTED ( ! zend_check_type ( cur_arg_info - > type , arg , & ce , cache_slot , default_value , zf - > common . scope , 0 ) ) ) {
zend_verify_arg_error ( zf , cur_arg_info , arg_num , ce , arg ) ;
2016-08-12 02:24:22 +08:00
return 0 ;
2005-05-26 21:46:17 +08:00
}
2016-08-12 02:24:22 +08:00
2015-04-29 04:57:21 +08:00
return 1 ;
2014-04-04 18:36:34 +08:00
}
2017-01-13 16:37:46 +08:00
static zend_never_inline int zend_verify_internal_arg_types ( zend_function * fbc , zend_execute_data * call )
{
uint32_t i ;
uint32_t num_args = ZEND_CALL_NUM_ARGS ( call ) ;
zval * p = ZEND_CALL_ARG ( call , 1 ) ;
void * dummy_cache_slot ;
for ( i = 0 ; i < num_args ; + + i ) {
dummy_cache_slot = NULL ;
if ( UNEXPECTED ( ! zend_verify_arg_type ( fbc , i + 1 , p , NULL , & dummy_cache_slot ) ) ) {
EG ( current_execute_data ) = call - > prev_execute_data ;
return 0 ;
}
p + + ;
}
return 1 ;
}
2016-06-16 07:32:02 +08:00
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error ( zend_execute_data * execute_data )
{
zend_execute_data * ptr = EX ( prev_execute_data ) ;
if ( ptr & & ptr - > func & & ZEND_USER_CODE ( ptr - > func - > common . type ) ) {
2016-08-31 03:09:26 +08:00
zend_throw_error ( zend_ce_argument_count_error , " Too few arguments to function %s%s%s(), %d passed in %s on line %d and %s %d expected " ,
2016-06-16 07:32:02 +08:00
EX ( func ) - > common . scope ? ZSTR_VAL ( EX ( func ) - > common . scope - > name ) : " " ,
EX ( func ) - > common . scope ? " :: " : " " ,
ZSTR_VAL ( EX ( func ) - > common . function_name ) ,
EX_NUM_ARGS ( ) ,
ZSTR_VAL ( ptr - > func - > op_array . filename ) ,
ptr - > opline - > lineno ,
EX ( func ) - > common . required_num_args = = EX ( func ) - > common . num_args ? " exactly " : " at least " ,
EX ( func ) - > common . required_num_args ) ;
2014-04-04 18:36:34 +08:00
} else {
2016-08-31 03:09:26 +08:00
zend_throw_error ( zend_ce_argument_count_error , " Too few arguments to function %s%s%s(), %d passed and %s %d expected " ,
2016-06-16 07:32:02 +08:00
EX ( func ) - > common . scope ? ZSTR_VAL ( EX ( func ) - > common . scope - > name ) : " " ,
EX ( func ) - > common . scope ? " :: " : " " ,
ZSTR_VAL ( EX ( func ) - > common . function_name ) ,
EX_NUM_ARGS ( ) ,
EX ( func ) - > common . required_num_args = = EX ( func ) - > common . num_args ? " exactly " : " at least " ,
EX ( func ) - > common . required_num_args ) ;
2014-04-04 18:36:34 +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
}
2016-08-12 02:24:22 +08:00
static ZEND_COLD void zend_verify_return_error (
const zend_function * zf , const zend_class_entry * ce , zval * value )
2015-01-09 04:40:36 +08:00
{
2016-08-12 02:24:22 +08:00
const zend_arg_info * arg_info = & zf - > common . arg_info [ - 1 ] ;
const char * fname , * fsep , * fclass ;
const char * need_msg , * need_kind , * need_or_null , * given_msg , * given_kind ;
2015-01-09 04:40:36 +08:00
2016-08-12 02:24:22 +08:00
zend_verify_type_error_common (
zf , arg_info , ce , value ,
2017-12-31 12:35:25 +08:00
& fname , & fsep , & fclass , & need_msg , & need_kind , & need_or_null , & given_msg , & given_kind ) ;
2015-01-09 04:40:36 +08:00
2016-08-08 23:15:59 +08:00
zend_type_error ( " Return value of %s%s%s() must %s%s%s, %s%s returned " ,
2016-08-12 02:24:22 +08:00
fclass , fsep , fname , need_msg , need_kind , need_or_null , given_msg , given_kind ) ;
2015-03-19 03:22:21 +08:00
}
2016-04-29 19:03:33 +08:00
# if ZEND_DEBUG
2016-08-12 02:24:22 +08:00
static ZEND_COLD void zend_verify_internal_return_error (
const zend_function * zf , const zend_class_entry * ce , zval * value )
2015-01-09 04:40:36 +08:00
{
2016-08-12 02:24:22 +08:00
const zend_arg_info * arg_info = & zf - > common . arg_info [ - 1 ] ;
const char * fname , * fsep , * fclass ;
const char * need_msg , * need_kind , * need_or_null , * given_msg , * given_kind ;
2015-01-09 04:40:36 +08:00
2016-08-12 02:24:22 +08:00
zend_verify_type_error_common (
zf , arg_info , ce , value ,
2017-12-31 12:35:25 +08:00
& fname , & fsep , & fclass , & need_msg , & need_kind , & need_or_null , & given_msg , & given_kind ) ;
2015-01-09 04:40:36 +08:00
2016-08-08 23:15:59 +08:00
zend_error_noreturn ( E_CORE_ERROR , " Return value of %s%s%s() must %s%s%s, %s%s returned " ,
2016-08-12 02:24:22 +08:00
fclass , fsep , fname , need_msg , need_kind , need_or_null , given_msg , given_kind ) ;
2015-01-09 04:40:36 +08:00
}
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-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
{
2016-08-12 02:24:22 +08:00
zend_internal_arg_info * ret_info = zf - > internal_function . arg_info - 1 ;
zend_class_entry * ce = NULL ;
2017-01-13 16:37:46 +08:00
void * dummy_cache_slot = NULL ;
2015-02-05 16:01:07 +08:00
2018-07-01 02:11:39 +08:00
if ( ZEND_TYPE_CODE ( ret_info - > type ) = = IS_VOID ) {
2018-07-01 02:10:57 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) ! = IS_NULL ) ) {
zend_verify_void_return_error ( zf , zend_zval_type_name ( ret ) , " " ) ;
return 0 ;
}
return 1 ;
2016-08-12 02:24:22 +08:00
}
2015-02-05 16:01:07 +08:00
2017-01-13 16:37:46 +08:00
if ( UNEXPECTED ( ! zend_check_type ( ret_info - > type , ret , & ce , & dummy_cache_slot , NULL , NULL , 1 ) ) ) {
2016-08-12 02:24:22 +08:00
zend_verify_internal_return_error ( zf , ce , ret ) ;
return 0 ;
2015-02-05 16:01:07 +08:00
}
2016-08-12 02:24:22 +08:00
2015-02-05 16:01:07 +08:00
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 ;
2016-08-12 02:24:22 +08:00
zend_class_entry * ce = NULL ;
2017-12-31 12:35:25 +08:00
2017-01-13 16:37:46 +08:00
if ( UNEXPECTED ( ! zend_check_type ( ret_info - > type , ret , & ce , cache_slot , NULL , NULL , 1 ) ) ) {
2016-08-12 02:24:22 +08:00
zend_verify_return_error ( zf , ce , ret ) ;
2015-01-09 04:40:36 +08:00
}
}
2018-02-16 07:45:31 +08:00
static ZEND_COLD int zend_verify_missing_return_type ( const zend_function * zf , void * * cache_slot )
2015-01-09 04:40:36 +08:00
{
zend_arg_info * ret_info = zf - > common . arg_info - 1 ;
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_SET ( ret_info - > type ) & & UNEXPECTED ( ZEND_TYPE_CODE ( ret_info - > type ) ! = IS_VOID ) ) {
2016-08-12 02:24:22 +08:00
zend_class_entry * ce = NULL ;
2017-01-13 16:37:46 +08:00
if ( ZEND_TYPE_IS_CLASS ( ret_info - > type ) ) {
2015-06-17 17:07:43 +08:00
if ( EXPECTED ( * cache_slot ) ) {
2016-08-12 02:24:22 +08:00
ce = ( zend_class_entry * ) * cache_slot ;
2015-06-17 17:07:43 +08:00
} else {
2017-01-13 16:37:46 +08:00
ce = zend_fetch_class ( ZEND_TYPE_NAME ( ret_info - > type ) , ( ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD ) ) ;
2016-08-12 02:24:22 +08:00
if ( ce ) {
* cache_slot = ( void * ) ce ;
2015-06-17 17:07:43 +08:00
}
}
2015-01-09 04:40:36 +08:00
}
2016-08-12 02:24:22 +08:00
zend_verify_return_error ( zf , ce , NULL ) ;
2015-01-09 04:40:36 +08:00
return 0 ;
}
return 1 ;
}
2018-02-16 07:45:31 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_object_as_array ( void )
{
zend_throw_error ( NULL , " Cannot use object as array " ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_illegal_offset ( void )
{
zend_error ( E_WARNING , " Illegal offset type " ) ;
}
2018-02-21 04:44:25 +08:00
static zend_never_inline void zend_assign_to_object_dim ( zval * object , zval * dim , zval * value OPLINE_DC EXECUTE_DATA_DC )
2014-12-09 05:10:23 +08:00
{
2016-04-13 00:36:24 +08:00
Z_OBJ_HT_P ( object ) - > write_dimension ( object , dim , value ) ;
2018-02-21 04:44:25 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , value ) ;
}
2002-03-10 21:42:37 +08:00
}
2019-07-04 22:25:43 +08:00
static zend_always_inline int zend_binary_op ( zval * ret , zval * op1 , zval * op2 OPLINE_DC )
{
static const binary_op_type zend_binary_ops [ ] = {
add_function ,
sub_function ,
mul_function ,
div_function ,
mod_function ,
shift_left_function ,
shift_right_function ,
concat_function ,
bitwise_or_function ,
bitwise_and_function ,
bitwise_xor_function ,
pow_function
} ;
/* size_t cast makes GCC to better optimize 64-bit PIC code */
2019-07-05 17:03:25 +08:00
size_t opcode = ( size_t ) opline - > extended_value ;
2019-07-04 22:25:43 +08:00
2019-07-05 17:03:25 +08:00
return zend_binary_ops [ opcode - ZEND_ADD ] ( ret , op1 , op2 ) ;
2019-07-04 22:25:43 +08:00
}
2019-07-17 05:52:26 +08:00
static zend_never_inline void zend_binary_assign_op_obj_dim ( zval * object , zval * property OPLINE_DC EXECUTE_DATA_DC )
2014-12-09 20:15:24 +08:00
{
2019-07-17 05:52:26 +08:00
zend_free_op free_op_data1 ;
zval * value ;
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
2019-07-17 05:52:26 +08:00
value = get_op_data_zval_ptr_r ( ( opline + 1 ) - > op1_type , ( opline + 1 ) - > op1 , & free_op_data1 ) ;
2018-10-13 21:30:27 +08:00
if ( ( 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 ) ;
}
2019-07-04 22:25:43 +08:00
if ( zend_binary_op ( & res , z , value OPLINE_CC ) = = SUCCESS ) {
2018-09-23 21:29:25 +08:00
Z_OBJ_HT_P ( object ) - > write_dimension ( object , property , & res ) ;
}
2015-01-26 16:25:05 +08:00
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
}
2018-11-20 16:55:16 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
2018-11-20 17:53:05 +08:00
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , & 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 {
2018-07-16 22:08:11 +08:00
zend_use_object_as_array ( ) ;
2018-11-20 16:55:16 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
2014-12-09 20:15:24 +08:00
}
}
2019-07-17 05:52:26 +08:00
FREE_OP ( free_op_data1 ) ;
2014-12-09 20:15:24 +08:00
}
2019-07-04 22:25:43 +08:00
static zend_never_inline void zend_binary_assign_op_typed_ref ( zend_reference * ref , zval * value OPLINE_DC EXECUTE_DATA_DC )
2019-01-15 23:49:05 +08:00
{
zval z_copy ;
2019-07-04 22:25:43 +08:00
zend_binary_op ( & z_copy , & ref - > val , value OPLINE_CC ) ;
2019-01-15 23:49:05 +08:00
if ( EXPECTED ( zend_verify_ref_assignable_zval ( ref , & z_copy , EX_USES_STRICT_TYPES ( ) ) ) ) {
zval_ptr_dtor ( & ref - > val ) ;
ZVAL_COPY_VALUE ( & ref - > val , & z_copy ) ;
} else {
zval_ptr_dtor ( & z_copy ) ;
}
}
2019-07-04 22:25:43 +08:00
static zend_never_inline void zend_binary_assign_op_typed_prop ( zend_property_info * prop_info , zval * zptr , zval * value OPLINE_DC EXECUTE_DATA_DC )
2019-01-15 23:49:05 +08:00
{
zval z_copy ;
2019-07-04 22:25:43 +08:00
zend_binary_op ( & z_copy , zptr , value OPLINE_CC ) ;
2019-01-15 23:49:05 +08:00
if ( EXPECTED ( zend_verify_property_type ( prop_info , & z_copy , EX_USES_STRICT_TYPES ( ) ) ) ) {
zval_ptr_dtor ( zptr ) ;
ZVAL_COPY_VALUE ( zptr , & z_copy ) ;
} else {
zval_ptr_dtor ( & z_copy ) ;
}
}
2017-06-16 06:42:49 +08:00
static zend_never_inline zend_long zend_check_string_offset ( zval * dim , int type EXECUTE_DATA_DC )
2016-04-13 00:36:24 +08:00
{
zend_long offset ;
try_again :
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 ;
2016-04-13 06:19:20 +08:00
case IS_UNDEF :
2018-12-18 22:34:18 +08:00
ZVAL_UNDEFINED_OP2 ( ) ;
2016-04-13 00:36:24 +08:00
case IS_DOUBLE :
case IS_NULL :
case IS_FALSE :
case IS_TRUE :
zend_error ( E_NOTICE , " String offset cast occurred " ) ;
break ;
case IS_REFERENCE :
dim = Z_REFVAL_P ( dim ) ;
goto try_again ;
default :
2018-02-16 07:45:31 +08:00
zend_illegal_offset ( ) ;
2016-04-13 00:36:24 +08:00
break ;
}
2017-11-16 22:09:01 +08:00
offset = zval_get_long_func ( dim ) ;
2016-04-13 00:36:24 +08:00
} else {
offset = Z_LVAL_P ( dim ) ;
}
return offset ;
}
2017-06-16 06:42:49 +08:00
static zend_never_inline ZEND_COLD void zend_wrong_string_offset ( EXECUTE_DATA_D )
2016-04-13 00:36:24 +08:00
{
const char * msg = NULL ;
2017-06-16 06:42:49 +08:00
const zend_op * opline = EX ( opline ) ;
2016-04-13 00:36:24 +08:00
const zend_op * end ;
uint32_t var ;
2018-06-27 18:34:15 +08:00
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
return ;
}
2016-04-13 00:36:24 +08:00
switch ( opline - > opcode ) {
2019-07-05 17:03:25 +08:00
case ZEND_ASSIGN_OP :
case ZEND_ASSIGN_DIM_OP :
case ZEND_ASSIGN_OBJ_OP :
case ZEND_ASSIGN_STATIC_PROP_OP :
2016-04-13 00:36:24 +08:00
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 :
2017-10-07 07:30:58 +08:00
case ZEND_FETCH_LIST_W :
2016-04-13 00:36:24 +08:00
/* 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 ) {
2019-07-05 17:03:25 +08:00
case ZEND_ASSIGN_OBJ_OP :
msg = " Cannot use string offset as an object " ;
break ;
case ZEND_ASSIGN_DIM_OP :
msg = " Cannot use string offset as an array " ;
break ;
case ZEND_ASSIGN_STATIC_PROP_OP :
case ZEND_ASSIGN_OP :
msg = " Cannot use assign-op operators with string offsets " ;
2016-04-13 00:36:24 +08:00
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 :
2017-10-07 07:30:58 +08:00
case ZEND_FETCH_LIST_W :
2016-04-13 00:36:24 +08:00
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 :
2016-07-10 21:13:21 +08:00
case ZEND_MAKE_REF :
2016-04-13 00:36:24 +08:00
msg = " Cannot create references to/from string offsets " ;
break ;
case ZEND_RETURN_BY_REF :
2016-07-10 21:13:21 +08:00
case ZEND_VERIFY_RETURN_TYPE :
2016-04-13 00:36:24 +08:00
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 :
2018-02-06 00:40:06 +08:00
case ZEND_SEND_FUNC_ARG :
2016-04-13 00:36:24 +08:00
msg = " Only variables can be passed by reference " ;
break ;
2016-12-20 21:53:06 +08:00
case ZEND_FE_RESET_RW :
msg = " Cannot iterate on string offsets by reference " ;
break ;
2016-04-13 00:36:24 +08:00
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 ) ;
2017-11-16 19:29:27 +08:00
zend_throw_error ( NULL , " %s " , msg ) ;
2016-04-13 00:36:24 +08:00
}
2017-12-22 21:35:52 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_property_read ( zval * property )
{
zend_string * tmp_property_name ;
zend_string * property_name = zval_get_tmp_string ( property , & tmp_property_name ) ;
zend_error ( E_NOTICE , " Trying to get property '%s' of non-object " , ZSTR_VAL ( property_name ) ) ;
2018-07-27 13:00:14 +08:00
zend_tmp_string_release ( tmp_property_name ) ;
2017-12-22 21:35:52 +08:00
}
2018-02-16 07:45:31 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_deprecated_function ( const zend_function * fbc )
{
zend_error ( E_DEPRECATED , " Function %s%s%s() is deprecated " ,
fbc - > common . scope ? ZSTR_VAL ( fbc - > common . scope - > name ) : " " ,
fbc - > common . scope ? " :: " : " " ,
ZSTR_VAL ( fbc - > common . function_name ) ) ;
}
2019-09-04 18:34:20 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_abstract_method ( const zend_function * fbc )
{
zend_throw_error ( NULL , " Cannot call abstract method %s::%s() " ,
ZSTR_VAL ( fbc - > common . scope - > name ) , ZSTR_VAL ( fbc - > common . function_name ) ) ;
}
2018-02-21 04:44:25 +08:00
static zend_never_inline void zend_assign_to_string_offset ( zval * str , zval * dim , zval * value OPLINE_DC EXECUTE_DATA_DC )
2014-09-07 06:54:47 +08:00
{
2016-02-12 07:01:59 +08:00
zend_uchar c ;
size_t string_len ;
2016-04-13 00:36:24 +08:00
zend_long offset ;
1999-04-08 02:10:10 +08:00
2017-06-16 06:42:49 +08:00
offset = zend_check_string_offset ( dim , BP_VAR_W EXECUTE_DATA_CC ) ;
2016-09-05 05:33:32 +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 ) ;
2018-02-21 04:44:25 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
2014-04-04 06:52:53 +08:00
}
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 */
2019-06-06 06:47:22 +08:00
zend_string * tmp = zval_try_get_string_func ( value ) ;
if ( UNEXPECTED ( ! tmp ) ) {
2019-02-26 22:32:18 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
}
return ;
}
2016-02-12 07:01:59 +08:00
string_len = ZSTR_LEN ( tmp ) ;
c = ( zend_uchar ) ZSTR_VAL ( tmp ) [ 0 ] ;
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( tmp , 0 ) ;
2016-02-12 07:01:59 +08:00
} 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 " ) ;
2018-02-21 04:44:25 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
2016-02-12 07:01:59 +08:00
}
return ;
}
2015-07-22 04:16:08 +08:00
if ( offset < 0 ) { /* Handle negative offset */
offset + = ( zend_long ) Z_STRLEN_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 ) ;
2018-01-18 07:30:07 +08:00
ZVAL_NEW_STR ( str , zend_string_extend ( Z_STR_P ( str ) , offset + 1 , 0 ) ) ;
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 ) ) {
2018-01-18 07:30:07 +08:00
ZVAL_NEW_STR ( str , zend_string_init ( Z_STRVAL_P ( str ) , Z_STRLEN_P ( str ) , 0 ) ) ;
} else if ( Z_REFCOUNT_P ( str ) > 1 ) {
Z_DELREF_P ( str ) ;
ZVAL_NEW_STR ( str , zend_string_init ( Z_STRVAL_P ( str ) , Z_STRLEN_P ( str ) , 0 ) ) ;
2016-04-13 00:36:24 +08:00
} else {
2016-08-26 18:30:08 +08:00
zend_string_forget_hash_val ( Z_STR_P ( str ) ) ;
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
2018-02-21 04:44:25 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
2016-02-12 07:01:59 +08:00
/* Return the new character */
2018-02-21 04:44:25 +08:00
ZVAL_INTERNED_STR ( EX_VAR ( opline - > result . var ) , ZSTR_CHAR ( c ) ) ;
2014-04-04 06:52:53 +08:00
}
2007-12-14 22:14:50 +08:00
}
1999-04-08 02:10:10 +08:00
2019-01-07 19:28:51 +08:00
static zend_property_info * zend_get_prop_not_accepting_double ( zend_reference * ref )
{
zend_property_info * prop ;
ZEND_REF_FOREACH_TYPE_SOURCES ( ref , prop ) {
if ( ZEND_TYPE_CODE ( prop - > type ) ! = IS_DOUBLE ) {
return prop ;
}
} ZEND_REF_FOREACH_TYPE_SOURCES_END ( ) ;
return NULL ;
}
2019-07-03 15:33:03 +08:00
static ZEND_COLD zend_long zend_throw_incdec_ref_error ( zend_reference * ref OPLINE_DC )
2019-01-07 19:28:51 +08:00
{
zend_property_info * error_prop = zend_get_prop_not_accepting_double ( ref ) ;
/* Currently there should be no way for a typed reference to accept both int and double.
* Generalize this and the related property code once this becomes possible . */
ZEND_ASSERT ( error_prop ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
zend_type_error (
" Cannot increment a reference held by property %s::$%s of type %sint past its maximal value " ,
ZSTR_VAL ( error_prop - > ce - > name ) ,
zend_get_unmangled_property_name ( error_prop - > name ) ,
ZEND_TYPE_ALLOW_NULL ( error_prop - > type ) ? " ? " : " " ) ;
return ZEND_LONG_MAX ;
} else {
zend_type_error (
" Cannot decrement a reference held by property %s::$%s of type %sint past its minimal value " ,
ZSTR_VAL ( error_prop - > ce - > name ) ,
zend_get_unmangled_property_name ( error_prop - > name ) ,
ZEND_TYPE_ALLOW_NULL ( error_prop - > type ) ? " ? " : " " ) ;
return ZEND_LONG_MIN ;
}
2019-01-07 19:28:51 +08:00
}
2019-07-03 15:33:03 +08:00
static ZEND_COLD zend_long zend_throw_incdec_prop_error ( zend_property_info * prop OPLINE_DC ) {
2019-01-07 19:28:51 +08:00
const char * prop_type1 , * prop_type2 ;
zend_format_type ( prop - > type , & prop_type1 , & prop_type2 ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
zend_type_error ( " Cannot increment property %s::$%s of type %s%s past its maximal value " ,
ZSTR_VAL ( prop - > ce - > name ) ,
zend_get_unmangled_property_name ( prop - > name ) ,
prop_type1 , prop_type2 ) ;
return ZEND_LONG_MAX ;
} else {
zend_type_error ( " Cannot decrement property %s::$%s of type %s%s past its minimal value " ,
ZSTR_VAL ( prop - > ce - > name ) ,
zend_get_unmangled_property_name ( prop - > name ) ,
prop_type1 , prop_type2 ) ;
return ZEND_LONG_MIN ;
}
2019-01-07 19:28:51 +08:00
}
2019-07-03 15:33:03 +08:00
static void zend_incdec_typed_ref ( zend_reference * ref , zval * copy OPLINE_DC EXECUTE_DATA_DC )
2019-01-15 23:03:46 +08:00
{
zval tmp ;
zval * var_ptr = & ref - > val ;
if ( ! copy ) {
copy = & tmp ;
}
ZVAL_COPY ( copy , var_ptr ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-15 23:03:46 +08:00
increment_function ( var_ptr ) ;
} else {
decrement_function ( var_ptr ) ;
}
if ( UNEXPECTED ( Z_TYPE_P ( var_ptr ) = = IS_DOUBLE ) & & Z_TYPE_P ( copy ) = = IS_LONG ) {
2019-07-03 15:33:03 +08:00
zend_long val = zend_throw_incdec_ref_error ( ref OPLINE_CC ) ;
ZVAL_LONG ( var_ptr , val ) ;
2019-01-15 23:03:46 +08:00
} else if ( UNEXPECTED ( ! zend_verify_ref_assignable_zval ( ref , var_ptr , EX_USES_STRICT_TYPES ( ) ) ) ) {
zval_ptr_dtor ( var_ptr ) ;
ZVAL_COPY_VALUE ( var_ptr , copy ) ;
2019-02-08 19:43:11 +08:00
ZVAL_UNDEF ( copy ) ;
2019-01-15 23:03:46 +08:00
} else if ( copy = = & tmp ) {
zval_ptr_dtor ( & tmp ) ;
}
}
2019-07-03 15:33:03 +08:00
static void zend_incdec_typed_prop ( zend_property_info * prop_info , zval * var_ptr , zval * copy OPLINE_DC EXECUTE_DATA_DC )
2019-01-16 05:22:34 +08:00
{
zval tmp ;
if ( ! copy ) {
copy = & tmp ;
}
ZVAL_COPY ( copy , var_ptr ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-16 05:22:34 +08:00
increment_function ( var_ptr ) ;
} else {
decrement_function ( var_ptr ) ;
}
if ( UNEXPECTED ( Z_TYPE_P ( var_ptr ) = = IS_DOUBLE ) & & Z_TYPE_P ( copy ) = = IS_LONG ) {
2019-07-03 15:33:03 +08:00
zend_long val = zend_throw_incdec_prop_error ( prop_info OPLINE_CC ) ;
ZVAL_LONG ( var_ptr , val ) ;
2019-01-16 05:22:34 +08:00
} else if ( UNEXPECTED ( ! zend_verify_property_type ( prop_info , var_ptr , EX_USES_STRICT_TYPES ( ) ) ) ) {
zval_ptr_dtor ( var_ptr ) ;
ZVAL_COPY_VALUE ( var_ptr , copy ) ;
2019-02-08 19:43:11 +08:00
ZVAL_UNDEF ( copy ) ;
2019-01-16 05:22:34 +08:00
} else if ( copy = = & tmp ) {
zval_ptr_dtor ( & tmp ) ;
}
}
2019-07-03 15:33:03 +08:00
static void zend_pre_incdec_property_zval ( zval * prop , zend_property_info * prop_info OPLINE_DC EXECUTE_DATA_DC )
2019-01-07 19:28:51 +08:00
{
if ( EXPECTED ( Z_TYPE_P ( prop ) = = IS_LONG ) ) {
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-07 19:28:51 +08:00
fast_long_increment_function ( prop ) ;
} else {
fast_long_decrement_function ( prop ) ;
}
if ( UNEXPECTED ( Z_TYPE_P ( prop ) ! = IS_LONG ) & & UNEXPECTED ( prop_info ) ) {
2019-07-03 15:33:03 +08:00
zend_long val = zend_throw_incdec_prop_error ( prop_info OPLINE_CC ) ;
ZVAL_LONG ( prop , val ) ;
2019-01-07 19:28:51 +08:00
}
} else {
2019-01-16 05:22:34 +08:00
do {
if ( Z_ISREF_P ( prop ) ) {
zend_reference * ref = Z_REF_P ( prop ) ;
if ( UNEXPECTED ( ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) ) {
2019-07-03 15:33:03 +08:00
zend_incdec_typed_ref ( ref , NULL OPLINE_CC EXECUTE_DATA_CC ) ;
2019-01-16 05:22:34 +08:00
break ;
2019-01-07 19:28:51 +08:00
}
2019-01-16 05:22:34 +08:00
prop = Z_REFVAL_P ( prop ) ;
2019-01-07 19:28:51 +08:00
}
2019-01-16 05:22:34 +08:00
if ( UNEXPECTED ( prop_info ) ) {
2019-07-03 15:33:03 +08:00
zend_incdec_typed_prop ( prop_info , prop , NULL OPLINE_CC EXECUTE_DATA_CC ) ;
} else if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-07 19:28:51 +08:00
increment_function ( prop ) ;
} else {
decrement_function ( prop ) ;
}
2019-01-16 05:22:34 +08:00
} while ( 0 ) ;
2019-01-07 19:28:51 +08:00
}
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , prop ) ;
}
}
2019-07-03 15:33:03 +08:00
static void zend_post_incdec_property_zval ( zval * prop , zend_property_info * prop_info OPLINE_DC EXECUTE_DATA_DC )
2019-01-07 19:28:51 +08:00
{
if ( EXPECTED ( Z_TYPE_P ( prop ) = = IS_LONG ) ) {
ZVAL_LONG ( EX_VAR ( opline - > result . var ) , Z_LVAL_P ( prop ) ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-07 19:28:51 +08:00
fast_long_increment_function ( prop ) ;
} else {
fast_long_decrement_function ( prop ) ;
}
if ( UNEXPECTED ( Z_TYPE_P ( prop ) ! = IS_LONG ) & & UNEXPECTED ( prop_info ) ) {
2019-07-03 15:33:03 +08:00
zend_long val = zend_throw_incdec_prop_error ( prop_info OPLINE_CC ) ;
ZVAL_LONG ( prop , val ) ;
2019-01-07 19:28:51 +08:00
}
} else {
if ( Z_ISREF_P ( prop ) ) {
2019-01-16 05:22:34 +08:00
zend_reference * ref = Z_REF_P ( prop ) ;
if ( ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) {
2019-07-03 15:33:03 +08:00
zend_incdec_typed_ref ( ref , EX_VAR ( opline - > result . var ) OPLINE_CC EXECUTE_DATA_CC ) ;
2019-01-16 05:22:34 +08:00
return ;
2019-01-07 19:28:51 +08:00
}
prop = Z_REFVAL_P ( prop ) ;
}
2019-01-16 05:22:34 +08:00
if ( UNEXPECTED ( prop_info ) ) {
2019-07-03 15:33:03 +08:00
zend_incdec_typed_prop ( prop_info , prop , EX_VAR ( opline - > result . var ) OPLINE_CC EXECUTE_DATA_CC ) ;
2019-01-07 19:28:51 +08:00
} else {
2019-01-16 05:22:34 +08:00
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , prop ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2019-01-07 19:28:51 +08:00
increment_function ( prop ) ;
} else {
decrement_function ( prop ) ;
}
}
}
}
2019-07-03 15:33:03 +08:00
static zend_never_inline void zend_post_incdec_overloaded_property ( zval * object , zval * property , void * * cache_slot OPLINE_DC EXECUTE_DATA_DC )
2015-06-03 23:44:25 +08:00
{
2018-10-13 21:30:27 +08:00
zval rv , obj ;
zval * z ;
zval z_copy ;
2015-06-03 23:44:25 +08:00
2018-10-13 21:30:27 +08:00
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 ) ) ;
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
return ;
}
2015-06-03 23:44:25 +08:00
2018-10-13 21:30:27 +08:00
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 ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
ZVAL_COPY_VALUE ( z , value ) ;
}
2015-08-10 17:12:33 +08:00
2018-10-13 21:30:27 +08:00
ZVAL_COPY_DEREF ( & z_copy , z ) ;
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , & z_copy ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2018-10-13 21:30:27 +08:00
increment_function ( & z_copy ) ;
2015-06-03 23:44:25 +08:00
} else {
2018-10-13 21:30:27 +08:00
decrement_function ( & z_copy ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
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 ) ;
2015-06-03 23:44:25 +08:00
}
2019-07-03 15:33:03 +08:00
static zend_never_inline void zend_pre_incdec_overloaded_property ( zval * object , zval * property , void * * cache_slot OPLINE_DC EXECUTE_DATA_DC )
2015-06-03 23:44:25 +08:00
{
zval rv ;
2018-10-13 21:30:27 +08:00
zval * z , obj ;
zval z_copy ;
2015-06-03 23:44:25 +08:00
2018-10-13 21:30:27 +08:00
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 ) ) ;
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_NULL ( EX_VAR ( opline - > result . var ) ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
return ;
}
2015-06-03 23:44:25 +08:00
2018-10-13 21:30:27 +08:00
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 ) ;
2015-06-03 23:44:25 +08:00
2018-10-13 21:30:27 +08:00
if ( z = = & rv ) {
zval_ptr_dtor ( & rv ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
ZVAL_COPY_VALUE ( z , value ) ;
}
ZVAL_COPY_DEREF ( & z_copy , z ) ;
2019-07-03 15:33:03 +08:00
if ( ZEND_IS_INCREMENT ( opline - > opcode ) ) {
2018-10-13 21:30:27 +08:00
increment_function ( & z_copy ) ;
2015-06-03 23:44:25 +08:00
} else {
2018-10-13 21:30:27 +08:00
decrement_function ( & z_copy ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , & 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 ) ;
2015-06-03 23:44:25 +08:00
}
2019-07-04 22:25:43 +08:00
static zend_never_inline void zend_assign_op_overloaded_property ( zval * object , zval * property , void * * cache_slot , zval * value OPLINE_DC EXECUTE_DATA_DC )
2015-06-03 23:44:25 +08:00
{
zval * z ;
2018-06-09 06:29:33 +08:00
zval rv , obj , res ;
2015-06-03 23:44:25 +08:00
ZVAL_OBJ ( & obj , Z_OBJ_P ( object ) ) ;
Z_ADDREF ( obj ) ;
2018-10-13 21:30:27 +08:00
z = Z_OBJ_HT ( obj ) - > read_property ( & obj , property , BP_VAR_R , cache_slot , & rv ) ;
if ( UNEXPECTED ( EG ( exception ) ) ) {
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
2018-02-21 04:44:25 +08:00
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
2018-10-13 21:30:27 +08:00
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
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 ) ;
2015-06-03 23:44:25 +08:00
}
2018-10-13 21:30:27 +08:00
ZVAL_COPY_VALUE ( z , value ) ;
2015-06-03 23:44:25 +08:00
}
2019-07-04 22:25:43 +08:00
if ( zend_binary_op ( & res , z , value OPLINE_CC ) = = SUCCESS ) {
2018-10-13 21:30:27 +08:00
Z_OBJ_HT ( obj ) - > write_property ( & obj , property , & res , cache_slot ) ;
}
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , & res ) ;
}
zval_ptr_dtor ( z ) ;
zval_ptr_dtor ( & res ) ;
2015-06-03 23:44:25 +08:00
OBJ_RELEASE ( Z_OBJ ( obj ) ) ;
}
1999-04-08 02:10:10 +08:00
/* Utility Functions for Extensions */
2016-05-04 16:25:59 +08:00
static void zend_extension_statement_handler ( const zend_extension * extension , zend_execute_data * frame )
1999-04-08 02:10:10 +08:00
{
if ( extension - > statement_handler ) {
2016-05-04 16:25:59 +08:00
extension - > statement_handler ( frame ) ;
1999-04-08 02:10:10 +08:00
}
}
2016-05-04 16:25:59 +08:00
static void zend_extension_fcall_begin_handler ( const zend_extension * extension , zend_execute_data * frame )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_begin_handler ) {
2016-05-04 16:25:59 +08:00
extension - > fcall_begin_handler ( frame ) ;
1999-04-08 02:10:10 +08:00
}
}
2016-05-04 16:25:59 +08:00
static void zend_extension_fcall_end_handler ( const zend_extension * extension , zend_execute_data * frame )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_end_handler ) {
2016-05-04 16:25:59 +08:00
extension - > fcall_end_handler ( frame ) ;
1999-04-08 02:10:10 +08:00
}
}
2017-06-16 06:42:49 +08:00
static zend_always_inline HashTable * zend_get_target_symbol_table ( int fetch_type EXECUTE_DATA_DC )
1999-04-08 02:10:10 +08:00
{
2014-04-08 04:38:54 +08:00
HashTable * ht ;
2018-01-31 03:06:05 +08:00
if ( EXPECTED ( fetch_type & ( ZEND_FETCH_GLOBAL_LOCK | ZEND_FETCH_GLOBAL ) ) ) {
2015-02-14 03:20:39 +08:00
ht = & EG ( symbol_table ) ;
2014-04-08 04:38:54 +08:00
} else {
2018-01-31 03:06:05 +08:00
ZEND_ASSERT ( fetch_type & ZEND_FETCH_LOCAL ) ;
2016-04-28 20:17:24 +08:00
if ( ! ( EX_CALL_INFO ( ) & ZEND_CALL_HAS_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
}
2018-02-16 07:45:31 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_offset ( zend_long lval )
{
zend_error ( E_NOTICE , " Undefined offset: " ZEND_LONG_FMT , lval ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_index ( const zend_string * offset )
{
zend_error ( E_NOTICE , " Undefined index: %s " , ZSTR_VAL ( offset ) ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_undefined_method ( const zend_class_entry * ce , const zend_string * method )
{
zend_throw_error ( NULL , " Call to undefined method %s::%s() " , ZSTR_VAL ( ce - > name ) , ZSTR_VAL ( method ) ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_invalid_method_call ( zval * object , zval * function_name )
{
zend_throw_error ( NULL , " Call to a member function %s() on %s " , Z_STRVAL_P ( function_name ) , zend_get_type_by_const ( Z_TYPE_P ( object ) ) ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_non_static_method_call ( const zend_function * fbc )
{
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 ) ) ;
} 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 ) ) ;
}
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_param_must_be_ref ( const zend_function * func , uint32_t arg_num )
{
zend_error ( E_WARNING , " Parameter %d to %s%s%s() expected to be a reference, value given " ,
arg_num ,
func - > common . scope ? ZSTR_VAL ( func - > common . scope - > name ) : " " ,
func - > common . scope ? " :: " : " " ,
ZSTR_VAL ( func - > common . function_name ) ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_scalar_as_array ( void )
{
zend_error ( E_WARNING , " Cannot use a scalar value as an array " ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element ( void )
{
zend_error ( E_WARNING , " Cannot add element to the array as the next element is already occupied " ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_resource_as_offset ( const zval * dim )
{
zend_error ( E_NOTICE , " Resource ID#%d used as offset, casting to integer (%d) " , Z_RES_HANDLE_P ( dim ) , Z_RES_HANDLE_P ( dim ) ) ;
}
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_use_new_element_for_string ( void )
{
zend_throw_error ( NULL , " [] operator not supported for strings " ) ;
}
2019-07-17 05:52:26 +08:00
static ZEND_COLD void zend_binary_assign_op_dim_slow ( zval * container , zval * dim OPLINE_DC EXECUTE_DATA_DC )
{
zend_free_op free_op_data1 ;
if ( UNEXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
if ( opline - > op2_type = = IS_UNUSED ) {
zend_use_new_element_for_string ( ) ;
} else {
zend_check_string_offset ( dim , BP_VAR_RW EXECUTE_DATA_CC ) ;
zend_wrong_string_offset ( EXECUTE_DATA_C ) ;
}
} else if ( EXPECTED ( ! Z_ISERROR_P ( container ) ) ) {
zend_use_scalar_as_array ( ) ;
}
get_op_data_zval_ptr_r ( ( opline + 1 ) - > op1_type , ( opline + 1 ) - > op1 , & free_op_data1 ) ;
FREE_OP ( free_op_data1 ) ;
}
2019-07-02 16:03:22 +08:00
static zend_never_inline zend_uchar slow_index_convert ( const zval * dim , zend_value * value EXECUTE_DATA_DC )
2019-07-02 06:16:34 +08:00
{
switch ( Z_TYPE_P ( dim ) ) {
case IS_UNDEF :
ZVAL_UNDEFINED_OP2 ( ) ;
/* break missing intentionally */
case IS_NULL :
value - > str = ZSTR_EMPTY_ALLOC ( ) ;
return IS_STRING ;
case IS_DOUBLE :
value - > lval = zend_dval_to_lval ( Z_DVAL_P ( dim ) ) ;
return IS_LONG ;
case IS_RESOURCE :
zend_use_resource_as_offset ( dim ) ;
value - > lval = Z_RES_HANDLE_P ( dim ) ;
return IS_LONG ;
case IS_FALSE :
value - > lval = 0 ;
return IS_LONG ;
case IS_TRUE :
value - > lval = 1 ;
return IS_LONG ;
default :
zend_illegal_offset ( ) ;
return IS_NULL ;
}
}
2017-06-16 06:42:49 +08:00
static zend_always_inline zval * zend_fetch_dimension_address_inner ( HashTable * ht , const zval * dim , int dim_type , int type EXECUTE_DATA_DC )
1999-04-08 02:10:10 +08:00
{
2018-02-22 16:33:26 +08:00
zval * retval = NULL ;
2014-02-10 14:04:30 +08:00
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 :
2016-05-04 22:33:35 +08:00
ZEND_HASH_INDEX_FIND ( ht , hval , retval , num_undef ) ;
return retval ;
num_undef :
switch ( type ) {
case BP_VAR_R :
2018-02-16 07:45:31 +08:00
zend_undefined_offset ( hval ) ;
2016-05-04 22:33:35 +08:00
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
2018-02-16 07:45:31 +08:00
zend_undefined_offset ( hval ) ;
2016-05-04 22:33:35 +08:00
retval = zend_hash_index_update ( ht , hval , & EG ( uninitialized_zval ) ) ;
break ;
case BP_VAR_W :
retval = zend_hash_index_add_new ( ht , hval , & EG ( uninitialized_zval ) ) ;
break ;
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 ) ;
2019-09-12 23:29:19 +08:00
if ( ZEND_CONST_COND ( dim_type ! = IS_CONST , 1 ) ) {
2018-07-03 01:54:44 +08:00
if ( ZEND_HANDLE_NUMERIC ( offset_key , hval ) ) {
goto num_index ;
}
2014-04-05 05:56:51 +08:00
}
str_index :
2019-09-12 23:29:19 +08:00
retval = zend_hash_find_ex ( ht , offset_key , ZEND_CONST_COND ( dim_type = = IS_CONST , 0 ) ) ;
2014-04-05 05:56:51 +08:00
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 :
2018-02-16 07:45:31 +08:00
zend_undefined_index ( 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 :
2018-02-16 07:45:31 +08:00
zend_undefined_index ( 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 :
2018-02-16 07:45:31 +08:00
zend_undefined_index ( 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 :
2018-02-16 07:45:31 +08:00
zend_undefined_index ( 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
}
2019-07-02 06:16:34 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( dim ) = = IS_REFERENCE ) ) {
dim = Z_REFVAL_P ( dim ) ;
goto try_again ;
2014-04-05 05:56:51 +08:00
} else {
2019-07-02 06:16:34 +08:00
zend_value val ;
2019-07-02 16:03:22 +08:00
zend_uchar t = slow_index_convert ( dim , & val EXECUTE_DATA_CC ) ;
2019-07-02 06:16:34 +08:00
if ( t = = IS_STRING ) {
offset_key = val . str ;
goto str_index ;
} else if ( t = = IS_LONG ) {
hval = val . lval ;
goto num_index ;
} else {
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 ;
}
2017-06-16 06:42:49 +08:00
static zend_never_inline zval * ZEND_FASTCALL zend_fetch_dimension_address_inner_W ( HashTable * ht , const zval * dim EXECUTE_DATA_DC )
2015-12-23 18:52:15 +08:00
{
2017-06-16 06:42:49 +08:00
return zend_fetch_dimension_address_inner ( ht , dim , IS_TMP_VAR , BP_VAR_W EXECUTE_DATA_CC ) ;
2015-12-23 18:52:15 +08:00
}
2017-06-16 06:42:49 +08:00
static zend_never_inline zval * ZEND_FASTCALL zend_fetch_dimension_address_inner_W_CONST ( HashTable * ht , const zval * dim EXECUTE_DATA_DC )
2014-10-21 23:30:43 +08:00
{
2017-06-16 06:42:49 +08:00
return zend_fetch_dimension_address_inner ( ht , dim , IS_CONST , BP_VAR_W EXECUTE_DATA_CC ) ;
2014-10-21 23:30:43 +08:00
}
2017-06-16 06:42:49 +08:00
static zend_never_inline zval * ZEND_FASTCALL zend_fetch_dimension_address_inner_RW ( HashTable * ht , const zval * dim EXECUTE_DATA_DC )
2016-04-14 07:35:53 +08:00
{
2017-06-16 06:42:49 +08:00
return zend_fetch_dimension_address_inner ( ht , dim , IS_TMP_VAR , BP_VAR_RW EXECUTE_DATA_CC ) ;
2016-04-14 07:35:53 +08:00
}
2017-06-16 06:42:49 +08:00
static zend_never_inline zval * ZEND_FASTCALL zend_fetch_dimension_address_inner_RW_CONST ( HashTable * ht , const zval * dim EXECUTE_DATA_DC )
2016-04-14 07:35:53 +08:00
{
2017-06-16 06:42:49 +08:00
return zend_fetch_dimension_address_inner ( ht , dim , IS_CONST , BP_VAR_RW EXECUTE_DATA_CC ) ;
2016-04-14 07:35:53 +08:00
}
2017-06-16 06:42:49 +08:00
static zend_always_inline void zend_fetch_dimension_address ( zval * result , zval * container , zval * dim , int dim_type , int type EXECUTE_DATA_DC )
1999-04-08 02:10:10 +08:00
{
2019-01-18 17:43:42 +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 ) ) {
2018-02-16 07:45:31 +08:00
zend_cannot_add_element ( ) ;
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 {
2017-06-16 06:42:49 +08:00
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type EXECUTE_DATA_CC ) ;
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 ) ) {
2019-01-18 17:43:42 +08:00
zend_reference * ref = Z_REF_P ( container ) ;
2015-06-01 22:22:04 +08:00
container = Z_REFVAL_P ( container ) ;
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
goto try_array ;
2019-01-18 17:43:42 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( container ) < = IS_FALSE ) ) {
if ( type ! = BP_VAR_UNSET ) {
if ( ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) {
2019-06-21 16:43:17 +08:00
if ( UNEXPECTED ( ! zend_verify_ref_array_assignable ( ref ) ) ) {
2019-01-18 17:43:42 +08:00
ZVAL_ERROR ( result ) ;
return ;
}
}
array_init ( container ) ;
goto fetch_from_array ;
} else {
goto return_null ;
}
2015-06-01 22:22:04 +08:00
}
}
2016-06-08 21:33:11 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
2015-04-01 19:50:09 +08:00
if ( dim = = NULL ) {
2018-02-16 07:45:31 +08:00
zend_use_new_element_for_string ( ) ;
2015-04-01 19:50:09 +08:00
} else {
2017-06-16 06:42:49 +08:00
zend_check_string_offset ( dim , type EXECUTE_DATA_CC ) ;
2018-06-27 18:34:15 +08:00
zend_wrong_string_offset ( EXECUTE_DATA_C ) ;
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 ) ) {
2019-09-12 23:29:19 +08:00
if ( ZEND_CONST_COND ( dim_type = = IS_CV , dim ! = NULL ) & & UNEXPECTED ( Z_TYPE_P ( dim ) = = IS_UNDEF ) ) {
2018-12-18 22:34:18 +08:00
dim = ZVAL_UNDEFINED_OP2 ( ) ;
2016-04-13 06:19:20 +08:00
}
2018-10-13 21:30:27 +08:00
if ( dim_type = = IS_CONST & & Z_EXTRA_P ( dim ) = = ZEND_EXTRA_VALUE ) {
dim + + ;
}
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result ) ;
2014-04-05 05:56:51 +08:00
2018-10-13 21:30:27 +08:00
if ( UNEXPECTED ( retval = = & EG ( uninitialized_zval ) ) ) {
zend_class_entry * ce = Z_OBJCE_P ( container ) ;
2014-07-09 17:30:47 +08:00
2018-10-13 21:30:27 +08:00
ZVAL_NULL ( result ) ;
zend_error ( E_NOTICE , " Indirect modification of overloaded element of %s has no effect " , ZSTR_VAL ( ce - > name ) ) ;
} else if ( EXPECTED ( retval & & Z_TYPE_P ( retval ) ! = IS_UNDEF ) ) {
if ( ! Z_ISREF_P ( retval ) ) {
2014-04-05 05:56:51 +08:00
if ( result ! = retval ) {
2018-10-13 21:30:27 +08:00
ZVAL_COPY ( result , retval ) ;
retval = result ;
2005-06-03 19:16:19 +08:00
}
2018-10-13 21:30:27 +08:00
if ( Z_TYPE_P ( retval ) ! = IS_OBJECT ) {
zend_class_entry * ce = Z_OBJCE_P ( container ) ;
zend_error ( E_NOTICE , " Indirect modification of overloaded element of %s has no effect " , ZSTR_VAL ( ce - > name ) ) ;
}
} else if ( UNEXPECTED ( Z_REFCOUNT_P ( retval ) = = 1 ) ) {
ZVAL_UNREF ( retval ) ;
2007-12-14 22:14:50 +08:00
}
2018-10-13 21:30:27 +08:00
if ( result ! = retval ) {
ZVAL_INDIRECT ( result , retval ) ;
}
} else {
ZVAL_ERROR ( result ) ;
2014-04-05 05:56:51 +08:00
}
} else {
2016-04-13 06:19:20 +08:00
if ( EXPECTED ( Z_TYPE_P ( container ) < = IS_FALSE ) ) {
2019-01-18 17:43:42 +08:00
if ( type ! = BP_VAR_W & & UNEXPECTED ( Z_TYPE_P ( container ) = = IS_UNDEF ) ) {
ZVAL_UNDEFINED_OP1 ( ) ;
}
2016-04-13 06:19:20 +08:00
if ( type ! = BP_VAR_UNSET ) {
2019-01-18 17:43:42 +08:00
array_init ( container ) ;
goto fetch_from_array ;
2016-04-13 06:19:20 +08:00
} else {
2019-01-18 17:43:42 +08:00
return_null :
2016-04-13 06:19:20 +08:00
/* for read-mode only */
2019-09-12 23:29:19 +08:00
if ( ZEND_CONST_COND ( dim_type = = IS_CV , dim ! = NULL ) & & UNEXPECTED ( Z_TYPE_P ( dim ) = = IS_UNDEF ) ) {
2019-01-18 17:43:42 +08:00
ZVAL_UNDEFINED_OP2 ( ) ;
}
2016-04-13 06:19:20 +08:00
ZVAL_NULL ( result ) ;
}
} else if ( EXPECTED ( Z_ISERROR_P ( container ) ) ) {
2016-01-28 23:00:06 +08:00
ZVAL_ERROR ( result ) ;
2016-04-13 06:19:20 +08:00
} else {
if ( type = = BP_VAR_UNSET ) {
zend_error ( E_WARNING , " Cannot unset offset in a non-array variable " ) ;
ZVAL_NULL ( result ) ;
} else {
2018-02-16 07:45:31 +08:00
zend_use_scalar_as_array ( ) ;
2016-04-13 06:19:20 +08:00
ZVAL_ERROR ( result ) ;
}
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
}
}
2018-02-21 21:06:29 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_W ( zval * container_ptr , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2007-12-14 22:14:50 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2017-06-16 06:42:49 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_W EXECUTE_DATA_CC ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2018-02-21 21:06:29 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_RW ( zval * container_ptr , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2014-04-05 05:56:51 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2017-06-16 06:42:49 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_RW EXECUTE_DATA_CC ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2018-02-21 21:06:29 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_UNSET ( zval * container_ptr , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2014-04-05 05:56:51 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2017-06-16 06:42:49 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_UNSET EXECUTE_DATA_CC ) ;
2014-04-05 05:56:51 +08:00
}
2007-12-14 22:14:50 +08:00
2019-07-10 16:17:40 +08:00
static zend_always_inline void zend_fetch_dimension_address_read ( zval * result , zval * container , zval * dim , int dim_type , int type , int is_list , int slow EXECUTE_DATA_DC )
2014-04-05 05:56:51 +08:00
{
zval * retval ;
2010-07-16 21:38:09 +08:00
2016-05-17 20:08:04 +08:00
if ( ! slow ) {
2015-06-01 22:22:04 +08:00
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
2016-05-17 20:08:04 +08:00
try_array :
2017-06-16 06:42:49 +08:00
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type EXECUTE_DATA_CC ) ;
2018-06-25 20:23:06 +08:00
ZVAL_COPY_DEREF ( result , retval ) ;
2016-05-17 20:08: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 ;
}
2015-06-01 22:22:04 +08:00
}
}
2019-07-10 16:17:40 +08:00
if ( ! is_list & & 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 ;
2016-04-13 05:05:19 +08:00
case IS_UNDEF :
2018-12-18 22:34:18 +08:00
ZVAL_UNDEFINED_OP2 ( ) ;
2014-04-05 05:56:51 +08:00
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 :
2018-02-16 07:45:31 +08:00
zend_illegal_offset ( ) ;
2014-04-05 05:56:51 +08:00
break ;
2007-12-14 22:14:50 +08:00
}
2017-11-16 22:09:01 +08:00
offset = zval_get_long_func ( 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 ) {
2016-06-21 21:00:37 +08:00
zend_error ( E_NOTICE , " Uninitialized string offset: " ZEND_LONG_FMT , 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
2017-03-04 17:39:13 +08:00
ZVAL_INTERNED_STR ( result , ZSTR_CHAR ( c ) ) ;
2014-04-05 05:56:51 +08:00
}
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
2019-09-12 23:29:19 +08:00
if ( ZEND_CONST_COND ( dim_type = = IS_CV , 1 ) & & UNEXPECTED ( Z_TYPE_P ( dim ) = = IS_UNDEF ) ) {
2018-12-18 22:34:18 +08:00
dim = ZVAL_UNDEFINED_OP2 ( ) ;
2016-04-13 05:05:19 +08:00
}
2018-10-13 21:30:27 +08:00
if ( dim_type = = IS_CONST & & Z_EXTRA_P ( dim ) = = ZEND_EXTRA_VALUE ) {
dim + + ;
}
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result ) ;
2014-04-05 05:56:51 +08:00
2018-10-13 21:30:27 +08:00
ZEND_ASSERT ( result ! = NULL ) ;
if ( retval ) {
if ( result ! = retval ) {
ZVAL_COPY_DEREF ( result , retval ) ;
} else if ( UNEXPECTED ( Z_ISREF_P ( retval ) ) ) {
zend_unwrap_reference ( result ) ;
1999-04-08 02:10:10 +08:00
}
2018-10-13 21:30:27 +08:00
} else {
ZVAL_NULL ( result ) ;
2014-04-05 05:56:51 +08:00
}
} else {
2016-04-13 05:05:19 +08:00
if ( type ! = BP_VAR_IS & & UNEXPECTED ( Z_TYPE_P ( container ) = = IS_UNDEF ) ) {
2019-07-10 16:28:58 +08:00
container = ZVAL_UNDEFINED_OP1 ( ) ;
2016-04-13 05:05:19 +08:00
}
2019-09-12 23:29:19 +08:00
if ( ZEND_CONST_COND ( dim_type = = IS_CV , 1 ) & & UNEXPECTED ( Z_TYPE_P ( dim ) = = IS_UNDEF ) ) {
2018-12-18 22:34:18 +08:00
ZVAL_UNDEFINED_OP2 ( ) ;
2016-04-13 05:05:19 +08:00
}
2019-07-10 16:28:58 +08:00
if ( ! is_list & & type ! = BP_VAR_IS ) {
zend_error ( E_NOTICE , " Trying to access array offset on value of type %s " ,
zend_zval_type_name ( container ) ) ;
}
2014-04-05 05:56:51 +08:00
ZVAL_NULL ( result ) ;
1999-04-08 02:10:10 +08:00
}
}
2018-02-21 21:06:29 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_R ( zval * container , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2014-04-05 05:56:51 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2019-07-10 16:17:40 +08:00
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_R , 0 , 0 EXECUTE_DATA_CC ) ;
2016-05-17 20:08:04 +08:00
}
2018-02-22 16:00:29 +08:00
static zend_never_inline void zend_fetch_dimension_address_read_R_slow ( zval * container , zval * dim OPLINE_DC EXECUTE_DATA_DC )
2016-05-17 20:08:04 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2019-07-10 16:17:40 +08:00
zend_fetch_dimension_address_read ( result , container , dim , IS_CV , BP_VAR_R , 0 , 1 EXECUTE_DATA_CC ) ;
2014-04-05 05:56:51 +08:00
}
2018-02-21 21:06:29 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_read_IS ( zval * container , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2014-04-05 05:56:51 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2019-07-10 16:17:40 +08:00
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_IS , 0 , 0 EXECUTE_DATA_CC ) ;
2016-04-13 03:53:01 +08:00
}
2018-07-03 06:09:58 +08:00
static zend_never_inline void ZEND_FASTCALL zend_fetch_dimension_address_LIST_r ( zval * container , zval * dim , int dim_type OPLINE_DC EXECUTE_DATA_DC )
2016-04-13 03:53:01 +08:00
{
2018-02-21 21:06:29 +08:00
zval * result = EX_VAR ( opline - > result . var ) ;
2019-07-10 16:17:40 +08:00
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_R , 1 , 0 EXECUTE_DATA_CC ) ;
2014-04-05 05:56:51 +08:00
}
2017-06-16 03:50:04 +08:00
ZEND_API void zend_fetch_dimension_const ( zval * result , zval * container , zval * dim , int type )
2014-08-04 17:56:27 +08:00
{
2019-07-10 16:17:40 +08:00
zend_fetch_dimension_address_read ( result , container , dim , IS_TMP_VAR , type , 0 , 0 NO_EXECUTE_DATA_CC ) ;
2016-04-17 16:27:15 +08:00
}
2018-02-20 19:42:53 +08:00
static zend_never_inline zval * ZEND_FASTCALL zend_find_array_dim_slow ( HashTable * ht , zval * offset EXECUTE_DATA_DC )
{
zend_ulong hval ;
if ( Z_TYPE_P ( offset ) = = IS_DOUBLE ) {
hval = zend_dval_to_lval ( Z_DVAL_P ( offset ) ) ;
num_idx :
return zend_hash_index_find ( ht , hval ) ;
} else if ( Z_TYPE_P ( offset ) = = IS_NULL ) {
str_idx :
return zend_hash_find_ex_ind ( ht , ZSTR_EMPTY_ALLOC ( ) , 1 ) ;
} else if ( Z_TYPE_P ( offset ) = = IS_FALSE ) {
hval = 0 ;
goto num_idx ;
} else if ( Z_TYPE_P ( offset ) = = IS_TRUE ) {
hval = 1 ;
goto num_idx ;
} else if ( Z_TYPE_P ( offset ) = = IS_RESOURCE ) {
hval = Z_RES_HANDLE_P ( offset ) ;
goto num_idx ;
} else if ( /*OP2_TYPE == IS_CV &&*/ Z_TYPE_P ( offset ) = = IS_UNDEF ) {
2018-12-18 22:34:18 +08:00
ZVAL_UNDEFINED_OP2 ( ) ;
2018-02-20 19:42:53 +08:00
goto str_idx ;
} else {
zend_error ( E_WARNING , " Illegal offset type in isset or empty " ) ;
return NULL ;
}
}
static zend_never_inline int ZEND_FASTCALL zend_isset_dim_slow ( zval * container , zval * offset EXECUTE_DATA_DC )
{
if ( /*OP2_TYPE == IS_CV &&*/ UNEXPECTED ( Z_TYPE_P ( offset ) = = IS_UNDEF ) ) {
2018-12-18 22:34:18 +08:00
offset = ZVAL_UNDEFINED_OP2 ( ) ;
2018-02-20 19:42:53 +08:00
}
if ( /*OP1_TYPE != IS_CONST &&*/ EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
2018-10-13 21:30:27 +08:00
return Z_OBJ_HT_P ( container ) - > has_dimension ( container , offset , 0 ) ;
2018-02-20 19:42:53 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) { /* string offsets */
zend_long lval ;
if ( EXPECTED ( Z_TYPE_P ( offset ) = = IS_LONG ) ) {
lval = Z_LVAL_P ( offset ) ;
str_offset :
if ( UNEXPECTED ( lval < 0 ) ) { /* Handle negative offset */
lval + = ( zend_long ) Z_STRLEN_P ( container ) ;
}
if ( EXPECTED ( lval > = 0 ) & & ( size_t ) lval < Z_STRLEN_P ( container ) ) {
return 1 ;
} else {
return 0 ;
}
} else {
/*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
ZVAL_DEREF ( offset ) ;
/*}*/
if ( Z_TYPE_P ( offset ) < IS_STRING /* simple scalar types */
| | ( Z_TYPE_P ( offset ) = = IS_STRING /* or numeric string */
& & IS_LONG = = is_numeric_string ( Z_STRVAL_P ( offset ) , Z_STRLEN_P ( offset ) , NULL , NULL , 0 ) ) ) {
lval = zval_get_long ( offset ) ;
goto str_offset ;
}
return 0 ;
}
} else {
return 0 ;
}
}
static zend_never_inline int ZEND_FASTCALL zend_isempty_dim_slow ( zval * container , zval * offset EXECUTE_DATA_DC )
{
if ( /*OP2_TYPE == IS_CV &&*/ UNEXPECTED ( Z_TYPE_P ( offset ) = = IS_UNDEF ) ) {
2018-12-18 22:34:18 +08:00
offset = ZVAL_UNDEFINED_OP2 ( ) ;
2018-02-20 19:42:53 +08:00
}
if ( /*OP1_TYPE != IS_CONST &&*/ EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
2018-10-13 21:30:27 +08:00
return ! Z_OBJ_HT_P ( container ) - > has_dimension ( container , offset , 1 ) ;
2018-02-20 19:42:53 +08:00
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) { /* string offsets */
zend_long lval ;
if ( EXPECTED ( Z_TYPE_P ( offset ) = = IS_LONG ) ) {
lval = Z_LVAL_P ( offset ) ;
str_offset :
if ( UNEXPECTED ( lval < 0 ) ) { /* Handle negative offset */
lval + = ( zend_long ) Z_STRLEN_P ( container ) ;
}
if ( EXPECTED ( lval > = 0 ) & & ( size_t ) lval < Z_STRLEN_P ( container ) ) {
return ( Z_STRVAL_P ( container ) [ lval ] = = ' 0 ' ) ;
} else {
return 1 ;
}
} else {
/*if (OP2_TYPE & (IS_CV|IS_VAR)) {*/
ZVAL_DEREF ( offset ) ;
/*}*/
if ( Z_TYPE_P ( offset ) < IS_STRING /* simple scalar types */
| | ( Z_TYPE_P ( offset ) = = IS_STRING /* or numeric string */
& & IS_LONG = = is_numeric_string ( Z_STRVAL_P ( offset ) , Z_STRLEN_P ( offset ) , NULL , NULL , 0 ) ) ) {
lval = zval_get_long ( offset ) ;
goto str_offset ;
}
return 1 ;
}
} else {
return 1 ;
}
}
2018-12-27 07:34:52 +08:00
static zend_never_inline uint32_t ZEND_FASTCALL zend_array_key_exists_fast ( HashTable * ht , zval * key OPLINE_DC EXECUTE_DATA_DC )
{
zend_string * str ;
zend_ulong hval ;
try_again :
if ( EXPECTED ( Z_TYPE_P ( key ) = = IS_STRING ) ) {
str = Z_STR_P ( key ) ;
if ( ZEND_HANDLE_NUMERIC ( str , hval ) ) {
goto num_key ;
}
str_key :
return zend_hash_find_ind ( ht , str ) ! = NULL ? IS_TRUE : IS_FALSE ;
} else if ( EXPECTED ( Z_TYPE_P ( key ) = = IS_LONG ) ) {
hval = Z_LVAL_P ( key ) ;
num_key :
return zend_hash_index_find ( ht , hval ) ! = NULL ? IS_TRUE : IS_FALSE ;
} else if ( EXPECTED ( Z_ISREF_P ( key ) ) ) {
key = Z_REFVAL_P ( key ) ;
goto try_again ;
} else if ( Z_TYPE_P ( key ) < = IS_NULL ) {
if ( UNEXPECTED ( Z_TYPE_P ( key ) = = IS_UNDEF ) ) {
ZVAL_UNDEFINED_OP1 ( ) ;
}
str = ZSTR_EMPTY_ALLOC ( ) ;
goto str_key ;
} else {
zend_error ( E_WARNING , " array_key_exists(): The first argument should be either a string or an integer " ) ;
return IS_FALSE ;
}
}
static zend_never_inline uint32_t ZEND_FASTCALL zend_array_key_exists_slow ( zval * subject , zval * key OPLINE_DC EXECUTE_DATA_DC )
{
if ( EXPECTED ( Z_TYPE_P ( subject ) = = IS_OBJECT ) ) {
2019-07-11 19:35:44 +08:00
zend_error ( E_DEPRECATED , " array_key_exists(): "
" Using array_key_exists() on objects is deprecated. "
" Use isset() or property_exists() instead " ) ;
2018-12-27 07:34:52 +08:00
HashTable * ht = zend_get_properties_for ( subject , ZEND_PROP_PURPOSE_ARRAY_CAST ) ;
uint32_t result = zend_array_key_exists_fast ( ht , key OPLINE_CC EXECUTE_DATA_CC ) ;
zend_release_properties ( ht ) ;
return result ;
} else {
if ( UNEXPECTED ( Z_TYPE_P ( key ) = = IS_UNDEF ) ) {
ZVAL_UNDEFINED_OP1 ( ) ;
}
if ( UNEXPECTED ( Z_TYPE_INFO_P ( subject ) = = IS_UNDEF ) ) {
ZVAL_UNDEFINED_OP2 ( ) ;
}
zend_internal_type_error ( EX_USES_STRICT_TYPES ( ) , " array_key_exists() expects parameter 2 to be array, %s given " , zend_get_type_by_const ( Z_TYPE_P ( subject ) ) ) ;
return IS_NULL ;
}
}
2019-01-07 19:28:51 +08:00
static zend_always_inline zend_bool promotes_to_array ( zval * val ) {
return Z_TYPE_P ( val ) < = IS_FALSE
| | ( Z_ISREF_P ( val ) & & Z_TYPE_P ( Z_REFVAL_P ( val ) ) < = IS_FALSE ) ;
}
static zend_always_inline zend_bool promotes_to_object ( zval * val ) {
ZVAL_DEREF ( val ) ;
return Z_TYPE_P ( val ) < = IS_FALSE
| | ( Z_TYPE_P ( val ) = = IS_STRING & & Z_STRLEN_P ( val ) = = 0 ) ;
}
static zend_always_inline zend_bool check_type_array_assignable ( zend_type type ) {
if ( ! type ) {
return 1 ;
}
return ZEND_TYPE_IS_CODE ( type )
& & ( ZEND_TYPE_CODE ( type ) = = IS_ARRAY | | ZEND_TYPE_CODE ( type ) = = IS_ITERABLE ) ;
}
static zend_always_inline zend_bool check_type_stdClass_assignable ( zend_type type ) {
if ( ! type ) {
return 1 ;
}
if ( ZEND_TYPE_IS_CLASS ( type ) ) {
if ( ZEND_TYPE_IS_CE ( type ) ) {
return ZEND_TYPE_CE ( type ) = = zend_standard_class_def ;
} else {
return zend_string_equals_literal_ci ( ZEND_TYPE_NAME ( type ) , " stdclass " ) ;
}
} else {
return ZEND_TYPE_CODE ( type ) = = IS_OBJECT ;
}
}
/* Checks whether an array can be assigned to the reference. Returns conflicting property if
* assignment is not possible , NULL otherwise . */
2019-06-21 16:43:17 +08:00
static zend_never_inline zend_bool zend_verify_ref_array_assignable ( zend_reference * ref ) {
2019-01-07 19:28:51 +08:00
zend_property_info * prop ;
2019-06-21 16:43:17 +08:00
ZEND_ASSERT ( ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) ;
2019-01-07 19:28:51 +08:00
ZEND_REF_FOREACH_TYPE_SOURCES ( ref , prop ) {
if ( ! check_type_array_assignable ( prop - > type ) ) {
2019-06-21 16:43:17 +08:00
zend_throw_auto_init_in_ref_error ( prop , " array " ) ;
return 0 ;
2019-01-07 19:28:51 +08:00
}
} ZEND_REF_FOREACH_TYPE_SOURCES_END ( ) ;
2019-06-21 16:43:17 +08:00
return 1 ;
2019-01-07 19:28:51 +08:00
}
/* Checks whether an stdClass can be assigned to the reference. Returns conflicting property if
* assignment is not possible , NULL otherwise . */
2019-06-21 16:43:17 +08:00
static zend_never_inline zend_bool zend_verify_ref_stdClass_assignable ( zend_reference * ref ) {
2019-01-07 19:28:51 +08:00
zend_property_info * prop ;
2019-06-21 16:43:17 +08:00
ZEND_ASSERT ( ZEND_REF_HAS_TYPE_SOURCES ( ref ) ) ;
2019-01-07 19:28:51 +08:00
ZEND_REF_FOREACH_TYPE_SOURCES ( ref , prop ) {
if ( ! check_type_stdClass_assignable ( prop - > type ) ) {
2019-06-21 16:43:17 +08:00
zend_throw_auto_init_in_ref_error ( prop , " stdClass " ) ;
return 0 ;
2019-01-07 19:28:51 +08:00
}
} ZEND_REF_FOREACH_TYPE_SOURCES_END ( ) ;
2019-06-21 16:43:17 +08:00
return 1 ;
2019-01-07 19:28:51 +08:00
}
2019-01-18 06:22:14 +08:00
static zend_property_info * zend_object_fetch_property_type_info (
zend_object * obj , zval * slot )
{
if ( EXPECTED ( ! ZEND_CLASS_HAS_TYPE_HINTS ( obj - > ce ) ) ) {
return NULL ;
}
/* Not a declared property */
if ( UNEXPECTED ( slot < obj - > properties_table | |
slot > = obj - > properties_table + obj - > ce - > default_properties_count ) ) {
return NULL ;
}
return zend_get_typed_property_info_for_slot ( obj , slot ) ;
2019-01-07 19:28:51 +08:00
}
static zend_never_inline zend_bool zend_handle_fetch_obj_flags (
2019-01-18 06:22:14 +08:00
zval * result , zval * ptr , zend_object * obj , zend_property_info * prop_info , uint32_t flags )
2019-01-07 19:28:51 +08:00
{
switch ( flags ) {
case ZEND_FETCH_DIM_WRITE :
2019-01-18 06:22:14 +08:00
if ( promotes_to_array ( ptr ) ) {
if ( ! prop_info ) {
prop_info = zend_object_fetch_property_type_info ( obj , ptr ) ;
if ( ! prop_info ) {
break ;
}
}
if ( ! check_type_array_assignable ( prop_info - > type ) ) {
zend_throw_auto_init_in_prop_error ( prop_info , " array " ) ;
if ( result ) ZVAL_ERROR ( result ) ;
return 0 ;
}
2019-01-07 19:28:51 +08:00
}
break ;
case ZEND_FETCH_OBJ_WRITE :
2019-01-18 06:22:14 +08:00
if ( promotes_to_object ( ptr ) ) {
if ( ! prop_info ) {
prop_info = zend_object_fetch_property_type_info ( obj , ptr ) ;
if ( ! prop_info ) {
break ;
}
}
if ( ! check_type_stdClass_assignable ( prop_info - > type ) ) {
zend_throw_auto_init_in_prop_error ( prop_info , " stdClass " ) ;
2019-01-07 19:28:51 +08:00
if ( result ) ZVAL_ERROR ( result ) ;
return 0 ;
}
2019-01-18 06:22:14 +08:00
}
break ;
case ZEND_FETCH_REF :
if ( Z_TYPE_P ( ptr ) ! = IS_REFERENCE ) {
if ( ! prop_info ) {
prop_info = zend_object_fetch_property_type_info ( obj , ptr ) ;
if ( ! prop_info ) {
break ;
}
}
if ( Z_TYPE_P ( ptr ) = = IS_UNDEF ) {
if ( ! ZEND_TYPE_ALLOW_NULL ( prop_info - > type ) ) {
zend_throw_access_uninit_prop_by_ref_error ( prop_info ) ;
if ( result ) ZVAL_ERROR ( result ) ;
return 0 ;
}
ZVAL_NULL ( ptr ) ;
}
2019-01-07 19:28:51 +08:00
2019-01-18 06:22:14 +08:00
ZVAL_NEW_REF ( ptr , ptr ) ;
ZEND_REF_ADD_TYPE_SOURCE ( Z_REF_P ( ptr ) , prop_info ) ;
}
2019-01-07 19:28:51 +08:00
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
return 1 ;
}
2019-02-14 21:01:39 +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 , uint32_t flags , zend_bool init_undef OPLINE_DC EXECUTE_DATA_DC )
1999-04-08 02:10:10 +08:00
{
2018-10-13 21:30:27 +08:00
zval * ptr ;
2019-01-07 19:28:51 +08:00
if ( container_op_type ! = IS_UNUSED & & UNEXPECTED ( Z_TYPE_P ( container ) ! = IS_OBJECT ) ) {
2014-12-09 06:09:44 +08:00
do {
2019-01-07 19:28:51 +08:00
if ( Z_ISREF_P ( container ) & & Z_TYPE_P ( Z_REFVAL_P ( container ) ) = = IS_OBJECT ) {
2014-12-09 06:09:44 +08:00
container = Z_REFVAL_P ( container ) ;
2019-01-07 19:28:51 +08:00
break ;
2014-12-09 06:09:44 +08:00
}
2019-07-16 16:16:45 +08:00
if ( container_op_type = = IS_CV
& & type ! = BP_VAR_W
& & UNEXPECTED ( Z_TYPE_P ( container ) = = IS_UNDEF ) ) {
container = ZVAL_UNDEFINED_OP1 ( ) ;
}
2014-10-10 20:36:12 +08:00
/* this should modify object only if it's empty */
2019-01-07 19:28:51 +08:00
if ( type = = BP_VAR_UNSET ) {
return ;
}
2019-02-14 21:01:39 +08:00
container = make_real_object ( container , prop_ptr OPLINE_CC EXECUTE_DATA_CC ) ;
2019-01-07 19:28:51 +08:00
if ( UNEXPECTED ( ! container ) ) {
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 ) ) ) {
2017-10-25 16:45:17 +08:00
uintptr_t prop_offset = ( uintptr_t ) CACHED_PTR_EX ( cache_slot + 1 ) ;
2014-11-06 19:50:03 +08:00
zend_object * zobj = Z_OBJ_P ( container ) ;
2017-09-18 18:13:24 +08:00
if ( EXPECTED ( IS_VALID_PROPERTY_OFFSET ( prop_offset ) ) ) {
2019-01-07 19:28:51 +08:00
ptr = OBJ_PROP ( zobj , prop_offset ) ;
if ( EXPECTED ( Z_TYPE_P ( ptr ) ! = IS_UNDEF ) ) {
ZVAL_INDIRECT ( result , ptr ) ;
2019-01-18 06:22:14 +08:00
if ( flags ) {
zend_property_info * prop_info = CACHED_PTR_EX ( cache_slot + 2 ) ;
if ( prop_info ) {
zend_handle_fetch_obj_flags ( result , ptr , NULL , prop_info , flags ) ;
}
2019-01-07 19:28:51 +08:00
}
2014-11-06 19:50:03 +08:00
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 ) ) ) {
2017-10-27 06:28:58 +08:00
GC_DELREF ( zobj - > properties ) ;
2015-12-09 21:07:59 +08:00
}
zobj - > properties = zend_array_dup ( zobj - > properties ) ;
}
2019-01-07 19:28:51 +08:00
ptr = zend_hash_find_ex ( zobj - > properties , Z_STR_P ( prop_ptr ) , 1 ) ;
if ( EXPECTED ( ptr ) ) {
ZVAL_INDIRECT ( result , ptr ) ;
2014-11-06 19:50:03 +08:00
return ;
}
}
}
2018-10-13 21:30:27 +08:00
ptr = Z_OBJ_HT_P ( container ) - > get_property_ptr_ptr ( container , prop_ptr , type , cache_slot ) ;
if ( NULL = = ptr ) {
ptr = Z_OBJ_HT_P ( container ) - > read_property ( container , prop_ptr , type , cache_slot , result ) ;
2019-01-07 19:28:51 +08:00
if ( ptr = = result ) {
if ( UNEXPECTED ( Z_ISREF_P ( ptr ) & & Z_REFCOUNT_P ( ptr ) = = 1 ) ) {
ZVAL_UNREF ( ptr ) ;
}
return ;
}
}
ZVAL_INDIRECT ( result , ptr ) ;
2019-01-18 06:22:14 +08:00
if ( flags ) {
zend_property_info * prop_info ;
if ( prop_op_type = = IS_CONST ) {
prop_info = CACHED_PTR_EX ( cache_slot + 2 ) ;
if ( prop_info ) {
if ( UNEXPECTED ( ! zend_handle_fetch_obj_flags ( result , ptr , NULL , prop_info , flags ) ) ) {
return ;
}
}
} else {
if ( UNEXPECTED ( ! zend_handle_fetch_obj_flags ( result , ptr , Z_OBJ_P ( container ) , NULL , flags ) ) ) {
return ;
}
2019-01-07 19:28:51 +08:00
}
}
if ( init_undef & & UNEXPECTED ( Z_TYPE_P ( ptr ) = = IS_UNDEF ) ) {
ZVAL_NULL ( ptr ) ;
}
}
2019-06-06 18:13:09 +08:00
static zend_always_inline void zend_assign_to_property_reference ( zval * container , uint32_t container_op_type , zval * prop_ptr , uint32_t prop_op_type , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
{
zval variable , * variable_ptr = & variable ;
void * * cache_addr = ( prop_op_type = = IS_CONST ) ? CACHE_ADDR ( opline - > extended_value & ~ ZEND_RETURNS_FUNCTION ) : NULL ;
zend_fetch_property_address ( variable_ptr , container , container_op_type , prop_ptr , prop_op_type ,
cache_addr , BP_VAR_W , 0 , 0 OPLINE_CC EXECUTE_DATA_CC ) ;
if ( Z_TYPE_P ( variable_ptr ) = = IS_INDIRECT ) {
variable_ptr = Z_INDIRECT_P ( variable_ptr ) ;
}
if ( UNEXPECTED ( Z_ISERROR_P ( variable_ptr ) ) ) {
variable_ptr = & EG ( uninitialized_zval ) ;
} else if ( UNEXPECTED ( Z_TYPE ( variable ) ! = IS_INDIRECT ) ) {
zend_throw_error ( NULL , " Cannot assign by reference to overloaded object " ) ;
variable_ptr = & EG ( uninitialized_zval ) ;
} else if ( /*OP_DATA_TYPE == IS_VAR &&*/ UNEXPECTED ( Z_ISERROR_P ( value_ptr ) ) ) {
variable_ptr = & EG ( uninitialized_zval ) ;
} else if ( /*OP_DATA_TYPE == IS_VAR &&*/
( opline - > extended_value & ZEND_RETURNS_FUNCTION ) & &
UNEXPECTED ( ! Z_ISREF_P ( value_ptr ) ) ) {
if ( UNEXPECTED ( ! zend_wrong_assign_to_variable_reference (
variable_ptr , value_ptr OPLINE_CC EXECUTE_DATA_CC ) ) ) {
variable_ptr = & EG ( uninitialized_zval ) ;
}
} else {
zend_property_info * prop_info = NULL ;
if ( prop_op_type = = IS_CONST ) {
prop_info = ( zend_property_info * ) CACHED_PTR_EX ( cache_addr + 2 ) ;
} else {
2019-06-19 22:35:12 +08:00
ZVAL_DEREF ( container ) ;
2019-06-06 18:13:09 +08:00
prop_info = zend_object_fetch_property_type_info ( Z_OBJ_P ( container ) , variable_ptr ) ;
}
if ( UNEXPECTED ( prop_info ) ) {
2019-06-06 20:56:42 +08:00
variable_ptr = zend_assign_to_typed_property_reference ( prop_info , variable_ptr , value_ptr EXECUTE_DATA_CC ) ;
2019-06-06 18:13:09 +08:00
} else {
zend_assign_to_variable_reference ( variable_ptr , value_ptr ) ;
}
}
if ( UNEXPECTED ( RETURN_VALUE_USED ( opline ) ) ) {
ZVAL_COPY ( EX_VAR ( opline - > result . var ) , variable_ptr ) ;
}
}
static zend_never_inline void zend_assign_to_property_reference_this_const ( zval * container , zval * prop_ptr , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
{
zend_assign_to_property_reference ( container , IS_UNUSED , prop_ptr , IS_CONST , value_ptr
OPLINE_CC EXECUTE_DATA_CC ) ;
}
static zend_never_inline void zend_assign_to_property_reference_var_const ( zval * container , zval * prop_ptr , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
{
zend_assign_to_property_reference ( container , IS_VAR , prop_ptr , IS_CONST , value_ptr
OPLINE_CC EXECUTE_DATA_CC ) ;
}
static zend_never_inline void zend_assign_to_property_reference_this_var ( zval * container , zval * prop_ptr , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
{
2019-06-13 15:37:30 +08:00
zend_assign_to_property_reference ( container , IS_UNUSED , prop_ptr , IS_VAR , value_ptr
2019-06-06 18:13:09 +08:00
OPLINE_CC EXECUTE_DATA_CC ) ;
}
static zend_never_inline void zend_assign_to_property_reference_var_var ( zval * container , zval * prop_ptr , zval * value_ptr OPLINE_DC EXECUTE_DATA_DC )
{
zend_assign_to_property_reference ( container , IS_VAR , prop_ptr , IS_VAR , value_ptr
OPLINE_CC EXECUTE_DATA_CC ) ;
}
2019-01-07 19:28:51 +08:00
static zend_never_inline int zend_fetch_static_property_address_ex ( zval * * retval , zend_property_info * * prop_info , uint32_t cache_slot , int fetch_type OPLINE_DC EXECUTE_DATA_DC ) {
zend_free_op free_op1 ;
zend_string * name , * tmp_name ;
zend_class_entry * ce ;
zend_property_info * property_info ;
zend_uchar op1_type = opline - > op1_type , op2_type = opline - > op2_type ;
if ( EXPECTED ( op2_type = = IS_CONST ) ) {
zval * class_name = RT_CONSTANT ( opline , opline - > op2 ) ;
ZEND_ASSERT ( op1_type ! = IS_CONST | | CACHED_PTR ( cache_slot ) = = NULL ) ;
if ( EXPECTED ( ( ce = CACHED_PTR ( cache_slot ) ) = = NULL ) ) {
ce = zend_fetch_class_by_name ( Z_STR_P ( class_name ) , Z_STR_P ( class_name + 1 ) , ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION ) ;
if ( UNEXPECTED ( ce = = NULL ) ) {
FREE_UNFETCHED_OP ( op1_type , opline - > op1 . var ) ;
return FAILURE ;
}
if ( UNEXPECTED ( op1_type ! = IS_CONST ) ) {
CACHE_PTR ( cache_slot , ce ) ;
}
}
} else {
if ( EXPECTED ( op2_type = = IS_UNUSED ) ) {
ce = zend_fetch_class ( NULL , opline - > op2 . num ) ;
if ( UNEXPECTED ( ce = = NULL ) ) {
FREE_UNFETCHED_OP ( op1_type , opline - > op1 . var ) ;
return FAILURE ;
}
} else {
ce = Z_CE_P ( EX_VAR ( opline - > op2 . var ) ) ;
}
if ( EXPECTED ( op1_type = = IS_CONST ) & & EXPECTED ( CACHED_PTR ( cache_slot ) = = ce ) ) {
* retval = CACHED_PTR ( cache_slot + sizeof ( void * ) ) ;
* prop_info = CACHED_PTR ( cache_slot + sizeof ( void * ) * 2 ) ;
return SUCCESS ;
}
}
if ( EXPECTED ( op1_type = = IS_CONST ) ) {
name = Z_STR_P ( RT_CONSTANT ( opline , opline - > op1 ) ) ;
} else {
zval * varname = get_zval_ptr_undef ( opline - > op1_type , opline - > op1 , & free_op1 , BP_VAR_R ) ;
if ( EXPECTED ( Z_TYPE_P ( varname ) = = IS_STRING ) ) {
name = Z_STR_P ( varname ) ;
tmp_name = NULL ;
} else {
if ( op1_type = = IS_CV & & UNEXPECTED ( Z_TYPE_P ( varname ) = = IS_UNDEF ) ) {
zval_undefined_cv ( opline - > op1 . var EXECUTE_DATA_CC ) ;
}
name = zval_get_tmp_string ( varname , & tmp_name ) ;
}
}
* retval = zend_std_get_static_property_with_info ( ce , name , fetch_type , & property_info ) ;
if ( UNEXPECTED ( op1_type ! = IS_CONST ) ) {
zend_tmp_string_release ( tmp_name ) ;
if ( op1_type ! = IS_CV ) {
zval_ptr_dtor_nogc ( free_op1 ) ;
}
}
if ( UNEXPECTED ( * retval = = NULL ) ) {
return FAILURE ;
}
* prop_info = property_info ;
if ( EXPECTED ( op1_type = = IS_CONST ) ) {
CACHE_POLYMORPHIC_PTR ( cache_slot , ce , * retval ) ;
CACHE_PTR ( cache_slot + sizeof ( void * ) * 2 , property_info ) ;
}
return SUCCESS ;
}
static zend_always_inline int zend_fetch_static_property_address ( zval * * retval , zend_property_info * * prop_info , uint32_t cache_slot , int fetch_type , int flags OPLINE_DC EXECUTE_DATA_DC ) {
int success ;
zend_property_info * property_info ;
if ( opline - > op1_type = = IS_CONST & & ( opline - > op2_type = = IS_CONST | | ( opline - > op2_type = = IS_UNUSED & & ( opline - > op2 . num = = ZEND_FETCH_CLASS_SELF | | opline - > op2 . num = = ZEND_FETCH_CLASS_PARENT ) ) ) & & EXPECTED ( CACHED_PTR ( cache_slot ) ! = NULL ) ) {
* retval = CACHED_PTR ( cache_slot + sizeof ( void * ) ) ;
property_info = CACHED_PTR ( cache_slot + sizeof ( void * ) * 2 ) ;
if ( ( fetch_type = = BP_VAR_R | | fetch_type = = BP_VAR_RW )
& & UNEXPECTED ( Z_TYPE_P ( * retval ) = = IS_UNDEF ) & & UNEXPECTED ( property_info - > type ! = 0 ) ) {
zend_throw_error ( NULL , " Typed static property %s::$%s must not be accessed before initialization " ,
ZSTR_VAL ( property_info - > ce - > name ) ,
zend_get_unmangled_property_name ( property_info - > name ) ) ;
return FAILURE ;
2002-02-07 22:08:43 +08:00
}
2004-09-24 05:43:32 +08:00
} else {
2019-01-07 19:28:51 +08:00
success = zend_fetch_static_property_address_ex ( retval , & property_info , cache_slot , fetch_type OPLINE_CC EXECUTE_DATA_CC ) ;
if ( UNEXPECTED ( success ! = SUCCESS ) ) {
return FAILURE ;
}
}
2019-01-18 06:22:14 +08:00
if ( flags & & property_info - > type ) {
zend_handle_fetch_obj_flags ( NULL , * retval , NULL , property_info , flags ) ;
2019-01-07 19:28:51 +08:00
}
if ( prop_info ) {
* prop_info = property_info ;
}
return SUCCESS ;
}
ZEND_API ZEND_COLD void zend_throw_ref_type_error_type ( zend_property_info * prop1 , zend_property_info * prop2 , zval * zv ) {
const char * prop1_type1 , * prop1_type2 , * prop2_type1 , * prop2_type2 ;
zend_format_type ( prop1 - > type , & prop1_type1 , & prop1_type2 ) ;
zend_format_type ( prop2 - > type , & prop2_type1 , & prop2_type2 ) ;
zend_type_error ( " Reference with value of type %s held by property %s::$%s of type %s%s is not compatible with property %s::$%s of type %s%s " ,
Z_TYPE_P ( zv ) = = IS_OBJECT ? ZSTR_VAL ( Z_OBJCE_P ( zv ) - > name ) : zend_get_type_by_const ( Z_TYPE_P ( zv ) ) ,
ZSTR_VAL ( prop1 - > ce - > name ) ,
zend_get_unmangled_property_name ( prop1 - > name ) ,
prop1_type1 , prop1_type2 ,
ZSTR_VAL ( prop2 - > ce - > name ) ,
zend_get_unmangled_property_name ( prop2 - > name ) ,
prop2_type1 , prop2_type2
) ;
}
ZEND_API ZEND_COLD void zend_throw_ref_type_error_zval ( zend_property_info * prop , zval * zv ) {
const char * prop_type1 , * prop_type2 ;
zend_format_type ( prop - > type , & prop_type1 , & prop_type2 ) ;
zend_type_error ( " Cannot assign %s to reference held by property %s::$%s of type %s%s " ,
Z_TYPE_P ( zv ) = = IS_OBJECT ? ZSTR_VAL ( Z_OBJCE_P ( zv ) - > name ) : zend_get_type_by_const ( Z_TYPE_P ( zv ) ) ,
ZSTR_VAL ( prop - > ce - > name ) ,
zend_get_unmangled_property_name ( prop - > name ) ,
prop_type1 , prop_type2
) ;
}
ZEND_API ZEND_COLD void zend_throw_conflicting_coercion_error ( zend_property_info * prop1 , zend_property_info * prop2 , zval * zv ) {
const char * prop1_type1 , * prop1_type2 , * prop2_type1 , * prop2_type2 ;
zend_format_type ( prop1 - > type , & prop1_type1 , & prop1_type2 ) ;
zend_format_type ( prop2 - > type , & prop2_type1 , & prop2_type2 ) ;
zend_type_error ( " Cannot assign %s to reference held by property %s::$%s of type %s%s and property %s::$%s of type %s%s, as this would result in an inconsistent type conversion " ,
Z_TYPE_P ( zv ) = = IS_OBJECT ? ZSTR_VAL ( Z_OBJCE_P ( zv ) - > name ) : zend_get_type_by_const ( Z_TYPE_P ( zv ) ) ,
ZSTR_VAL ( prop1 - > ce - > name ) ,
zend_get_unmangled_property_name ( prop1 - > name ) ,
prop1_type1 , prop1_type2 ,
ZSTR_VAL ( prop2 - > ce - > name ) ,
zend_get_unmangled_property_name ( prop2 - > name ) ,
prop2_type1 , prop2_type2
) ;
}
/* 1: valid, 0: invalid, -1: may be valid after type coercion */
static zend_always_inline int i_zend_verify_type_assignable_zval (
zend_type * type_ptr , zend_class_entry * self_ce , zval * zv , zend_bool strict ) {
zend_type type = * type_ptr ;
zend_uchar type_code ;
zend_uchar zv_type = Z_TYPE_P ( zv ) ;
if ( ZEND_TYPE_ALLOW_NULL ( type ) & & zv_type = = IS_NULL ) {
return 1 ;
}
if ( ZEND_TYPE_IS_CLASS ( type ) ) {
if ( ! ZEND_TYPE_IS_CE ( type ) ) {
if ( ! zend_resolve_class_type ( type_ptr , self_ce ) ) {
return 0 ;
}
type = * type_ptr ;
}
return zv_type = = IS_OBJECT & & instanceof_function ( Z_OBJCE_P ( zv ) , ZEND_TYPE_CE ( type ) ) ;
}
type_code = ZEND_TYPE_CODE ( type ) ;
if ( type_code = = zv_type | |
( type_code = = _IS_BOOL & & ( zv_type = = IS_FALSE | | zv_type = = IS_TRUE ) ) ) {
return 1 ;
}
if ( type_code = = IS_ITERABLE ) {
return zend_is_iterable ( zv ) ;
}
/* SSTH Exception: IS_LONG may be accepted as IS_DOUBLE (converted) */
if ( strict ) {
if ( type_code = = IS_DOUBLE & & zv_type = = IS_LONG ) {
return - 1 ;
}
return 0 ;
}
/* No weak conversions for arrays and objects */
if ( type_code = = IS_ARRAY | | type_code = = IS_OBJECT ) {
return 0 ;
}
/* NULL may be accepted only by nullable hints (this is already checked) */
if ( zv_type = = IS_NULL ) {
return 0 ;
}
/* Coercion may be necessary, check separately */
return - 1 ;
}
2019-06-21 16:43:17 +08:00
ZEND_API zend_bool ZEND_FASTCALL zend_verify_ref_assignable_zval ( zend_reference * ref , zval * zv , zend_bool strict )
{
2019-01-07 19:28:51 +08:00
zend_property_info * prop ;
/* The value must satisfy each property type, and coerce to the same value for each property
* type . Right now , the latter rule means that * if * coercion is necessary , then all types
* must be the same ( modulo nullability ) . To handle this , remember the first type we see and
* compare against it when coercion becomes necessary . */
zend_property_info * seen_prop = NULL ;
zend_uchar seen_type ;
zend_bool needs_coercion = 0 ;
ZEND_ASSERT ( Z_TYPE_P ( zv ) ! = IS_REFERENCE ) ;
ZEND_REF_FOREACH_TYPE_SOURCES ( ref , prop ) {
int result = i_zend_verify_type_assignable_zval ( & prop - > type , prop - > ce , zv , strict ) ;
if ( result = = 0 ) {
zend_throw_ref_type_error_zval ( prop , zv ) ;
return 0 ;
}
if ( result < 0 ) {
needs_coercion = 1 ;
}
if ( ! seen_prop ) {
seen_prop = prop ;
seen_type = ZEND_TYPE_IS_CLASS ( prop - > type ) ? IS_OBJECT : ZEND_TYPE_CODE ( prop - > type ) ;
} else if ( needs_coercion & & seen_type ! = ZEND_TYPE_CODE ( prop - > type ) ) {
zend_throw_conflicting_coercion_error ( seen_prop , prop , zv ) ;
return 0 ;
}
} ZEND_REF_FOREACH_TYPE_SOURCES_END ( ) ;
if ( UNEXPECTED ( needs_coercion & & ! zend_verify_weak_scalar_type_hint ( seen_type , zv ) ) ) {
zend_throw_ref_type_error_zval ( seen_prop , zv ) ;
return 0 ;
}
return 1 ;
}
2019-05-29 18:58:37 +08:00
ZEND_API zval * zend_assign_to_typed_ref ( zval * variable_ptr , zval * value , zend_uchar value_type , zend_bool strict , zend_refcounted * ref )
{
zend_bool need_copy = ZEND_CONST_COND ( value_type & ( IS_CONST | IS_CV ) , 1 ) | |
( ( value_type & IS_VAR ) & & UNEXPECTED ( ref ) & & GC_REFCOUNT ( ref ) > 1 ) ;
zend_bool ret ;
zval tmp ;
if ( need_copy ) {
ZVAL_COPY ( & tmp , value ) ;
value = & tmp ;
}
ret = zend_verify_ref_assignable_zval ( Z_REF_P ( variable_ptr ) , value , strict ) ;
if ( need_copy ) {
Z_TRY_DELREF_P ( value ) ;
}
if ( ! ret ) {
zval_ptr_dtor ( value ) ;
return Z_REFVAL_P ( variable_ptr ) ;
}
variable_ptr = Z_REFVAL_P ( variable_ptr ) ;
if ( EXPECTED ( Z_REFCOUNTED_P ( variable_ptr ) ) ) {
zend_refcounted * garbage = Z_COUNTED_P ( variable_ptr ) ;
zend_copy_to_variable ( variable_ptr , value , value_type , ref ) ;
if ( GC_DELREF ( garbage ) = = 0 ) {
rc_dtor_func ( garbage ) ;
} else { /* we need to split */
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
if ( UNEXPECTED ( GC_MAY_LEAK ( garbage ) ) ) {
gc_possible_root ( garbage ) ;
}
}
return variable_ptr ;
}
zend_copy_to_variable ( variable_ptr , value , value_type , ref ) ;
return variable_ptr ;
}
2019-01-15 16:14:33 +08:00
ZEND_API zend_bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref ( zend_property_info * prop_info , zval * orig_val , zend_bool strict ) {
2019-01-07 19:28:51 +08:00
zval * val = orig_val ;
if ( Z_ISREF_P ( val ) & & ZEND_REF_HAS_TYPE_SOURCES ( Z_REF_P ( val ) ) ) {
int result ;
val = Z_REFVAL_P ( val ) ;
result = i_zend_verify_type_assignable_zval ( & prop_info - > type , prop_info - > ce , val , strict ) ;
if ( result > 0 ) {
return 1 ;
}
if ( result < 0 ) {
zend_property_info * ref_prop = ZEND_REF_FIRST_SOURCE ( Z_REF_P ( orig_val ) ) ;
if ( ZEND_TYPE_CODE ( prop_info - > type ) ! = ZEND_TYPE_CODE ( ref_prop - > type ) ) {
/* Invalid due to conflicting coercion */
zend_throw_ref_type_error_type ( ref_prop , prop_info , val ) ;
return 0 ;
}
if ( zend_verify_weak_scalar_type_hint ( ZEND_TYPE_CODE ( prop_info - > type ) , val ) ) {
return 1 ;
}
}
} else {
ZVAL_DEREF ( val ) ;
if ( i_zend_check_property_type ( prop_info , val , strict ) ) {
return 1 ;
}
}
zend_verify_property_type_error ( prop_info , val ) ;
return 0 ;
}
2019-01-15 16:14:33 +08:00
ZEND_API void ZEND_FASTCALL zend_ref_add_type_source ( zend_property_info_source_list * source_list , zend_property_info * prop )
2019-01-07 19:28:51 +08:00
{
zend_property_info_list * list ;
if ( source_list - > ptr = = NULL ) {
source_list - > ptr = prop ;
return ;
}
list = ZEND_PROPERTY_INFO_SOURCE_TO_LIST ( source_list - > list ) ;
if ( ! ZEND_PROPERTY_INFO_SOURCE_IS_LIST ( source_list - > list ) ) {
list = emalloc ( sizeof ( zend_property_info_list ) + ( 4 - 1 ) * sizeof ( zend_property_info * ) ) ;
list - > ptr [ 0 ] = source_list - > ptr ;
list - > num_allocated = 4 ;
list - > num = 1 ;
} else if ( list - > num_allocated = = list - > num ) {
list - > num_allocated = list - > num * 2 ;
list = erealloc ( list , sizeof ( zend_property_info_list ) + ( list - > num_allocated - 1 ) * sizeof ( zend_property_info * ) ) ;
}
list - > ptr [ list - > num + + ] = prop ;
source_list - > list = ZEND_PROPERTY_INFO_SOURCE_FROM_LIST ( list ) ;
}
2019-01-15 16:14:33 +08:00
ZEND_API void ZEND_FASTCALL zend_ref_del_type_source ( zend_property_info_source_list * source_list , zend_property_info * prop )
2019-01-07 19:28:51 +08:00
{
zend_property_info_list * list = ZEND_PROPERTY_INFO_SOURCE_TO_LIST ( source_list - > list ) ;
zend_property_info * * ptr , * * end ;
if ( ! ZEND_PROPERTY_INFO_SOURCE_IS_LIST ( source_list - > list ) ) {
ZEND_ASSERT ( source_list - > ptr = = prop ) ;
source_list - > ptr = NULL ;
return ;
}
if ( list - > num = = 1 ) {
ZEND_ASSERT ( * list - > ptr = = prop ) ;
efree ( list ) ;
source_list - > ptr = NULL ;
return ;
}
/* Checking against end here to get a more graceful failure mode if we missed adding a type
* source at some point . */
ptr = list - > ptr ;
end = ptr + list - > num ;
while ( ptr < end & & * ptr ! = prop ) {
ptr + + ;
}
ZEND_ASSERT ( * ptr = = prop ) ;
/* Copy the last list element into the deleted slot. */
* ptr = list - > ptr [ - - list - > num ] ;
if ( list - > num > = 4 & & list - > num * 4 = = list - > num_allocated ) {
list - > num_allocated = list - > num * 2 ;
source_list - > list = ZEND_PROPERTY_INFO_SOURCE_FROM_LIST ( erealloc ( list , sizeof ( zend_property_info_list ) + ( list - > num_allocated - 1 ) * sizeof ( zend_property_info * ) ) ) ;
2001-05-03 03:51:33 +08:00
}
1999-04-08 02:10:10 +08:00
}
2018-02-21 22:09:42 +08:00
static zend_never_inline void zend_fetch_this_var ( int type OPLINE_DC EXECUTE_DATA_DC )
{
zval * result = EX_VAR ( opline - > result . var ) ;
switch ( type ) {
case BP_VAR_R :
if ( EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
ZVAL_OBJ ( result , Z_OBJ ( EX ( This ) ) ) ;
Z_ADDREF_P ( result ) ;
} else {
ZVAL_NULL ( result ) ;
zend_error ( E_NOTICE , " Undefined variable: this " ) ;
}
break ;
case BP_VAR_IS :
if ( EXPECTED ( Z_TYPE ( EX ( This ) ) = = IS_OBJECT ) ) {
ZVAL_OBJ ( result , Z_OBJ ( EX ( This ) ) ) ;
Z_ADDREF_P ( result ) ;
} else {
ZVAL_NULL ( result ) ;
}
break ;
case BP_VAR_RW :
case BP_VAR_W :
ZVAL_UNDEF ( result ) ;
zend_throw_error ( NULL , " Cannot re-assign $this " ) ;
break ;
case BP_VAR_UNSET :
ZVAL_UNDEF ( result ) ;
zend_throw_error ( NULL , " Cannot unset $this " ) ;
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
}
}
2018-09-13 18:36:09 +08:00
static zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_wrong_clone_call ( zend_function * clone , zend_class_entry * scope )
{
zend_throw_error ( NULL , " Call to %s %s::__clone() from context '%s' " , zend_visibility_string ( clone - > common . fn_flags ) , ZSTR_VAL ( clone - > common . scope - > name ) , scope ? ZSTR_VAL ( scope - > name ) : " " ) ;
}
2018-02-21 22:09:42 +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 ) ;
2019-06-20 16:52:18 +08:00
* ( EG ( symtable_cache_ptr ) + + ) = symbol_table ;
2012-05-28 12:43:18 +08:00
}
}
/* }}} */
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 ) ;
2017-12-14 08:39:22 +08:00
int count = EX ( func ) - > op_array . last_var ;
while ( EXPECTED ( count ! = 0 ) ) {
2015-04-17 02:45:40 +08:00
if ( Z_REFCOUNTED_P ( cv ) ) {
2016-10-21 22:47:30 +08:00
zend_refcounted * r = Z_COUNTED_P ( cv ) ;
2017-10-27 06:28:58 +08:00
if ( ! GC_DELREF ( r ) ) {
2015-04-17 02:45:40 +08:00
ZVAL_NULL ( cv ) ;
2018-07-06 19:14:44 +08:00
rc_dtor_func ( r ) ;
2015-04-17 02:45:40 +08:00
} else {
2016-10-21 22:47:30 +08:00
gc_check_possible_root ( r ) ;
2015-04-17 02:45:40 +08:00
}
}
2015-04-16 19:46:54 +08:00
cv + + ;
2017-12-14 08:39:22 +08:00
count - - ;
}
2012-12-05 17:23:37 +08:00
}
/* }}} */
2017-11-22 20:36:09 +08:00
ZEND_API 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
}
/* }}} */
2016-04-20 18:52:21 +08:00
# define ZEND_VM_INTERRUPT_CHECK() do { \
2016-06-23 20:01:23 +08:00
if ( UNEXPECTED ( EG ( vm_interrupt ) ) ) { \
ZEND_VM_INTERRUPT ( ) ; \
2015-03-17 00:48:29 +08:00
} \
} while ( 0 )
2016-06-27 15:36:41 +08:00
# define ZEND_VM_LOOP_INTERRUPT_CHECK() do { \
if ( UNEXPECTED ( EG ( vm_interrupt ) ) ) { \
ZEND_VM_LOOP_INTERRUPT ( ) ; \
2015-03-17 00:48:29 +08:00
} \
} while ( 0 )
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
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2019-03-01 14:15:32 +08:00
* EX_VAR_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
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2019-03-01 14:15:32 +08:00
/* zend_copy_extra_args is used when the actually passed number of arguments
* ( EX_NUM_ARGS ) is greater than what the function defined ( op_array - > num_args ) .
*
* The extra arguments will be copied into the call frame after all the compiled variables .
*
* If there are extra arguments copied , a flag " ZEND_CALL_FREE_EXTRA_ARGS " will be set
* on the zend_execute_data , and when the executor leaves the function , the
* args will be freed in zend_leave_helper .
*/
2017-12-06 07:53:30 +08:00
static zend_never_inline void zend_copy_extra_args ( EXECUTE_DATA_D )
{
zend_op_array * op_array = & EX ( func ) - > op_array ;
uint32_t first_extra_arg = op_array - > num_args ;
uint32_t num_args = EX_NUM_ARGS ( ) ;
zval * src ;
size_t delta ;
uint32_t count ;
uint32_t type_flags = 0 ;
if ( EXPECTED ( ( op_array - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) = = 0 ) ) {
/* Skip useless ZEND_RECV and ZEND_RECV_INIT opcodes */
2019-02-12 22:39:02 +08:00
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
opline + = first_extra_arg ;
# else
EX ( opline ) + = first_extra_arg ;
# endif
}
/* move extra args into separate array after all CV and TMP vars */
src = EX_VAR_NUM ( num_args - 1 ) ;
delta = op_array - > last_var + op_array - > T - first_extra_arg ;
count = num_args - first_extra_arg ;
if ( EXPECTED ( delta ! = 0 ) ) {
delta * = sizeof ( zval ) ;
do {
type_flags | = Z_TYPE_INFO_P ( src ) ;
ZVAL_COPY_VALUE ( ( zval * ) ( ( ( char * ) src ) + delta ) , src ) ;
ZVAL_UNDEF ( src ) ;
src - - ;
} while ( - - count ) ;
2018-02-16 02:54:49 +08:00
if ( Z_TYPE_INFO_REFCOUNTED ( type_flags ) ) {
2018-02-02 22:38:07 +08:00
ZEND_ADD_CALL_FLAG ( execute_data , ZEND_CALL_FREE_EXTRA_ARGS ) ;
}
2017-12-06 07:53:30 +08:00
} else {
do {
2018-02-02 22:38:07 +08:00
if ( Z_REFCOUNTED_P ( src ) ) {
ZEND_ADD_CALL_FLAG ( execute_data , ZEND_CALL_FREE_EXTRA_ARGS ) ;
break ;
}
2017-12-06 07:53:30 +08:00
src - - ;
} while ( - - count ) ;
}
}
static zend_always_inline void zend_init_cvs ( uint32_t first , uint32_t last EXECUTE_DATA_DC )
{
if ( EXPECTED ( first < last ) ) {
2017-12-14 08:39:22 +08:00
uint32_t count = last - first ;
2017-12-06 07:53:30 +08:00
zval * var = EX_VAR_NUM ( first ) ;
do {
ZVAL_UNDEF ( var ) ;
var + + ;
2017-12-14 08:39:22 +08:00
} while ( - - count ) ;
2017-12-06 07:53:30 +08:00
}
}
static zend_always_inline void i_init_func_execute_data ( zend_op_array * op_array , zval * return_value , zend_bool may_be_trampoline EXECUTE_DATA_DC ) /* { { { */
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 ) ;
2019-02-12 22:39:02 +08:00
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
opline = op_array - > opcodes ;
# else
2014-07-08 01:33:09 +08:00
EX ( opline ) = op_array - > opcodes ;
2017-12-06 07:53:30 +08:00
# endif
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 ) ) {
2017-12-06 07:53:30 +08:00
if ( ! may_be_trampoline | | EXPECTED ( ! ( op_array - > fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE ) ) ) {
zend_copy_extra_args ( EXECUTE_DATA_C ) ;
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 */
2019-02-12 22:39:02 +08:00
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
opline + = num_args ;
# else
2014-09-17 20:17:58 +08:00
EX ( opline ) + = num_args ;
2017-12-06 07:53:30 +08:00
# endif
2014-09-17 20:17:58 +08:00
}
/* Initialize CV variables (skip arguments) */
2017-12-06 07:53:30 +08:00
zend_init_cvs ( num_args , op_array - > last_var EXECUTE_DATA_CC ) ;
2014-07-04 22:03:45 +08:00
2019-05-15 16:06:26 +08:00
EX ( run_time_cache ) = RUN_TIME_CACHE ( op_array ) ;
2014-07-04 22:03:45 +08:00
EG ( current_execute_data ) = execute_data ;
}
2014-07-08 17:53:13 +08:00
/* }}} */
2014-07-04 22:03:45 +08:00
2018-10-17 20:52:50 +08:00
static zend_always_inline void init_func_run_time_cache_i ( zend_op_array * op_array ) /* { { { */
2016-04-05 05:01:00 +08:00
{
2018-10-17 20:52:50 +08:00
void * * run_time_cache ;
2016-04-05 05:01:00 +08:00
2018-10-17 20:52:50 +08:00
ZEND_ASSERT ( RUN_TIME_CACHE ( op_array ) = = NULL ) ;
run_time_cache = zend_arena_alloc ( & CG ( arena ) , op_array - > cache_size ) ;
memset ( run_time_cache , 0 , op_array - > cache_size ) ;
ZEND_MAP_PTR_SET ( op_array - > run_time_cache , run_time_cache ) ;
2018-06-26 00:53:58 +08:00
}
/* }}} */
2018-10-17 20:52:50 +08:00
static zend_never_inline void ZEND_FASTCALL init_func_run_time_cache ( zend_op_array * op_array ) /* { { { */
2018-06-26 00:53:58 +08:00
{
2018-10-17 20:52:50 +08:00
init_func_run_time_cache_i ( op_array ) ;
2018-06-26 00:53:58 +08:00
}
/* }}} */
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function ( zend_string * name ) /* { { { */
{
zval * zv = zend_hash_find ( EG ( function_table ) , name ) ;
if ( EXPECTED ( zv ! = NULL ) ) {
zend_function * fbc = Z_FUNC_P ( zv ) ;
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
init_func_run_time_cache_i ( & fbc - > op_array ) ;
2018-06-26 00:53:58 +08:00
}
return fbc ;
}
return NULL ;
} /* }}} */
2018-06-26 04:01:21 +08:00
ZEND_API zend_function * ZEND_FASTCALL zend_fetch_function_str ( const char * name , size_t len ) /* { { { */
{
zval * zv = zend_hash_str_find ( EG ( function_table ) , name , len ) ;
if ( EXPECTED ( zv ! = NULL ) ) {
zend_function * fbc = Z_FUNC_P ( zv ) ;
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
init_func_run_time_cache_i ( & fbc - > op_array ) ;
2018-06-26 04:01:21 +08:00
}
return fbc ;
}
return NULL ;
} /* }}} */
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
2015-09-24 04:16:30 +08:00
zend_attach_symbol_table ( execute_data ) ;
2018-10-17 20:52:50 +08:00
if ( ! ZEND_MAP_PTR ( op_array - > run_time_cache ) ) {
void * ptr ;
2018-10-03 17:31:47 +08:00
ZEND_ASSERT ( op_array - > fn_flags & ZEND_ACC_HEAP_RT_CACHE ) ;
2018-10-17 20:52:50 +08:00
ptr = emalloc ( op_array - > cache_size + sizeof ( void * ) ) ;
ZEND_MAP_PTR_INIT ( op_array - > run_time_cache , ptr ) ;
ptr = ( char * ) ptr + sizeof ( void * ) ;
ZEND_MAP_PTR_SET ( op_array - > run_time_cache , ptr ) ;
memset ( ptr , 0 , op_array - > cache_size ) ;
2014-07-04 22:03:45 +08:00
}
2019-05-15 16:06:26 +08:00
EX ( run_time_cache ) = RUN_TIME_CACHE ( op_array ) ;
2014-07-04 22:03:45 +08:00
EG ( current_execute_data ) = execute_data ;
}
2014-07-08 17:53:13 +08:00
/* }}} */
2014-07-04 22:03:45 +08:00
2017-12-06 07:53:30 +08:00
ZEND_API void zend_init_func_execute_data ( zend_execute_data * ex , zend_op_array * op_array , zval * return_value ) /* { { { */
2012-12-04 14:42:19 +08:00
{
2017-12-06 07:53:30 +08:00
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
zend_execute_data * orig_execute_data = execute_data ;
2019-02-12 22:39:02 +08:00
# endif
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
const zend_op * orig_opline = opline ;
2019-02-12 22:39:02 +08:00
# endif
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
execute_data = ex ;
# else
zend_execute_data * execute_data = ex ;
# endif
2017-06-29 15:10:57 +08:00
EX ( prev_execute_data ) = EG ( current_execute_data ) ;
2018-10-17 20:52:50 +08:00
if ( ! RUN_TIME_CACHE ( op_array ) ) {
2018-06-26 00:53:58 +08:00
init_func_run_time_cache ( op_array ) ;
2012-12-04 14:42:19 +08:00
}
2017-12-06 07:53:30 +08:00
i_init_func_execute_data ( op_array , return_value , 1 EXECUTE_DATA_CC ) ;
2019-02-12 22:39:02 +08:00
# if defined(ZEND_VM_IP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
EX ( opline ) = opline ;
opline = orig_opline ;
2019-02-12 22:39:02 +08:00
# endif
# if defined(ZEND_VM_FP_GLOBAL_REG) && ((ZEND_VM_KIND == ZEND_VM_KIND_CALL) || (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID))
2017-12-06 07:53:30 +08:00
execute_data = orig_execute_data ;
# endif
2017-06-29 15:10:57 +08:00
}
/* }}} */
2012-12-04 14:42:19 +08:00
2017-06-29 15:10:57 +08:00
ZEND_API void zend_init_code_execute_data ( zend_execute_data * execute_data , zend_op_array * op_array , zval * return_value ) /* { { { */
{
EX ( prev_execute_data ) = EG ( current_execute_data ) ;
i_init_code_execute_data ( execute_data , op_array , return_value ) ;
2014-06-27 03:51:14 +08:00
}
/* }}} */
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
{
2017-06-29 15:10:57 +08:00
if ( EX_CALL_INFO ( ) & ZEND_CALL_HAS_SYMBOL_TABLE ) {
zend_init_code_execute_data ( execute_data , op_array , return_value ) ;
} else {
zend_init_func_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_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
2019-02-19 00:35:35 +08:00
/* delete previous stack segment if it became 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
}
}
/* }}} */
2017-06-16 06:42:49 +08:00
static zend_always_inline zend_generator * zend_get_running_generator ( EXECUTE_DATA_D ) /* { { { */
2015-02-20 19:59:56 +08:00
{
/* 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 ;
2017-12-31 12:35:25 +08:00
2015-07-24 15:49:01 +08:00
if ( UNEXPECTED ( opline - > opcode = = ZEND_INIT_FCALL | |
opline - > opcode = = ZEND_INIT_FCALL_BY_NAME | |
2016-07-14 05:55:19 +08:00
opline - > opcode = = ZEND_INIT_NS_FCALL_BY_NAME | |
2015-07-24 15:49:01 +08:00
opline - > opcode = = ZEND_INIT_DYNAMIC_CALL | |
2016-07-14 05:55:19 +08:00
opline - > opcode = = ZEND_INIT_USER_CALL | |
2015-07-24 15:49:01 +08:00
opline - > opcode = = ZEND_INIT_METHOD_CALL | |
2016-07-14 05:55:19 +08:00
opline - > opcode = = ZEND_INIT_STATIC_METHOD_CALL | |
opline - > opcode = = ZEND_NEW ) ) {
2015-07-24 15:49:01 +08:00
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 :
2018-02-06 00:40:06 +08:00
case ZEND_SEND_FUNC_ARG :
2015-06-21 00:35:27 +08:00
case ZEND_SEND_REF :
case ZEND_SEND_VAR_NO_REF :
2016-05-31 09:06:00 +08:00
case ZEND_SEND_VAR_NO_REF_EX :
2015-06-21 00:35:27 +08:00
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 ) {
OBJ_RELEASE ( Z_OBJ ( call - > This ) ) ;
}
2015-06-26 11:10:58 +08:00
if ( call - > func - > common . fn_flags & ZEND_ACC_CLOSURE ) {
2018-01-12 03:15:45 +08:00
zend_object_release ( ZEND_CLOSURE_OBJECT ( call - > func ) ) ;
2015-07-07 18:19:57 +08:00
} else if ( call - > func - > common . fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE ) {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( call - > func - > common . function_name , 0 ) ;
2015-06-21 00:35:27 +08:00
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
}
/* }}} */
2018-02-17 04:25:49 +08:00
static const zend_live_range * find_live_range ( const zend_op_array * op_array , uint32_t op_num , uint32_t var_num ) /* { { { */
{
int i ;
for ( i = 0 ; i < op_array - > last_live_range ; i + + ) {
const zend_live_range * range = & op_array - > live_range [ i ] ;
if ( op_num > = range - > start & & op_num < range - > end
& & var_num = = ( range - > var & ~ ZEND_LIVE_MASK ) ) {
return range ;
}
}
return NULL ;
}
/* }}} */
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 ) ;
2019-04-12 05:49:45 +08:00
} else if ( kind = = ZEND_LIVE_NEW ) {
zend_object * obj ;
ZEND_ASSERT ( Z_TYPE_P ( var ) = = IS_OBJECT ) ;
obj = Z_OBJ_P ( var ) ;
zend_object_store_ctor_failed ( obj ) ;
OBJ_RELEASE ( obj ) ;
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 ) {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( * rope , 0 ) ;
2015-07-10 08:31:52 +08:00
} else {
int j = last - > extended_value ;
do {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( rope [ j ] , 0 ) ;
2015-07-10 08:31:52 +08:00
} 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 */
2019-01-31 16:39:10 +08:00
if ( ! EG ( error_reporting ) & & Z_LVAL_P ( var ) ! = 0 ) {
2015-11-11 02:48:03 +08:00
EG ( error_reporting ) = Z_LVAL_P ( var ) ;
2015-07-10 08:31:52 +08:00
}
}
}
}
}
2015-06-21 00:35:27 +08:00
}
/* }}} */
2017-11-22 20:36:09 +08:00
ZEND_API 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
}
2019-07-24 15:44:55 +08:00
# if ZEND_VM_SPEC
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 ;
}
/* }}} */
2019-07-24 15:44:55 +08:00
# endif
2016-03-18 03:00:27 +08:00
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 ) ) {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( lcname , 0 ) ;
2016-04-12 19:41:06 +08:00
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 ) ) ) {
2018-02-16 07:45:31 +08:00
zend_undefined_method ( called_scope , mname ) ;
2016-04-12 19:41:06 +08:00
}
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( lcname , 0 ) ;
zend_string_release_ex ( mname , 0 ) ;
2016-04-12 19:41:06 +08:00
return NULL ;
}
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( lcname , 0 ) ;
zend_string_release_ex ( mname , 0 ) ;
2016-04-12 19:41:06 +08:00
if ( UNEXPECTED ( ! ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ) ) {
2018-02-16 07:45:31 +08:00
zend_non_static_method_call ( fbc ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
2016-04-12 19:41:06 +08:00
return NULL ;
}
}
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
2018-06-26 00:53:58 +08:00
init_func_run_time_cache ( & fbc - > op_array ) ;
}
2016-04-12 19:41:06 +08:00
} 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 ) ) ;
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( lcname , 0 ) ;
2016-04-12 19:41:06 +08:00
return NULL ;
}
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( lcname , 0 ) ;
2016-04-12 19:41:06 +08:00
fbc = Z_FUNC_P ( func ) ;
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
init_func_run_time_cache ( & fbc - > op_array ) ;
2018-06-26 00:53:58 +08:00
}
2016-04-12 19:41:06 +08:00
called_scope = NULL ;
}
2016-04-25 05:49:52 +08:00
return zend_vm_stack_push_call_frame ( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC ,
2019-04-12 07:35:42 +08:00
fbc , num_args , called_scope ) ;
2016-04-12 19:41:06 +08:00
}
/* }}} */
static zend_never_inline zend_execute_data * zend_init_dynamic_call_object ( zval * function , uint32_t num_args ) /* { { { */
{
zend_function * fbc ;
2019-04-12 07:35:42 +08:00
void * object_or_called_scope ;
2016-04-12 19:41:06 +08:00
zend_class_entry * called_scope ;
zend_object * object ;
2016-04-25 05:49:52 +08:00
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC ;
2016-04-12 19:41:06 +08:00
if ( EXPECTED ( Z_OBJ_HANDLER_P ( function , get_closure ) ) & &
EXPECTED ( Z_OBJ_HANDLER_P ( function , get_closure ) ( function , & called_scope , & fbc , & object ) = = SUCCESS ) ) {
2019-04-12 07:35:42 +08:00
object_or_called_scope = called_scope ;
2016-04-12 19:41:06 +08:00
if ( fbc - > common . fn_flags & ZEND_ACC_CLOSURE ) {
/* Delay closure destruction until its invocation */
2018-01-12 03:15:45 +08:00
GC_ADDREF ( ZEND_CLOSURE_OBJECT ( fbc ) ) ;
2016-04-12 19:41:06 +08:00
call_info | = ZEND_CALL_CLOSURE ;
2016-09-26 22:44:28 +08:00
if ( fbc - > common . fn_flags & ZEND_ACC_FAKE_CLOSURE ) {
call_info | = ZEND_CALL_FAKE_CLOSURE ;
}
2019-04-12 07:35:42 +08:00
if ( object ) {
call_info | = ZEND_CALL_HAS_THIS ;
object_or_called_scope = object ;
}
2016-04-12 19:41:06 +08:00
} else if ( object ) {
2019-04-12 07:35:42 +08:00
call_info | = ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS ;
2017-10-27 06:28:58 +08:00
GC_ADDREF ( object ) ; /* For $this pointer */
2019-04-12 07:35:42 +08:00
object_or_called_scope = object ;
2016-04-12 19:41:06 +08:00
}
} else {
zend_throw_error ( NULL , " Function name must be a string " ) ;
return NULL ;
}
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
2016-04-12 19:41:06 +08:00
init_func_run_time_cache ( & fbc - > op_array ) ;
}
return zend_vm_stack_push_call_frame ( call_info ,
2019-04-12 07:35:42 +08:00
fbc , num_args , object_or_called_scope ) ;
2016-04-12 19:41:06 +08:00
}
/* }}} */
static zend_never_inline zend_execute_data * zend_init_dynamic_call_array ( zend_array * function , uint32_t num_args ) /* { { { */
{
zend_function * fbc ;
2019-04-12 07:35:42 +08:00
void * object_or_called_scope ;
2016-04-25 05:49:52 +08:00
uint32_t call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC ;
2016-04-12 19:41:06 +08:00
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 ) {
2019-04-12 07:35:42 +08:00
zend_class_entry * called_scope = zend_fetch_class_by_name ( Z_STR_P ( obj ) , NULL , ZEND_FETCH_CLASS_DEFAULT | ZEND_FETCH_CLASS_EXCEPTION ) ;
2016-04-12 19:41:06 +08:00
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 ) ) ) {
2018-02-16 07:45:31 +08:00
zend_undefined_method ( called_scope , Z_STR_P ( method ) ) ;
2016-04-12 19:41:06 +08:00
}
return NULL ;
}
if ( ! ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ) {
2018-02-16 07:45:31 +08:00
zend_non_static_method_call ( fbc ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
2016-04-12 19:41:06 +08:00
return NULL ;
}
}
2019-04-12 07:35:42 +08:00
object_or_called_scope = called_scope ;
2016-04-12 19:41:06 +08:00
} else {
2019-04-12 07:35:42 +08:00
zend_object * object = Z_OBJ_P ( obj ) ;
2016-04-12 19:41:06 +08:00
fbc = Z_OBJ_HT_P ( obj ) - > get_method ( & object , Z_STR_P ( method ) , NULL ) ;
if ( UNEXPECTED ( fbc = = NULL ) ) {
if ( EXPECTED ( ! EG ( exception ) ) ) {
2018-02-16 07:45:31 +08:00
zend_undefined_method ( object - > ce , Z_STR_P ( method ) ) ;
2016-04-12 19:41:06 +08:00
}
return NULL ;
}
if ( ( fbc - > common . fn_flags & ZEND_ACC_STATIC ) ! = 0 ) {
2019-04-12 07:35:42 +08:00
object_or_called_scope = object - > ce ;
2016-04-12 19:41:06 +08:00
} else {
2019-04-12 07:35:42 +08:00
call_info | = ZEND_CALL_RELEASE_THIS | ZEND_CALL_HAS_THIS ;
2017-10-27 06:28:58 +08:00
GC_ADDREF ( object ) ; /* For $this pointer */
2019-04-12 07:35:42 +08:00
object_or_called_scope = object ;
2016-04-12 19:41:06 +08:00
}
}
} else {
zend_throw_error ( NULL , " Function name must be a string " ) ;
return NULL ;
}
2018-10-17 20:52:50 +08:00
if ( EXPECTED ( fbc - > type = = ZEND_USER_FUNCTION ) & & UNEXPECTED ( ! RUN_TIME_CACHE ( & fbc - > op_array ) ) ) {
2016-04-12 19:41:06 +08:00
init_func_run_time_cache ( & fbc - > op_array ) ;
}
return zend_vm_stack_push_call_frame ( call_info ,
2019-04-12 07:35:42 +08:00
fbc , num_args , object_or_called_scope ) ;
2016-04-12 19:41:06 +08:00
}
/* }}} */
2016-04-13 20:29:01 +08:00
# define ZEND_FAKE_OP_ARRAY ((zend_op_array*)(zend_intptr_t)-1)
static zend_never_inline zend_op_array * ZEND_FASTCALL zend_include_or_eval ( zval * inc_filename , int type ) /* { { { */
{
zend_op_array * new_op_array = NULL ;
zval tmp_inc_filename ;
ZVAL_UNDEF ( & tmp_inc_filename ) ;
if ( Z_TYPE_P ( inc_filename ) ! = IS_STRING ) {
2019-06-06 06:47:22 +08:00
zend_string * tmp = zval_try_get_string_func ( inc_filename ) ;
if ( UNEXPECTED ( ! tmp ) ) {
2019-02-26 22:32:18 +08:00
return NULL ;
}
2019-06-06 06:47:22 +08:00
ZVAL_STR ( & tmp_inc_filename , tmp ) ;
inc_filename = & tmp_inc_filename ;
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
switch ( type ) {
case ZEND_INCLUDE_ONCE :
case ZEND_REQUIRE_ONCE : {
zend_file_handle file_handle ;
zend_string * resolved_path ;
resolved_path = zend_resolve_path ( Z_STRVAL_P ( inc_filename ) , Z_STRLEN_P ( inc_filename ) ) ;
if ( EXPECTED ( resolved_path ) ) {
if ( zend_hash_exists ( & EG ( included_files ) , resolved_path ) ) {
goto already_compiled ;
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
} else if ( UNEXPECTED ( strlen ( Z_STRVAL_P ( inc_filename ) ) ! = Z_STRLEN_P ( inc_filename ) ) ) {
zend_message_dispatcher (
( type = = ZEND_INCLUDE_ONCE ) ?
ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN ,
Z_STRVAL_P ( inc_filename ) ) ;
break ;
} else {
resolved_path = zend_string_copy ( Z_STR_P ( inc_filename ) ) ;
}
2016-04-13 20:29:01 +08:00
2018-05-30 23:24:31 +08:00
if ( SUCCESS = = zend_stream_open ( ZSTR_VAL ( resolved_path ) , & file_handle ) ) {
2016-04-13 20:29:01 +08:00
2018-05-30 23:24:31 +08:00
if ( ! file_handle . opened_path ) {
file_handle . opened_path = zend_string_copy ( resolved_path ) ;
}
2016-04-13 20:29:01 +08:00
2018-05-30 23:24:31 +08:00
if ( zend_hash_add_empty_element ( & EG ( included_files ) , file_handle . opened_path ) ) {
zend_op_array * op_array = zend_compile_file ( & file_handle , ( type = = ZEND_INCLUDE_ONCE ? ZEND_INCLUDE : ZEND_REQUIRE ) ) ;
zend_destroy_file_handle ( & file_handle ) ;
zend_string_release_ex ( resolved_path , 0 ) ;
if ( Z_TYPE ( tmp_inc_filename ) ! = IS_UNDEF ) {
2018-07-04 17:08:07 +08:00
zval_ptr_dtor_str ( & tmp_inc_filename ) ;
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
return op_array ;
2016-04-13 20:29:01 +08:00
} else {
2018-05-30 23:24:31 +08:00
zend_file_handle_dtor ( & file_handle ) ;
already_compiled :
new_op_array = ZEND_FAKE_OP_ARRAY ;
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
} else {
zend_message_dispatcher (
( type = = ZEND_INCLUDE_ONCE ) ?
ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN ,
Z_STRVAL_P ( inc_filename ) ) ;
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
zend_string_release_ex ( resolved_path , 0 ) ;
}
break ;
case ZEND_INCLUDE :
case ZEND_REQUIRE :
if ( UNEXPECTED ( strlen ( Z_STRVAL_P ( inc_filename ) ) ! = Z_STRLEN_P ( inc_filename ) ) ) {
zend_message_dispatcher (
( type = = ZEND_INCLUDE ) ?
ZMSG_FAILED_INCLUDE_FOPEN : ZMSG_FAILED_REQUIRE_FOPEN ,
Z_STRVAL_P ( inc_filename ) ) ;
2016-04-13 20:29:01 +08:00
break ;
2018-05-30 23:24:31 +08:00
}
new_op_array = compile_filename ( type , inc_filename ) ;
break ;
case ZEND_EVAL : {
char * eval_desc = zend_make_compiled_string_description ( " eval()'d code " ) ;
new_op_array = zend_compile_string ( inc_filename , eval_desc ) ;
efree ( eval_desc ) ;
}
break ;
EMPTY_SWITCH_DEFAULT_CASE ( )
2016-04-13 20:29:01 +08:00
}
2018-05-30 23:24:31 +08:00
2016-04-13 20:29:01 +08:00
if ( Z_TYPE ( tmp_inc_filename ) ! = IS_UNDEF ) {
2018-07-04 17:08:07 +08:00
zval_ptr_dtor_str ( & tmp_inc_filename ) ;
2016-04-13 20:29:01 +08:00
}
return new_op_array ;
}
/* }}} */
2019-05-29 15:32:30 +08:00
static ZEND_COLD int ZEND_FASTCALL zend_do_fcall_overloaded ( zend_execute_data * call , zval * ret ) /* { { { */
2016-04-14 01:13:17 +08:00
{
2016-11-22 23:36:27 +08:00
zend_function * fbc = call - > func ;
2016-04-14 01:13:17 +08:00
zend_object * object ;
/* Not sure what should be done here if it's a static method */
if ( UNEXPECTED ( Z_TYPE ( call - > This ) ! = IS_OBJECT ) ) {
zend_vm_stack_free_args ( call ) ;
if ( fbc - > type = = ZEND_OVERLOADED_FUNCTION_TEMPORARY ) {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( fbc - > common . function_name , 0 ) ;
2016-04-14 01:13:17 +08:00
}
efree ( fbc ) ;
zend_vm_stack_free_call_frame ( call ) ;
zend_throw_error ( NULL , " Cannot call overloaded function for non-object " ) ;
return 0 ;
}
object = Z_OBJ ( call - > This ) ;
ZVAL_NULL ( ret ) ;
EG ( current_execute_data ) = call ;
object - > handlers - > call_method ( fbc - > common . function_name , object , call , ret ) ;
EG ( current_execute_data ) = call - > prev_execute_data ;
zend_vm_stack_free_args ( call ) ;
if ( fbc - > type = = ZEND_OVERLOADED_FUNCTION_TEMPORARY ) {
2018-05-28 21:27:12 +08:00
zend_string_release_ex ( fbc - > common . function_name , 0 ) ;
2016-04-14 01:13:17 +08:00
}
efree ( fbc ) ;
return 1 ;
}
/* }}} */
2018-05-29 02:44:58 +08:00
static zend_never_inline zend_bool ZEND_FASTCALL zend_fe_reset_iterator ( zval * array_ptr , int by_ref OPLINE_DC EXECUTE_DATA_DC ) /* { { { */
2018-05-28 23:11:43 +08:00
{
zend_class_entry * ce = Z_OBJCE_P ( array_ptr ) ;
zend_object_iterator * iter = ce - > get_iterator ( ce , array_ptr , by_ref ) ;
zend_bool is_empty ;
if ( UNEXPECTED ( ! iter ) | | UNEXPECTED ( EG ( exception ) ) ) {
if ( iter ) {
OBJ_RELEASE ( & iter - > std ) ;
}
if ( ! EG ( exception ) ) {
zend_throw_exception_ex ( NULL , 0 , " Object of type %s did not create an Iterator " , ZSTR_VAL ( ce - > name ) ) ;
}
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
return 1 ;
}
iter - > index = 0 ;
if ( iter - > funcs - > rewind ) {
iter - > funcs - > rewind ( iter ) ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
OBJ_RELEASE ( & iter - > std ) ;
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
return 1 ;
}
}
is_empty = iter - > funcs - > valid ( iter ) ! = SUCCESS ;
if ( UNEXPECTED ( EG ( exception ) ! = NULL ) ) {
OBJ_RELEASE ( & iter - > std ) ;
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
return 1 ;
}
iter - > index = - 1 ; /* will be set to 0 before using next handler */
ZVAL_OBJ ( EX_VAR ( opline - > result . var ) , & iter - > std ) ;
Z_FE_ITER_P ( EX_VAR ( opline - > result . var ) ) = ( uint32_t ) - 1 ;
return is_empty ;
}
/* }}} */
2018-07-17 17:58:58 +08:00
static zend_always_inline int _zend_quick_get_constant (
const zval * key , uint32_t flags , int check_defined_only OPLINE_DC EXECUTE_DATA_DC ) /* {{{ */
{
zval * zv ;
const zval * orig_key = key ;
zend_constant * c = NULL ;
zv = zend_hash_find_ex ( EG ( zend_constants ) , Z_STR_P ( key ) , 1 ) ;
if ( zv ) {
c = ( zend_constant * ) Z_PTR_P ( zv ) ;
} else {
key + + ;
zv = zend_hash_find_ex ( EG ( zend_constants ) , Z_STR_P ( key ) , 1 ) ;
2018-07-26 17:58:07 +08:00
if ( zv & & ( ZEND_CONSTANT_FLAGS ( ( zend_constant * ) Z_PTR_P ( zv ) ) & CONST_CS ) = = 0 ) {
2018-07-17 17:58:58 +08:00
c = ( zend_constant * ) Z_PTR_P ( zv ) ;
} else {
if ( ( flags & ( IS_CONSTANT_IN_NAMESPACE | IS_CONSTANT_UNQUALIFIED ) ) = = ( IS_CONSTANT_IN_NAMESPACE | IS_CONSTANT_UNQUALIFIED ) ) {
key + + ;
zv = zend_hash_find_ex ( EG ( zend_constants ) , Z_STR_P ( key ) , 1 ) ;
if ( zv ) {
c = ( zend_constant * ) Z_PTR_P ( zv ) ;
} else {
key + + ;
zv = zend_hash_find_ex ( EG ( zend_constants ) , Z_STR_P ( key ) , 1 ) ;
2018-07-26 17:58:07 +08:00
if ( zv & & ( ZEND_CONSTANT_FLAGS ( ( zend_constant * ) Z_PTR_P ( zv ) ) & CONST_CS ) = = 0 ) {
2018-07-17 17:58:58 +08:00
c = ( zend_constant * ) Z_PTR_P ( zv ) ;
}
}
}
}
}
if ( ! c ) {
if ( ! check_defined_only ) {
if ( ( opline - > op1 . num & IS_CONSTANT_UNQUALIFIED ) ! = 0 ) {
char * actual = ( char * ) zend_memrchr ( Z_STRVAL_P ( RT_CONSTANT ( opline , opline - > op2 ) ) , ' \\ ' , Z_STRLEN_P ( RT_CONSTANT ( opline , opline - > op2 ) ) ) ;
if ( ! actual ) {
ZVAL_STR_COPY ( EX_VAR ( opline - > result . var ) , Z_STR_P ( RT_CONSTANT ( opline , opline - > op2 ) ) ) ;
} else {
actual + + ;
ZVAL_STRINGL ( EX_VAR ( opline - > result . var ) ,
actual , Z_STRLEN_P ( RT_CONSTANT ( opline , opline - > op2 ) ) - ( actual - Z_STRVAL_P ( RT_CONSTANT ( opline , opline - > op2 ) ) ) ) ;
}
/* non-qualified constant - allow text substitution */
zend_error ( E_WARNING , " Use of undefined constant %s - assumed '%s' (this will throw an Error in a future version of PHP) " ,
Z_STRVAL_P ( EX_VAR ( opline - > result . var ) ) , Z_STRVAL_P ( EX_VAR ( opline - > result . var ) ) ) ;
} else {
zend_throw_error ( NULL , " Undefined constant '%s' " , Z_STRVAL_P ( RT_CONSTANT ( opline , opline - > op2 ) ) ) ;
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ;
}
}
return FAILURE ;
}
if ( ! check_defined_only ) {
ZVAL_COPY_OR_DUP ( EX_VAR ( opline - > result . var ) , & c - > value ) ;
2018-07-26 17:58:07 +08:00
if ( ! ( ZEND_CONSTANT_FLAGS ( c ) & ( CONST_CS | CONST_CT_SUBST ) ) ) {
2018-07-17 17:58:58 +08:00
const char * ns_sep ;
size_t shortname_offset ;
size_t shortname_len ;
zend_bool is_deprecated ;
if ( flags & IS_CONSTANT_UNQUALIFIED ) {
const zval * access_key ;
if ( ! ( flags & IS_CONSTANT_IN_NAMESPACE ) ) {
access_key = orig_key - 1 ;
} else {
if ( key < orig_key + 2 ) {
goto check_short_name ;
} else {
access_key = orig_key + 2 ;
}
}
is_deprecated = ! zend_string_equals ( c - > name , Z_STR_P ( access_key ) ) ;
} else {
check_short_name :
ns_sep = zend_memrchr ( ZSTR_VAL ( c - > name ) , ' \\ ' , ZSTR_LEN ( c - > name ) ) ;
ZEND_ASSERT ( ns_sep ) ;
/* Namespaces are always case-insensitive. Only compare shortname. */
shortname_offset = ns_sep - ZSTR_VAL ( c - > name ) + 1 ;
shortname_len = ZSTR_LEN ( c - > name ) - shortname_offset ;
is_deprecated = memcmp ( ZSTR_VAL ( c - > name ) + shortname_offset , Z_STRVAL_P ( orig_key - 1 ) + shortname_offset , shortname_len ) ! = 0 ;
}
if ( is_deprecated ) {
zend_error ( E_DEPRECATED ,
" Case-insensitive constants are deprecated. "
" The correct casing for this constant is \" %s \" " ,
ZSTR_VAL ( c - > name ) ) ;
return SUCCESS ;
}
}
}
CACHE_PTR ( opline - > extended_value , c ) ;
return SUCCESS ;
}
/* }}} */
static zend_never_inline void ZEND_FASTCALL zend_quick_get_constant (
const zval * key , uint32_t flags OPLINE_DC EXECUTE_DATA_DC ) /* {{{ */
{
_zend_quick_get_constant ( key , flags , 0 OPLINE_CC EXECUTE_DATA_CC ) ;
2018-07-23 15:52:00 +08:00
} /* }}} */
2018-07-17 17:58:58 +08:00
static zend_never_inline int ZEND_FASTCALL zend_quick_check_constant (
2018-07-23 15:52:00 +08:00
const zval * key OPLINE_DC EXECUTE_DATA_DC ) /* {{{ */
2018-07-17 17:58:58 +08:00
{
2018-07-23 15:52:00 +08:00
return _zend_quick_get_constant ( key , 0 , 1 OPLINE_CC EXECUTE_DATA_CC ) ;
} /* }}} */
2018-07-17 17:58:58 +08:00
2018-02-19 21:50:24 +08:00
# ifdef ZEND_VM_TRACE_HANDLERS
# include "zend_vm_trace_handlers.h"
2018-02-22 20:31:00 +08:00
# elif defined(ZEND_VM_TRACE_MAP)
# include "zend_vm_trace_map.h"
2018-02-19 21:50:24 +08:00
# 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
2018-06-05 16:26:15 +08:00
# define ZEND_VM_JMP_EX(new_op, check_exception) do { \
if ( check_exception & & UNEXPECTED ( EG ( exception ) ) ) { \
2016-11-22 16:50:48 +08:00
HANDLE_EXCEPTION ( ) ; \
} \
2016-12-02 16:58:41 +08:00
ZEND_VM_SET_OPCODE ( new_op ) ; \
ZEND_VM_CONTINUE ( ) ; \
2016-11-22 16:50:48 +08:00
} while ( 0 )
2012-12-05 17:23:37 +08:00
2018-06-05 16:26:15 +08:00
# define ZEND_VM_JMP(new_op) \
ZEND_VM_JMP_EX ( new_op , 1 )
2012-12-05 17:23:37 +08:00
# 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 { \
2018-09-19 16:47:02 +08:00
if ( ( _check ) & & UNEXPECTED ( EG ( exception ) ) ) { \
break ; \
} \
2015-04-29 09:17:59 +08:00
if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPZ ) ) { \
2018-09-19 16:47:02 +08:00
if ( _result ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
} else { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
} \
2015-04-29 09:17:59 +08:00
} else if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPNZ ) ) { \
2018-09-19 16:47:02 +08:00
if ( ! ( _result ) ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
} else { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
} \
2015-04-29 09:17:59 +08:00
} else { \
break ; \
} \
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 ) ) ) { \
2018-09-19 16:47:02 +08:00
break ; \
2016-03-11 17:17:03 +08:00
} \
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 ) ) ) { \
2018-09-19 16:47:02 +08:00
break ; \
2016-03-11 17:17:03 +08:00
} \
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 )
2019-04-05 05:25:45 +08:00
# define ZEND_VM_SMART_BRANCH_TRUE() do { \
if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPNZ ) ) { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
ZEND_VM_CONTINUE ( ) ; \
} else if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPZ ) ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
ZEND_VM_CONTINUE ( ) ; \
} \
} while ( 0 )
2019-07-12 01:44:39 +08:00
# define ZEND_VM_SMART_BRANCH_TRUE_JMPZ() do { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
# define ZEND_VM_SMART_BRANCH_TRUE_JMPNZ() do { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
2019-04-05 05:25:45 +08:00
# define ZEND_VM_SMART_BRANCH_FALSE() do { \
if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPNZ ) ) { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
ZEND_VM_CONTINUE ( ) ; \
} else if ( EXPECTED ( ( opline + 1 ) - > opcode = = ZEND_JMPZ ) ) { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
ZEND_VM_CONTINUE ( ) ; \
} \
} while ( 0 )
2019-07-12 01:44:39 +08:00
# define ZEND_VM_SMART_BRANCH_FALSE_JMPZ() do { \
ZEND_VM_SET_OPCODE ( OP_JMP_ADDR ( opline + 1 , ( opline + 1 ) - > op2 ) ) ; \
ZEND_VM_CONTINUE ( ) ; \
} while ( 0 )
# define ZEND_VM_SMART_BRANCH_FALSE_JMPNZ() do { \
ZEND_VM_SET_NEXT_OPCODE ( opline + 2 ) ; \
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)
2019-04-05 05:25:45 +08:00
# define ZEND_VM_SMART_BRANCH_TRUE()
2019-04-05 13:51:30 +08:00
# define ZEND_VM_SMART_BRANCH_FALSE()
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
2016-12-07 05:41:07 +08:00
# define UNDEF_RESULT() do { \
if ( opline - > result_type & ( IS_VAR | IS_TMP_VAR ) ) { \
ZVAL_UNDEF ( EX_VAR ( opline - > result . var ) ) ; \
} \
} while ( 0 )
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 ] ;
}
2017-10-04 21:53:01 +08:00
ZEND_API zval * zend_get_zval_ptr ( const zend_op * opline , int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type )
2015-08-12 00:11:21 +08:00
{
2017-06-16 06:42:49 +08:00
zval * ret ;
switch ( op_type ) {
case IS_CONST :
2017-10-04 21:53:01 +08:00
ret = RT_CONSTANT ( opline , * node ) ;
2017-06-16 06:42:49 +08:00
* should_free = NULL ;
2017-06-28 16:21:19 +08:00
break ;
2017-06-16 06:42:49 +08:00
case IS_TMP_VAR :
case IS_VAR :
ret = EX_VAR ( node - > var ) ;
* should_free = ret ;
2017-06-28 16:21:19 +08:00
break ;
2017-06-16 06:42:49 +08:00
case IS_CV :
ret = EX_VAR ( node - > var ) ;
* should_free = NULL ;
2017-06-28 16:21:19 +08:00
break ;
2017-06-16 06:42:49 +08:00
default :
ret = NULL ;
* should_free = ret ;
2017-06-28 16:21:19 +08:00
break ;
2017-06-16 06:42:49 +08:00
}
return ret ;
2012-12-05 17:23:37 +08:00
}