xref: /PHP-7.0/Zend/zend_variables.c (revision d7a10f0e)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2017 Zend Technologies Ltd. (http://www.zend.com) |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@zend.com>                                |
16    |          Zeev Suraski <zeev@zend.com>                                |
17    |          Dmitry Stogov <dmitry@zend.com>                             |
18    +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 
23 #include <stdio.h>
24 #include "zend.h"
25 #include "zend_API.h"
26 #include "zend_ast.h"
27 #include "zend_globals.h"
28 #include "zend_constants.h"
29 #include "zend_list.h"
30 
_zval_dtor_func(zend_refcounted * p ZEND_FILE_LINE_DC)31 ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC)
32 {
33 	if (--GC_REFCOUNT(p)) {
34 		return;
35 	}
36 
37 	switch (GC_TYPE(p)) {
38 		case IS_STRING:
39 		case IS_CONSTANT: {
40 				zend_string *str = (zend_string*)p;
41 				CHECK_ZVAL_STRING_REL(str);
42 				zend_string_free(str);
43 				break;
44 			}
45 		case IS_ARRAY: {
46 				zend_array *arr = (zend_array*)p;
47 				zend_array_destroy(arr);
48 				break;
49 			}
50 		case IS_CONSTANT_AST: {
51 				zend_ast_ref *ast = (zend_ast_ref*)p;
52 
53 				zend_ast_destroy_and_free(ast->ast);
54 				efree_size(ast, sizeof(zend_ast_ref));
55 				break;
56 			}
57 		case IS_OBJECT: {
58 				zend_object *obj = (zend_object*)p;
59 
60 				zend_objects_store_del(obj);
61 				break;
62 			}
63 		case IS_RESOURCE: {
64 				zend_resource *res = (zend_resource*)p;
65 
66 				/* destroy resource */
67 				zend_list_free(res);
68 				break;
69 			}
70 		case IS_REFERENCE: {
71 				zend_reference *ref = (zend_reference*)p;
72 
73 				i_zval_ptr_dtor(&ref->val ZEND_FILE_LINE_RELAY_CC);
74 				efree_size(ref, sizeof(zend_reference));
75 				break;
76 			}
77 		default:
78 			break;
79 	}
80 }
81 
_zval_dtor_func_for_ptr(zend_refcounted * p ZEND_FILE_LINE_DC)82 ZEND_API void ZEND_FASTCALL _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC)
83 {
84 	switch (GC_TYPE(p)) {
85 		case IS_STRING:
86 		case IS_CONSTANT: {
87 				zend_string *str = (zend_string*)p;
88 				CHECK_ZVAL_STRING_REL(str);
89 				zend_string_free(str);
90 				break;
91 			}
92 		case IS_ARRAY: {
93 				zend_array *arr = (zend_array*)p;
94 
95 				zend_array_destroy(arr);
96 				break;
97 			}
98 		case IS_CONSTANT_AST: {
99 				zend_ast_ref *ast = (zend_ast_ref*)p;
100 
101 				zend_ast_destroy_and_free(ast->ast);
102 				efree_size(ast, sizeof(zend_ast_ref));
103 				break;
104 			}
105 		case IS_OBJECT: {
106 				zend_object *obj = (zend_object*)p;
107 
108 				zend_objects_store_del(obj);
109 				break;
110 			}
111 		case IS_RESOURCE: {
112 				zend_resource *res = (zend_resource*)p;
113 
114 				/* destroy resource */
115 				zend_list_free(res);
116 				break;
117 			}
118 		case IS_REFERENCE: {
119 				zend_reference *ref = (zend_reference*)p;
120 
121 				i_zval_ptr_dtor(&ref->val ZEND_FILE_LINE_RELAY_CC);
122 				efree_size(ref, sizeof(zend_reference));
123 				break;
124 			}
125 		default:
126 			break;
127 	}
128 }
129 
_zval_internal_dtor(zval * zvalue ZEND_FILE_LINE_DC)130 ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC)
131 {
132 	switch (Z_TYPE_P(zvalue)) {
133 		case IS_STRING:
134 		case IS_CONSTANT:
135 			CHECK_ZVAL_STRING_REL(Z_STR_P(zvalue));
136 			zend_string_release(Z_STR_P(zvalue));
137 			break;
138 		case IS_ARRAY:
139 		case IS_CONSTANT_AST:
140 		case IS_OBJECT:
141 		case IS_RESOURCE:
142 			zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
143 			break;
144 		case IS_REFERENCE: {
145 				zend_reference *ref = (zend_reference*)Z_REF_P(zvalue);
146 
147 				zval_internal_ptr_dtor(&ref->val);
148 				free(ref);
149 				break;
150 			}
151 		case IS_LONG:
152 		case IS_DOUBLE:
153 		case IS_FALSE:
154 		case IS_TRUE:
155 		case IS_NULL:
156 		default:
157 			break;
158 	}
159 }
160 
_zval_internal_dtor_for_ptr(zval * zvalue ZEND_FILE_LINE_DC)161 ZEND_API void _zval_internal_dtor_for_ptr(zval *zvalue ZEND_FILE_LINE_DC)
162 {
163 	switch (Z_TYPE_P(zvalue)) {
164 		case IS_STRING:
165 		case IS_CONSTANT:
166 			CHECK_ZVAL_STRING_REL(Z_STR_P(zvalue));
167 			zend_string_free(Z_STR_P(zvalue));
168 			break;
169 		case IS_ARRAY:
170 		case IS_CONSTANT_AST:
171 		case IS_OBJECT:
172 		case IS_RESOURCE:
173 			zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects or resources");
174 			break;
175 		case IS_REFERENCE: {
176 				zend_reference *ref = (zend_reference*)Z_REF_P(zvalue);
177 
178 				zval_internal_ptr_dtor(&ref->val);
179 				free(ref);
180 				break;
181 			}
182 		case IS_LONG:
183 		case IS_DOUBLE:
184 		case IS_FALSE:
185 		case IS_TRUE:
186 		case IS_NULL:
187 		default:
188 			break;
189 	}
190 }
191 
192 /* This function should only be used as a copy constructor, i.e. it
193  * should only be called AFTER a zval has been copied to another
194  * location using ZVAL_COPY_VALUE. Do not call it before copying,
195  * otherwise a reference may be leaked. */
zval_add_ref(zval * p)196 ZEND_API void zval_add_ref(zval *p)
197 {
198 	if (Z_REFCOUNTED_P(p)) {
199 		if (Z_ISREF_P(p) && Z_REFCOUNT_P(p) == 1) {
200 			ZVAL_COPY(p, Z_REFVAL_P(p));
201 		} else {
202 			Z_ADDREF_P(p);
203 		}
204 	}
205 }
206 
zval_add_ref_unref(zval * p)207 ZEND_API void zval_add_ref_unref(zval *p)
208 {
209 	if (Z_REFCOUNTED_P(p)) {
210 		if (Z_ISREF_P(p)) {
211 			ZVAL_COPY(p, Z_REFVAL_P(p));
212 		} else {
213 			Z_ADDREF_P(p);
214 		}
215 	}
216 }
217 
_zval_copy_ctor_func(zval * zvalue ZEND_FILE_LINE_DC)218 ZEND_API void ZEND_FASTCALL _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC)
219 {
220 	if (EXPECTED(Z_TYPE_P(zvalue) == IS_ARRAY)) {
221 		ZVAL_ARR(zvalue, zend_array_dup(Z_ARRVAL_P(zvalue)));
222 	} else if (EXPECTED(Z_TYPE_P(zvalue) == IS_STRING)) {
223 		CHECK_ZVAL_STRING_REL(Z_STR_P(zvalue));
224 		ZVAL_NEW_STR(zvalue, zend_string_dup(Z_STR_P(zvalue), 0));
225 	} else if (EXPECTED(Z_TYPE_P(zvalue) == IS_CONSTANT)) {
226 		CHECK_ZVAL_STRING_REL(Z_STR_P(zvalue));
227 		Z_STR_P(zvalue) = zend_string_dup(Z_STR_P(zvalue), 0);
228 	} else if (EXPECTED(Z_TYPE_P(zvalue) == IS_CONSTANT_AST)) {
229 		zend_ast_ref *ast = emalloc(sizeof(zend_ast_ref));
230 
231 		GC_REFCOUNT(ast) = 1;
232 		GC_TYPE_INFO(ast) = IS_CONSTANT_AST;
233 		ast->ast = zend_ast_copy(Z_ASTVAL_P(zvalue));
234 		Z_AST_P(zvalue) = ast;
235 	}
236 }
237 
238 
zend_print_variable(zval * var)239 ZEND_API size_t zend_print_variable(zval *var)
240 {
241 	return zend_print_zval(var, 0);
242 }
243 
244 
_zval_dtor_wrapper(zval * zvalue)245 ZEND_API void _zval_dtor_wrapper(zval *zvalue)
246 {
247 	zval_dtor(zvalue);
248 }
249 
250 
251 #if ZEND_DEBUG
_zval_internal_dtor_wrapper(zval * zvalue)252 ZEND_API void _zval_internal_dtor_wrapper(zval *zvalue)
253 {
254 	zval_internal_dtor(zvalue);
255 }
256 
257 
_zval_ptr_dtor_wrapper(zval * zval_ptr)258 ZEND_API void _zval_ptr_dtor_wrapper(zval *zval_ptr)
259 {
260 
261 	i_zval_ptr_dtor(zval_ptr ZEND_FILE_LINE_CC);
262 }
263 
264 
_zval_internal_ptr_dtor_wrapper(zval * zval_ptr)265 ZEND_API void _zval_internal_ptr_dtor_wrapper(zval *zval_ptr)
266 {
267 	zval_internal_ptr_dtor(zval_ptr);
268 }
269 #endif
270 
zval_copy_static_var(zval * p,int num_args,va_list args,zend_hash_key * key)271 ZEND_API int zval_copy_static_var(zval *p, int num_args, va_list args, zend_hash_key *key) /* {{{ */
272 {
273 	zend_array *symbol_table;
274 	HashTable *target = va_arg(args, HashTable*);
275 	zend_bool is_ref;
276 	zval tmp;
277 
278 	if (Z_CONST_FLAGS_P(p) & (IS_LEXICAL_VAR|IS_LEXICAL_REF)) {
279 		is_ref = Z_CONST_FLAGS_P(p) & IS_LEXICAL_REF;
280 
281 		symbol_table = zend_rebuild_symbol_table();
282 		p = zend_hash_find(symbol_table, key->key);
283 		if (!p) {
284 			p = &tmp;
285 			ZVAL_NULL(&tmp);
286 			if (is_ref) {
287 				ZVAL_NEW_REF(&tmp, &tmp);
288 				zend_hash_add_new(symbol_table, key->key, &tmp);
289 				Z_ADDREF_P(p);
290 			} else {
291 				zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(key->key));
292 			}
293 		} else {
294 			if (Z_TYPE_P(p) == IS_INDIRECT) {
295 				p = Z_INDIRECT_P(p);
296 				if (Z_TYPE_P(p) == IS_UNDEF) {
297 					if (!is_ref) {
298 						zend_error(E_NOTICE,"Undefined variable: %s", ZSTR_VAL(key->key));
299 						p = &tmp;
300 						ZVAL_NULL(&tmp);
301 					} else {
302 						ZVAL_NULL(p);
303 					}
304 				}
305 			}
306 			if (is_ref) {
307 				ZVAL_MAKE_REF(p);
308 				Z_ADDREF_P(p);
309 			} else if (Z_ISREF_P(p)) {
310 				ZVAL_DUP(&tmp, Z_REFVAL_P(p));
311 				p = &tmp;
312 			} else if (Z_REFCOUNTED_P(p)) {
313 				Z_ADDREF_P(p);
314 			}
315 		}
316 	} else if (Z_REFCOUNTED_P(p)) {
317 		Z_ADDREF_P(p);
318 	}
319 	zend_hash_add(target, key->key, p);
320 	return ZEND_HASH_APPLY_KEEP;
321 }
322 /* }}} */
323 
324 /*
325  * Local variables:
326  * tab-width: 4
327  * c-basic-offset: 4
328  * indent-tabs-mode: t
329  * End:
330  */
331