1999-04-08 02:10:10 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Zend Engine |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-01-03 11:08:10 +08:00
| Copyright ( c ) 1998 - 2014 Zend Technologies Ltd . ( http : //www.zend.com) |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license , |
2002-10-25 02:04:12 +08:00
| that is bundled with this package in the file LICENSE , and is |
2003-06-11 04:04:29 +08:00
| available through the world - wide - web at the following url : |
2001-12-11 23:16:21 +08:00
| http : //www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ zend . com so we can mail you a copy immediately . |
1999-04-08 02:10:10 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Andi Gutmans < andi @ zend . com > |
| Zeev Suraski < zeev @ zend . com > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2003-02-01 09:49:15 +08:00
/* $Id$ */
2000-02-10 05:48:16 +08:00
# define ZEND_INTENSIVE_DEBUGGING 0
1999-07-16 22:58:16 +08:00
1999-04-08 02:10:10 +08:00
# include <stdio.h>
# include <signal.h>
# include "zend.h"
# include "zend_compile.h"
# include "zend_execute.h"
# include "zend_API.h"
# include "zend_ptr_stack.h"
# include "zend_constants.h"
# include "zend_extensions.h"
2002-11-20 01:51:30 +08:00
# include "zend_ini.h"
2004-02-12 18:38:14 +08:00
# include "zend_exceptions.h"
2006-05-10 07:53:23 +08:00
# include "zend_interfaces.h"
2008-07-14 17:49:03 +08:00
# include "zend_closures.h"
2012-05-20 20:45:01 +08:00
# include "zend_generators.h"
2004-09-24 05:43:32 +08:00
# include "zend_vm.h"
2010-04-24 21:32:30 +08:00
# include "zend_dtrace.h"
2004-09-24 05:43:32 +08:00
2006-05-15 23:31:27 +08:00
/* Virtual current working directory support */
2013-10-17 15:43:52 +08:00
# include "zend_virtual_cwd.h"
2006-05-15 23:31:27 +08:00
2004-10-23 05:42:14 +08:00
# define _CONST_CODE 0
# define _TMP_CODE 1
# define _VAR_CODE 2
# define _UNUSED_CODE 3
# define _CV_CODE 4
2004-09-24 05:43:32 +08:00
typedef int ( * incdec_t ) ( zval * ) ;
1999-04-08 02:10:10 +08:00
2012-12-04 14:14:39 +08:00
# define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
2014-04-17 06:12:06 +08:00
# define get_zval_ptr_deref(op_type, node, ex, should_free, type) _get_zval_ptr_deref(op_type, node, ex, should_free, type TSRMLS_CC)
2012-12-04 14:14:39 +08:00
# define get_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
2014-04-17 06:12:06 +08:00
# define get_zval_ptr_ptr_undef(op_type, node, ex, should_free, type) _get_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
2012-12-04 14:14:39 +08:00
# define get_obj_zval_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
# define get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type) _get_obj_zval_ptr_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
1999-04-08 02:10:10 +08:00
/* Prototypes */
2008-08-13 01:20:25 +08:00
static void zend_extension_statement_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC ) ;
static void zend_extension_fcall_begin_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC ) ;
static void zend_extension_fcall_end_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC ) ;
1999-04-08 02:10:10 +08:00
2010-04-20 18:57:45 +08:00
# define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
1999-12-21 23:55:46 +08:00
2004-08-02 10:35:01 +08:00
# define TEMP_VAR_STACK_LIMIT 2000
2003-08-19 07:11:58 +08:00
2014-04-04 06:52:53 +08:00
static zend_always_inline void zend_pzval_unlock_func ( zval * z , zend_free_op * should_free )
2003-08-19 07:11:58 +08:00
{
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-04-04 06:52:53 +08:00
if ( Z_REFCOUNTED_P ( z ) & & ! Z_DELREF_P ( z ) ) {
Z_SET_REFCOUNT_P ( z , 1 ) ;
should_free - > var = z ;
/* should_free->is_var = 1; */
2003-08-19 07:11:58 +08:00
}
}
2010-04-20 19:16:39 +08:00
# undef zval_ptr_dtor
2014-02-10 14:04:30 +08:00
# define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC TSRMLS_CC)
# define zval_ptr_dtor_nogc(zv) i_zval_ptr_dtor_nogc(zv ZEND_FILE_LINE_CC TSRMLS_CC)
2010-04-20 19:16:39 +08:00
2014-04-04 06:52:53 +08:00
# define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f)
2014-02-22 00:35:40 +08:00
# define PZVAL_LOCK(z) if (Z_REFCOUNTED_P(z)) Z_ADDREF_P((z))
2010-04-20 18:57:45 +08:00
# define SELECTIVE_PZVAL_LOCK(pzv, opline) if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
2004-02-12 00:28:46 +08:00
2014-03-04 21:23:23 +08:00
# define EXTRACT_ZVAL_PTR(zv) do { \
zval * __zv = ( zv ) ; \
if ( Z_TYPE_P ( __zv ) = = IS_INDIRECT ) { \
2014-04-04 23:01:53 +08:00
ZVAL_COPY ( __zv , Z_INDIRECT_P ( __zv ) ) ; \
2014-03-04 21:23:23 +08:00
} \
2010-04-20 19:16:39 +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) \
if ( should_free . var ) { \
2007-04-16 16:09:56 +08:00
if ( ( zend_uintptr_t ) should_free . var & 1L ) { \
zval_dtor ( ( zval * ) ( ( zend_uintptr_t ) should_free . var & ~ 1L ) ) ; \
2004-08-20 04:03:06 +08:00
} else { \
2014-02-10 14:04:30 +08:00
zval_ptr_dtor_nogc ( should_free . var ) ; \
2004-08-20 04:03:06 +08:00
} \
}
2004-09-24 05:43:32 +08:00
# define FREE_OP_IF_VAR(should_free) \
2007-04-16 16:09:56 +08:00
if ( should_free . var ! = NULL & & ( ( ( zend_uintptr_t ) should_free . var & 1L ) = = 0 ) ) { \
2014-02-10 14:04:30 +08:00
zval_ptr_dtor_nogc ( should_free . var ) ; \
2004-08-20 04:03:06 +08:00
}
# define FREE_OP_VAR_PTR(should_free) \
if ( should_free . var ) { \
2014-02-10 14:04:30 +08:00
zval_ptr_dtor_nogc ( should_free . var ) ; \
2004-08-20 04:03:06 +08:00
}
2007-04-16 16:09:56 +08:00
# define TMP_FREE(z) (zval*)(((zend_uintptr_t)(z)) | 1L)
2004-09-24 05:43:32 +08:00
2007-04-16 16:09:56 +08:00
# define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
2004-09-24 05:43:32 +08:00
2005-06-03 19:16:19 +08:00
# define MAKE_REAL_ZVAL_PTR(val) \
do { \
2014-02-10 14:04:30 +08:00
zval _tmp ; \
ZVAL_COPY_VALUE ( & _tmp , ( val ) ) ; \
( val ) = & _tmp ; \
2005-06-03 19:16:19 +08:00
} while ( 0 )
2003-08-19 07:11:58 +08:00
/* End of zend_execute_locks.h */
2004-10-05 03:54:35 +08:00
# define CV_DEF_OF(i) (EG(active_op_array)->vars[i])
2007-09-29 15:28:34 +08:00
# define CTOR_CALL_BIT 0x1
# define CTOR_USED_BIT 0x2
# define IS_CTOR_CALL(ce) (((zend_uintptr_t)(ce)) & CTOR_CALL_BIT)
# define IS_CTOR_USED(ce) (((zend_uintptr_t)(ce)) & CTOR_USED_BIT)
# define ENCODE_CTOR(ce, used) \
( ( zend_class_entry * ) ( ( ( zend_uintptr_t ) ( ce ) ) | CTOR_CALL_BIT | ( ( used ) ? CTOR_USED_BIT : 0 ) ) )
# define DECODE_CTOR(ce) \
( ( zend_class_entry * ) ( ( ( zend_uintptr_t ) ( ce ) ) & ~ ( CTOR_CALL_BIT | CTOR_USED_BIT ) ) )
2012-12-05 17:23:37 +08:00
# undef EX
# define EX(element) execute_data->element
2014-02-10 14:04:30 +08:00
ZEND_API zval * zend_get_compiled_variable_value ( const zend_execute_data * execute_data , zend_uint 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
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_tmp ( zend_uint var , const zend_execute_data * execute_data , zend_free_op * should_free TSRMLS_DC )
2005-06-14 01:50:07 +08:00
{
2014-03-04 16:27:50 +08:00
zval * ret = EX_VAR ( var ) ;
should_free - > var = ret ;
return ret ;
2005-06-14 01:50:07 +08:00
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_var ( zend_uint var , const zend_execute_data * execute_data , zend_free_op * should_free TSRMLS_DC )
2005-03-24 05:05:56 +08:00
{
2014-02-18 20:27:38 +08:00
zval * ret = EX_VAR ( var ) ;
should_free - > var = ret ;
return ret ;
}
static zend_always_inline zval * _get_zval_ptr_var_deref ( zend_uint var , const zend_execute_data * execute_data , zend_free_op * should_free TSRMLS_DC )
{
zval * ret = EX_VAR ( var ) ;
should_free - > var = 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
2014-02-19 05:12:05 +08:00
static zend_never_inline zval * _get_zval_cv_lookup ( zval * ptr , zend_uint var , int type TSRMLS_DC )
2009-03-11 20:14:34 +08:00
{
2014-03-26 22:07:31 +08:00
zend_string * cv ;
2014-02-19 05:12:05 +08:00
switch ( type ) {
case BP_VAR_R :
case BP_VAR_UNSET :
2014-03-27 20:00:25 +08:00
cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
2014-02-19 05:12:05 +08:00
zend_error ( E_NOTICE , " Undefined variable: %s " , cv - > val ) ;
/* break missing intentionally */
case BP_VAR_IS :
2014-03-26 22:07:31 +08:00
ptr = & EG ( uninitialized_zval ) ;
break ;
2014-02-19 05:12:05 +08:00
case BP_VAR_RW :
2014-03-27 20:00:25 +08:00
cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
2014-02-19 05:12:05 +08:00
zend_error ( E_NOTICE , " Undefined variable: %s " , cv - > val ) ;
/* break missing intentionally */
case BP_VAR_W :
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
2014-02-19 05:12:05 +08:00
break ;
}
2014-03-26 22:07:31 +08:00
return ptr ;
2005-03-24 05:05:56 +08:00
}
2014-03-27 15:19:34 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_R ( zval * ptr , zend_uint var TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zend_string * cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
2014-02-19 05:12:05 +08:00
zend_error ( E_NOTICE , " Undefined variable: %s " , cv - > val ) ;
return & EG ( uninitialized_zval ) ;
2010-04-20 19:16:39 +08:00
}
2014-03-27 15:19:34 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_UNSET ( zval * ptr , zend_uint var TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zend_string * cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
2014-02-19 05:12:05 +08:00
zend_error ( E_NOTICE , " Undefined variable: %s " , cv - > val ) ;
return & EG ( uninitialized_zval ) ;
2010-04-20 19:16:39 +08:00
}
2014-03-27 15:19:34 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_IS ( zval * ptr , zend_uint var TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-02-19 05:12:05 +08:00
return & EG ( uninitialized_zval ) ;
2010-04-20 19:16:39 +08:00
}
2014-03-27 15:19:34 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_RW ( zval * ptr , zend_uint var TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-03-27 20:00:25 +08:00
zend_string * cv = CV_DEF_OF ( EX_VAR_TO_NUM ( var ) ) ;
2010-04-20 19:16:39 +08:00
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
zend_error ( E_NOTICE , " Undefined variable: %s " , cv - > val ) ;
return ptr ;
2010-04-20 19:16:39 +08:00
}
2014-03-27 15:19:34 +08:00
static zend_always_inline zval * _get_zval_cv_lookup_BP_VAR_W ( zval * ptr , zend_uint var TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-03-26 22:07:31 +08:00
ZVAL_NULL ( ptr ) ;
return ptr ;
2010-04-20 19:16:39 +08:00
}
2014-03-27 20:00:25 +08:00
static zend_always_inline zval * _get_zval_ptr_cv ( const zend_execute_data * execute_data , zend_uint var , int type TSRMLS_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 ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup ( ret , var , type TSRMLS_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
}
2014-03-27 20:00:25 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref ( const zend_execute_data * execute_data , zend_uint var , int type TSRMLS_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 ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup ( ret , var , type TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_R ( const zend_execute_data * execute_data , zend_uint var TSRMLS_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 ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_R ( ret , var TSRMLS_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
}
2014-02-18 20:27:38 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_R ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_R ( ret , var TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_UNSET ( const zend_execute_data * execute_data , zend_uint var TSRMLS_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 ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_UNSET ( ret , var TSRMLS_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
}
2014-02-18 20:27:38 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_UNSET ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_UNSET ( ret , var TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_IS ( const zend_execute_data * execute_data , zend_uint var TSRMLS_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 ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_IS ( ret , var TSRMLS_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
}
2014-02-18 20:27:38 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_IS ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
2014-03-27 15:19:34 +08:00
if ( Z_TYPE_P ( ret ) = = IS_UNDEF ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_IS ( ret , var TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_RW ( const zend_execute_data * execute_data , zend_uint var TSRMLS_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 ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_RW ( ret , var TSRMLS_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
}
2014-02-18 20:27:38 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_RW ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( ret ) = = IS_UNDEF ) ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_RW ( ret , var TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_BP_VAR_W ( const zend_execute_data * execute_data , zend_uint var TSRMLS_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 ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_W ( ret , var TSRMLS_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
}
2014-04-04 18:36:34 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_undef_BP_VAR_W ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
return EX_VAR ( var ) ;
}
2014-02-18 20:27:38 +08:00
static zend_always_inline zval * _get_zval_ptr_cv_deref_BP_VAR_W ( const zend_execute_data * execute_data , zend_uint var TSRMLS_DC )
{
2014-03-27 20:00:25 +08:00
zval * ret = EX_VAR ( var ) ;
2014-02-18 20:27:38 +08:00
2014-03-27 15:19:34 +08:00
if ( Z_TYPE_P ( ret ) = = IS_UNDEF ) {
2014-02-19 05:12:05 +08:00
return _get_zval_cv_lookup_BP_VAR_W ( ret , var TSRMLS_CC ) ;
}
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( ret ) ;
2014-02-18 20:27:38 +08:00
return ret ;
}
2012-12-04 14:14:39 +08:00
static inline zval * _get_zval_ptr ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC )
2004-09-24 05:43:32 +08:00
{
2014-03-04 16:27:50 +08:00
zval * ret ;
2010-04-20 18:57:45 +08:00
switch ( op_type ) {
2005-06-14 01:50:07 +08:00
case IS_CONST :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2010-04-20 18:57:45 +08:00
return node - > zv ;
2005-06-14 01:50:07 +08:00
break ;
case IS_TMP_VAR :
2014-03-04 16:27:50 +08:00
ret = EX_VAR ( node - > var ) ;
should_free - > var = TMP_FREE ( ret ) ;
return ret ;
2005-06-14 01:50:07 +08:00
break ;
case IS_VAR :
2012-12-04 14:14:39 +08:00
return _get_zval_ptr_var ( node - > var , execute_data , should_free TSRMLS_CC ) ;
2005-06-14 01:50:07 +08:00
break ;
case IS_UNUSED :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2005-06-14 01:50:07 +08:00
return NULL ;
break ;
case IS_CV :
2014-04-22 21:46:34 +08:00
default :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-03-27 20:00:25 +08:00
return _get_zval_ptr_cv ( execute_data , node - > var , type TSRMLS_CC ) ;
2005-06-14 01:50:07 +08:00
break ;
}
2004-09-24 05:43:32 +08:00
return NULL ;
}
2014-02-18 20:27:38 +08:00
static inline zval * _get_zval_ptr_deref ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC )
{
2014-03-04 16:27:50 +08:00
zval * ret ;
2014-02-18 20:27:38 +08:00
switch ( op_type ) {
case IS_CONST :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-02-18 20:27:38 +08:00
return node - > zv ;
break ;
case IS_TMP_VAR :
2014-03-04 16:27:50 +08:00
ret = EX_VAR ( node - > var ) ;
should_free - > var = TMP_FREE ( ret ) ;
return ret ;
2014-02-18 20:27:38 +08:00
break ;
case IS_VAR :
return _get_zval_ptr_var_deref ( node - > var , execute_data , should_free TSRMLS_CC ) ;
break ;
case IS_UNUSED :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-02-18 20:27:38 +08:00
return NULL ;
break ;
case IS_CV :
2014-04-22 21:46:34 +08:00
default :
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-03-27 20:00:25 +08:00
return _get_zval_ptr_cv_deref ( execute_data , node - > var , type TSRMLS_CC ) ;
2014-02-18 20:27:38 +08:00
break ;
}
return NULL ;
}
2014-03-04 16:27:50 +08:00
static zend_always_inline zval * _get_zval_ptr_ptr_var ( zend_uint var , const zend_execute_data * execute_data , zend_free_op * should_free TSRMLS_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-04-04 23:01:53 +08:00
should_free - > var = NULL ;
return Z_INDIRECT_P ( ret ) ;
2014-03-04 16:27:50 +08:00
} else if ( ! Z_REFCOUNTED_P ( ret ) ) {
2014-04-04 23:01:53 +08:00
should_free - > var = ret ; //???
return ret ;
} else {
PZVAL_UNLOCK ( ret , should_free ) ;
2014-03-04 16:27:50 +08:00
return ret ;
2002-03-10 21:42:37 +08:00
}
2004-09-24 05:43:32 +08:00
}
2014-04-17 06:12:06 +08:00
static inline zval * _get_zval_ptr_ptr ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC )
{
if ( op_type = = IS_CV ) {
should_free - > var = NULL ;
return _get_zval_ptr_cv ( execute_data , node - > var , type TSRMLS_CC ) ;
} else /* if (op_type == IS_VAR) */ {
ZEND_ASSERT ( op_type = = IS_VAR ) ;
return _get_zval_ptr_ptr_var ( node - > var , execute_data , should_free TSRMLS_CC ) ;
}
}
2009-03-18 22:15:28 +08:00
static zend_always_inline zval * _get_obj_zval_ptr_unused ( TSRMLS_D )
2004-09-24 05:43:32 +08:00
{
2014-03-28 06:11:22 +08:00
if ( EXPECTED ( Z_OBJ ( EG ( This ) ) ! = NULL ) ) {
2004-09-24 05:43:32 +08:00
return & EG ( This ) ;
} else {
zend_error_noreturn ( E_ERROR , " Using $this when not in object context " ) ;
return NULL ;
}
}
1999-12-23 02:10:38 +08:00
2012-12-04 14:14:39 +08:00
static inline zval * _get_obj_zval_ptr ( int op_type , znode_op * op , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC )
2005-06-14 01:50:07 +08:00
{
2010-04-20 18:57:45 +08:00
if ( op_type = = IS_UNUSED ) {
2014-03-28 06:11:22 +08:00
if ( EXPECTED ( Z_OBJ ( EG ( This ) ) ! = NULL ) ) {
2014-03-04 16:27:50 +08:00
should_free - > var = NULL ;
2014-02-10 14:04:30 +08:00
return & EG ( This ) ;
2005-06-14 01:50:07 +08:00
} else {
zend_error_noreturn ( E_ERROR , " Using $this when not in object context " ) ;
}
}
2012-12-04 14:14:39 +08:00
return get_zval_ptr ( op_type , op , execute_data , should_free , type ) ;
2005-06-14 01:50:07 +08:00
}
2014-04-17 06:12:06 +08:00
static inline zval * _get_obj_zval_ptr_ptr ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC )
{
if ( op_type = = IS_UNUSED ) {
if ( EXPECTED ( Z_OBJ ( EG ( This ) ) ! = NULL ) ) {
should_free - > var = NULL ;
return & EG ( This ) ;
} else {
zend_error_noreturn ( E_ERROR , " Using $this when not in object context " ) ;
}
}
return get_zval_ptr_ptr ( op_type , node , execute_data , should_free , type ) ;
}
2014-04-03 20:53:30 +08:00
static inline void zend_assign_to_variable_reference ( zval * variable_ptr , zval * value_ptr TSRMLS_DC )
2001-06-22 05:17:10 +08:00
{
2014-04-03 20:53:30 +08:00
if ( EXPECTED ( variable_ptr ! = value_ptr ) ) {
2014-02-10 14:04:30 +08:00
SEPARATE_ZVAL_TO_MAKE_IS_REF ( value_ptr ) ;
2014-04-03 20:53:30 +08:00
Z_ADDREF_P ( value_ptr ) ;
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( variable_ptr ) ;
2014-04-03 20:53:30 +08:00
ZVAL_COPY_VALUE ( variable_ptr , value_ptr ) ;
2007-10-07 13:22:07 +08:00
} else if ( ! Z_ISREF_P ( variable_ptr ) ) {
2014-02-24 16:15:11 +08:00
ZVAL_NEW_REF ( variable_ptr , variable_ptr ) ;
2001-06-22 05:17:10 +08:00
}
}
2007-07-19 23:29:30 +08:00
/* this should modify object only if it's empty */
2014-04-04 06:52:53 +08:00
static inline zval * make_real_object ( zval * object_ptr TSRMLS_DC )
2002-03-11 05:02:00 +08:00
{
2014-03-14 02:56:18 +08:00
zval * object = object_ptr ;
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( object ) ;
2014-04-04 06:52:53 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( object ) ! = IS_OBJECT ) ) {
if ( Z_TYPE_P ( object ) = = IS_NULL
2014-04-30 22:32:42 +08:00
| | Z_TYPE_P ( object ) = = IS_FALSE
2014-04-04 06:52:53 +08:00
| | ( Z_TYPE_P ( object ) = = IS_STRING & & Z_STRLEN_P ( object ) = = 0 ) ) {
if ( EXPECTED ( object = = object_ptr ) ) {
/* object_ptr is not a reference */
SEPARATE_ZVAL ( object ) ;
}
zval_dtor ( object ) ;
object_init ( object ) ;
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
2014-03-14 02:56:18 +08:00
}
2002-03-10 21:42:37 +08:00
}
2014-04-04 06:52:53 +08:00
return object ;
2002-03-10 21:42:37 +08:00
}
2002-10-17 02:06:36 +08:00
2014-02-10 14:04:30 +08:00
ZEND_API char * zend_verify_arg_class_kind ( const zend_arg_info * cur_arg_info , ulong fetch_type , char * * class_name , zend_class_entry * * pce TSRMLS_DC )
2006-05-26 08:36:13 +08:00
{
2014-05-02 23:01:36 +08:00
zend_string * key ;
ALLOCA_FLAG ( use_heap ) ;
STR_ALLOCA_INIT ( key , cur_arg_info - > class_name , cur_arg_info - > class_name_len , use_heap ) ;
2014-02-10 14:04:30 +08:00
* pce = zend_fetch_class ( key , ( fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD ) TSRMLS_CC ) ;
2014-05-02 23:01:36 +08:00
STR_ALLOCA_FREE ( key , use_heap ) ;
2014-02-10 14:04:30 +08:00
* class_name = ( * pce ) ? ( * pce ) - > name - > val : ( char * ) cur_arg_info - > class_name ;
2006-10-02 19:09:52 +08:00
if ( * pce & & ( * pce ) - > ce_flags & ZEND_ACC_INTERFACE ) {
2006-05-26 08:36:13 +08:00
return " implement interface " ;
} else {
return " be an instance of " ;
}
}
2014-04-04 18:36:34 +08:00
ZEND_API void zend_verify_arg_error ( int error_type , const zend_function * zf , zend_uint arg_num , const char * need_msg , const char * need_kind , const char * given_msg , const char * given_kind TSRMLS_DC )
2006-05-26 08:36:13 +08:00
{
zend_execute_data * ptr = EG ( current_execute_data ) - > prev_execute_data ;
2014-02-10 14:04:30 +08:00
const char * fname = zf - > common . function_name - > val ;
const char * fsep ;
2010-10-15 05:33:10 +08:00
const char * fclass ;
2006-05-26 08:36:13 +08:00
if ( zf - > common . scope ) {
fsep = " :: " ;
2014-02-10 14:04:30 +08:00
fclass = zf - > common . scope - > name - > val ;
2006-05-26 08:36:13 +08:00
} else {
fsep = " " ;
fclass = " " ;
}
if ( ptr & & ptr - > op_array ) {
2014-02-10 14:04:30 +08:00
zend_error ( error_type , " Argument %d passed to %s%s%s() must %s%s, %s%s given, called in %s on line %d and defined " , arg_num , fclass , fsep , fname , need_msg , need_kind , given_msg , given_kind , ptr - > op_array - > filename - > val , ptr - > opline - > lineno ) ;
2006-05-26 08:36:13 +08:00
} else {
2010-10-19 18:42:38 +08:00
zend_error ( error_type , " Argument %d passed to %s%s%s() must %s%s, %s%s given " , arg_num , fclass , fsep , fname , need_msg , need_kind , given_msg , given_kind ) ;
2006-05-26 08:36:13 +08:00
}
}
2014-04-04 18:36:34 +08:00
static void zend_verify_arg_type ( zend_function * zf , zend_uint arg_num , zval * arg , ulong fetch_type TSRMLS_DC )
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-26 08:36:13 +08:00
char * need_msg ;
2006-05-22 02:10:31 +08:00
zend_class_entry * ce ;
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
2014-04-04 18:36:34 +08:00
if ( UNEXPECTED ( ! zf - > common . arg_info ) ) {
return ;
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 ] ;
} else if ( zf - > common . fn_flags & ZEND_ACC_VARIADIC ) {
cur_arg_info = & zf - > common . arg_info [ zf - > common . num_args - 1 ] ;
} else {
2014-04-04 18:36:34 +08:00
return ;
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
if ( cur_arg_info - > class_name ) {
2014-02-10 14:04:30 +08:00
char * class_name ;
2006-10-02 19:09:52 +08:00
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( arg ) ;
2006-05-26 08:36:13 +08:00
if ( Z_TYPE_P ( arg ) = = IS_OBJECT ) {
2007-10-01 18:37:14 +08:00
need_msg = zend_verify_arg_class_kind ( cur_arg_info , fetch_type , & class_name , & ce TSRMLS_CC ) ;
2006-10-02 19:09:52 +08:00
if ( ! ce | | ! instanceof_function ( Z_OBJCE_P ( arg ) , ce TSRMLS_CC ) ) {
2014-04-04 18:36:34 +08:00
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , need_msg , class_name , " instance of " , Z_OBJCE_P ( arg ) - > name - > val TSRMLS_CC ) ;
2006-05-22 02:10:31 +08:00
}
2006-05-26 08:36:13 +08:00
} else if ( Z_TYPE_P ( arg ) ! = IS_NULL | | ! cur_arg_info - > allow_null ) {
2007-10-01 18:37:14 +08:00
need_msg = zend_verify_arg_class_kind ( cur_arg_info , fetch_type , & class_name , & ce TSRMLS_CC ) ;
2014-04-04 18:36:34 +08:00
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , need_msg , class_name , zend_zval_type_name ( arg ) , " " TSRMLS_CC ) ;
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
}
2011-08-16 18:44:47 +08:00
} else if ( cur_arg_info - > type_hint ) {
switch ( cur_arg_info - > type_hint ) {
case IS_ARRAY :
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( arg ) ;
2011-08-16 18:44:47 +08:00
if ( Z_TYPE_P ( arg ) ! = IS_ARRAY & & ( Z_TYPE_P ( arg ) ! = IS_NULL | | ! cur_arg_info - > allow_null ) ) {
2014-04-04 18:36:34 +08:00
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , " be of the type array " , " " , zend_zval_type_name ( arg ) , " " TSRMLS_CC ) ;
2011-08-16 18:44:47 +08:00
}
break ;
case IS_CALLABLE :
2011-08-16 20:01:36 +08:00
if ( ! zend_is_callable ( arg , IS_CALLABLE_CHECK_SILENT , NULL TSRMLS_CC ) & & ( Z_TYPE_P ( arg ) ! = IS_NULL | | ! cur_arg_info - > allow_null ) ) {
2014-04-04 18:36:34 +08:00
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , " be callable " , " " , zend_zval_type_name ( arg ) , " " TSRMLS_CC ) ;
2011-08-16 18:44:47 +08:00
}
break ;
2010-05-21 03:18:35 +08:00
2011-08-16 18:44:47 +08:00
default :
zend_error ( E_ERROR , " Unknown typehint " ) ;
2010-05-21 03:18:35 +08:00
}
2005-05-26 21:46:17 +08:00
}
2014-04-04 18:36:34 +08:00
}
static inline int zend_verify_missing_arg_type ( zend_function * zf , zend_uint arg_num , ulong fetch_type TSRMLS_DC )
{
zend_arg_info * cur_arg_info ;
char * need_msg ;
zend_class_entry * ce ;
if ( UNEXPECTED ( ! zf - > common . arg_info ) ) {
return 1 ;
}
if ( EXPECTED ( arg_num < = zf - > common . num_args ) ) {
cur_arg_info = & zf - > common . arg_info [ arg_num - 1 ] ;
} else if ( zf - > common . fn_flags & ZEND_ACC_VARIADIC ) {
cur_arg_info = & zf - > common . arg_info [ zf - > common . num_args - 1 ] ;
} else {
return 1 ;
}
if ( cur_arg_info - > class_name ) {
char * class_name ;
need_msg = zend_verify_arg_class_kind ( cur_arg_info , fetch_type , & class_name , & ce TSRMLS_CC ) ;
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , need_msg , class_name , " none " , " " TSRMLS_CC ) ;
} else if ( cur_arg_info - > type_hint ) {
switch ( cur_arg_info - > type_hint ) {
case IS_ARRAY :
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , " be of the type array " , " " , " none " , " " TSRMLS_CC ) ;
break ;
case IS_CALLABLE :
zend_verify_arg_error ( E_RECOVERABLE_ERROR , zf , arg_num , " be callable " , " " , " none " , " " TSRMLS_CC ) ;
break ;
default :
zend_error ( E_ERROR , " Unknown typehint " ) ;
}
}
return 0 ;
}
static void zend_verify_missing_arg ( zend_execute_data * execute_data , zend_uint arg_num TSRMLS_DC )
{
if ( EXPECTED ( ! ( EX ( op_array ) - > fn_flags & ZEND_ACC_HAS_TYPE_HINTS ) ) | |
zend_verify_missing_arg_type ( ( zend_function * ) EX ( op_array ) , arg_num , EX ( opline ) - > extended_value TSRMLS_CC ) ) {
const char * class_name = EX ( op_array ) - > scope ? EX ( op_array ) - > scope - > name - > val : " " ;
const char * space = EX ( op_array ) - > scope ? " :: " : " " ;
const char * func_name = EX ( op_array ) - > function_name ? EX ( op_array ) - > function_name - > val : " main " ;
zend_execute_data * ptr = EX ( prev_execute_data ) ;
if ( ptr & & ptr - > op_array ) {
zend_error ( E_WARNING , " Missing argument %u for %s%s%s(), called in %s on line %d and defined " , arg_num , class_name , space , func_name , ptr - > op_array - > filename - > val , ptr - > opline - > lineno ) ;
} else {
zend_error ( E_WARNING , " Missing argument %u for %s%s%s() " , arg_num , class_name , space , func_name ) ;
}
}
ntroduce infrastructure for supplying information about arguments,
including:
- Whether or not to pass by ref (replaces the old arg_types, with arg_info)
- Argument name (for future use, maybe introspection)
- Class/Interface name (for type hints)
- If a class/interface name is available, whether to allow a null instance
Both user and builtin functions share the same data structures.
To declare a builtin function that expects its first arg to be an instance
of class 'Person', its second argument as a regular arg, and its third by
reference, use:
ZEND_BEGIN_ARG_INFO(my_func_arg_info, 0)
ZEND_ARG_OBJ_INFO(0, someone, Person, 1)
ZEND_ARG_PASS_INFO(0)
ZEND_ARG_PASS_INFO(1)
ZEND_END_ARG_INFO();
and use my_func_arg_info as the arg_info parameter to the ZEND_FE() family
of macros.
The first arg to each ZEND_ARG_*() macro is whether or not to pass by ref.
The boolean arg to ZEND_BEGIN_ARG_INFO() tells the engine whether to treat
the arguments for which there's no explicit information as pass by reference
or not.
The boolean argument to ZEND_ARG_OBJ_INFO() (4th arg) is whether or not to allownull values.
2003-08-04 01:40:44 +08:00
}
2014-04-17 19:40:45 +08:00
static inline void zend_assign_to_object ( zval * retval , zval * object_ptr , zval * property_name , int value_type , znode_op * value_op , const zend_execute_data * execute_data , int opcode , zend_uint cache_slot TSRMLS_DC )
2002-03-10 21:42:37 +08:00
{
2007-12-14 22:14:50 +08:00
zend_free_op free_value ;
2012-12-04 14:14:39 +08:00
zval * value = get_zval_ptr ( value_type , value_op , execute_data , & free_value , BP_VAR_R ) ;
2014-02-28 02:53:56 +08:00
zval tmp ;
2014-02-28 04:21:12 +08:00
zval * object = object_ptr ;
2002-03-10 21:42:37 +08:00
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( object ) ;
2009-04-21 16:12:07 +08:00
if ( Z_TYPE_P ( object ) ! = IS_OBJECT ) {
2010-04-20 19:16:39 +08:00
if ( object = = & EG ( error_zval ) ) {
2010-04-20 18:57:45 +08:00
if ( retval ) {
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( retval ) ;
2007-12-14 22:14:50 +08:00
}
FREE_OP ( free_value ) ;
return ;
2006-01-19 15:23:32 +08:00
}
2009-04-21 16:12:07 +08:00
if ( Z_TYPE_P ( object ) = = IS_NULL | |
2014-04-30 22:32:42 +08:00
Z_TYPE_P ( object ) = = IS_FALSE | |
2009-04-21 16:12:07 +08:00
( Z_TYPE_P ( object ) = = IS_STRING & & Z_STRLEN_P ( object ) = = 0 ) ) {
2014-04-09 21:55:40 +08:00
//??? The following block may handle only non-interned empty string,
//??? but it doesn't work anyway
//??? see: Zend/tests/bug54265.phpt
#if 0
2014-02-20 15:39:46 +08:00
if ( Z_REFCOUNTED_P ( object ) ) {
2014-02-28 04:21:12 +08:00
if ( ! Z_ISREF_P ( object_ptr ) ) {
SEPARATE_ZVAL ( object ) ;
}
2014-02-20 15:39:46 +08:00
Z_ADDREF_P ( object ) ;
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
if ( Z_REFCOUNT_P ( object ) = = 1 ) {
/* object was removed by error handler, nothing to assign to */
zval_ptr_dtor ( object ) ;
if ( retval ) {
ZVAL_NULL ( retval ) ;
}
FREE_OP ( free_value ) ;
return ;
2011-03-16 23:21:38 +08:00
}
2014-02-20 15:39:46 +08:00
Z_DELREF_P ( object ) ;
} else {
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
2014-04-15 19:40:40 +08:00
}
# else
zend_error ( E_WARNING , " Creating default object from empty value " ) ;
# endif
2011-03-16 23:21:38 +08:00
zval_dtor ( object ) ;
object_init ( object ) ;
2007-12-14 22:14:50 +08:00
} else {
zend_error ( E_WARNING , " Attempt to assign property of non-object " ) ;
2010-04-20 18:57:45 +08:00
if ( retval ) {
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( retval ) ;
2007-12-14 22:14:50 +08:00
}
FREE_OP ( free_value ) ;
return ;
2004-08-20 04:03:06 +08:00
}
2002-03-10 21:42:37 +08:00
}
2011-03-16 13:41:50 +08:00
2003-01-29 16:55:12 +08:00
/* separate our value if necessary */
2014-02-28 02:53:56 +08:00
if ( value_type = = IS_TMP_VAR ) {
2014-05-29 06:02:13 +08:00
ZEND_ASSERT ( Z_TYPE_P ( value ) ! = IS_REFERENCE ) ;
2014-03-27 17:39:09 +08:00
ZVAL_COPY_VALUE ( & tmp , value ) ;
2014-03-04 16:27:50 +08:00
value = & tmp ;
2014-02-28 02:53:56 +08:00
} else if ( value_type = = IS_CONST ) {
ZVAL_DUP ( & tmp , value ) ;
2014-04-10 19:50:25 +08:00
value = & tmp ;
2014-02-28 02:53:56 +08:00
} else if ( Z_REFCOUNTED_P ( value ) ) {
2014-02-10 14:04:30 +08:00
Z_ADDREF_P ( value ) ;
2003-01-29 16:55:12 +08:00
}
2014-02-28 02:53:56 +08:00
2003-07-07 17:00:36 +08:00
if ( opcode = = ZEND_ASSIGN_OBJ ) {
2007-12-14 22:14:50 +08:00
if ( ! Z_OBJ_HT_P ( object ) - > write_property ) {
zend_error ( E_WARNING , " Attempt to assign property of non-object " ) ;
2010-04-20 18:57:45 +08:00
if ( retval ) {
2014-02-10 14:04:30 +08:00
ZVAL_NULL ( retval ) ;
2007-12-14 22:14:50 +08:00
}
2014-02-10 14:04:30 +08:00
if ( value_type = = IS_CONST ) {
zval_ptr_dtor ( value ) ;
2008-07-26 22:08:11 +08:00
}
2007-12-14 22:14:50 +08:00
FREE_OP ( free_value ) ;
return ;
2004-02-11 23:56:13 +08:00
}
2014-04-17 19:40:45 +08:00
Z_OBJ_HT_P ( object ) - > write_property ( object , property_name , value , cache_slot TSRMLS_CC ) ;
2003-07-07 17:00:36 +08:00
} else {
2004-02-11 23:56:13 +08:00
/* Note: property_name in this case is really the array index! */
2003-07-31 01:12:06 +08:00
if ( ! Z_OBJ_HT_P ( object ) - > write_dimension ) {
2004-09-24 05:43:32 +08:00
zend_error_noreturn ( E_ERROR , " Cannot use object as array " ) ;
2003-07-31 01:12:06 +08:00
}
2004-02-11 23:56:13 +08:00
Z_OBJ_HT_P ( object ) - > write_dimension ( object , property_name , value TSRMLS_CC ) ;
2002-03-10 21:42:37 +08:00
}
2006-05-10 07:53:23 +08:00
2014-02-28 14:41:28 +08:00
if ( retval & & ! EG ( exception ) ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY ( retval , value ) ;
2002-03-10 21:42:37 +08:00
}
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( value ) ;
2004-09-24 05:43:32 +08:00
FREE_OP_IF_VAR ( free_value ) ;
2002-03-10 21:42:37 +08:00
}
2014-04-04 06:52:53 +08:00
static void zend_assign_to_string_offset ( zval * str_offset , zval * value , int value_type , zval * result TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2014-04-04 06:52:53 +08:00
zval * str = Z_STR_OFFSET_STR_P ( str_offset ) ;
zend_uint offset = Z_STR_OFFSET_IDX_P ( str_offset ) ;
zend_string * old_str ;
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
if ( ( int ) offset < 0 ) {
zend_error ( E_WARNING , " Illegal string offset: %d " , offset ) ;
2014-04-04 06:52:53 +08:00
STR_RELEASE ( Z_STR_P ( str ) ) ;
if ( result ) {
ZVAL_NULL ( result ) ;
}
return ;
2014-02-10 14:04:30 +08:00
}
2014-04-04 06:52:53 +08:00
old_str = Z_STR_P ( str ) ;
2014-02-28 21:39:08 +08:00
if ( offset > = Z_STRLEN_P ( str ) ) {
int old_len = Z_STRLEN_P ( str ) ;
Z_STR_P ( str ) = STR_REALLOC ( Z_STR_P ( str ) , offset + 1 , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO_P ( str ) = IS_STRING_EX ;
2014-02-28 21:39:08 +08:00
memset ( Z_STRVAL_P ( str ) + old_len , ' ' , offset - old_len ) ;
Z_STRVAL_P ( str ) [ offset + 1 ] = 0 ;
} else if ( IS_INTERNED ( Z_STR_P ( str ) ) ) {
2014-04-01 20:31:03 +08:00
Z_STR_P ( str ) = STR_INIT ( Z_STRVAL_P ( str ) , Z_STRLEN_P ( str ) , 0 ) ;
2014-04-03 19:26:23 +08:00
Z_TYPE_INFO_P ( str ) = IS_STRING_EX ;
2014-02-10 14:04:30 +08:00
}
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
if ( Z_TYPE_P ( value ) ! = IS_STRING ) {
zval tmp ;
2011-03-16 13:41:50 +08:00
2014-02-10 14:04:30 +08:00
ZVAL_COPY_VALUE ( & tmp , value ) ;
if ( value_type ! = IS_TMP_VAR ) {
2014-04-04 06:52:53 +08:00
zval_opt_copy_ctor ( & tmp ) ;
2014-02-10 14:04:30 +08:00
}
convert_to_string ( & tmp ) ;
2014-02-28 21:39:08 +08:00
Z_STRVAL_P ( str ) [ offset ] = Z_STRVAL ( tmp ) [ 0 ] ;
2014-02-10 14:04:30 +08:00
zval_dtor ( & tmp ) ;
} else {
2014-02-28 21:39:08 +08:00
Z_STRVAL_P ( str ) [ offset ] = Z_STRVAL_P ( value ) [ 0 ] ;
2014-02-10 14:04:30 +08:00
if ( value_type = = IS_TMP_VAR ) {
/* we can safely free final_value here
* because separation is done only
* in case value_type = = IS_VAR */
zval_dtor ( value ) ;
2004-08-20 04:03:06 +08:00
}
1999-04-08 02:10:10 +08:00
}
2014-02-10 14:04:30 +08:00
/*
* the value of an assignment to a string offset is undefined
T ( result - > u . var ) . var = & T - > str_offset . str ;
*/
2014-04-04 06:52:53 +08:00
STR_RELEASE ( old_str ) ;
if ( result ) {
zend_uchar c = ( zend_uchar ) Z_STRVAL_P ( str ) [ offset ] ;
if ( CG ( one_char_string ) [ c ] ) {
ZVAL_INT_STR ( result , CG ( one_char_string ) [ c ] ) ;
} else {
ZVAL_NEW_STR ( result , STR_INIT ( Z_STRVAL_P ( str ) + offset , 1 , 0 ) ) ;
}
}
2007-12-14 22:14:50 +08:00
}
1999-04-08 02:10:10 +08:00
2014-02-10 14:04:30 +08:00
static inline zval * zend_assign_tmp_to_variable ( zval * variable_ptr , zval * value TSRMLS_DC )
2007-12-14 22:14:50 +08:00
{
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( variable_ptr ) ;
2006-05-12 05:07:39 +08:00
2014-04-04 06:52:53 +08:00
if ( UNEXPECTED ( Z_REFCOUNTED_P ( variable_ptr ) ) ) {
zend_refcounted * garbage ;
2014-02-10 14:04:30 +08:00
2014-04-04 06:52:53 +08:00
if ( Z_TYPE_P ( variable_ptr ) = = IS_OBJECT & &
UNEXPECTED ( Z_OBJ_HANDLER_P ( variable_ptr , set ) ! = NULL ) ) {
Z_OBJ_HANDLER_P ( variable_ptr , set ) ( variable_ptr , value TSRMLS_CC ) ;
return variable_ptr ;
}
garbage = Z_COUNTED_P ( variable_ptr ) ;
if ( UNEXPECTED ( GC_REFCOUNT ( garbage ) > 1 ) ) {
/* we need to split */
GC_REFCOUNT ( garbage ) - - ;
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
if ( ( Z_COLLECTABLE_P ( variable_ptr ) ) & &
UNEXPECTED ( ! GC_INFO ( garbage ) ) ) {
gc_possible_root ( garbage TSRMLS_CC ) ;
}
} else {
ZVAL_COPY_VALUE ( variable_ptr , value ) ;
_zval_dtor_func ( garbage ZEND_FILE_LINE_CC ) ;
return variable_ptr ;
}
2010-04-20 19:16:39 +08:00
}
2014-04-04 06:52:53 +08:00
ZVAL_COPY_VALUE ( variable_ptr , value ) ;
2014-02-10 14:04:30 +08:00
return variable_ptr ;
2010-04-20 19:16:39 +08:00
}
2014-02-10 14:04:30 +08:00
static inline zval * zend_assign_const_to_variable ( zval * variable_ptr , zval * value TSRMLS_DC )
2010-08-11 23:34:06 +08:00
{
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( variable_ptr ) ;
2010-08-11 23:34:06 +08:00
2014-04-04 06:52:53 +08:00
if ( UNEXPECTED ( Z_REFCOUNTED_P ( variable_ptr ) ) ) {
zend_refcounted * garbage ;
if ( Z_TYPE_P ( variable_ptr ) = = IS_OBJECT & &
UNEXPECTED ( Z_OBJ_HANDLER_P ( variable_ptr , set ) ! = NULL ) ) {
Z_OBJ_HANDLER_P ( variable_ptr , set ) ( variable_ptr , value TSRMLS_CC ) ;
return variable_ptr ;
2014-02-10 14:04:30 +08:00
}
2014-04-04 06:52:53 +08:00
garbage = Z_COUNTED_P ( variable_ptr ) ;
if ( UNEXPECTED ( GC_REFCOUNT ( garbage ) > 1 ) ) {
/* we need to split */
GC_REFCOUNT ( garbage ) - - ;
/* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
if ( Z_COLLECTABLE_P ( variable_ptr ) & &
UNEXPECTED ( ! GC_INFO ( garbage ) ) ) {
gc_possible_root ( garbage TSRMLS_CC ) ;
}
} else {
ZVAL_COPY_VALUE ( variable_ptr , value ) ;
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if ( UNEXPECTED ( Z_OPT_COPYABLE_P ( variable_ptr ) ) ) {
_zval_copy_ctor_func ( variable_ptr ZEND_FILE_LINE_CC ) ;
}
_zval_dtor_func ( garbage ZEND_FILE_LINE_CC ) ;
return variable_ptr ;
2010-08-11 23:34:06 +08:00
}
}
2014-04-04 06:52:53 +08:00
ZVAL_COPY_VALUE ( variable_ptr , value ) ;
/* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
if ( UNEXPECTED ( Z_OPT_COPYABLE_P ( variable_ptr ) ) ) {
_zval_copy_ctor_func ( variable_ptr ZEND_FILE_LINE_CC ) ;
}
2014-02-10 14:04:30 +08:00
return variable_ptr ;
2010-08-11 23:34:06 +08:00
}
2010-04-20 19:16:39 +08:00
2014-02-10 14:04:30 +08:00
static inline zval * zend_assign_to_variable ( zval * variable_ptr , zval * value TSRMLS_DC )
2010-04-20 19:16:39 +08:00
{
2014-03-19 21:00:28 +08:00
zend_refcounted * garbage ;
2014-03-20 02:43:06 +08:00
zval * is_ref = NULL ;
2014-02-18 15:44:58 +08:00
2014-03-13 18:24:08 +08:00
if ( EXPECTED ( ! Z_REFCOUNTED_P ( variable_ptr ) ) ) {
2014-02-28 02:16:15 +08:00
if ( EXPECTED ( ! Z_ISREF_P ( value ) ) ) {
ZVAL_COPY ( variable_ptr , value ) ;
} else {
2014-03-13 18:24:08 +08:00
goto assign_ref ;
2014-02-28 02:16:15 +08:00
}
2014-02-18 15:44:58 +08:00
return variable_ptr ;
} else if ( Z_ISREF_P ( variable_ptr ) ) {
2014-03-20 02:43:06 +08:00
is_ref = variable_ptr ;
2014-02-10 14:04:30 +08:00
variable_ptr = Z_REFVAL_P ( variable_ptr ) ;
}
2010-04-20 19:16:39 +08:00
2014-03-05 17:55:56 +08:00
if ( EXPECTED ( ! Z_REFCOUNTED_P ( variable_ptr ) ) ) {
2014-03-13 18:24:08 +08:00
goto assign_simple ;
2014-02-18 15:44:58 +08:00
} else if ( Z_TYPE_P ( variable_ptr ) = = IS_OBJECT & &
2010-04-20 19:16:39 +08:00
UNEXPECTED ( Z_OBJ_HANDLER_P ( variable_ptr , set ) ! = NULL ) ) {
2014-02-10 14:04:30 +08:00
Z_OBJ_HANDLER_P ( variable_ptr , set ) ( variable_ptr , value TSRMLS_CC ) ;
2014-02-18 15:44:58 +08:00
} else if ( EXPECTED ( variable_ptr ! = value ) ) {
2010-08-10 22:43:17 +08:00
if ( Z_REFCOUNT_P ( variable_ptr ) = = 1 ) {
2014-03-19 21:00:28 +08:00
garbage = Z_COUNTED_P ( variable_ptr ) ;
2014-03-13 18:24:08 +08:00
if ( EXPECTED ( ! Z_ISREF_P ( value ) ) ) {
if ( ! is_ref ) {
ZVAL_COPY ( variable_ptr , value ) ;
} else {
2014-02-28 02:16:15 +08:00
ZVAL_DUP ( variable_ptr , value ) ;
2014-03-13 18:24:08 +08:00
}
2014-03-20 02:43:06 +08:00
} else if ( is_ref = = value ) {
return variable_ptr ;
2014-03-13 18:24:08 +08:00
} else {
if ( Z_REFCOUNT_P ( value ) = = 1 ) {
2014-03-19 21:00:28 +08:00
ZVAL_UNREF ( value ) ;
2014-03-13 18:24:08 +08:00
ZVAL_COPY ( variable_ptr , value ) ;
2014-02-28 02:16:15 +08:00
} else {
ZVAL_DUP ( variable_ptr , Z_REFVAL_P ( value ) ) ;
2014-03-13 18:24:08 +08:00
}
}
2014-03-19 21:00:28 +08:00
_zval_dtor_func ( garbage ZEND_FILE_LINE_CC ) ;
1999-04-08 02:10:10 +08:00
} else { /* we need to split */
2010-08-10 22:43:17 +08:00
Z_DELREF_P ( variable_ptr ) ;
2010-04-20 23:29:03 +08:00
GC_ZVAL_CHECK_POSSIBLE_ROOT ( variable_ptr ) ;
2014-03-13 18:24:08 +08:00
assign_simple :
2014-02-28 02:16:15 +08:00
if ( EXPECTED ( ! Z_ISREF_P ( value ) ) ) {
2014-03-13 18:24:08 +08:00
if ( ! is_ref ) {
ZVAL_COPY ( variable_ptr , value ) ;
} else {
ZVAL_DUP ( variable_ptr , value ) ;
}
2014-03-20 02:43:06 +08:00
} else if ( is_ref ! = value ) {
2014-03-13 18:24:08 +08:00
assign_ref :
if ( Z_REFCOUNT_P ( value ) = = 1 ) {
2014-03-19 21:00:28 +08:00
ZVAL_UNREF ( value ) ;
2014-03-13 18:24:08 +08:00
ZVAL_COPY ( variable_ptr , value ) ;
} else {
ZVAL_DUP ( variable_ptr , Z_REFVAL_P ( value ) ) ;
}
2010-08-11 23:34:06 +08:00
}
2010-04-20 19:16:39 +08:00
}
}
2014-02-10 14:04:30 +08:00
return variable_ptr ;
1999-04-08 02:10:10 +08:00
}
/* Utility Functions for Extensions */
2008-08-13 01:20:25 +08:00
static void zend_extension_statement_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
if ( extension - > statement_handler ) {
extension - > statement_handler ( op_array ) ;
}
}
2008-08-13 01:20:25 +08:00
static void zend_extension_fcall_begin_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_begin_handler ) {
extension - > fcall_begin_handler ( op_array ) ;
}
}
2008-08-13 01:20:25 +08:00
static void zend_extension_fcall_end_handler ( const zend_extension * extension , zend_op_array * op_array TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
if ( extension - > fcall_end_handler ) {
extension - > fcall_end_handler ( op_array ) ;
}
}
2014-04-21 19:18:05 +08:00
static zend_always_inline HashTable * zend_get_target_symbol_table ( int fetch_type TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2014-04-08 04:38:54 +08:00
HashTable * ht ;
if ( EXPECTED ( fetch_type = = ZEND_FETCH_GLOBAL_LOCK ) | |
EXPECTED ( fetch_type = = ZEND_FETCH_GLOBAL ) ) {
ht = & EG ( symbol_table ) . ht ;
} else if ( EXPECTED ( fetch_type = = ZEND_FETCH_STATIC ) ) {
ZEND_ASSERT ( EG ( active_op_array ) - > static_variables ! = NULL ) ;
ht = EG ( active_op_array ) - > static_variables ;
} else {
ZEND_ASSERT ( fetch_type = = ZEND_FETCH_LOCAL ) ;
if ( ! EG ( active_symbol_table ) ) {
zend_rebuild_symbol_table ( TSRMLS_C ) ;
}
ht = & EG ( active_symbol_table ) - > ht ;
1999-04-08 02:10:10 +08:00
}
2014-04-08 04:38:54 +08:00
return ht ;
2002-02-05 03:29:56 +08:00
}
2014-04-05 05:56:51 +08:00
static zend_always_inline zval * zend_fetch_dimension_address_inner ( HashTable * ht , const zval * dim , int dim_type , int type TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval * retval ;
zend_string * offset_key ;
2010-04-20 18:57:45 +08:00
ulong hval ;
1999-04-08 02:10:10 +08:00
2014-04-05 05:56:51 +08:00
if ( EXPECTED ( Z_TYPE_P ( dim ) = = IS_LONG ) ) {
hval = Z_LVAL_P ( dim ) ;
num_index :
retval = zend_hash_index_find ( ht , hval ) ;
if ( retval = = NULL ) {
switch ( type ) {
case BP_VAR_R :
zend_error ( E_NOTICE , " Undefined offset: %ld " , hval ) ;
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
zend_error ( E_NOTICE , " Undefined offset: %ld " , hval ) ;
/* break missing intentionally */
case BP_VAR_W :
2014-05-27 04:38:58 +08:00
retval = zend_hash_index_add_new ( ht , hval , & EG ( uninitialized_zval ) ) ;
2014-04-05 05:56:51 +08:00
break ;
2011-03-16 13:41:50 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else if ( EXPECTED ( Z_TYPE_P ( dim ) = = IS_STRING ) ) {
offset_key = Z_STR_P ( dim ) ;
if ( dim_type ! = IS_CONST ) {
ZEND_HANDLE_NUMERIC_EX ( offset_key - > val , offset_key - > len + 1 , hval , goto num_index ) ;
}
str_index :
retval = zend_hash_find ( ht , offset_key ) ;
if ( retval ) {
/* support for $GLOBALS[...] */
if ( UNEXPECTED ( Z_TYPE_P ( retval ) = = IS_INDIRECT ) ) {
retval = Z_INDIRECT_P ( retval ) ;
if ( UNEXPECTED ( Z_TYPE_P ( retval ) = = IS_UNDEF ) ) {
switch ( type ) {
case BP_VAR_R :
zend_error ( E_NOTICE , " Undefined index: %s " , offset_key - > val ) ;
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
zend_error ( E_NOTICE , " Undefined index: %s " , offset_key - > val ) ;
/* break missing intentionally */
case BP_VAR_W :
ZVAL_NULL ( retval ) ;
break ;
2014-03-26 22:07:31 +08:00
}
}
1999-04-08 02:10:10 +08:00
}
2014-04-05 05:56:51 +08:00
} else {
switch ( type ) {
case BP_VAR_R :
zend_error ( E_NOTICE , " Undefined index: %s " , offset_key - > val ) ;
/* break missing intentionally */
case BP_VAR_UNSET :
case BP_VAR_IS :
retval = & EG ( uninitialized_zval ) ;
break ;
case BP_VAR_RW :
zend_error ( E_NOTICE , " Undefined index: %s " , offset_key - > val ) ;
/* break missing intentionally */
case BP_VAR_W :
2014-05-26 21:16:16 +08:00
retval = zend_hash_add_new ( ht , offset_key , & EG ( uninitialized_zval ) ) ;
2014-04-05 05:56:51 +08:00
break ;
1999-04-08 02:10:10 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else {
switch ( Z_TYPE_P ( dim ) ) {
case IS_NULL :
offset_key = STR_EMPTY_ALLOC ( ) ;
goto str_index ;
case IS_DOUBLE :
hval = zend_dval_to_lval ( Z_DVAL_P ( dim ) ) ;
goto num_index ;
case IS_RESOURCE :
zend_error ( E_STRICT , " Resource ID#%ld used as offset, casting to integer (%ld) " , Z_RES_HANDLE_P ( dim ) , Z_RES_HANDLE_P ( dim ) ) ;
hval = Z_RES_HANDLE_P ( dim ) ;
goto num_index ;
2014-04-30 22:32:42 +08:00
case IS_FALSE :
hval = 0 ;
goto num_index ;
case IS_TRUE :
hval = 1 ;
2014-04-05 05:56:51 +08:00
goto num_index ;
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
retval = ( type = = BP_VAR_W | | type = = BP_VAR_RW ) ?
& EG ( error_zval ) : & EG ( uninitialized_zval ) ;
}
1999-04-08 02:10:10 +08:00
}
return retval ;
}
2014-04-05 05:56:51 +08:00
static zend_always_inline void zend_fetch_dimension_address ( zval * result , zval * container_ptr , zval * dim , int dim_type , int type , int is_ref TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2014-02-10 14:04:30 +08:00
zval * retval ;
2014-02-25 04:17:13 +08:00
zval * container = container_ptr ;
1999-04-08 02:10:10 +08:00
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( container ) ;
2014-04-05 05:56:51 +08:00
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
if ( container = = container_ptr ) {
SEPARATE_ZVAL ( 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 ) ) ;
if ( retval = = NULL ) {
zend_error ( E_WARNING , " Cannot add element to the array as the next element is already occupied " ) ;
retval = & EG ( error_zval ) ;
2014-04-04 23:01:53 +08:00
}
2014-04-05 05:56:51 +08:00
} else {
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type TSRMLS_CC ) ;
}
if ( is_ref ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( retval ) ;
ZVAL_COPY ( result , retval ) ;
} else {
ZVAL_INDIRECT ( result , retval ) ;
}
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
if ( type ! = BP_VAR_UNSET & & UNEXPECTED ( Z_STRLEN_P ( container ) = = 0 ) ) {
2007-11-20 19:01:28 +08:00
convert_to_array :
2014-04-10 19:50:25 +08:00
zval_dtor ( container ) ;
2014-04-05 05:56:51 +08:00
array_init ( container ) ;
goto fetch_from_array ;
}
if ( dim = = NULL ) {
zend_error_noreturn ( E_ERROR , " [] operator not supported for strings " ) ;
}
2007-11-20 19:01:28 +08:00
2014-04-05 05:56:51 +08:00
if ( type ! = BP_VAR_UNSET ) {
if ( container = = container_ptr ) {
SEPARATE_ZVAL ( container ) ;
}
}
1999-04-08 02:10:10 +08:00
2014-04-05 05:56:51 +08:00
if ( UNEXPECTED ( Z_TYPE_P ( dim ) ! = IS_LONG ) ) {
zval tmp ;
2000-01-04 04:01:54 +08:00
2014-04-05 05:56:51 +08:00
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 ;
2014-02-25 04:17:13 +08:00
}
2014-04-05 05:56:51 +08:00
if ( type ! = BP_VAR_UNSET ) {
zend_error ( E_WARNING , " Illegal string offset '%s' " , Z_STRVAL_P ( dim ) ) ;
2006-06-01 19:56:44 +08:00
}
2014-04-05 05:56:51 +08:00
break ;
case IS_DOUBLE :
case IS_NULL :
2014-04-30 22:32:42 +08:00
case IS_FALSE :
case IS_TRUE :
2014-04-05 05:56:51 +08:00
zend_error ( E_NOTICE , " String offset cast occurred " ) ;
break ;
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
break ;
1999-04-08 02:10:10 +08:00
}
2007-11-20 19:01:28 +08:00
2014-04-05 05:56:51 +08:00
ZVAL_DUP ( & tmp , dim ) ;
convert_to_long ( & tmp ) ;
dim = & tmp ;
}
if ( ! IS_INTERNED ( Z_STR_P ( container ) ) ) STR_ADDREF ( Z_STR_P ( container ) ) ;
ZVAL_STR_OFFSET ( result , container , Z_LVAL_P ( dim ) ) ;
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
if ( ! Z_OBJ_HT_P ( container ) - > read_dimension ) {
zend_error_noreturn ( E_ERROR , " Cannot use object as array " ) ;
} else {
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result TSRMLS_CC ) ;
2014-04-10 03:49:58 +08:00
if ( UNEXPECTED ( retval = = & EG ( uninitialized_zval ) ) ) {
ZVAL_NULL ( result ) ;
} else if ( retval & & Z_TYPE_P ( retval ) ! = IS_UNDEF ) {
2014-04-05 05:56:51 +08:00
if ( ! Z_ISREF_P ( retval ) ) {
if ( Z_REFCOUNTED_P ( retval ) & &
Z_REFCOUNT_P ( retval ) > 1 ) {
if ( Z_TYPE_P ( retval ) ! = IS_OBJECT ) {
Z_DELREF_P ( retval ) ;
ZVAL_DUP ( result , retval ) ;
retval = result ;
2014-04-04 23:01:53 +08:00
} else {
2014-04-05 05:56:51 +08:00
ZVAL_COPY ( result , retval ) ;
retval = result ;
2014-04-04 23:01:53 +08:00
}
2014-02-27 19:40:13 +08:00
}
2014-04-05 05:56:51 +08:00
if ( Z_TYPE_P ( retval ) ! = IS_OBJECT ) {
zend_class_entry * ce = Z_OBJCE_P ( container ) ;
zend_error ( E_NOTICE , " Indirect modification of overloaded element of %s has no effect " , ce - > name - > val ) ;
}
}
if ( result ! = retval ) {
2014-04-10 03:49:58 +08:00
if ( is_ref ) {
2014-04-05 05:56:51 +08:00
SEPARATE_ZVAL_TO_MAKE_IS_REF ( retval ) ;
ZVAL_COPY ( result , retval ) ;
} else {
ZVAL_INDIRECT ( result , retval ) ;
}
2005-06-03 19:16:19 +08:00
}
2007-12-14 22:14:50 +08:00
} else {
2014-03-04 20:32:40 +08:00
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
2007-12-14 22:14:50 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_NULL ) ) {
if ( container = = & EG ( error_zval ) ) {
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
} else if ( type ! = BP_VAR_UNSET ) {
goto convert_to_array ;
} else {
/* for read-mode only */
ZVAL_NULL ( result ) ;
}
} else {
if ( type ! = BP_VAR_UNSET & &
2014-04-30 22:32:42 +08:00
Z_TYPE_P ( container ) = = IS_FALSE ) {
2014-04-05 05:56:51 +08:00
goto convert_to_array ;
}
if ( type = = BP_VAR_UNSET ) {
zend_error ( E_WARNING , " Cannot unset offset in a non-array variable " ) ;
ZVAL_NULL ( result ) ;
} else {
zend_error ( E_WARNING , " Cannot use a scalar value as an array " ) ;
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
}
2007-12-14 22:14:50 +08:00
}
}
2014-04-05 05:56:51 +08:00
static zend_never_inline void zend_fetch_dimension_address_W ( zval * result , zval * container_ptr , zval * dim , int dim_type TSRMLS_DC )
2007-12-14 22:14:50 +08:00
{
2014-04-05 05:56:51 +08:00
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_W , 0 TSRMLS_CC ) ;
}
2007-12-14 22:14:50 +08:00
2014-04-05 05:56:51 +08:00
static zend_never_inline void zend_fetch_dimension_address_W_ref ( zval * result , zval * container_ptr , zval * dim , int dim_type TSRMLS_DC )
{
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_W , 1 TSRMLS_CC ) ;
}
2007-12-14 22:14:50 +08:00
2014-04-05 05:56:51 +08:00
static zend_never_inline void zend_fetch_dimension_address_RW ( zval * result , zval * container_ptr , zval * dim , int dim_type TSRMLS_DC )
{
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_RW , 0 TSRMLS_CC ) ;
}
2007-12-14 22:14:50 +08:00
2014-04-05 05:56:51 +08:00
static zend_never_inline void zend_fetch_dimension_address_UNSET ( zval * result , zval * container_ptr , zval * dim , int dim_type TSRMLS_DC )
{
zend_fetch_dimension_address ( result , container_ptr , dim , dim_type , BP_VAR_UNSET , 0 TSRMLS_CC ) ;
}
2007-12-14 22:14:50 +08:00
2014-04-05 05:56:51 +08:00
static zend_always_inline void zend_fetch_dimension_address_read ( zval * result , zval * container , zval * dim , int dim_type , int type TSRMLS_DC )
{
zval * retval ;
2010-07-16 21:38:09 +08:00
2014-04-05 05:56:51 +08:00
ZVAL_DEREF ( container ) ;
if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_ARRAY ) ) {
retval = zend_fetch_dimension_address_inner ( Z_ARRVAL_P ( container ) , dim , dim_type , type TSRMLS_CC ) ;
ZVAL_COPY ( result , retval ) ;
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_STRING ) ) {
if ( UNEXPECTED ( Z_TYPE_P ( dim ) ! = IS_LONG ) ) {
zval tmp ;
switch ( Z_TYPE_P ( dim ) ) {
/* case IS_LONG: */
case IS_STRING :
if ( IS_LONG = = is_numeric_string ( Z_STRVAL_P ( dim ) , Z_STRLEN_P ( dim ) , NULL , NULL , - 1 ) ) {
break ;
}
2011-02-14 16:46:53 +08:00
if ( type ! = BP_VAR_IS ) {
2014-04-05 05:56:51 +08:00
zend_error ( E_WARNING , " Illegal string offset '%s' " , Z_STRVAL_P ( dim ) ) ;
2011-02-14 16:46:53 +08:00
}
2014-04-05 05:56:51 +08:00
break ;
case IS_DOUBLE :
case IS_NULL :
2014-04-30 22:32:42 +08:00
case IS_FALSE :
case IS_TRUE :
2014-04-05 05:56:51 +08:00
if ( type ! = BP_VAR_IS ) {
zend_error ( E_NOTICE , " String offset cast occurred " ) ;
2014-04-01 22:06:50 +08:00
}
2014-04-05 05:56:51 +08:00
break ;
default :
zend_error ( E_WARNING , " Illegal offset type " ) ;
break ;
2007-12-14 22:14:50 +08:00
}
2014-04-05 05:56:51 +08:00
ZVAL_DUP ( & tmp , dim ) ;
convert_to_long ( & tmp ) ;
dim = & tmp ;
}
if ( UNEXPECTED ( Z_LVAL_P ( dim ) < 0 ) | | UNEXPECTED ( Z_STRLEN_P ( container ) < = Z_LVAL_P ( dim ) ) ) {
if ( type ! = BP_VAR_IS ) {
zend_error ( E_NOTICE , " Uninitialized string offset: %ld " , Z_LVAL_P ( dim ) ) ;
}
ZVAL_EMPTY_STRING ( result ) ;
} else {
zend_uchar c = ( zend_uchar ) Z_STRVAL_P ( container ) [ Z_LVAL_P ( dim ) ] ;
if ( CG ( one_char_string ) [ c ] ) {
ZVAL_INT_STR ( result , CG ( one_char_string ) [ c ] ) ;
2007-12-14 22:14:50 +08:00
} else {
2014-04-05 05:56:51 +08:00
ZVAL_NEW_STR ( result , STR_INIT ( Z_STRVAL_P ( container ) + Z_LVAL_P ( dim ) , 1 , 0 ) ) ;
}
}
} else if ( EXPECTED ( Z_TYPE_P ( container ) = = IS_OBJECT ) ) {
if ( ! Z_OBJ_HT_P ( container ) - > read_dimension ) {
zend_error_noreturn ( E_ERROR , " Cannot use object as array " ) ;
} else {
retval = Z_OBJ_HT_P ( container ) - > read_dimension ( container , dim , type , result TSRMLS_CC ) ;
if ( result ) {
if ( retval ) {
if ( result ! = retval ) {
ZVAL_COPY ( result , retval ) ;
2013-11-28 00:30:35 +08:00
}
2014-04-05 05:56:51 +08:00
} else {
ZVAL_NULL ( result ) ;
2007-12-14 22:14:50 +08:00
}
1999-04-08 02:10:10 +08:00
}
2014-04-05 05:56:51 +08:00
}
} else {
ZVAL_NULL ( result ) ;
1999-04-08 02:10:10 +08:00
}
}
2014-04-05 05:56:51 +08:00
static zend_never_inline void zend_fetch_dimension_address_read_R ( zval * result , zval * container , zval * dim , int dim_type TSRMLS_DC )
{
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_R TSRMLS_CC ) ;
}
static zend_never_inline void zend_fetch_dimension_address_read_IS ( zval * result , zval * container , zval * dim , int dim_type TSRMLS_DC )
{
zend_fetch_dimension_address_read ( result , container , dim , dim_type , BP_VAR_IS TSRMLS_CC ) ;
}
2014-04-17 19:40:45 +08:00
static void zend_fetch_property_address ( zval * result , zval * container_ptr , zval * prop_ptr , zend_uint cache_slot , int type , int is_ref TSRMLS_DC )
1999-04-08 02:10:10 +08:00
{
2014-02-28 04:21:12 +08:00
zval * container = container_ptr ;
2014-03-27 17:39:09 +08:00
ZVAL_DEREF ( container ) ;
2007-12-14 22:14:50 +08:00
if ( Z_TYPE_P ( container ) ! = IS_OBJECT ) {
2010-04-20 19:16:39 +08:00
if ( container = = & EG ( error_zval ) ) {
2014-02-26 03:39:25 +08:00
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
2007-12-14 22:14:50 +08:00
return ;
1999-04-08 02:10:10 +08:00
}
2006-05-10 07:53:23 +08:00
2007-12-14 22:14:50 +08:00
/* this should modify object only if it's empty */
if ( type ! = BP_VAR_UNSET & &
( ( Z_TYPE_P ( container ) = = IS_NULL | |
2014-04-30 22:32:42 +08:00
Z_TYPE_P ( container ) = = IS_FALSE | |
( Z_TYPE_P ( container ) = = IS_STRING & & Z_STRLEN_P ( container ) = = 0 ) ) ) ) {
2014-04-04 23:01:53 +08:00
if ( container = = container_ptr ) {
2014-02-10 14:04:30 +08:00
SEPARATE_ZVAL ( container ) ;
2007-12-14 22:14:50 +08:00
}
object_init ( container ) ;
} else {
2008-07-27 01:59:54 +08:00
zend_error ( E_WARNING , " Attempt to modify property of non-object " ) ;
2014-02-26 03:39:25 +08:00
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
2007-12-14 22:14:50 +08:00
return ;
1999-04-08 02:10:10 +08:00
}
}
2006-05-10 07:53:23 +08:00
2004-09-24 05:43:32 +08:00
if ( Z_OBJ_HT_P ( container ) - > get_property_ptr_ptr ) {
2014-04-17 19:40:45 +08:00
zval * ptr = Z_OBJ_HT_P ( container ) - > get_property_ptr_ptr ( container , prop_ptr , type , cache_slot TSRMLS_CC ) ;
2014-02-10 14:04:30 +08:00
if ( NULL = = ptr ) {
2005-01-18 17:05:39 +08:00
if ( Z_OBJ_HT_P ( container ) - > read_property & &
2014-04-17 19:40:45 +08:00
( ptr = Z_OBJ_HT_P ( container ) - > read_property ( container , prop_ptr , type , cache_slot , result TSRMLS_CC ) ) ! = NULL ) {
2014-02-27 19:40:13 +08:00
if ( ptr ! = result ) {
2014-04-04 23:01:53 +08:00
if ( is_ref & & ptr ! = & EG ( uninitialized_zval ) ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( ptr ) ;
ZVAL_COPY ( result , ptr ) ;
} else {
ZVAL_INDIRECT ( result , ptr ) ;
}
2014-02-27 19:40:13 +08:00
}
2005-01-18 17:05:39 +08:00
} else {
2008-01-24 01:55:55 +08:00
zend_error_noreturn ( E_ERROR , " Cannot access undefined property for object with overloaded property access " ) ;
2005-01-18 17:05:39 +08:00
}
2008-01-24 01:55:55 +08:00
} else {
2014-04-04 23:01:53 +08:00
if ( is_ref ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( ptr ) ;
ZVAL_COPY ( result , ptr ) ;
} else {
ZVAL_INDIRECT ( result , ptr ) ;
}
2002-02-07 22:08:43 +08:00
}
2004-09-24 05:43:32 +08:00
} else if ( Z_OBJ_HT_P ( container ) - > read_property ) {
2014-04-17 19:40:45 +08:00
zval * ptr = Z_OBJ_HT_P ( container ) - > read_property ( container , prop_ptr , type , cache_slot , result TSRMLS_CC ) ;
2014-02-27 19:40:13 +08:00
if ( ptr ! = result ) {
2014-04-04 23:01:53 +08:00
if ( is_ref & & ptr ! = & EG ( uninitialized_zval ) ) {
SEPARATE_ZVAL_TO_MAKE_IS_REF ( ptr ) ;
ZVAL_COPY ( result , ptr ) ;
} else {
ZVAL_INDIRECT ( result , ptr ) ;
}
2014-02-27 19:40:13 +08:00
}
2004-09-24 05:43:32 +08:00
} else {
zend_error ( E_WARNING , " This object doesn't support property references " ) ;
2014-02-26 03:39:25 +08:00
ZVAL_INDIRECT ( result , & EG ( error_zval ) ) ;
2001-05-03 03:51:33 +08:00
}
1999-04-08 02:10:10 +08:00
}
2012-12-04 14:14:39 +08:00
static inline zend_brk_cont_element * zend_brk_cont ( int nest_levels , int array_offset , const zend_op_array * op_array , const zend_execute_data * execute_data TSRMLS_DC )
2002-03-10 21:42:37 +08:00
{
2010-11-24 20:19:56 +08:00
int original_nest_levels = nest_levels ;
2004-09-24 05:43:32 +08:00
zend_brk_cont_element * jmp_to ;
2002-03-10 21:42:37 +08:00
2004-09-24 05:43:32 +08:00
do {
if ( array_offset = = - 1 ) {
zend_error_noreturn ( E_ERROR , " Cannot break/continue %d level%s " , original_nest_levels , ( original_nest_levels = = 1 ) ? " " : " s " ) ;
2004-09-10 00:47:22 +08:00
}
2004-09-24 05:43:32 +08:00
jmp_to = & op_array - > brk_cont_array [ array_offset ] ;
if ( nest_levels > 1 ) {
zend_op * brk_opline = & op_array - > opcodes [ jmp_to - > brk ] ;
2004-09-10 00:47:22 +08:00
2004-09-24 05:43:32 +08:00
switch ( brk_opline - > opcode ) {
case ZEND_SWITCH_FREE :
2010-04-20 18:57:45 +08:00
if ( ! ( brk_opline - > extended_value & EXT_TYPE_FREE_ON_RETURN ) ) {
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( EX_VAR ( brk_opline - > op1 . var ) ) ;
2008-05-05 19:03:35 +08:00
}
2004-09-24 05:43:32 +08:00
break ;
case ZEND_FREE :
2010-04-20 18:57:45 +08:00
if ( ! ( brk_opline - > extended_value & EXT_TYPE_FREE_ON_RETURN ) ) {
2014-02-10 14:04:30 +08:00
zval_dtor ( EX_VAR ( brk_opline - > op1 . var ) ) ;
2008-05-05 19:03:35 +08:00
}
2004-09-24 05:43:32 +08:00
break ;
2004-09-10 00:47:22 +08:00
}
}
2004-09-24 05:43:32 +08:00
array_offset = jmp_to - > parent ;
} while ( - - nest_levels > 0 ) ;
return jmp_to ;
2002-03-10 21:42:37 +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() \
zend_hash_apply ( & EG ( symbol_table ) , zend_check_symbol TSRMLS_CC ) ; \
if ( & EG ( symbol_table ) ! = EG ( active_symbol_table ) ) { \
zend_hash_apply ( EG ( active_symbol_table ) , zend_check_symbol TSRMLS_CC ) ; \
2000-02-10 05:48:16 +08:00
}
2014-05-25 18:32:35 +08:00
static int zend_check_symbol ( zval * pz TSRMLS_DC )
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 */
# ifdef PHP_WIN32
fflush ( stderr ) ;
# endif
2014-05-25 18:32:35 +08:00
} else if ( Z_TYPE_P ( pz ) = = IS_ARRAY ) {
zend_hash_apply ( Z_ARRVAL_P ( pz ) , zend_check_symbol TSRMLS_CC ) ;
} 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-05-25 18:32:35 +08:00
zend_hash_apply ( Z_OBJPROP_P ( pz ) , zend_check_symbol TSRMLS_CC ) ;
2000-02-10 05:48:16 +08:00
}
return 0 ;
}
# else
# define CHECK_SYMBOL_TABLES()
# endif
2004-09-24 05:43:32 +08:00
ZEND_API opcode_handler_t * zend_opcode_handlers ;
2001-08-30 23:26:30 +08:00
2014-03-28 06:11:22 +08:00
ZEND_API void execute_internal ( zend_execute_data * execute_data_ptr , zend_fcall_info * fci TSRMLS_DC )
2003-01-12 00:12:44 +08:00
{
2013-08-27 01:06:36 +08:00
if ( fci ! = NULL ) {
execute_data_ptr - > function_state . function - > internal_function . handler (
2014-03-28 06:11:22 +08:00
fci - > param_count , fci - > retval TSRMLS_CC
2013-08-27 01:06:36 +08:00
) ;
2012-10-05 14:14:20 +08:00
} else {
2014-02-10 14:04:30 +08:00
zval * return_value = EX_VAR_2 ( execute_data_ptr , execute_data_ptr - > opline - > result . var ) ;
2013-08-27 01:06:36 +08:00
execute_data_ptr - > function_state . function - > internal_function . handler (
2014-03-28 06:11:22 +08:00
execute_data_ptr - > opline - > extended_value , return_value TSRMLS_CC
2013-08-27 01:06:36 +08:00
) ;
2012-10-05 14:14:20 +08:00
}
2003-01-12 00:12:44 +08:00
}
2014-03-18 03:15:22 +08:00
void zend_clean_and_cache_symbol_table ( zend_array * symbol_table TSRMLS_DC ) /* { { { */
2012-05-28 12:43:18 +08:00
{
if ( EG ( symtable_cache_ptr ) > = EG ( symtable_cache_limit ) ) {
2014-03-18 03:15:22 +08:00
zend_hash_destroy ( & symbol_table - > ht ) ;
2014-04-25 15:54:10 +08:00
FREE_HASHTABLE ( 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 */
2014-03-18 03:15:22 +08:00
zend_hash_clean ( & symbol_table - > ht ) ;
2012-05-28 12:43:18 +08:00
* ( + + EG ( symtable_cache_ptr ) ) = symbol_table ;
}
}
/* }}} */
2013-09-14 20:40:48 +08:00
static zend_always_inline void i_free_compiled_variables ( zend_execute_data * execute_data TSRMLS_DC ) /* { { { */
2012-05-28 12:43:18 +08:00
{
2014-03-27 20:00:25 +08:00
zval * cv = EX_VAR_NUM ( 0 ) ;
2014-02-10 14:04:30 +08:00
zval * end = cv + EX ( op_array ) - > last_var ;
2012-12-05 17:23:37 +08:00
while ( cv ! = end ) {
2014-02-10 14:04:30 +08:00
zval_ptr_dtor ( cv ) ;
2012-12-05 17:23:37 +08:00
cv + + ;
}
}
/* }}} */
2013-09-14 20:40:48 +08:00
void zend_free_compiled_variables ( zend_execute_data * execute_data TSRMLS_DC ) /* { { { */
2012-12-05 17:23:37 +08:00
{
2013-09-14 20:40:48 +08:00
i_free_compiled_variables ( execute_data TSRMLS_CC ) ;
2012-05-28 12:43:18 +08:00
}
/* }}} */
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
*
* + = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +
* | zend_execute_data | < - - - +
* | EX ( function_state ) . arguments | - - + |
* | . . . | | |
* | ARGUMENT [ 1 ] | | |
* | . . . | | |
* | ARGUMENT [ ARGS_NUMBER ] | | |
* | ARGS_NUMBER | < - + |
* + = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + |
* |
* + = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + |
* EG ( current_execute_data ) - > | zend_execute_data | |
* | EX ( prev_execute_data ) | - - - - +
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2014-02-10 14:04:30 +08:00
* EX_CV_NUM ( 0 ) - - - - - - - - - > | VAR [ 0 ] |
* | . . . |
* | VAR [ op_array - > last_var - 1 ] |
* | VAR [ op_array - > last_var ] |
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 ] |
2012-12-04 14:42:19 +08:00
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* EX ( call_slots ) - > | CALL_SLOT [ 0 ] |
* | . . . |
* | CALL_SLOT [ op_array - > nested_calls - 1 ] |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* zend_vm_stack_frame_base - > | ARGUMENTS STACK [ 0 ] |
* | . . . |
* zend_vm_stack_top - - - - - - - - > | . . . |
* | . . . |
* | ARGUMENTS STACK [ op_array - > used_stack ] |
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2014-04-18 17:46:36 +08:00
static zend_always_inline zend_execute_data * i_create_execute_data_from_op_array ( zend_op_array * op_array , zval * return_value , vm_frame_kind frame_kind TSRMLS_DC ) /* { { { */
2012-12-04 14:42:19 +08:00
{
zend_execute_data * execute_data ;
/*
* When allocating the execute_data , memory for compiled variables and
2012-12-05 20:02:47 +08:00
* temporary variables is also allocated before and after the actual
* zend_execute_data struct . In addition we also allocate space to store
* information about syntactically nested called functions and actual
* parameters . op_array - > last_var specifies the number of compiled
* variables and op_array - > T is the number of temporary variables . If there
* is no symbol table , then twice as much memory is allocated for compiled
* variables . In that case the first half contains zval * * s and the second
* half the actual zval * s ( which would otherwise be in the symbol table ) .
2012-12-04 14:42:19 +08:00
*/
size_t execute_data_size = ZEND_MM_ALIGNED_SIZE ( sizeof ( zend_execute_data ) ) ;
2014-02-10 14:04:30 +08:00
size_t vars_size = ZEND_MM_ALIGNED_SIZE ( sizeof ( zval ) ) * ( op_array - > last_var + op_array - > T ) ;
2012-12-04 14:42:19 +08:00
size_t call_slots_size = ZEND_MM_ALIGNED_SIZE ( sizeof ( call_slot ) ) * op_array - > nested_calls ;
2014-02-10 14:04:30 +08:00
size_t stack_size = ZEND_MM_ALIGNED_SIZE ( sizeof ( zval ) ) * op_array - > used_stack ;
size_t total_size = execute_data_size + vars_size + call_slots_size + stack_size ;
2012-12-04 14:42:19 +08:00
/*
* Normally the execute_data is allocated on the VM stack ( because it does
* not actually do any allocation and thus is faster ) . For generators
* though this behavior would be suboptimal , because the ( rather large )
* structure would have to be copied back and forth every time execution is
* suspended or resumed . That ' s why for generators the execution context
2012-12-05 20:02:47 +08:00
* is allocated using a separate VM stack , thus allowing to save and
* restore it simply by replacing a pointer . The same segment also keeps
* a copy of previous execute_data and passed parameters .
2012-12-04 14:42:19 +08:00
*/
2012-12-06 17:14:31 +08:00
if ( UNEXPECTED ( ( op_array - > fn_flags & ZEND_ACC_GENERATOR ) ! = 0 ) ) {
2012-12-25 20:23:52 +08:00
/* Prepend the regular stack frame with a copy of prev_execute_data
* and the passed arguments
2012-12-04 14:42:19 +08:00
*/
int args_count = zend_vm_stack_get_args_count_ex ( EG ( current_execute_data ) ) ;
2014-02-26 17:58:59 +08:00
size_t args_size = ZEND_MM_ALIGNED_SIZE ( sizeof ( zval ) ) * ( args_count + 1 ) ;
2012-12-04 14:42:19 +08:00
total_size + = args_size + execute_data_size ;
2014-02-26 17:58:59 +08:00
EG ( argument_stack ) = zend_vm_stack_new_page ( ( total_size + ( sizeof ( zval ) - 1 ) ) / sizeof ( zval ) ) ;
2012-12-04 14:42:19 +08:00
EG ( argument_stack ) - > prev = NULL ;
2014-02-26 17:58:59 +08:00
execute_data = ( zend_execute_data * ) ( ( char * ) ZEND_VM_STACK_ELEMETS ( EG ( argument_stack ) ) + execute_data_size + args_size ) ;
2012-12-04 14:42:19 +08:00
/* copy prev_execute_data */
2014-02-26 17:58:59 +08:00
EX ( prev_execute_data ) = ( zend_execute_data * ) ZEND_VM_STACK_ELEMETS ( EG ( argument_stack ) ) ;
2012-12-04 14:42:19 +08:00
memset ( EX ( prev_execute_data ) , 0 , sizeof ( zend_execute_data ) ) ;
EX ( prev_execute_data ) - > function_state . function = ( zend_function * ) op_array ;
2014-02-26 17:58:59 +08:00
EX ( prev_execute_data ) - > function_state . arguments = ( zval * ) ( ( ( char * ) ZEND_VM_STACK_ELEMETS ( EG ( argument_stack ) ) + execute_data_size + args_size - sizeof ( zval ) ) ) ;
2012-12-04 14:42:19 +08:00
2012-12-25 20:23:52 +08:00
/* copy arguments */
2014-02-10 14:04:30 +08:00
ZVAL_LONG ( EX ( prev_execute_data ) - > function_state . arguments , args_count ) ;
2012-12-04 14:42:19 +08:00
if ( args_count > 0 ) {
2014-02-10 14:04:30 +08:00
zval * arg_src = zend_vm_stack_get_arg_ex ( EG ( current_execute_data ) , 1 ) ;
zval * arg_dst = zend_vm_stack_get_arg_ex ( EX ( prev_execute_data ) , 1 ) ;
2012-12-04 14:42:19 +08:00
int i ;
for ( i = 0 ; i < args_count ; i + + ) {
2014-02-10 14:04:30 +08:00
ZVAL_COPY ( arg_dst + i , arg_src + i ) ;
2012-12-04 14:42:19 +08:00
}
}
} else {
execute_data = zend_vm_stack_alloc ( total_size TSRMLS_CC ) ;
EX ( prev_execute_data ) = EG ( current_execute_data ) ;
}
2014-04-24 19:53:20 +08:00
EX ( return_value ) = return_value ;
EX ( frame_kind ) = frame_kind ;
ZVAL_UNDEF ( & EX ( old_error_reporting ) ) ;
EX ( delayed_exception ) = NULL ;
2014-02-10 14:04:30 +08:00
EX ( call_slots ) = ( call_slot * ) ( ( char * ) execute_data + execute_data_size + vars_size ) ;
2014-04-24 19:53:20 +08:00
EX ( call ) = NULL ;
2012-12-04 14:42:19 +08:00
2014-04-24 19:53:20 +08:00
EG ( opline_ptr ) = & EX ( opline ) ;
EX ( opline ) = UNEXPECTED ( ( op_array - > fn_flags & ZEND_ACC_INTERACTIVE ) ! = 0 ) & & EG ( start_op ) ? EG ( start_op ) : op_array - > opcodes ;
EX ( function_state ) . function = ( zend_function * ) op_array ;
EX ( function_state ) . arguments = NULL ;
2012-12-04 14:42:19 +08:00
EX ( op_array ) = op_array ;
2014-04-24 19:53:20 +08:00
EX ( object ) = Z_OBJ ( EG ( This ) ) ;
EX ( scope ) = EG ( scope ) ;
EX ( called_scope ) = EG ( called_scope ) ;
2012-12-04 14:42:19 +08:00
EX ( symbol_table ) = EG ( active_symbol_table ) ;
2014-04-18 17:46:36 +08:00
if ( EX ( symbol_table ) ) {
zend_attach_symbol_table ( execute_data ) ;
2014-04-24 19:53:20 +08:00
} else {
do {
/* Initialize CV variables */
zval * var = EX_VAR_NUM ( 0 ) ;
zval * end = var + op_array - > last_var ;
while ( var ! = end ) {
ZVAL_UNDEF ( var ) ;
var + + ;
}
} while ( 0 ) ;
2014-03-26 22:07:31 +08:00
2014-04-24 19:53:20 +08:00
if ( op_array - > this_var ! = - 1 & & Z_OBJ ( EG ( This ) ) ) {
ZVAL_OBJ ( EX_VAR ( op_array - > this_var ) , Z_OBJ ( EG ( This ) ) ) ;
Z_ADDREF ( EG ( This ) ) ;
}
2012-12-04 14:42:19 +08:00
}
2014-04-24 19:53:20 +08:00
if ( ! op_array - > run_time_cache & & op_array - > last_cache_slot ) {
op_array - > run_time_cache = ecalloc ( op_array - > last_cache_slot , sizeof ( void * ) ) ;
}
EX ( run_time_cache ) = op_array - > run_time_cache ;
2012-12-04 14:42:19 +08:00
2014-04-24 19:53:20 +08:00
EG ( argument_stack ) - > top = ( zval * ) zend_vm_stack_frame_base ( execute_data ) ;
EG ( current_execute_data ) = execute_data ;
2012-12-04 14:42:19 +08:00
return execute_data ;
}
/* }}} */
2014-04-18 17:46:36 +08:00
ZEND_API zend_execute_data * zend_create_execute_data_from_op_array ( zend_op_array * op_array , zval * return_value , vm_frame_kind frame_kind TSRMLS_DC ) /* { { { */
2012-12-05 17:23:37 +08:00
{
2014-04-18 17:46:36 +08:00
return i_create_execute_data_from_op_array ( op_array , return_value , frame_kind TSRMLS_CC ) ;
2012-12-05 17:23:37 +08:00
}
/* }}} */
2014-01-12 08:59:22 +08:00
static zend_always_inline zend_bool zend_is_by_ref_func_arg_fetch ( zend_op * opline , call_slot * call TSRMLS_DC ) /* { { { */
2013-08-29 17:35:11 +08:00
{
2014-02-26 23:25:10 +08:00
zend_uint arg_num = opline - > extended_value & ZEND_FETCH_ARG_MASK ;
2013-08-29 17:35:11 +08:00
return ARG_SHOULD_BE_SENT_BY_REF ( call - > fbc , arg_num ) ;
}
/* }}} */
2014-02-10 14:04:30 +08:00
static zval * zend_vm_stack_push_args_with_copy ( int count TSRMLS_DC ) /* { { { */
2014-01-18 19:30:44 +08:00
{
zend_vm_stack p = EG ( argument_stack ) ;
zend_vm_stack_extend ( count + 1 TSRMLS_CC ) ;
EG ( argument_stack ) - > top + = count ;
2014-02-10 14:04:30 +08:00
ZVAL_LONG ( EG ( argument_stack ) - > top , count ) ;
2014-01-18 19:30:44 +08:00
while ( count - - > 0 ) {
2014-02-10 14:04:30 +08:00
zval * data = - - p - > top ;
2014-04-12 01:53:14 +08:00
ZVAL_COPY_VALUE ( ZEND_VM_STACK_ELEMETS ( EG ( argument_stack ) ) + count , data ) ;
2014-01-18 19:30:44 +08:00
if ( UNEXPECTED ( p - > top = = ZEND_VM_STACK_ELEMETS ( p ) ) ) {
zend_vm_stack r = p ;
EG ( argument_stack ) - > prev = p - > prev ;
p = p - > prev ;
efree ( r ) ;
}
}
return EG ( argument_stack ) - > top + + ;
}
/* }}} */
2014-02-10 14:04:30 +08:00
static zend_always_inline zval * zend_vm_stack_push_args ( int count TSRMLS_DC ) /* { { { */
2014-01-18 19:30:44 +08:00
{
if ( UNEXPECTED ( EG ( argument_stack ) - > top - ZEND_VM_STACK_ELEMETS ( EG ( argument_stack ) ) < count )
| | UNEXPECTED ( EG ( argument_stack ) - > top = = EG ( argument_stack ) - > end ) ) {
return zend_vm_stack_push_args_with_copy ( count TSRMLS_CC ) ;
}
2014-02-10 14:04:30 +08:00
ZVAL_LONG ( EG ( argument_stack ) - > top , count ) ;
2014-01-18 19:30:44 +08:00
return EG ( argument_stack ) - > top + + ;
}
/* }}} */
2012-12-05 17:23:37 +08:00
# define ZEND_VM_NEXT_OPCODE() \
CHECK_SYMBOL_TABLES ( ) \
ZEND_VM_INC_OPCODE ( ) ; \
ZEND_VM_CONTINUE ( )
# define ZEND_VM_SET_OPCODE(new_op) \
CHECK_SYMBOL_TABLES ( ) \
OPLINE = new_op
2014-04-30 15:23:19 +08:00
# define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \
CHECK_SYMBOL_TABLES ( ) \
OPLINE = ( ( zend_op * ) ( ( ( char * ) opline ) + ( offset ) ) )
2012-12-05 17:23:37 +08:00
# define ZEND_VM_JMP(new_op) \
if ( EXPECTED ( ! EG ( exception ) ) ) { \
ZEND_VM_SET_OPCODE ( new_op ) ; \
} else { \
LOAD_OPLINE ( ) ; \
} \
ZEND_VM_CONTINUE ( )
# define ZEND_VM_INC_OPCODE() \
OPLINE + +
# ifdef __GNUC__
# define ZEND_VM_GUARD(name) __asm__("#" #name)
# else
# define ZEND_VM_GUARD(name)
# endif
# 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 ] ;
}
ZEND_API zval * zend_get_zval_ptr ( int op_type , const znode_op * node , const zend_execute_data * execute_data , zend_free_op * should_free , int type TSRMLS_DC ) {
return get_zval_ptr ( op_type , node , execute_data , should_free , type ) ;
}
2003-02-01 09:49:15 +08:00
/*
* Local variables :
* tab - width : 4
* c - basic - offset : 4
* indent - tabs - mode : t
* End :
*/