xref: /PHP-8.2/Zend/zend_constants.c (revision 1a0ef2c1)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 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@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    +----------------------------------------------------------------------+
18 */
19 
20 #include "zend.h"
21 #include "zend_constants.h"
22 #include "zend_exceptions.h"
23 #include "zend_execute.h"
24 #include "zend_variables.h"
25 #include "zend_operators.h"
26 #include "zend_globals.h"
27 #include "zend_API.h"
28 #include "zend_constants_arginfo.h"
29 
30 /* Protection from recursive self-referencing class constants */
31 #define IS_CONSTANT_VISITED_MARK    0x80
32 
33 #define IS_CONSTANT_VISITED(zv)     (Z_CONSTANT_FLAGS_P(zv) & IS_CONSTANT_VISITED_MARK)
34 #define MARK_CONSTANT_VISITED(zv)   Z_CONSTANT_FLAGS_P(zv) |= IS_CONSTANT_VISITED_MARK
35 #define RESET_CONSTANT_VISITED(zv)  Z_CONSTANT_FLAGS_P(zv) &= ~IS_CONSTANT_VISITED_MARK
36 
37 /* Use for special null/true/false constants. */
38 static zend_constant *null_const, *true_const, *false_const;
39 
free_zend_constant(zval * zv)40 void free_zend_constant(zval *zv)
41 {
42 	zend_constant *c = Z_PTR_P(zv);
43 
44 	if (!(ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT)) {
45 		zval_ptr_dtor_nogc(&c->value);
46 		if (c->name) {
47 			zend_string_release_ex(c->name, 0);
48 		}
49 		efree(c);
50 	} else {
51 		zval_internal_ptr_dtor(&c->value);
52 		if (c->name) {
53 			zend_string_release_ex(c->name, 1);
54 		}
55 		free(c);
56 	}
57 }
58 
59 
60 #ifdef ZTS
copy_zend_constant(zval * zv)61 static void copy_zend_constant(zval *zv)
62 {
63 	zend_constant *c = Z_PTR_P(zv);
64 
65 	ZEND_ASSERT(ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
66 	Z_PTR_P(zv) = pemalloc(sizeof(zend_constant), 1);
67 	memcpy(Z_PTR_P(zv), c, sizeof(zend_constant));
68 
69 	c = Z_PTR_P(zv);
70 	c->name = zend_string_copy(c->name);
71 	if (Z_TYPE(c->value) == IS_STRING) {
72 		Z_STR(c->value) = zend_string_dup(Z_STR(c->value), 1);
73 	}
74 }
75 
76 
zend_copy_constants(HashTable * target,HashTable * source)77 void zend_copy_constants(HashTable *target, HashTable *source)
78 {
79 	zend_hash_copy(target, source, copy_zend_constant);
80 }
81 #endif
82 
83 
clean_module_constant(zval * el,void * arg)84 static int clean_module_constant(zval *el, void *arg)
85 {
86 	zend_constant *c = (zend_constant *)Z_PTR_P(el);
87 	int module_number = *(int *)arg;
88 
89 	if (ZEND_CONSTANT_MODULE_NUMBER(c) == module_number) {
90 		return ZEND_HASH_APPLY_REMOVE;
91 	} else {
92 		return ZEND_HASH_APPLY_KEEP;
93 	}
94 }
95 
96 
clean_module_constants(int module_number)97 void clean_module_constants(int module_number)
98 {
99 	zend_hash_apply_with_argument(EG(zend_constants), clean_module_constant, (void *) &module_number);
100 }
101 
zend_startup_constants(void)102 void zend_startup_constants(void)
103 {
104 	EG(zend_constants) = (HashTable *) malloc(sizeof(HashTable));
105 	zend_hash_init(EG(zend_constants), 128, NULL, ZEND_CONSTANT_DTOR, 1);
106 }
107 
108 
109 
zend_register_standard_constants(void)110 void zend_register_standard_constants(void)
111 {
112 	register_zend_constants_symbols(0);
113 
114 	true_const = zend_hash_str_find_ptr(EG(zend_constants), "TRUE", sizeof("TRUE")-1);
115 	false_const = zend_hash_str_find_ptr(EG(zend_constants), "FALSE", sizeof("FALSE")-1);
116 	null_const = zend_hash_str_find_ptr(EG(zend_constants), "NULL", sizeof("NULL")-1);
117 }
118 
119 
zend_shutdown_constants(void)120 void zend_shutdown_constants(void)
121 {
122 	zend_hash_destroy(EG(zend_constants));
123 	free(EG(zend_constants));
124 }
125 
zend_register_null_constant(const char * name,size_t name_len,int flags,int module_number)126 ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number)
127 {
128 	zend_constant c;
129 
130 	ZVAL_NULL(&c.value);
131 	ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number);
132 	c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT);
133 	zend_register_constant(&c);
134 }
135 
zend_register_bool_constant(const char * name,size_t name_len,bool bval,int flags,int module_number)136 ZEND_API void zend_register_bool_constant(const char *name, size_t name_len, bool bval, int flags, int module_number)
137 {
138 	zend_constant c;
139 
140 	ZVAL_BOOL(&c.value, bval);
141 	ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number);
142 	c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT);
143 	zend_register_constant(&c);
144 }
145 
zend_register_long_constant(const char * name,size_t name_len,zend_long lval,int flags,int module_number)146 ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zend_long lval, int flags, int module_number)
147 {
148 	zend_constant c;
149 
150 	ZVAL_LONG(&c.value, lval);
151 	ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number);
152 	c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT);
153 	zend_register_constant(&c);
154 }
155 
156 
zend_register_double_constant(const char * name,size_t name_len,double dval,int flags,int module_number)157 ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number)
158 {
159 	zend_constant c;
160 
161 	ZVAL_DOUBLE(&c.value, dval);
162 	ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number);
163 	c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT);
164 	zend_register_constant(&c);
165 }
166 
167 
zend_register_stringl_constant(const char * name,size_t name_len,const char * strval,size_t strlen,int flags,int module_number)168 ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, const char *strval, size_t strlen, int flags, int module_number)
169 {
170 	zend_constant c;
171 
172 	ZVAL_STR(&c.value, zend_string_init_interned(strval, strlen, flags & CONST_PERSISTENT));
173 	ZEND_CONSTANT_SET_FLAGS(&c, flags, module_number);
174 	c.name = zend_string_init_interned(name, name_len, flags & CONST_PERSISTENT);
175 	zend_register_constant(&c);
176 }
177 
178 
zend_register_string_constant(const char * name,size_t name_len,const char * strval,int flags,int module_number)179 ZEND_API void zend_register_string_constant(const char *name, size_t name_len, const char *strval, int flags, int module_number)
180 {
181 	zend_register_stringl_constant(name, name_len, strval, strlen(strval), flags, module_number);
182 }
183 
zend_get_halt_offset_constant(const char * name,size_t name_len)184 static zend_constant *zend_get_halt_offset_constant(const char *name, size_t name_len)
185 {
186 	zend_constant *c;
187 	static const char haltoff[] = "__COMPILER_HALT_OFFSET__";
188 
189 	if (!EG(current_execute_data)) {
190 		return NULL;
191 	} else if (name_len == sizeof("__COMPILER_HALT_OFFSET__")-1 &&
192 	          !memcmp(name, "__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__")-1)) {
193 		const char *cfilename;
194 		zend_string *haltname;
195 		size_t clen;
196 
197 		cfilename = zend_get_executed_filename();
198 		clen = strlen(cfilename);
199 		/* check for __COMPILER_HALT_OFFSET__ */
200 		haltname = zend_mangle_property_name(haltoff,
201 			sizeof("__COMPILER_HALT_OFFSET__") - 1, cfilename, clen, 0);
202 		c = zend_hash_find_ptr(EG(zend_constants), haltname);
203 		zend_string_efree(haltname);
204 		return c;
205 	} else {
206 		return NULL;
207 	}
208 }
209 
_zend_get_special_const(const char * name,size_t len)210 ZEND_API zend_constant *_zend_get_special_const(const char *name, size_t len) /* {{{ */
211 {
212 	if (len == 4) {
213 		if ((name[0] == 'n' || name[0] == 'N') &&
214 			(name[1] == 'u' || name[1] == 'U') &&
215 			(name[2] == 'l' || name[2] == 'L') &&
216 			(name[3] == 'l' || name[3] == 'L')
217 		) {
218 			return null_const;
219 		}
220 		if ((name[0] == 't' || name[0] == 'T') &&
221 			(name[1] == 'r' || name[1] == 'R') &&
222 			(name[2] == 'u' || name[2] == 'U') &&
223 			(name[3] == 'e' || name[3] == 'E')
224 		) {
225 			return true_const;
226 		}
227 	} else {
228 		if ((name[0] == 'f' || name[0] == 'F') &&
229 			(name[1] == 'a' || name[1] == 'A') &&
230 			(name[2] == 'l' || name[2] == 'L') &&
231 			(name[3] == 's' || name[3] == 'S') &&
232 			(name[4] == 'e' || name[4] == 'E')
233 		) {
234 			return false_const;
235 		}
236 	}
237 	return NULL;
238 }
239 /* }}} */
240 
zend_verify_const_access(zend_class_constant * c,zend_class_entry * scope)241 ZEND_API bool zend_verify_const_access(zend_class_constant *c, zend_class_entry *scope) /* {{{ */
242 {
243 	if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PUBLIC) {
244 		return 1;
245 	} else if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PRIVATE) {
246 		return (c->ce == scope);
247 	} else {
248 		ZEND_ASSERT(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_PROTECTED);
249 		return zend_check_protected(c->ce, scope);
250 	}
251 }
252 /* }}} */
253 
zend_get_constant_str_impl(const char * name,size_t name_len)254 static zend_constant *zend_get_constant_str_impl(const char *name, size_t name_len)
255 {
256 	zend_constant *c = zend_hash_str_find_ptr(EG(zend_constants), name, name_len);
257 	if (c) {
258 		return c;
259 	}
260 
261 	c = zend_get_halt_offset_constant(name, name_len);
262 	if (c) {
263 		return c;
264 	}
265 
266 	return zend_get_special_const(name, name_len);
267 }
268 
zend_get_constant_str(const char * name,size_t name_len)269 ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len)
270 {
271 	zend_constant *c = zend_get_constant_str_impl(name, name_len);
272 	if (c) {
273 		return &c->value;
274 	}
275 	return NULL;
276 }
277 
zend_get_constant_impl(zend_string * name)278 static zend_constant *zend_get_constant_impl(zend_string *name)
279 {
280 	zend_constant *c = zend_hash_find_ptr(EG(zend_constants), name);
281 	if (c) {
282 		return c;
283 	}
284 
285 	c = zend_get_halt_offset_constant(ZSTR_VAL(name), ZSTR_LEN(name));
286 	if (c) {
287 		return c;
288 	}
289 
290 	return zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name));
291 }
292 
zend_get_constant(zend_string * name)293 ZEND_API zval *zend_get_constant(zend_string *name)
294 {
295 	zend_constant *c = zend_get_constant_impl(name);
296 	if (c) {
297 		return &c->value;
298 	}
299 	return NULL;
300 }
301 
zend_get_class_constant_ex(zend_string * class_name,zend_string * constant_name,zend_class_entry * scope,uint32_t flags)302 ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *constant_name, zend_class_entry *scope, uint32_t flags)
303 {
304 	zend_class_entry *ce = NULL;
305 	zend_class_constant *c = NULL;
306 	zval *ret_constant = NULL;
307 
308 	if (ZSTR_HAS_CE_CACHE(class_name)) {
309 		ce = ZSTR_GET_CE_CACHE(class_name);
310 		if (!ce) {
311 			ce = zend_fetch_class(class_name, flags);
312 		}
313 	} else if (zend_string_equals_literal_ci(class_name, "self")) {
314 		if (UNEXPECTED(!scope)) {
315 			zend_throw_error(NULL, "Cannot access \"self\" when no class scope is active");
316 			goto failure;
317 		}
318 		ce = scope;
319 	} else if (zend_string_equals_literal_ci(class_name, "parent")) {
320 		if (UNEXPECTED(!scope)) {
321 			zend_throw_error(NULL, "Cannot access \"parent\" when no class scope is active");
322 			goto failure;
323 		} else if (UNEXPECTED(!scope->parent)) {
324 			zend_throw_error(NULL, "Cannot access \"parent\" when current class scope has no parent");
325 			goto failure;
326 		} else {
327 			ce = scope->parent;
328 		}
329 	} else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_STATIC))) {
330 		ce = zend_get_called_scope(EG(current_execute_data));
331 		if (UNEXPECTED(!ce)) {
332 			zend_throw_error(NULL, "Cannot access \"static\" when no class scope is active");
333 			goto failure;
334 		}
335 	} else {
336 		ce = zend_fetch_class(class_name, flags);
337 	}
338 	if (ce) {
339 		c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constant_name);
340 		if (c == NULL) {
341 			if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
342 				zend_throw_error(NULL, "Undefined constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
343 				goto failure;
344 			}
345 			ret_constant = NULL;
346 		} else {
347 			if (!zend_verify_const_access(c, scope)) {
348 				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
349 					zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
350 				}
351 				goto failure;
352 			}
353 
354 			if (UNEXPECTED(ce->ce_flags & ZEND_ACC_TRAIT)) {
355 				/** Prevent accessing trait constants directly on cases like \defined() or \constant(), etc. */
356 				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
357 					zend_throw_error(NULL, "Cannot access trait constant %s::%s directly", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
358 				}
359 				goto failure;
360 			}
361 
362 			if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) {
363 				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
364 					zend_error(E_DEPRECATED, "Constant %s::%s is deprecated", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
365 					if (EG(exception)) {
366 						goto failure;
367 					}
368 				}
369 			}
370 			ret_constant = &c->value;
371 		}
372 	}
373 
374 	if (ret_constant && Z_TYPE_P(ret_constant) == IS_CONSTANT_AST) {
375 		zend_result ret;
376 
377 		if (IS_CONSTANT_VISITED(ret_constant)) {
378 			zend_throw_error(NULL, "Cannot declare self-referencing constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
379 			ret_constant = NULL;
380 			goto failure;
381 		}
382 
383 		MARK_CONSTANT_VISITED(ret_constant);
384 		ret = zend_update_class_constant(c, constant_name, c->ce);
385 		RESET_CONSTANT_VISITED(ret_constant);
386 
387 		if (UNEXPECTED(ret != SUCCESS)) {
388 			ret_constant = NULL;
389 			goto failure;
390 		}
391 	}
392 failure:
393 	return ret_constant;
394 }
395 
zend_get_constant_ex(zend_string * cname,zend_class_entry * scope,uint32_t flags)396 ZEND_API zval *zend_get_constant_ex(zend_string *cname, zend_class_entry *scope, uint32_t flags)
397 {
398 	zend_constant *c;
399 	const char *colon;
400 	const char *name = ZSTR_VAL(cname);
401 	size_t name_len = ZSTR_LEN(cname);
402 
403 	/* Skip leading \\ */
404 	if (name[0] == '\\') {
405 		name += 1;
406 		name_len -= 1;
407 		cname = NULL;
408 	}
409 
410 	if ((colon = zend_memrchr(name, ':', name_len)) &&
411 	    colon > name && (*(colon - 1) == ':')) {
412 		int class_name_len = colon - name - 1;
413 		size_t const_name_len = name_len - class_name_len - 2;
414 		zend_string *constant_name = zend_string_init(colon + 1, const_name_len, 0);
415 		zend_string *class_name = zend_string_init_interned(name, class_name_len, 0);
416 		zval *ret_constant = zend_get_class_constant_ex(class_name, constant_name, scope, flags);
417 
418 		zend_string_release_ex(class_name, 0);
419 		zend_string_efree(constant_name);
420 		return ret_constant;
421 /*
422 		zend_class_entry *ce = NULL;
423 		zend_class_constant *c = NULL;
424 		zval *ret_constant = NULL;
425 
426 		if (zend_string_equals_literal_ci(class_name, "self")) {
427 			if (UNEXPECTED(!scope)) {
428 				zend_throw_error(NULL, "Cannot access \"self\" when no class scope is active");
429 				goto failure;
430 			}
431 			ce = scope;
432 		} else if (zend_string_equals_literal_ci(class_name, "parent")) {
433 			if (UNEXPECTED(!scope)) {
434 				zend_throw_error(NULL, "Cannot access \"parent\" when no class scope is active");
435 				goto failure;
436 			} else if (UNEXPECTED(!scope->parent)) {
437 				zend_throw_error(NULL, "Cannot access \"parent\" when current class scope has no parent");
438 				goto failure;
439 			} else {
440 				ce = scope->parent;
441 			}
442 		} else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_STATIC))) {
443 			ce = zend_get_called_scope(EG(current_execute_data));
444 			if (UNEXPECTED(!ce)) {
445 				zend_throw_error(NULL, "Cannot access \"static\" when no class scope is active");
446 				goto failure;
447 			}
448 		} else {
449 			ce = zend_fetch_class(class_name, flags);
450 		}
451 		if (ce) {
452 			c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constant_name);
453 			if (c == NULL) {
454 				if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
455 					zend_throw_error(NULL, "Undefined constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
456 					goto failure;
457 				}
458 				ret_constant = NULL;
459 			} else {
460 				if (!zend_verify_const_access(c, scope)) {
461 					if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
462 						zend_throw_error(NULL, "Cannot access %s constant %s::%s", zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c)), ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
463 					}
464 					goto failure;
465 				}
466 				ret_constant = &c->value;
467 			}
468 		}
469 
470 		if (ret_constant && Z_TYPE_P(ret_constant) == IS_CONSTANT_AST) {
471 			zend_result ret;
472 
473 			if (IS_CONSTANT_VISITED(ret_constant)) {
474 				zend_throw_error(NULL, "Cannot declare self-referencing constant %s::%s", ZSTR_VAL(class_name), ZSTR_VAL(constant_name));
475 				ret_constant = NULL;
476 				goto failure;
477 			}
478 
479 			MARK_CONSTANT_VISITED(ret_constant);
480 			ret = zval_update_constant_ex(ret_constant, c->ce);
481 			RESET_CONSTANT_VISITED(ret_constant);
482 
483 			if (UNEXPECTED(ret != SUCCESS)) {
484 				ret_constant = NULL;
485 				goto failure;
486 			}
487 		}
488 failure:
489 		zend_string_release_ex(class_name, 0);
490 		zend_string_efree(constant_name);
491 		return ret_constant;
492 */
493 	}
494 
495 	/* non-class constant */
496 	if ((colon = zend_memrchr(name, '\\', name_len)) != NULL) {
497 		/* compound constant name */
498 		int prefix_len = colon - name;
499 		size_t const_name_len = name_len - prefix_len - 1;
500 		const char *constant_name = colon + 1;
501 		char *lcname;
502 		size_t lcname_len;
503 		ALLOCA_FLAG(use_heap)
504 
505 		/* Lowercase the namespace portion */
506 		lcname_len = prefix_len + 1 + const_name_len;
507 		lcname = do_alloca(lcname_len + 1, use_heap);
508 		zend_str_tolower_copy(lcname, name, prefix_len);
509 
510 		lcname[prefix_len] = '\\';
511 		memcpy(lcname + prefix_len + 1, constant_name, const_name_len + 1);
512 
513 		c = zend_hash_str_find_ptr(EG(zend_constants), lcname, lcname_len);
514 		free_alloca(lcname, use_heap);
515 
516 		if (!c) {
517 			if (flags & IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE) {
518 				/* name requires runtime resolution, need to check non-namespaced name */
519 				c = zend_get_constant_str_impl(constant_name, const_name_len);
520 			}
521 		}
522 	} else {
523 		if (cname) {
524 			c = zend_get_constant_impl(cname);
525 		} else {
526 			c = zend_get_constant_str_impl(name, name_len);
527 		}
528 	}
529 
530 	if (!c) {
531 		if (!(flags & ZEND_FETCH_CLASS_SILENT)) {
532 			zend_throw_error(NULL, "Undefined constant \"%s\"", name);
533 		}
534 		return NULL;
535 	}
536 
537 	if (!(flags & ZEND_FETCH_CLASS_SILENT) && (ZEND_CONSTANT_FLAGS(c) & CONST_DEPRECATED)) {
538 		zend_error(E_DEPRECATED, "Constant %s is deprecated", name);
539 	}
540 	return &c->value;
541 }
542 
zend_hash_add_constant(HashTable * ht,zend_string * key,zend_constant * c)543 static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_constant *c)
544 {
545 	void *ret;
546 	zend_constant *copy = pemalloc(sizeof(zend_constant), ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
547 
548 	memcpy(copy, c, sizeof(zend_constant));
549 	ret = zend_hash_add_ptr(ht, key, copy);
550 	if (!ret) {
551 		pefree(copy, ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT);
552 	}
553 	return ret;
554 }
555 
zend_register_constant(zend_constant * c)556 ZEND_API zend_result zend_register_constant(zend_constant *c)
557 {
558 	zend_string *lowercase_name = NULL;
559 	zend_string *name;
560 	zend_result ret = SUCCESS;
561 	bool persistent = (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) != 0;
562 
563 #if 0
564 	printf("Registering constant for module %d\n", c->module_number);
565 #endif
566 
567 	const char *slash = strrchr(ZSTR_VAL(c->name), '\\');
568 	if (slash) {
569 		lowercase_name = zend_string_init(ZSTR_VAL(c->name), ZSTR_LEN(c->name), persistent);
570 		zend_str_tolower(ZSTR_VAL(lowercase_name), slash - ZSTR_VAL(c->name));
571 		lowercase_name = zend_new_interned_string(lowercase_name);
572 		name = lowercase_name;
573 	} else {
574 		name = c->name;
575 	}
576 
577 	/* Check if the user is trying to define any special constant */
578 	if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__")
579 		|| (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)))
580 		|| zend_hash_add_constant(EG(zend_constants), name, c) == NULL
581 	) {
582 		zend_error(E_WARNING, "Constant %s already defined", ZSTR_VAL(name));
583 		zend_string_release(c->name);
584 		if (!persistent) {
585 			zval_ptr_dtor_nogc(&c->value);
586 		}
587 		ret = FAILURE;
588 	}
589 	if (lowercase_name) {
590 		zend_string_release(lowercase_name);
591 	}
592 	return ret;
593 }
594