zend_execute.c 57.8 KB
Newer Older
1 2 3 4
/*
   +----------------------------------------------------------------------+
   | Zend Engine                                                          |
   +----------------------------------------------------------------------+
5
   | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
6 7 8 9 10 11 12 13 14 15 16 17 18 19
   +----------------------------------------------------------------------+
   | This source file is subject to version 2.00 of the Zend license,     |
   | that is bundled with this package in the file LICENSE, and is        |
   | available through the world-wide-web at the following url:           |
   | http://www.zend.com/license/2_00.txt.                                |
   | 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.              |
   +----------------------------------------------------------------------+
   | Authors: Andi Gutmans <andi@zend.com>                                |
   |          Zeev Suraski <zeev@zend.com>                                |
   +----------------------------------------------------------------------+
*/

20
/* $Id$ */
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35

#define ZEND_INTENSIVE_DEBUGGING 0

#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"
#include "zend_ini.h"
#include "zend_exceptions.h"
36
#include "zend_interfaces.h"
37
#include "zend_closures.h"
38
#include "zend_generators.h"
39
#include "zend_vm.h"
40
#include "zend_dtrace.h"
41

42
/* Virtual current working directory support */
43
#include "zend_virtual_cwd.h"
44

45 46 47 48 49 50 51 52
#define _CONST_CODE  0
#define _TMP_CODE    1
#define _VAR_CODE    2
#define _UNUSED_CODE 3
#define _CV_CODE     4

typedef int (*incdec_t)(zval *);

53 54 55 56
#define get_zval_ptr(op_type, node, ex, should_free, type) _get_zval_ptr(op_type, node, ex, should_free, type TSRMLS_CC)
#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)
#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)
57 58

/* Prototypes */
59 60 61
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);
62

63
#define RETURN_VALUE_USED(opline) (!((opline)->result_type & EXT_TYPE_UNUSED))
64

65 66
#define EX_T(offset) (*EX_TMP_VAR(execute_data, offset))
#define EX_CV(var)   (*EX_CV_NUM(execute_data, var))
67 68 69

#define TEMP_VAR_STACK_LIMIT 2000

70
static zend_always_inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC)
71
{
72 73 74
	if (!Z_DELREF_P(z)) {
		Z_SET_REFCOUNT_P(z, 1);
		Z_UNSET_ISREF_P(z);
75 76 77 78
		should_free->var = z;
/*		should_free->is_var = 1; */
	} else {
		should_free->var = 0;
79 80
		if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
			Z_UNSET_ISREF_P(z);
81 82 83 84
		}
	}
}

85
static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
86
{
87
	if (!Z_DELREF_P(z)) {
88 89 90 91
		ZEND_ASSERT(z != &EG(uninitialized_zval));
		GC_REMOVE_ZVAL_FROM_BUFFER(z);
		zval_dtor(z);
		efree(z);
92 93 94
	}
}

95
#undef zval_ptr_dtor
96 97
#define zval_ptr_dtor(pzv) i_zval_ptr_dtor(*(pzv) ZEND_FILE_LINE_CC TSRMLS_CC)
#define zval_ptr_dtor_nogc(pzv) i_zval_ptr_dtor_nogc(*(pzv) ZEND_FILE_LINE_CC TSRMLS_CC)
98

99 100 101 102
#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
#define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC)
#define PZVAL_LOCK(z) Z_ADDREF_P((z))
103 104
#define SELECTIVE_PZVAL_LOCK(pzv, opline)	if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }

105 106 107 108 109 110 111 112
#define EXTRACT_ZVAL_PTR(t) do {				\
		temp_variable *__t = (t);				\
		__t->var.ptr = *__t->var.ptr_ptr;		\
		__t->var.ptr_ptr = &__t->var.ptr;		\
		if (!PZVAL_IS_REF(__t->var.ptr) && 		\
		    Z_REFCOUNT_P(__t->var.ptr) > 2) {	\
			SEPARATE_ZVAL(__t->var.ptr_ptr);	\
		}										\
113
	} while (0)
114

115 116 117 118 119
#define AI_SET_PTR(t, val) do {				\
		temp_variable *__t = (t);			\
		__t->var.ptr = (val);				\
		__t->var.ptr_ptr = &__t->var.ptr;	\
	} while (0)
120

121 122
#define FREE_OP(should_free) \
	if (should_free.var) { \
123 124
		if ((zend_uintptr_t)should_free.var & 1L) { \
			zval_dtor((zval*)((zend_uintptr_t)should_free.var & ~1L)); \
125
		} else { \
126
			zval_ptr_dtor_nogc(&should_free.var); \
127 128 129 130
		} \
	}

#define FREE_OP_IF_VAR(should_free) \
131
	if (should_free.var != NULL && (((zend_uintptr_t)should_free.var & 1L) == 0)) { \
132
		zval_ptr_dtor_nogc(&should_free.var); \
133 134 135 136
	}

#define FREE_OP_VAR_PTR(should_free) \
	if (should_free.var) { \
137
		zval_ptr_dtor_nogc(&should_free.var); \
138 139
	}

140
#define TMP_FREE(z) (zval*)(((zend_uintptr_t)(z)) | 1L)
141

142
#define IS_TMP_FREE(should_free) ((zend_uintptr_t)should_free.var & 1L)
143

144 145 146 147
#define MAKE_REAL_ZVAL_PTR(val) \
	do { \
		zval *_tmp; \
		ALLOC_ZVAL(_tmp); \
148 149
		INIT_PZVAL_COPY(_tmp, (val)); \
		(val) = _tmp; \
150 151
	} while (0)

152 153 154 155
/* End of zend_execute_locks.h */

#define CV_DEF_OF(i) (EG(active_op_array)->vars[i])

156 157 158 159 160 161 162 163 164 165 166
#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)))

167 168 169 170
#undef EX
#define EX(element) execute_data->element

ZEND_API zval** zend_get_compiled_variable_value(const zend_execute_data *execute_data, zend_uint var)
171
{
172
	return EX_CV(var);
173 174
}

175
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)
176
{
177
	return should_free->var = &EX_T(var).tmp_var;
178 179
}

180
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)
181
{
182
	zval *ptr = EX_T(var).var.ptr;
183

184
	return should_free->var = ptr;
185
}
186

187
static zend_never_inline zval **_get_zval_cv_lookup(zval ***ptr, zend_uint var, int type TSRMLS_DC)
188 189
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);
190

191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
	if (!EG(active_symbol_table) ||
	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		switch (type) {
			case BP_VAR_R:
			case BP_VAR_UNSET:
				zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
				/* break missing intentionally */
			case BP_VAR_IS:
				return &EG(uninitialized_zval_ptr);
				break;
			case BP_VAR_RW:
				zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
				/* break missing intentionally */
			case BP_VAR_W:
				Z_ADDREF(EG(uninitialized_zval));
				if (!EG(active_symbol_table)) {
207
					*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
208 209 210 211 212
					**ptr = &EG(uninitialized_zval);
				} else {
					zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
				}
				break;
213 214
		}
	}
215
	return *ptr;
216
}
217

218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_R(zval ***ptr, zend_uint var TSRMLS_DC)
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);

	if (!EG(active_symbol_table) ||
	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
		return &EG(uninitialized_zval_ptr);
	}
	return *ptr;
}

static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_UNSET(zval ***ptr, zend_uint var TSRMLS_DC)
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);

	if (!EG(active_symbol_table) ||
	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
		return &EG(uninitialized_zval_ptr);
	}
	return *ptr;
}

static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_IS(zval ***ptr, zend_uint var TSRMLS_DC)
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);

	if (!EG(active_symbol_table) ||
	    zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		return &EG(uninitialized_zval_ptr);
	}
	return *ptr;
}

static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_RW(zval ***ptr, zend_uint var TSRMLS_DC)
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);

	if (!EG(active_symbol_table)) {
		Z_ADDREF(EG(uninitialized_zval));
259
		*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
		**ptr = &EG(uninitialized_zval);
		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
	} else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		Z_ADDREF(EG(uninitialized_zval));
		zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
		zend_error(E_NOTICE, "Undefined variable: %s", cv->name);
	}
	return *ptr;
}

static zend_never_inline zval **_get_zval_cv_lookup_BP_VAR_W(zval ***ptr, zend_uint var TSRMLS_DC)
{
	zend_compiled_variable *cv = &CV_DEF_OF(var);

	if (!EG(active_symbol_table)) {
		Z_ADDREF(EG(uninitialized_zval));
276
		*ptr = (zval**)EX_CV_NUM(EG(current_execute_data), EG(active_op_array)->last_var + var);
277 278 279 280 281 282 283 284 285 286
		**ptr = &EG(uninitialized_zval);
	} else if (zend_hash_quick_find(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, (void **)ptr)==FAILURE) {
		Z_ADDREF(EG(uninitialized_zval));
		zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, &EG(uninitialized_zval_ptr), sizeof(zval *), (void **)ptr);
	}
	return *ptr;
}

static zend_always_inline zval *_get_zval_ptr_cv(zend_uint var, int type TSRMLS_DC)
{
287
	zval ***ptr = EX_CV_NUM(EG(current_execute_data), var);
288 289 290 291 292 293 294

	if (UNEXPECTED(*ptr == NULL)) {
		return *_get_zval_cv_lookup(ptr, var, type TSRMLS_CC);
	}
	return **ptr;
}

295
static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
296
{
297
	zval ***ptr = EX_CV_NUM(execute_data, var);
298 299 300 301 302 303 304

	if (UNEXPECTED(*ptr == NULL)) {
		return *_get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
	}
	return **ptr;
}

305
static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
306
{
307
	zval ***ptr = EX_CV_NUM(execute_data, var);
308 309 310 311 312 313 314

	if (UNEXPECTED(*ptr == NULL)) {
		return *_get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
	}
	return **ptr;
}

315
static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
316
{
317
	zval ***ptr = EX_CV_NUM(execute_data, var);
318 319 320 321 322 323 324

	if (UNEXPECTED(*ptr == NULL)) {
		return *_get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
	}
	return **ptr;
}

325
static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
326
{
327
	zval ***ptr = EX_CV_NUM(execute_data, var);
328 329 330 331 332 333 334

	if (UNEXPECTED(*ptr == NULL)) {
		return *_get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
	}
	return **ptr;
}

335
static zend_always_inline zval *_get_zval_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
336
{
337
	zval ***ptr = EX_CV_NUM(execute_data, var);
338

339
	if (UNEXPECTED(*ptr == NULL)) {
340
		return *_get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
341 342 343
	}
	return **ptr;
}
344

345
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)
346
{
347
/*	should_free->is_var = 0; */
348
	switch (op_type) {
349
		case IS_CONST:
350
			should_free->var = 0;
351
			return node->zv;
352 353
			break;
		case IS_TMP_VAR:
354 355
			should_free->var = TMP_FREE(&EX_T(node->var).tmp_var);
			return &EX_T(node->var).tmp_var;
356 357
			break;
		case IS_VAR:
358
			return _get_zval_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
359 360
			break;
		case IS_UNUSED:
361
			should_free->var = 0;
362 363
			return NULL;
			break;
364 365
		case IS_CV:
			should_free->var = 0;
366
			return _get_zval_ptr_cv(node->var, type TSRMLS_CC);
367
			break;
368 369 370 371 372
		EMPTY_SWITCH_DEFAULT_CASE()
	}
	return NULL;
}

373
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)
374
{
375
	zval** ptr_ptr = EX_T(var).var.ptr_ptr;
376

377
	if (EXPECTED(ptr_ptr != NULL)) {
378 379 380
		PZVAL_UNLOCK(*ptr_ptr, should_free);
	} else {
		/* string offset */
381
		PZVAL_UNLOCK(EX_T(var).str_offset.str, should_free);
382 383 384 385
	}
	return ptr_ptr;
}

386 387 388 389 390 391 392 393 394 395 396 397 398
static zend_always_inline zval **_get_zval_ptr_ptr_var_fast(zend_uint var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
{
	zval** ptr_ptr = EX_T(var).var.ptr_ptr;

	if (EXPECTED(ptr_ptr != NULL)) {
		should_free->var = *ptr_ptr;
	} else {
		/* string offset */
		should_free->var = EX_T(var).str_offset.str;
	}
	return ptr_ptr;
}

399
static zend_always_inline zval **_get_zval_ptr_ptr_cv(zend_uint var, int type TSRMLS_DC)
400
{
401
	zval ***ptr = EX_CV_NUM(EG(current_execute_data), var);
402

403
	if (UNEXPECTED(*ptr == NULL)) {
404
		return _get_zval_cv_lookup(ptr, var, type TSRMLS_CC);
405 406 407 408
	}
	return *ptr;
}

409
static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_R(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
410
{
411
	zval ***ptr = EX_CV_NUM(execute_data, var);
412 413 414 415 416 417 418

	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup_BP_VAR_R(ptr, var TSRMLS_CC);
	}
	return *ptr;
}

419
static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_UNSET(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
420
{
421
	zval ***ptr = EX_CV_NUM(execute_data, var);
422 423 424 425 426 427 428

	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup_BP_VAR_UNSET(ptr, var TSRMLS_CC);
	}
	return *ptr;
}

429
static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_IS(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
430
{
431
	zval ***ptr = EX_CV_NUM(execute_data, var);
432 433 434 435 436 437 438

	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup_BP_VAR_IS(ptr, var TSRMLS_CC);
	}
	return *ptr;
}

439
static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_RW(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
440
{
441
	zval ***ptr = EX_CV_NUM(execute_data, var);
442 443 444 445 446 447 448

	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup_BP_VAR_RW(ptr, var TSRMLS_CC);
	}
	return *ptr;
}

449
static zend_always_inline zval **_get_zval_ptr_ptr_cv_BP_VAR_W(const zend_execute_data *execute_data, zend_uint var TSRMLS_DC)
450
{
451
	zval ***ptr = EX_CV_NUM(execute_data, var);
452 453 454 455 456 457 458

	if (UNEXPECTED(*ptr == NULL)) {
		return _get_zval_cv_lookup_BP_VAR_W(ptr, var TSRMLS_CC);
	}
	return *ptr;
}

459
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)
460 461
{
	if (op_type == IS_CV) {
462
		should_free->var = 0;
463 464
		return _get_zval_ptr_ptr_cv(node->var, type TSRMLS_CC);
	} else if (op_type == IS_VAR) {
465
		return _get_zval_ptr_ptr_var(node->var, execute_data, should_free TSRMLS_CC);
466
	} else {
467
		should_free->var = 0;
468 469 470 471
		return NULL;
	}
}

472
static zend_always_inline zval *_get_obj_zval_ptr_unused(TSRMLS_D)
473
{
474
	if (EXPECTED(EG(This) != NULL)) {
475 476 477 478
		return EG(This);
	} else {
		zend_error_noreturn(E_ERROR, "Using $this when not in object context");
		return NULL;
479
	}
480
}
481

482
static inline zval **_get_obj_zval_ptr_ptr(int op_type, const znode_op *op, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC)
483
{
484
	if (op_type == IS_UNUSED) {
485
		if (EXPECTED(EG(This) != NULL)) {
486 487 488 489
			/* this should actually never be modified, _ptr_ptr is modified only when
			   the object is empty */
			should_free->var = 0;
			return &EG(This);
490
		} else {
491
			zend_error_noreturn(E_ERROR, "Using $this when not in object context");
492 493
		}
	}
494
	return get_zval_ptr_ptr(op_type, op, execute_data, should_free, type);
495 496
}

497
static zend_always_inline zval **_get_obj_zval_ptr_ptr_unused(TSRMLS_D)
498
{
499
	if (EXPECTED(EG(This) != NULL)) {
500 501 502 503 504 505
		return &EG(This);
	} else {
		zend_error_noreturn(E_ERROR, "Using $this when not in object context");
		return NULL;
	}
}
506

507
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)
508
{
509
	if (op_type == IS_UNUSED) {
510
		if (EXPECTED(EG(This) != NULL)) {
511 512 513 514 515 516
			should_free->var = 0;
			return EG(This);
		} else {
			zend_error_noreturn(E_ERROR, "Using $this when not in object context");
		}
	}
517
	return get_zval_ptr(op_type, op, execute_data, should_free, type);
518 519
}

520
static void zend_assign_to_variable_reference(zval **variable_ptr_ptr, zval **value_ptr_ptr TSRMLS_DC)
521
{
522 523
	zval *variable_ptr = *variable_ptr_ptr;
	zval *value_ptr = *value_ptr_ptr;
524

525
	if (variable_ptr != value_ptr) {
526 527
		if (!PZVAL_IS_REF(value_ptr)) {
			/* break it away */
528 529
			Z_DELREF_P(value_ptr);
			if (Z_REFCOUNT_P(value_ptr)>0) {
530
				ALLOC_ZVAL(*value_ptr_ptr);
531
				ZVAL_COPY_VALUE(*value_ptr_ptr, value_ptr);
532 533 534
				value_ptr = *value_ptr_ptr;
				zendi_zval_copy_ctor(*value_ptr);
			}
535 536
			Z_SET_REFCOUNT_P(value_ptr, 1);
			Z_SET_ISREF_P(value_ptr);
537
		}
538

539
		*variable_ptr_ptr = value_ptr;
540
		Z_ADDREF_P(value_ptr);
541

542
		zval_ptr_dtor(&variable_ptr);
543
	} else if (!Z_ISREF_P(variable_ptr)) {
544 545
		if (variable_ptr_ptr == value_ptr_ptr) {
			SEPARATE_ZVAL(variable_ptr_ptr);
546
		} else if (variable_ptr==&EG(uninitialized_zval)
547
			|| Z_REFCOUNT_P(variable_ptr)>2) {
548
			/* we need to separate */
549
			Z_SET_REFCOUNT_P(variable_ptr, Z_REFCOUNT_P(variable_ptr) - 2);
550
			ALLOC_ZVAL(*variable_ptr_ptr);
551
			ZVAL_COPY_VALUE(*variable_ptr_ptr, variable_ptr);
552 553
			zval_copy_ctor(*variable_ptr_ptr);
			*value_ptr_ptr = *variable_ptr_ptr;
554
			Z_SET_REFCOUNT_PP(variable_ptr_ptr, 2);
555
		}
556
		Z_SET_ISREF_PP(variable_ptr_ptr);
557 558 559
	}
}

560
/* this should modify object only if it's empty */
561 562
static inline void make_real_object(zval **object_ptr TSRMLS_DC)
{
563
	if (Z_TYPE_PP(object_ptr) == IS_NULL
564 565 566 567
		|| (Z_TYPE_PP(object_ptr) == IS_BOOL && Z_LVAL_PP(object_ptr) == 0)
		|| (Z_TYPE_PP(object_ptr) == IS_STRING && Z_STRLEN_PP(object_ptr) == 0)
	) {
		SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
568
		zval_dtor(*object_ptr);
569
		object_init(*object_ptr);
570
		zend_error(E_WARNING, "Creating default object from empty value");
571 572 573
	}
}

574
ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, const char **class_name, zend_class_entry **pce TSRMLS_DC)
575
{
576
	*pce = zend_fetch_class(cur_arg_info->class_name, cur_arg_info->class_name_len, (fetch_type | ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD) TSRMLS_CC);
577 578 579 580 581 582 583 584 585

	*class_name = (*pce) ? (*pce)->name: cur_arg_info->class_name;
	if (*pce && (*pce)->ce_flags & ZEND_ACC_INTERFACE) {
		return "implement interface ";
	} else {
		return "be an instance of ";
	}
}

586
ZEND_API int 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)
587
{
588
	zend_execute_data *ptr = EG(current_execute_data)->prev_execute_data;
589
	const char *fname = zf->common.function_name;
590
	char *fsep;
591
	const char *fclass;
592 593 594 595 596 597 598 599 600 601

	if (zf->common.scope) {
		fsep =  "::";
		fclass = zf->common.scope->name;
	} else {
		fsep =  "";
		fclass = "";
	}

	if (ptr && ptr->op_array) {
602
		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, ptr->opline->lineno);
603
	} else {
604
		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);
605 606 607 608
	}
	return 0;
}

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
static int is_null_constant(zval *default_value TSRMLS_DC)
{
	if (IS_CONSTANT_TYPE(Z_TYPE_P(default_value))) {
		zval constant = *default_value;
		zval *constant_ptr = &constant;

		zval_update_constant(&constant_ptr, 0 TSRMLS_CC);
		if (Z_TYPE(constant) == IS_NULL) {
			return 1;
		}
		zval_dtor(&constant);
	}
	return 0;
}

static inline int zend_verify_arg_type(zend_function *zf, zend_uint arg_num, zval *arg, ulong fetch_type, zval *default_value TSRMLS_DC)
625 626 627 628
{
	zend_arg_info *cur_arg_info;
	char *need_msg;
	zend_class_entry *ce;
629

630
	if (!zf->common.arg_info) {
631
		return 1;
632 633
	}

634 635 636 637 638 639 640
	if (arg_num <= zf->common.num_args) {
		cur_arg_info = &zf->common.arg_info[arg_num-1];
	} else if (zf->common.fn_flags & ZEND_ACC_VARIADIC) {
		cur_arg_info = &zf->common.arg_info[zf->common.num_args-1];
	} else {
		return 1;
	}
641 642

	if (cur_arg_info->class_name) {
643
		const char *class_name;
644

645
		if (!arg) {
646
			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
647
			return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "none", "" TSRMLS_CC);
648
		}
649
		if (Z_TYPE_P(arg) == IS_OBJECT) {
650
			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
651
			if (!ce || !instanceof_function(Z_OBJCE_P(arg), ce TSRMLS_CC)) {
652
				return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, "instance of ", Z_OBJCE_P(arg)->name TSRMLS_CC);
653
			}
654
		} else if (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value TSRMLS_CC)))) {
655
			need_msg = zend_verify_arg_class_kind(cur_arg_info, fetch_type, &class_name, &ce TSRMLS_CC);
656
			return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, need_msg, class_name, zend_zval_type_name(arg), "" TSRMLS_CC);
657
		}
658 659 660 661 662 663 664
	} else if (cur_arg_info->type_hint) {
		switch(cur_arg_info->type_hint) {
			case IS_ARRAY:
				if (!arg) {
					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", "none", "" TSRMLS_CC);
				}

665
				if (Z_TYPE_P(arg) != IS_ARRAY && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value TSRMLS_CC))))) {
666 667 668 669 670 671 672 673
					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be of the type array", "", zend_zval_type_name(arg), "" TSRMLS_CC);
				}
				break;

			case IS_CALLABLE:
				if (!arg) {
					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", "none", "" TSRMLS_CC);
				}
674
				if (!zend_is_callable(arg, IS_CALLABLE_CHECK_SILENT, NULL TSRMLS_CC) && (Z_TYPE_P(arg) != IS_NULL || !(cur_arg_info->allow_null || (default_value && is_null_constant(default_value TSRMLS_CC))))) {
675 676 677 678 679 680
					return zend_verify_arg_error(E_RECOVERABLE_ERROR, zf, arg_num, "be callable", "", zend_zval_type_name(arg), "" TSRMLS_CC);
				}
				break;

			default:
				zend_error(E_ERROR, "Unknown typehint");
681 682
		}
	}
683
	return 1;
684 685
}

686
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, const zend_literal *key TSRMLS_DC)
687
{
688
	zval *object = *object_ptr;
689
	zend_free_op free_value;
690
 	zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R);
691

692
	if (Z_TYPE_P(object) != IS_OBJECT) {
693 694 695
		if (object == &EG(error_zval)) {
 			if (retval) {
				*retval = &EG(uninitialized_zval);
696 697 698 699
				PZVAL_LOCK(*retval);
			}
			FREE_OP(free_value);
			return;
700
		}
701 702 703
		if (Z_TYPE_P(object) == IS_NULL ||
		    (Z_TYPE_P(object) == IS_BOOL && Z_LVAL_P(object) == 0) ||
		    (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
704
			SEPARATE_ZVAL_IF_NOT_REF(object_ptr);
705
			object = *object_ptr;
706
			Z_ADDREF_P(object);
707
			zend_error(E_WARNING, "Creating default object from empty value");
708 709 710 711 712 713 714 715 716 717 718 719 720
			if (Z_REFCOUNT_P(object) == 1) {
				/* object was removed by error handler, nothing to assign to */
				zval_ptr_dtor(&object);
				if (retval) {
					*retval = &EG(uninitialized_zval);
					PZVAL_LOCK(*retval);
				}
				FREE_OP(free_value);
				return;
			}
			Z_DELREF_P(object);
			zval_dtor(object);
			object_init(object);
721 722
		} else {
			zend_error(E_WARNING, "Attempt to assign property of non-object");
723 724
			if (retval) {
				*retval = &EG(uninitialized_zval);
725 726 727 728
				PZVAL_LOCK(*retval);
			}
			FREE_OP(free_value);
			return;
729
		}
730
	}
731

732
	/* separate our value if necessary */
733
	if (value_type == IS_TMP_VAR) {
734 735 736
		zval *orig_value = value;

		ALLOC_ZVAL(value);
737
		ZVAL_COPY_VALUE(value, orig_value);
738 739
		Z_UNSET_ISREF_P(value);
		Z_SET_REFCOUNT_P(value, 0);
740
	} else if (value_type == IS_CONST) {
741 742 743
		zval *orig_value = value;

		ALLOC_ZVAL(value);
744
		ZVAL_COPY_VALUE(value, orig_value);
745 746
		Z_UNSET_ISREF_P(value);
		Z_SET_REFCOUNT_P(value, 0);
747 748
		zval_copy_ctor(value);
	}
749

750

751
	Z_ADDREF_P(value);
752
	if (opcode == ZEND_ASSIGN_OBJ) {
753 754
		if (!Z_OBJ_HT_P(object)->write_property) {
			zend_error(E_WARNING, "Attempt to assign property of non-object");
755 756 757
			if (retval) {
				*retval = &EG(uninitialized_zval);
				PZVAL_LOCK(&EG(uninitialized_zval));
758
			}
759
			if (value_type == IS_TMP_VAR) {
760
				FREE_ZVAL(value);
761
			} else if (value_type == IS_CONST) {
762 763 764 765
				zval_ptr_dtor(&value);
			}
			FREE_OP(free_value);
			return;
766
		}
767
		Z_OBJ_HT_P(object)->write_property(object, property_name, value, key TSRMLS_CC);
768 769 770
	} else {
		/* Note:  property_name in this case is really the array index! */
		if (!Z_OBJ_HT_P(object)->write_dimension) {
771
			zend_error_noreturn(E_ERROR, "Cannot use object as array");
772 773 774
		}
		Z_OBJ_HT_P(object)->write_dimension(object, property_name, value TSRMLS_CC);
	}
775

776 777
	if (retval && !EG(exception)) {
		*retval = value;
778
		PZVAL_LOCK(value);
779 780
	}
	zval_ptr_dtor(&value);
781
	FREE_OP_IF_VAR(free_value);
782 783
}

784
static inline int zend_assign_to_string_offset(const temp_variable *T, const zval *value, int value_type TSRMLS_DC)
785
{
786 787 788 789 790
	zval *str = T->str_offset.str;
	zend_uint offset = T->str_offset.offset;
	if (Z_TYPE_P(str) == IS_STRING) {
		if ((int)offset < 0) {
			zend_error(E_WARNING, "Illegal string offset:  %d", offset);
791 792
			return 0;
		}
793

794 795 796 797 798 799 800
		if (offset >= Z_STRLEN_P(str)) {
			Z_STRVAL_P(str) = str_erealloc(Z_STRVAL_P(str), offset+1+1);
			memset(Z_STRVAL_P(str) + Z_STRLEN_P(str), ' ', offset - Z_STRLEN_P(str));
			Z_STRVAL_P(str)[offset+1] = 0;
			Z_STRLEN_P(str) = offset+1;
		} else if (IS_INTERNED(Z_STRVAL_P(str))) {
			Z_STRVAL_P(str) = estrndup(Z_STRVAL_P(str), Z_STRLEN_P(str));
801
		}
802

803
		if (Z_TYPE_P(value) != IS_STRING) {
804
			zval tmp;
805

806
			ZVAL_COPY_VALUE(&tmp, value);
807 808 809 810
			if (value_type != IS_TMP_VAR) {
				zval_copy_ctor(&tmp);
			}
			convert_to_string(&tmp);
811 812
			Z_STRVAL_P(str)[offset] = Z_STRVAL(tmp)[0];
			str_efree(Z_STRVAL(tmp));
813
		} else {
814
			Z_STRVAL_P(str)[offset] = Z_STRVAL_P(value)[0];
815
			if (value_type == IS_TMP_VAR) {
816 817
				/* we can safely free final_value here
				 * because separation is done only
818
				 * in case value_type == IS_VAR */
819
				str_efree(Z_STRVAL_P(value));
820
			}
821
		}
822 823 824 825
		/*
		 * the value of an assignment to a string offset is undefined
		T(result->u.var).var = &T->str_offset.str;
		*/
826
	}
827 828
	return 1;
}
829

830 831

static inline zval* zend_assign_tmp_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
832 833 834
{
	zval *variable_ptr = *variable_ptr_ptr;
	zval garbage;
835

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
	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_ptr, value TSRMLS_CC);
		return variable_ptr;
	}

 	if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1) &&
 	    EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
 	    /* we need to split */
		Z_DELREF_P(variable_ptr);
		GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
		ALLOC_ZVAL(variable_ptr);
		INIT_PZVAL_COPY(variable_ptr, value);
		*variable_ptr_ptr = variable_ptr;
		return variable_ptr;
	} else {
		if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
			/* nothing to destroy */
			ZVAL_COPY_VALUE(variable_ptr, value);
		} else {
			ZVAL_COPY_VALUE(&garbage, variable_ptr);
			ZVAL_COPY_VALUE(variable_ptr, value);
			_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
859
		}
860
		return variable_ptr;
861
	}
862
}
863

864 865 866 867 868 869 870
static inline zval* zend_assign_const_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
{
	zval *variable_ptr = *variable_ptr_ptr;
	zval garbage;

	if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
	    UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
871
		Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr_ptr, value TSRMLS_CC);
872
		return variable_ptr;
873
	}
874

875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
 	if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1) &&
 	    EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
		/* we need to split */
		Z_DELREF_P(variable_ptr);
		GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
		ALLOC_ZVAL(variable_ptr);
		INIT_PZVAL_COPY(variable_ptr, value);
		zval_copy_ctor(variable_ptr);
		*variable_ptr_ptr = variable_ptr;
		return variable_ptr;
 	} else {
		if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
			/* nothing to destroy */
			ZVAL_COPY_VALUE(variable_ptr, value);
			zendi_zval_copy_ctor(*variable_ptr);
		} else {
			ZVAL_COPY_VALUE(&garbage, variable_ptr);
			ZVAL_COPY_VALUE(variable_ptr, value);
			zendi_zval_copy_ctor(*variable_ptr);
			_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
895
		}
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917
		return variable_ptr;
	}
}

static inline zval* zend_assign_to_variable(zval **variable_ptr_ptr, zval *value TSRMLS_DC)
{
	zval *variable_ptr = *variable_ptr_ptr;
	zval 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_ptr, value TSRMLS_CC);
		return variable_ptr;
	}

 	if (EXPECTED(!PZVAL_IS_REF(variable_ptr))) {
		if (Z_REFCOUNT_P(variable_ptr)==1) {
			if (UNEXPECTED(variable_ptr == value)) {
				return variable_ptr;
			} else if (EXPECTED(!PZVAL_IS_REF(value))) {
				Z_ADDREF_P(value);
				*variable_ptr_ptr = value;
918 919 920 921
				ZEND_ASSERT(variable_ptr != &EG(uninitialized_zval));
				GC_REMOVE_ZVAL_FROM_BUFFER(variable_ptr);
				zval_dtor(variable_ptr);
				efree(variable_ptr);
922
				return value;
923
			} else {
924
				goto copy_value;
925 926
			}
		} else { /* we need to split */
927 928
			Z_DELREF_P(variable_ptr);
			GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
929
			if (PZVAL_IS_REF(value)) {
930 931 932 933 934
				ALLOC_ZVAL(variable_ptr);
				*variable_ptr_ptr = variable_ptr;
				INIT_PZVAL_COPY(variable_ptr, value);
				zval_copy_ctor(variable_ptr);
				return variable_ptr;
935
			} else {
936 937 938
				*variable_ptr_ptr = value;
				Z_ADDREF_P(value);
				return value;
939
			}
940
		}
941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
 	} else {
		if (EXPECTED(variable_ptr != value)) {
copy_value:
			if (EXPECTED(Z_TYPE_P(variable_ptr) <= IS_BOOL)) {
				/* nothing to destroy */
				ZVAL_COPY_VALUE(variable_ptr, value);
				zendi_zval_copy_ctor(*variable_ptr);
			} else {
				ZVAL_COPY_VALUE(&garbage, variable_ptr);
				ZVAL_COPY_VALUE(variable_ptr, value);
				zendi_zval_copy_ctor(*variable_ptr);
				_zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
			}
		}
		return variable_ptr;
956 957 958
	}
}

959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
static void zval_deep_copy(zval **p)
{
	zval *value;

	ALLOC_ZVAL(value);
	*value = **p;
	if (Z_TYPE_P(value) == IS_ARRAY) {
		HashTable *ht;

		ALLOC_HASHTABLE(ht);
		zend_hash_init(ht, zend_hash_num_elements(Z_ARRVAL_P(value)), NULL, ZVAL_PTR_DTOR, 0);
		zend_hash_copy(ht, Z_ARRVAL_P(value), (copy_ctor_func_t) zval_deep_copy, NULL, sizeof(zval *));
		Z_ARRVAL_P(value) = ht;
	} else {
		zval_copy_ctor(value);
	}
	INIT_PZVAL(value);
	*p = value;
}

979
/* Utility Functions for Extensions */
980
static void zend_extension_statement_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
981 982 983 984 985 986 987
{
	if (extension->statement_handler) {
		extension->statement_handler(op_array);
	}
}


988
static void zend_extension_fcall_begin_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
989 990 991 992 993 994 995
{
	if (extension->fcall_begin_handler) {
		extension->fcall_begin_handler(op_array);
	}
}


996
static void zend_extension_fcall_end_handler(const zend_extension *extension, zend_op_array *op_array TSRMLS_DC)
997 998 999 1000 1001 1002 1003
{
	if (extension->fcall_end_handler) {
		extension->fcall_end_handler(op_array);
	}
}


1004
static inline HashTable *zend_get_target_symbol_table(int fetch_type TSRMLS_DC)
1005
{
1006
	switch (fetch_type) {
1007
		case ZEND_FETCH_LOCAL:
1008 1009 1010
			if (!EG(active_symbol_table)) {
				zend_rebuild_symbol_table(TSRMLS_C);
			}
1011 1012 1013
			return EG(active_symbol_table);
			break;
		case ZEND_FETCH_GLOBAL:
1014
		case ZEND_FETCH_GLOBAL_LOCK:
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
			return &EG(symbol_table);
			break;
		case ZEND_FETCH_STATIC:
			if (!EG(active_op_array)->static_variables) {
				ALLOC_HASHTABLE(EG(active_op_array)->static_variables);
				zend_hash_init(EG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0);
			}
			return EG(active_op_array)->static_variables;
			break;
		EMPTY_SWITCH_DEFAULT_CASE()
	}
	return NULL;
}

1029
static inline zval **zend_fetch_dimension_address_inner(HashTable *ht, const zval *dim, int dim_type, int type TSRMLS_DC)
1030 1031
{
	zval **retval;
1032 1033
	char *offset_key;
	int offset_key_length;
1034
	ulong hval;
1035 1036 1037 1038 1039

	switch (dim->type) {
		case IS_NULL:
			offset_key = "";
			offset_key_length = 0;
1040
			hval = zend_inline_hash_func("", 1);
1041
			goto fetch_string_dim;
1042

1043
		case IS_STRING:
1044

1045 1046
			offset_key = dim->value.str.val;
			offset_key_length = dim->value.str.len;
1047 1048 1049 1050 1051

			if (dim_type == IS_CONST) {
				hval = Z_HASH_P(dim);
			} else {
				ZEND_HANDLE_NUMERIC_EX(offset_key, offset_key_length+1, hval, goto num_index);
1052
				hval = str_hash(offset_key, offset_key_length);
1053
			}
1054
fetch_string_dim:
1055
			if (zend_hash_quick_find(ht, offset_key, offset_key_length+1, hval, (void **) &retval) == FAILURE) {
1056 1057
				switch (type) {
					case BP_VAR_R:
1058
						zend_error(E_NOTICE, "Undefined index: %s", offset_key);
1059 1060 1061 1062 1063 1064
						/* break missing intentionally */
					case BP_VAR_UNSET:
					case BP_VAR_IS:
						retval = &EG(uninitialized_zval_ptr);
						break;
					case BP_VAR_RW:
1065
						zend_error(E_NOTICE,"Undefined index: %s", offset_key);
1066 1067 1068 1069
						/* break missing intentionally */
					case BP_VAR_W: {
							zval *new_zval = &EG(uninitialized_zval);

1070
							Z_ADDREF_P(new_zval);
1071
							zend_hash_quick_update(ht, offset_key, offset_key_length+1, hval, &new_zval, sizeof(zval *), (void **) &retval);
1072 1073 1074 1075 1076
						}
						break;
				}
			}
			break;
1077
		case IS_DOUBLE:
1078
			hval = zend_dval_to_lval(Z_DVAL_P(dim));
1079
			goto num_index;
1080
		case IS_RESOURCE:
1081
			zend_error(E_STRICT, "Resource ID#%ld used as offset, casting to integer (%ld)", Z_LVAL_P(dim), Z_LVAL_P(dim));
1082
			/* Fall Through */
1083
		case IS_BOOL:
1084
		case IS_LONG:
1085
			hval = Z_LVAL_P(dim);
1086
num_index:
1087
			if (zend_hash_index_find(ht, hval, (void **) &retval) == FAILURE) {
1088 1089
				switch (type) {
					case BP_VAR_R:
1090
						zend_error(E_NOTICE,"Undefined offset: %ld", hval);
1091 1092 1093 1094
						/* break missing intentionally */
					case BP_VAR_UNSET:
					case BP_VAR_IS:
						retval = &EG(uninitialized_zval_ptr);
1095
						break;
1096
					case BP_VAR_RW:
1097
						zend_error(E_NOTICE,"Undefined offset: %ld", hval);
1098 1099 1100 1101 1102
						/* break missing intentionally */
					case BP_VAR_W: {
						zval *new_zval = &EG(uninitialized_zval);

						Z_ADDREF_P(new_zval);
1103
						zend_hash_index_update(ht, hval, &new_zval, sizeof(zval *), (void **) &retval);
1104
					}
1105
					break;
1106 1107 1108
				}
			}
			break;
1109

1110
		default:
1111
			zend_error(E_WARNING, "Illegal offset type");
1112 1113
			return (type == BP_VAR_W || type == BP_VAR_RW) ?
				&EG(error_zval_ptr) : &EG(uninitialized_zval_ptr);
1114 1115 1116 1117
	}
	return retval;
}

1118
static void zend_fetch_dimension_address(temp_variable *result, zval **container_ptr, zval *dim, int dim_type, int type TSRMLS_DC)
1119
{
1120 1121
	zval *container = *container_ptr;
	zval **retval;
1122

1123
	switch (Z_TYPE_P(container)) {
1124

1125
		case IS_ARRAY:
1126
			if (type != BP_VAR_UNSET && Z_REFCOUNT_P(container)>1 && !PZVAL_IS_REF(container)) {
1127 1128 1129
				SEPARATE_ZVAL(container_ptr);
				container = *container_ptr;
			}
1130
fetch_from_array:
1131
			if (dim == NULL) {
1132 1133
				zval *new_zval = &EG(uninitialized_zval);

1134
				Z_ADDREF_P(new_zval);
1135
				if (zend_hash_next_index_insert(Z_ARRVAL_P(container), &new_zval, sizeof(zval *), (void **) &retval) == FAILURE) {
1136
					zend_error(E_WARNING, "Cannot add element to the array as the next element is already occupied");
1137
					retval = &EG(error_zval_ptr);
1138
					Z_DELREF_P(new_zval);
1139 1140
				}
			} else {
1141
				retval = zend_fetch_dimension_address_inner(Z_ARRVAL_P(container), dim, dim_type, type TSRMLS_CC);
1142
			}
1143 1144 1145
			result->var.ptr_ptr = retval;
			PZVAL_LOCK(*retval);
			return;
1146
			break;
1147 1148

		case IS_NULL:
1149
			if (container == &EG(error_zval)) {
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
				result->var.ptr_ptr = &EG(error_zval_ptr);
				PZVAL_LOCK(EG(error_zval_ptr));
			} else if (type != BP_VAR_UNSET) {
convert_to_array:
				if (!PZVAL_IS_REF(container)) {
					SEPARATE_ZVAL(container_ptr);
					container = *container_ptr;
				}
				zval_dtor(container);
				array_init(container);
				goto fetch_from_array;
			} else {
				/* for read-mode only */
1163
				result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
1164
				PZVAL_LOCK(EG(uninitialized_zval_ptr));
1165
			}
1166
			return;
1167
			break;
1168

1169 1170 1171
		case IS_STRING: {
				zval tmp;

1172 1173 1174
				if (type != BP_VAR_UNSET && Z_STRLEN_P(container)==0) {
					goto convert_to_array;
				}
1175 1176
				if (dim == NULL) {
					zend_error_noreturn(E_ERROR, "[] operator not supported for strings");
1177 1178
				}

1179 1180 1181 1182
				if (type != BP_VAR_UNSET) {
					SEPARATE_ZVAL_IF_NOT_REF(container_ptr);
				}

1183
				if (Z_TYPE_P(dim) != IS_LONG) {
1184

1185 1186 1187
					switch(Z_TYPE_P(dim)) {
						/* case IS_LONG: */
						case IS_STRING:
1188 1189 1190 1191 1192 1193 1194 1195
							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'", dim->value.str.val);
							}

							break;
1196 1197 1198
						case IS_DOUBLE:
						case IS_NULL:
						case IS_BOOL:
1199
							zend_error(E_NOTICE, "String offset cast occurred");
1200 1201 1202 1203 1204 1205
							break;
						default:
							zend_error(E_WARNING, "Illegal offset type");
							break;
					}

1206
					tmp = *dim;
1207 1208
					zval_copy_ctor(&tmp);
					convert_to_long(&tmp);
1209
					dim = &tmp;
1210
				}
1211 1212 1213 1214
				container = *container_ptr;
				result->str_offset.str = container;
				PZVAL_LOCK(container);
				result->str_offset.offset = Z_LVAL_P(dim);
1215
				result->str_offset.ptr_ptr = NULL;
1216 1217 1218
				return;
			}
			break;
1219

1220 1221
		case IS_OBJECT:
			if (!Z_OBJ_HT_P(container)->read_dimension) {
1222
				zend_error_noreturn(E_ERROR, "Cannot use object as array");
1223
			} else {
1224
				zval *overloaded_result;
1225

1226
				if (dim_type == IS_TMP_VAR) {
1227
					zval *orig = dim;
1228
					MAKE_REAL_ZVAL_PTR(dim);