xref: /PHP-5.3/Zend/zend_constants.c (revision 831fbcf3)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2013 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    +----------------------------------------------------------------------+
18 */
19 
20 /* $Id$ */
21 
22 #include "zend.h"
23 #include "zend_constants.h"
24 #include "zend_execute.h"
25 #include "zend_variables.h"
26 #include "zend_operators.h"
27 #include "zend_globals.h"
28 
29 
free_zend_constant(zend_constant * c)30 void free_zend_constant(zend_constant *c)
31 {
32 	if (!(c->flags & CONST_PERSISTENT)) {
33 		zval_dtor(&c->value);
34 	}
35 	free(c->name);
36 }
37 
38 
copy_zend_constant(zend_constant * c)39 void copy_zend_constant(zend_constant *c)
40 {
41 	c->name = zend_strndup(c->name, c->name_len - 1);
42 	if (!(c->flags & CONST_PERSISTENT)) {
43 		zval_copy_ctor(&c->value);
44 	}
45 }
46 
47 
zend_copy_constants(HashTable * target,HashTable * source)48 void zend_copy_constants(HashTable *target, HashTable *source)
49 {
50 	zend_constant tmp_constant;
51 
52 	zend_hash_copy(target, source, (copy_ctor_func_t) copy_zend_constant, &tmp_constant, sizeof(zend_constant));
53 }
54 
55 
clean_non_persistent_constant(const zend_constant * c TSRMLS_DC)56 static int clean_non_persistent_constant(const zend_constant *c TSRMLS_DC)
57 {
58 	return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
59 }
60 
61 
clean_non_persistent_constant_full(const zend_constant * c TSRMLS_DC)62 static int clean_non_persistent_constant_full(const zend_constant *c TSRMLS_DC)
63 {
64 	return (c->flags & CONST_PERSISTENT) ? 0 : 1;
65 }
66 
67 
clean_module_constant(const zend_constant * c,int * module_number TSRMLS_DC)68 static int clean_module_constant(const zend_constant *c, int *module_number TSRMLS_DC)
69 {
70 	if (c->module_number == *module_number) {
71 		return 1;
72 	} else {
73 		return 0;
74 	}
75 }
76 
77 
clean_module_constants(int module_number TSRMLS_DC)78 void clean_module_constants(int module_number TSRMLS_DC)
79 {
80 	zend_hash_apply_with_argument(EG(zend_constants), (apply_func_arg_t) clean_module_constant, (void *) &module_number TSRMLS_CC);
81 }
82 
83 
zend_startup_constants(TSRMLS_D)84 int zend_startup_constants(TSRMLS_D)
85 {
86 	EG(zend_constants) = (HashTable *) malloc(sizeof(HashTable));
87 
88 	if (zend_hash_init(EG(zend_constants), 20, NULL, ZEND_CONSTANT_DTOR, 1)==FAILURE) {
89 		return FAILURE;
90 	}
91 	return SUCCESS;
92 }
93 
94 
95 
zend_register_standard_constants(TSRMLS_D)96 void zend_register_standard_constants(TSRMLS_D)
97 {
98 	REGISTER_MAIN_LONG_CONSTANT("E_ERROR", E_ERROR, CONST_PERSISTENT | CONST_CS);
99 	REGISTER_MAIN_LONG_CONSTANT("E_RECOVERABLE_ERROR", E_RECOVERABLE_ERROR, CONST_PERSISTENT | CONST_CS);
100 	REGISTER_MAIN_LONG_CONSTANT("E_WARNING", E_WARNING, CONST_PERSISTENT | CONST_CS);
101 	REGISTER_MAIN_LONG_CONSTANT("E_PARSE", E_PARSE, CONST_PERSISTENT | CONST_CS);
102 	REGISTER_MAIN_LONG_CONSTANT("E_NOTICE", E_NOTICE, CONST_PERSISTENT | CONST_CS);
103 	REGISTER_MAIN_LONG_CONSTANT("E_STRICT", E_STRICT, CONST_PERSISTENT | CONST_CS);
104 	REGISTER_MAIN_LONG_CONSTANT("E_DEPRECATED", E_DEPRECATED, CONST_PERSISTENT | CONST_CS);
105 	REGISTER_MAIN_LONG_CONSTANT("E_CORE_ERROR", E_CORE_ERROR, CONST_PERSISTENT | CONST_CS);
106 	REGISTER_MAIN_LONG_CONSTANT("E_CORE_WARNING", E_CORE_WARNING, CONST_PERSISTENT | CONST_CS);
107 	REGISTER_MAIN_LONG_CONSTANT("E_COMPILE_ERROR", E_COMPILE_ERROR, CONST_PERSISTENT | CONST_CS);
108 	REGISTER_MAIN_LONG_CONSTANT("E_COMPILE_WARNING", E_COMPILE_WARNING, CONST_PERSISTENT | CONST_CS);
109 	REGISTER_MAIN_LONG_CONSTANT("E_USER_ERROR", E_USER_ERROR, CONST_PERSISTENT | CONST_CS);
110 	REGISTER_MAIN_LONG_CONSTANT("E_USER_WARNING", E_USER_WARNING, CONST_PERSISTENT | CONST_CS);
111 	REGISTER_MAIN_LONG_CONSTANT("E_USER_NOTICE", E_USER_NOTICE, CONST_PERSISTENT | CONST_CS);
112 	REGISTER_MAIN_LONG_CONSTANT("E_USER_DEPRECATED", E_USER_DEPRECATED, CONST_PERSISTENT | CONST_CS);
113 
114 	REGISTER_MAIN_LONG_CONSTANT("E_ALL", E_ALL, CONST_PERSISTENT | CONST_CS);
115 
116 	REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_PROVIDE_OBJECT", DEBUG_BACKTRACE_PROVIDE_OBJECT, CONST_PERSISTENT | CONST_CS);
117 	REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_IGNORE_ARGS", DEBUG_BACKTRACE_IGNORE_ARGS, CONST_PERSISTENT | CONST_CS);
118 	/* true/false constants */
119 	{
120 		zend_constant c;
121 
122 		c.flags = CONST_PERSISTENT | CONST_CT_SUBST;
123 		c.module_number = 0;
124 
125 		c.name = zend_strndup(ZEND_STRL("TRUE"));
126 		c.name_len = sizeof("TRUE");
127 		c.value.value.lval = 1;
128 		c.value.type = IS_BOOL;
129 		zend_register_constant(&c TSRMLS_CC);
130 
131 		c.name = zend_strndup(ZEND_STRL("FALSE"));
132 		c.name_len = sizeof("FALSE");
133 		c.value.value.lval = 0;
134 		c.value.type = IS_BOOL;
135 		zend_register_constant(&c TSRMLS_CC);
136 
137 		c.name = zend_strndup(ZEND_STRL("NULL"));
138 		c.name_len = sizeof("NULL");
139 		c.value.type = IS_NULL;
140 		zend_register_constant(&c TSRMLS_CC);
141 
142 		c.flags = CONST_PERSISTENT;
143 
144 		c.name = zend_strndup(ZEND_STRL("ZEND_THREAD_SAFE"));
145 		c.name_len = sizeof("ZEND_THREAD_SAFE");
146 		c.value.value.lval = ZTS_V;
147 		c.value.type = IS_BOOL;
148 		zend_register_constant(&c TSRMLS_CC);
149 
150 		c.name = zend_strndup(ZEND_STRL("ZEND_DEBUG_BUILD"));
151 		c.name_len = sizeof("ZEND_DEBUG_BUILD");
152 		c.value.value.lval = ZEND_DEBUG;
153 		c.value.type = IS_BOOL;
154 		zend_register_constant(&c TSRMLS_CC);
155 	}
156 }
157 
158 
zend_shutdown_constants(TSRMLS_D)159 int zend_shutdown_constants(TSRMLS_D)
160 {
161 	zend_hash_destroy(EG(zend_constants));
162 	free(EG(zend_constants));
163 	return SUCCESS;
164 }
165 
166 
clean_non_persistent_constants(TSRMLS_D)167 void clean_non_persistent_constants(TSRMLS_D)
168 {
169 	if (EG(full_tables_cleanup)) {
170 		zend_hash_apply(EG(zend_constants), (apply_func_t) clean_non_persistent_constant_full TSRMLS_CC);
171 	} else {
172 		zend_hash_reverse_apply(EG(zend_constants), (apply_func_t) clean_non_persistent_constant TSRMLS_CC);
173 	}
174 }
175 
176 
zend_register_long_constant(const char * name,uint name_len,long lval,int flags,int module_number TSRMLS_DC)177 ZEND_API void zend_register_long_constant(const char *name, uint name_len, long lval, int flags, int module_number TSRMLS_DC)
178 {
179 	zend_constant c;
180 
181 	c.value.type = IS_LONG;
182 	c.value.value.lval = lval;
183 	c.flags = flags;
184 	c.name = zend_strndup(name, name_len-1);
185 	c.name_len = name_len;
186 	c.module_number = module_number;
187 	zend_register_constant(&c TSRMLS_CC);
188 }
189 
190 
zend_register_double_constant(const char * name,uint name_len,double dval,int flags,int module_number TSRMLS_DC)191 ZEND_API void zend_register_double_constant(const char *name, uint name_len, double dval, int flags, int module_number TSRMLS_DC)
192 {
193 	zend_constant c;
194 
195 	c.value.type = IS_DOUBLE;
196 	c.value.value.dval = dval;
197 	c.flags = flags;
198 	c.name = zend_strndup(name, name_len-1);
199 	c.name_len = name_len;
200 	c.module_number = module_number;
201 	zend_register_constant(&c TSRMLS_CC);
202 }
203 
204 
zend_register_stringl_constant(const char * name,uint name_len,char * strval,uint strlen,int flags,int module_number TSRMLS_DC)205 ZEND_API void zend_register_stringl_constant(const char *name, uint name_len, char *strval, uint strlen, int flags, int module_number TSRMLS_DC)
206 {
207 	zend_constant c;
208 
209 	c.value.type = IS_STRING;
210 	c.value.value.str.val = strval;
211 	c.value.value.str.len = strlen;
212 	c.flags = flags;
213 	c.name = zend_strndup(name, name_len-1);
214 	c.name_len = name_len;
215 	c.module_number = module_number;
216 	zend_register_constant(&c TSRMLS_CC);
217 }
218 
219 
zend_register_string_constant(const char * name,uint name_len,char * strval,int flags,int module_number TSRMLS_DC)220 ZEND_API void zend_register_string_constant(const char *name, uint name_len, char *strval, int flags, int module_number TSRMLS_DC)
221 {
222 	zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number TSRMLS_CC);
223 }
224 
225 
zend_get_constant(const char * name,uint name_len,zval * result TSRMLS_DC)226 ZEND_API int zend_get_constant(const char *name, uint name_len, zval *result TSRMLS_DC)
227 {
228 	zend_constant *c;
229 	int retval = 1;
230 	char *lookup_name;
231 
232 	if (zend_hash_find(EG(zend_constants), name, name_len+1, (void **) &c) == FAILURE) {
233 		lookup_name = zend_str_tolower_dup(name, name_len);
234 
235 		if (zend_hash_find(EG(zend_constants), lookup_name, name_len+1, (void **) &c)==SUCCESS) {
236 			if (c->flags & CONST_CS) {
237 				retval=0;
238 			}
239 		} else {
240 			static char haltoff[] = "__COMPILER_HALT_OFFSET__";
241 
242 			if (!EG(in_execution)) {
243 				retval = 0;
244 			} else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
245 			          !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
246 				char *cfilename, *haltname;
247 				int len, clen;
248 
249 				cfilename = zend_get_executed_filename(TSRMLS_C);
250 				clen = strlen(cfilename);
251 				/* check for __COMPILER_HALT_OFFSET__ */
252 				zend_mangle_property_name(&haltname, &len, haltoff,
253 					sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
254 				if (zend_hash_find(EG(zend_constants), haltname, len+1, (void **) &c) == SUCCESS) {
255 					retval = 1;
256 				} else {
257 					retval=0;
258 				}
259 				pefree(haltname, 0);
260 			} else {
261 				retval=0;
262 			}
263 		}
264 		efree(lookup_name);
265 	}
266 
267 	if (retval) {
268 		*result = c->value;
269 		zval_copy_ctor(result);
270 		Z_SET_REFCOUNT_P(result, 1);
271 		Z_UNSET_ISREF_P(result);
272 	}
273 
274 	return retval;
275 }
276 
zend_get_constant_ex(const char * name,uint name_len,zval * result,zend_class_entry * scope,ulong flags TSRMLS_DC)277 ZEND_API int zend_get_constant_ex(const char *name, uint name_len, zval *result, zend_class_entry *scope, ulong flags TSRMLS_DC)
278 {
279 	zend_constant *c;
280 	int retval = 1;
281 	char *colon;
282 	zend_class_entry *ce = NULL;
283 	char *class_name;
284 	zval **ret_constant;
285 
286 	/* Skip leading \\ */
287 	if (name[0] == '\\') {
288 		name += 1;
289 		name_len -= 1;
290 	}
291 
292 
293 	if ((colon = zend_memrchr(name, ':', name_len)) &&
294 	    colon > name && (*(colon - 1) == ':')) {
295 		int class_name_len = colon - name - 1;
296 		int const_name_len = name_len - class_name_len - 2;
297 		char *constant_name = colon + 1;
298 		char *lcname;
299 
300 		class_name = estrndup(name, class_name_len);
301 		lcname = zend_str_tolower_dup(class_name, class_name_len);
302 		if (!scope) {
303 			if (EG(in_execution)) {
304 				scope = EG(scope);
305 			} else {
306 				scope = CG(active_class_entry);
307 			}
308 		}
309 
310 		if (class_name_len == sizeof("self")-1 &&
311 		    !memcmp(lcname, "self", sizeof("self")-1)) {
312 			if (scope) {
313 				ce = scope;
314 			} else {
315 				zend_error(E_ERROR, "Cannot access self:: when no class scope is active");
316 				retval = 0;
317 			}
318 			efree(lcname);
319 		} else if (class_name_len == sizeof("parent")-1 &&
320 		           !memcmp(lcname, "parent", sizeof("parent")-1)) {
321 			if (!scope) {
322 				zend_error(E_ERROR, "Cannot access parent:: when no class scope is active");
323 			} else if (!scope->parent) {
324 				zend_error(E_ERROR, "Cannot access parent:: when current class scope has no parent");
325 			} else {
326 				ce = scope->parent;
327 			}
328 			efree(lcname);
329 		} else if (class_name_len == sizeof("static")-1 &&
330 		           !memcmp(lcname, "static", sizeof("static")-1)) {
331 			if (EG(called_scope)) {
332 				ce = EG(called_scope);
333 			} else {
334 				zend_error(E_ERROR, "Cannot access static:: when no class scope is active");
335 			}
336 			efree(lcname);
337 		} else {
338 			efree(lcname);
339 			ce = zend_fetch_class(class_name, class_name_len, flags TSRMLS_CC);
340 		}
341 		if (retval && ce) {
342 			if (zend_hash_find(&ce->constants_table, constant_name, const_name_len+1, (void **) &ret_constant) != SUCCESS) {
343 				retval = 0;
344 				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
345 					zend_error(E_ERROR, "Undefined class constant '%s::%s'", class_name, constant_name);
346 				}
347 			}
348 		} else if (!ce) {
349 			retval = 0;
350 		}
351 		efree(class_name);
352 		goto finish;
353 	}
354 
355 	/* non-class constant */
356 	if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
357 		/* compound constant name */
358 		int prefix_len = colon - name;
359 		int const_name_len = name_len - prefix_len - 1;
360 		char *constant_name = colon + 1;
361 		char *lcname;
362 		int found_const = 0;
363 
364 		lcname = zend_str_tolower_dup(name, prefix_len);
365 		/* Check for namespace constant */
366 
367 		/* Concatenate lowercase namespace name and constant name */
368 		lcname = erealloc(lcname, prefix_len + 1 + const_name_len + 1);
369 		lcname[prefix_len] = '\\';
370 		memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);
371 
372 		if (zend_hash_find(EG(zend_constants), lcname, prefix_len + 1 + const_name_len + 1, (void **) &c) == SUCCESS) {
373 			found_const = 1;
374 		} else {
375 			/* try lowercase */
376 			zend_str_tolower(lcname + prefix_len + 1, const_name_len);
377 			if (zend_hash_find(EG(zend_constants), lcname, prefix_len + 1 + const_name_len + 1, (void **) &c) == SUCCESS) {
378 				if ((c->flags & CONST_CS) == 0) {
379 					found_const = 1;
380 				}
381 			}
382 		}
383 		efree(lcname);
384 		if(found_const) {
385 			*result = c->value;
386 			zval_update_constant_ex(&result, (void*)1, NULL TSRMLS_CC);
387 			zval_copy_ctor(result);
388 			Z_SET_REFCOUNT_P(result, 1);
389 			Z_UNSET_ISREF_P(result);
390 			return 1;
391 		}
392 		/* name requires runtime resolution, need to check non-namespaced name */
393 		if ((flags & IS_CONSTANT_UNQUALIFIED) != 0) {
394 			name = constant_name;
395 			name_len = const_name_len;
396 			return zend_get_constant(name, name_len, result TSRMLS_CC);
397 		}
398 		retval = 0;
399 finish:
400 		if (retval) {
401 			zval_update_constant_ex(ret_constant, (void*)1, ce TSRMLS_CC);
402 			*result = **ret_constant;
403 			zval_copy_ctor(result);
404 			INIT_PZVAL(result);
405 		}
406 
407 		return retval;
408 	}
409 
410 	return zend_get_constant(name, name_len, result TSRMLS_CC);
411 }
412 
zend_register_constant(zend_constant * c TSRMLS_DC)413 ZEND_API int zend_register_constant(zend_constant *c TSRMLS_DC)
414 {
415 	char *lowercase_name = NULL;
416 	char *name;
417 	int ret = SUCCESS;
418 
419 #if 0
420 	printf("Registering constant for module %d\n", c->module_number);
421 #endif
422 
423 	if (!(c->flags & CONST_CS)) {
424 		/* keep in mind that c->name_len already contains the '\0' */
425 		lowercase_name = estrndup(c->name, c->name_len-1);
426 		zend_str_tolower(lowercase_name, c->name_len-1);
427 		name = lowercase_name;
428 	} else {
429 		char *slash = strrchr(c->name, '\\');
430 		if(slash) {
431 			lowercase_name = estrndup(c->name, c->name_len-1);
432 			zend_str_tolower(lowercase_name, slash-c->name);
433 			name = lowercase_name;
434 		} else {
435 			name = c->name;
436 		}
437 	}
438 
439 	/* Check if the user is trying to define the internal pseudo constant name __COMPILER_HALT_OFFSET__ */
440 	if ((c->name_len == sizeof("__COMPILER_HALT_OFFSET__")
441 		&& !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1))
442 		|| zend_hash_add(EG(zend_constants), name, c->name_len, (void *) c, sizeof(zend_constant), NULL)==FAILURE) {
443 
444 		/* The internal __COMPILER_HALT_OFFSET__ is prefixed by NULL byte */
445 		if (c->name[0] == '\0' && c->name_len > sizeof("\0__COMPILER_HALT_OFFSET__")
446 			&& memcmp(name, "\0__COMPILER_HALT_OFFSET__", sizeof("\0__COMPILER_HALT_OFFSET__")) == 0) {
447 			name++;
448 		}
449 		zend_error(E_NOTICE,"Constant %s already defined", name);
450 		free(c->name);
451 		if (!(c->flags & CONST_PERSISTENT)) {
452 			zval_dtor(&c->value);
453 		}
454 		ret = FAILURE;
455 	}
456 	if (lowercase_name) {
457 		efree(lowercase_name);
458 	}
459 	return ret;
460 }
461 
462 
463 /*
464  * Local variables:
465  * tab-width: 4
466  * c-basic-offset: 4
467  * indent-tabs-mode: t
468  * End:
469  */
470