xref: /PHP-8.0/ext/zend_test/test.c (revision 62228a25)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | http://www.php.net/license/3_01.txt                                  |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author:                                                              |
14   +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "ext/standard/php_var.h"
25 #include "php_test.h"
26 #include "test_arginfo.h"
27 #include "zend_attributes.h"
28 #include "zend_observer.h"
29 #include "zend_smart_str.h"
30 #include "zend_weakrefs.h"
31 
32 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
33 # include <libxml/globals.h>
34 # include <libxml/parser.h>
35 #endif
36 
37 ZEND_BEGIN_MODULE_GLOBALS(zend_test)
38 	int observer_enabled;
39 	int observer_show_output;
40 	int observer_observe_all;
41 	int observer_observe_includes;
42 	int observer_observe_functions;
43 	zend_array *observer_observe_function_names;
44 	int observer_show_return_type;
45 	int observer_show_return_value;
46 	int observer_show_init_backtrace;
47 	int observer_show_opcode;
48 	int observer_nesting_depth;
49 	int replace_zend_execute_ex;
50 	HashTable global_weakmap;
51 ZEND_END_MODULE_GLOBALS(zend_test)
52 
53 ZEND_DECLARE_MODULE_GLOBALS(zend_test)
54 
55 #define ZT_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(zend_test, v)
56 
57 static zend_class_entry *zend_test_interface;
58 static zend_class_entry *zend_test_class;
59 static zend_class_entry *zend_test_child_class;
60 static zend_class_entry *zend_test_trait;
61 static zend_class_entry *zend_test_attribute;
62 static zend_object_handlers zend_test_class_handlers;
63 
ZEND_FUNCTION(zend_test_func)64 static ZEND_FUNCTION(zend_test_func)
65 {
66 	RETVAL_STR_COPY(EX(func)->common.function_name);
67 
68 	/* Cleanup trampoline */
69 	ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
70 	zend_string_release(EX(func)->common.function_name);
71 	zend_free_trampoline(EX(func));
72 	EX(func) = NULL;
73 }
74 
ZEND_FUNCTION(zend_test_array_return)75 static ZEND_FUNCTION(zend_test_array_return)
76 {
77 	ZEND_PARSE_PARAMETERS_NONE();
78 }
79 
ZEND_FUNCTION(zend_test_nullable_array_return)80 static ZEND_FUNCTION(zend_test_nullable_array_return)
81 {
82 	ZEND_PARSE_PARAMETERS_NONE();
83 }
84 
ZEND_FUNCTION(zend_test_void_return)85 static ZEND_FUNCTION(zend_test_void_return)
86 {
87 	/* dummy */
88 	ZEND_PARSE_PARAMETERS_NONE();
89 }
90 
ZEND_FUNCTION(zend_test_deprecated)91 static ZEND_FUNCTION(zend_test_deprecated)
92 {
93 	zval *arg1;
94 
95 	zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1);
96 }
97 
98 /* Create a string without terminating null byte. Must be terminated with
99  * zend_terminate_string() before destruction, otherwise a warning is issued
100  * in debug builds. */
ZEND_FUNCTION(zend_create_unterminated_string)101 static ZEND_FUNCTION(zend_create_unterminated_string)
102 {
103 	zend_string *str, *res;
104 
105 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
106 		RETURN_THROWS();
107 	}
108 
109 	res = zend_string_alloc(ZSTR_LEN(str), 0);
110 	memcpy(ZSTR_VAL(res), ZSTR_VAL(str), ZSTR_LEN(str));
111 	/* No trailing null byte */
112 
113 	RETURN_STR(res);
114 }
115 
116 /* Enforce terminate null byte on string. This avoids a warning in debug builds. */
ZEND_FUNCTION(zend_terminate_string)117 static ZEND_FUNCTION(zend_terminate_string)
118 {
119 	zend_string *str;
120 
121 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
122 		RETURN_THROWS();
123 	}
124 
125 	ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
126 }
127 
128 /* {{{ Cause an intentional memory leak, for testing/debugging purposes */
ZEND_FUNCTION(zend_leak_bytes)129 static ZEND_FUNCTION(zend_leak_bytes)
130 {
131 	zend_long leakbytes = 3;
132 
133 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &leakbytes) == FAILURE) {
134 		RETURN_THROWS();
135 	}
136 
137 	emalloc(leakbytes);
138 }
139 /* }}} */
140 
141 /* {{{ Leak a refcounted variable */
ZEND_FUNCTION(zend_leak_variable)142 static ZEND_FUNCTION(zend_leak_variable)
143 {
144 	zval *zv;
145 
146 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
147 		RETURN_THROWS();
148 	}
149 
150 	if (!Z_REFCOUNTED_P(zv)) {
151 		zend_error(E_WARNING, "Cannot leak variable that is not refcounted");
152 		return;
153 	}
154 
155 	Z_ADDREF_P(zv);
156 }
157 /* }}} */
158 
159 /* Tests Z_PARAM_OBJ_OR_STR */
ZEND_FUNCTION(zend_string_or_object)160 static ZEND_FUNCTION(zend_string_or_object)
161 {
162 	zend_string *str;
163 	zend_object *object;
164 
165 	ZEND_PARSE_PARAMETERS_START(1, 1)
166 		Z_PARAM_OBJ_OR_STR(object, str)
167 	ZEND_PARSE_PARAMETERS_END();
168 
169 	if (str) {
170 		RETURN_STR_COPY(str);
171 	} else {
172 		RETURN_OBJ_COPY(object);
173 	}
174 }
175 /* }}} */
176 
177 /* Tests Z_PARAM_OBJ_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_object_or_null)178 static ZEND_FUNCTION(zend_string_or_object_or_null)
179 {
180 	zend_string *str;
181 	zend_object *object;
182 
183 	ZEND_PARSE_PARAMETERS_START(1, 1)
184 		Z_PARAM_OBJ_OR_STR_OR_NULL(object, str)
185 	ZEND_PARSE_PARAMETERS_END();
186 
187 	if (str) {
188 		RETURN_STR_COPY(str);
189 	} else if (object) {
190 		RETURN_OBJ_COPY(object);
191 	} else {
192 		RETURN_NULL();
193 	}
194 }
195 /* }}} */
196 
197 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR */
ZEND_FUNCTION(zend_string_or_stdclass)198 static ZEND_FUNCTION(zend_string_or_stdclass)
199 {
200 	zend_string *str;
201 	zend_object *object;
202 
203 	ZEND_PARSE_PARAMETERS_START(1, 1)
204 		Z_PARAM_OBJ_OF_CLASS_OR_STR(object, zend_standard_class_def, str)
205 	ZEND_PARSE_PARAMETERS_END();
206 
207 	if (str) {
208 		RETURN_STR_COPY(str);
209 	} else {
210 		RETURN_OBJ_COPY(object);
211 	}
212 }
213 /* }}} */
214 
215 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_stdclass_or_null)216 static ZEND_FUNCTION(zend_string_or_stdclass_or_null)
217 {
218 	zend_string *str;
219 	zend_object *object;
220 
221 	ZEND_PARSE_PARAMETERS_START(1, 1)
222 		Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(object, zend_standard_class_def, str)
223 	ZEND_PARSE_PARAMETERS_END();
224 
225 	if (str) {
226 		RETURN_STR_COPY(str);
227 	} else if (object) {
228 		RETURN_OBJ_COPY(object);
229 	} else {
230 		RETURN_NULL();
231 	}
232 }
233 /* }}} */
234 
ZEND_FUNCTION(zend_weakmap_attach)235 static ZEND_FUNCTION(zend_weakmap_attach)
236 {
237 	zval *value;
238 	zend_object *obj;
239 
240 	ZEND_PARSE_PARAMETERS_START(2, 2)
241 			Z_PARAM_OBJ(obj)
242 			Z_PARAM_ZVAL(value)
243 	ZEND_PARSE_PARAMETERS_END();
244 
245 	if (zend_weakrefs_hash_add(&ZT_G(global_weakmap), obj, value)) {
246 		Z_TRY_ADDREF_P(value);
247 		RETURN_TRUE;
248 	}
249 	RETURN_FALSE;
250 }
251 
ZEND_FUNCTION(zend_weakmap_remove)252 static ZEND_FUNCTION(zend_weakmap_remove)
253 {
254 	zend_object *obj;
255 
256 	ZEND_PARSE_PARAMETERS_START(1, 1)
257 			Z_PARAM_OBJ(obj)
258 	ZEND_PARSE_PARAMETERS_END();
259 
260 	RETURN_BOOL(zend_weakrefs_hash_del(&ZT_G(global_weakmap), obj) == SUCCESS);
261 }
262 
ZEND_FUNCTION(zend_weakmap_dump)263 static ZEND_FUNCTION(zend_weakmap_dump)
264 {
265 	ZEND_PARSE_PARAMETERS_NONE();
266 	RETURN_ARR(zend_array_dup(&ZT_G(global_weakmap)));
267 }
268 
ZEND_FUNCTION(zend_get_current_func_name)269 static ZEND_FUNCTION(zend_get_current_func_name)
270 {
271     ZEND_PARSE_PARAMETERS_NONE();
272 
273     zend_string *function_name = get_function_or_method_name(EG(current_execute_data)->prev_execute_data->func);
274 
275     RETURN_STR(function_name);
276 }
277 
278 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
ZEND_FUNCTION(zend_test_override_libxml_global_state)279 static ZEND_FUNCTION(zend_test_override_libxml_global_state)
280 {
281 	ZEND_PARSE_PARAMETERS_NONE();
282 
283 	xmlLoadExtDtdDefaultValue = 1;
284 	xmlDoValidityCheckingDefaultValue = 1;
285 	(void) xmlPedanticParserDefault(1);
286 	(void) xmlSubstituteEntitiesDefault(1);
287 	(void) xmlLineNumbersDefault(1);
288 	(void) xmlKeepBlanksDefault(0);
289 }
290 #endif
291 
292 /* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */
ZEND_FUNCTION(zend_iterable)293 static ZEND_FUNCTION(zend_iterable)
294 {
295 	zval *arg1, *arg2;
296 
297 	ZEND_PARSE_PARAMETERS_START(1, 2)
298 		Z_PARAM_ITERABLE(arg1)
299 		Z_PARAM_OPTIONAL
300 		Z_PARAM_ITERABLE_OR_NULL(arg2)
301 	ZEND_PARSE_PARAMETERS_END();
302 }
303 
ZEND_FUNCTION(namespaced_func)304 static ZEND_FUNCTION(namespaced_func)
305 {
306        ZEND_PARSE_PARAMETERS_NONE();
307        RETURN_TRUE;
308 }
309 
zend_test_class_new(zend_class_entry * class_type)310 static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */ {
311 	zend_object *obj = zend_objects_new(class_type);
312 	object_properties_init(obj, class_type);
313 	obj->handlers = &zend_test_class_handlers;
314 	return obj;
315 }
316 /* }}} */
317 
zend_test_class_method_get(zend_object ** object,zend_string * name,const zval * key)318 static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ {
319 	zend_internal_function *fptr;
320 
321 	if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
322 		fptr = (zend_internal_function *) &EG(trampoline);
323 	} else {
324 		fptr = emalloc(sizeof(zend_internal_function));
325 	}
326 	memset(fptr, 0, sizeof(zend_internal_function));
327 	fptr->type = ZEND_INTERNAL_FUNCTION;
328 	fptr->num_args = 1;
329 	fptr->scope = (*object)->ce;
330 	fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
331 	fptr->function_name = zend_string_copy(name);
332 	fptr->handler = ZEND_FN(zend_test_func);
333 
334 	return (zend_function*)fptr;
335 }
336 /* }}} */
337 
zend_test_class_static_method_get(zend_class_entry * ce,zend_string * name)338 static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name) /* {{{ */ {
339 	if (zend_string_equals_literal_ci(name, "test")) {
340 		zend_internal_function *fptr;
341 
342 		if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
343 			fptr = (zend_internal_function *) &EG(trampoline);
344 		} else {
345 			fptr = emalloc(sizeof(zend_internal_function));
346 		}
347 		memset(fptr, 0, sizeof(zend_internal_function));
348 		fptr->type = ZEND_INTERNAL_FUNCTION;
349 		fptr->num_args = 1;
350 		fptr->scope = ce;
351 		fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC;
352 		fptr->function_name = zend_string_copy(name);
353 		fptr->handler = ZEND_FN(zend_test_func);
354 
355 		return (zend_function*)fptr;
356 	}
357 	return zend_std_get_static_method(ce, name, NULL);
358 }
359 /* }}} */
360 
zend_attribute_validate_zendtestattribute(zend_attribute * attr,uint32_t target,zend_class_entry * scope)361 void zend_attribute_validate_zendtestattribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
362 {
363 	if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
364 		zend_error(E_COMPILE_ERROR, "Only classes can be marked with #[ZendTestAttribute]");
365 	}
366 }
367 
ZEND_METHOD(_ZendTestClass,__toString)368 static ZEND_METHOD(_ZendTestClass, __toString) {
369 	ZEND_PARSE_PARAMETERS_NONE();
370 	RETURN_EMPTY_STRING();
371 }
372 
373 /* Internal function returns bool, we return int. */
ZEND_METHOD(_ZendTestClass,is_object)374 static ZEND_METHOD(_ZendTestClass, is_object) {
375 	ZEND_PARSE_PARAMETERS_NONE();
376 	RETURN_LONG(42);
377 }
378 
ZEND_METHOD(_ZendTestClass,returnsStatic)379 static ZEND_METHOD(_ZendTestClass, returnsStatic) {
380 	ZEND_PARSE_PARAMETERS_NONE();
381 	object_init_ex(return_value, zend_get_called_scope(execute_data));
382 }
383 
ZEND_METHOD(_ZendTestTrait,testMethod)384 static ZEND_METHOD(_ZendTestTrait, testMethod) {
385 	ZEND_PARSE_PARAMETERS_NONE();
386 	RETURN_TRUE;
387 }
388 
ZEND_METHOD(ZendTestNS_Foo,method)389 static ZEND_METHOD(ZendTestNS_Foo, method) {
390 	ZEND_PARSE_PARAMETERS_NONE();
391 }
392 
ZEND_METHOD(ZendTestNS2_Foo,method)393 static ZEND_METHOD(ZendTestNS2_Foo, method) {
394 	ZEND_PARSE_PARAMETERS_NONE();
395 }
396 
ZEND_INI_MH(zend_test_observer_OnUpdateCommaList)397 static ZEND_INI_MH(zend_test_observer_OnUpdateCommaList)
398 {
399 	zend_array **p = (zend_array **) ZEND_INI_GET_ADDR();
400 	if (*p) {
401 		zend_hash_release(*p);
402 	}
403 	*p = NULL;
404 	if (new_value && ZSTR_LEN(new_value)) {
405 		*p = malloc(sizeof(HashTable));
406 		_zend_hash_init(*p, 8, ZVAL_PTR_DTOR, 1);
407 		const char *start = ZSTR_VAL(new_value), *ptr;
408 		while ((ptr = strchr(start, ','))) {
409 			zend_hash_str_add_empty_element(*p, start, ptr - start);
410 			start = ptr + 1;
411 		}
412 		zend_hash_str_add_empty_element(*p, start, ZSTR_VAL(new_value) + ZSTR_LEN(new_value) - start);
413 	}
414 	return SUCCESS;
415 }
416 
417 PHP_INI_BEGIN()
418 	STD_PHP_INI_BOOLEAN("zend_test.observer.enabled", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_enabled, zend_zend_test_globals, zend_test_globals)
419 	STD_PHP_INI_BOOLEAN("zend_test.observer.show_output", "1", PHP_INI_SYSTEM, OnUpdateBool, observer_show_output, zend_zend_test_globals, zend_test_globals)
420 	STD_PHP_INI_BOOLEAN("zend_test.observer.observe_all", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_all, zend_zend_test_globals, zend_test_globals)
421 	STD_PHP_INI_BOOLEAN("zend_test.observer.observe_includes", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_includes, zend_zend_test_globals, zend_test_globals)
422 	STD_PHP_INI_BOOLEAN("zend_test.observer.observe_functions", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_observe_functions, zend_zend_test_globals, zend_test_globals)
423 	STD_PHP_INI_ENTRY("zend_test.observer.observe_function_names", "", PHP_INI_SYSTEM, zend_test_observer_OnUpdateCommaList, observer_observe_function_names, zend_zend_test_globals, zend_test_globals)
424 	STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_type", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_type, zend_zend_test_globals, zend_test_globals)
425 	STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
426 	STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
427 	STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
428 	STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
429 PHP_INI_END()
430 
431 static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data);
432 
433 void (*old_zend_execute_ex)(zend_execute_data *execute_data);
custom_zend_execute_ex(zend_execute_data * execute_data)434 static void custom_zend_execute_ex(zend_execute_data *execute_data)
435 {
436 	old_zend_execute_ex(execute_data);
437 }
438 
PHP_MINIT_FUNCTION(zend_test)439 PHP_MINIT_FUNCTION(zend_test)
440 {
441 	zend_class_entry class_entry;
442 
443 	INIT_CLASS_ENTRY(class_entry, "_ZendTestInterface", NULL);
444 	zend_test_interface = zend_register_internal_interface(&class_entry);
445 	zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0);
446 	INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", class__ZendTestClass_methods);
447 	zend_test_class = zend_register_internal_class(&class_entry);
448 	zend_class_implements(zend_test_class, 1, zend_test_interface);
449 	zend_test_class->create_object = zend_test_class_new;
450 	zend_test_class->get_static_method = zend_test_class_static_method_get;
451 
452 	zend_declare_property_null(zend_test_class, "_StaticProp", sizeof("_StaticProp") - 1, ZEND_ACC_STATIC);
453 
454 	{
455 		zend_string *name = zend_string_init("intProp", sizeof("intProp") - 1, 1);
456 		zval val;
457 		ZVAL_LONG(&val, 123);
458 		zend_declare_typed_property(
459 			zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL,
460 			(zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0));
461 		zend_string_release(name);
462 	}
463 
464 	{
465 		zend_string *name = zend_string_init("classProp", sizeof("classProp") - 1, 1);
466 		zend_string *class_name = zend_string_init("stdClass", sizeof("stdClass") - 1, 1);
467 		zval val;
468 		ZVAL_NULL(&val);
469 		zend_declare_typed_property(
470 			zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL,
471 			(zend_type) ZEND_TYPE_INIT_CLASS(class_name, 1, 0));
472 		zend_string_release(name);
473 	}
474 
475 	{
476 		zend_string *name = zend_string_init("classUnionProp", sizeof("classUnionProp") - 1, 1);
477 		zend_string *class_name1 = zend_string_init("stdClass", sizeof("stdClass") - 1, 1);
478 		zend_string *class_name2 = zend_string_init("Iterator", sizeof("Iterator") - 1, 1);
479 		zend_type_list *type_list = malloc(ZEND_TYPE_LIST_SIZE(2));
480 		type_list->num_types = 2;
481 		type_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name1, 0, 0);
482 		type_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(class_name2, 0, 0);
483 		zend_type type = ZEND_TYPE_INIT_PTR(type_list, _ZEND_TYPE_LIST_BIT, 1, 0);
484 		zval val;
485 		ZVAL_NULL(&val);
486 		zend_declare_typed_property(zend_test_class, name, &val, ZEND_ACC_PUBLIC, NULL, type);
487 		zend_string_release(name);
488 	}
489 
490 	{
491 		zend_string *name = zend_string_init("staticIntProp", sizeof("staticIntProp") - 1, 1);
492 		zval val;
493 		ZVAL_LONG(&val, 123);
494 		zend_declare_typed_property(
495 			zend_test_class, name, &val, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC, NULL,
496 			(zend_type) ZEND_TYPE_INIT_CODE(IS_LONG, 0, 0));
497 		zend_string_release(name);
498 	}
499 
500 	INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", NULL);
501 	zend_test_child_class = zend_register_internal_class_ex(&class_entry, zend_test_class);
502 
503 	memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
504 	zend_test_class_handlers.get_method = zend_test_class_method_get;
505 
506 	INIT_CLASS_ENTRY(class_entry, "_ZendTestTrait", class__ZendTestTrait_methods);
507 	zend_test_trait = zend_register_internal_class(&class_entry);
508 	zend_test_trait->ce_flags |= ZEND_ACC_TRAIT;
509 	zend_declare_property_null(zend_test_trait, "testProp", sizeof("testProp")-1, ZEND_ACC_PUBLIC);
510 
511 	zend_register_class_alias("_ZendTestClassAlias", zend_test_class);
512 
513 	REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED);
514 
515 	INIT_CLASS_ENTRY(class_entry, "ZendTestAttribute", NULL);
516 	zend_test_attribute = zend_register_internal_class(&class_entry);
517 	zend_test_attribute->ce_flags |= ZEND_ACC_FINAL;
518 
519 	{
520 		zend_internal_attribute *attr = zend_internal_attribute_register(zend_test_attribute, ZEND_ATTRIBUTE_TARGET_ALL);
521 		attr->validator = zend_attribute_validate_zendtestattribute;
522 	}
523 
524 	// Loading via dl() not supported with the observer API
525 	if (type != MODULE_TEMPORARY) {
526 		REGISTER_INI_ENTRIES();
527 		if (ZT_G(observer_enabled)) {
528 			zend_observer_fcall_register(observer_fcall_init);
529 		}
530 	} else {
531 		(void)ini_entries;
532 	}
533 
534 	if (ZT_G(replace_zend_execute_ex)) {
535 		old_zend_execute_ex = zend_execute_ex;
536 		zend_execute_ex = custom_zend_execute_ex;
537 	}
538 
539 	return SUCCESS;
540 }
541 
PHP_MSHUTDOWN_FUNCTION(zend_test)542 PHP_MSHUTDOWN_FUNCTION(zend_test)
543 {
544 	if (type != MODULE_TEMPORARY) {
545 		UNREGISTER_INI_ENTRIES();
546 	}
547 
548 	return SUCCESS;
549 }
550 
observer_show_opcode(zend_execute_data * execute_data)551 static void observer_show_opcode(zend_execute_data *execute_data)
552 {
553 	if (!ZT_G(observer_show_opcode)) {
554 		return;
555 	}
556 	php_printf("%*s<!-- opcode: '%s' -->\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode));
557 }
558 
observer_begin(zend_execute_data * execute_data)559 static void observer_begin(zend_execute_data *execute_data)
560 {
561 	if (!ZT_G(observer_show_output)) {
562 		return;
563 	}
564 
565 	if (execute_data->func && execute_data->func->common.function_name) {
566 		if (execute_data->func->common.scope) {
567 			php_printf("%*s<%s::%s>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->common.scope->name), ZSTR_VAL(execute_data->func->common.function_name));
568 		} else {
569 			php_printf("%*s<%s>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->common.function_name));
570 		}
571 	} else {
572 		php_printf("%*s<file '%s'>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->op_array.filename));
573 	}
574 	ZT_G(observer_nesting_depth)++;
575 	observer_show_opcode(execute_data);
576 }
577 
get_retval_info(zval * retval,smart_str * buf)578 static void get_retval_info(zval *retval, smart_str *buf)
579 {
580 	if (!ZT_G(observer_show_return_type) && !ZT_G(observer_show_return_value)) {
581 		return;
582 	}
583 
584 	smart_str_appendc(buf, ':');
585 	if (retval == NULL) {
586 		smart_str_appendl(buf, "NULL", 4);
587 	} else if (ZT_G(observer_show_return_value)) {
588 		if (Z_TYPE_P(retval) == IS_OBJECT) {
589 			smart_str_appendl(buf, "object(", 7);
590 			smart_str_append(buf, Z_OBJCE_P(retval)->name);
591 			smart_str_appendl(buf, ")#", 2);
592 			smart_str_append_long(buf, Z_OBJ_HANDLE_P(retval));
593 		} else {
594 			php_var_export_ex(retval, 2 * ZT_G(observer_nesting_depth) + 3, buf);
595 		}
596 	} else if (ZT_G(observer_show_return_type)) {
597 		smart_str_appends(buf, zend_zval_type_name(retval));
598 	}
599 	smart_str_0(buf);
600 }
601 
observer_end(zend_execute_data * execute_data,zval * retval)602 static void observer_end(zend_execute_data *execute_data, zval *retval)
603 {
604 	if (!ZT_G(observer_show_output)) {
605 		return;
606 	}
607 
608 	if (EG(exception)) {
609 		php_printf("%*s<!-- Exception: %s -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(EG(exception)->ce->name));
610 	}
611 	observer_show_opcode(execute_data);
612 	ZT_G(observer_nesting_depth)--;
613 	if (execute_data->func && execute_data->func->common.function_name) {
614 		smart_str retval_info = {0};
615 		get_retval_info(retval, &retval_info);
616 		if (execute_data->func->common.scope) {
617 			php_printf("%*s</%s::%s%s>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->common.scope->name), ZSTR_VAL(execute_data->func->common.function_name), retval_info.s ? ZSTR_VAL(retval_info.s) : "");
618 		} else {
619 			php_printf("%*s</%s%s>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->common.function_name), retval_info.s ? ZSTR_VAL(retval_info.s) : "");
620 		}
621 		smart_str_free(&retval_info);
622 	} else {
623 		php_printf("%*s</file '%s'>\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(execute_data->func->op_array.filename));
624 	}
625 }
626 
observer_show_init(zend_function * fbc)627 static void observer_show_init(zend_function *fbc)
628 {
629 	if (fbc->common.function_name) {
630 		if (fbc->common.scope) {
631 			php_printf("%*s<!-- init %s::%s() -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
632 		} else {
633 			php_printf("%*s<!-- init %s() -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->common.function_name));
634 		}
635 	} else {
636 		php_printf("%*s<!-- init '%s' -->\n", 2 * ZT_G(observer_nesting_depth), "", ZSTR_VAL(fbc->op_array.filename));
637 	}
638 }
639 
observer_show_init_backtrace(zend_execute_data * execute_data)640 static void observer_show_init_backtrace(zend_execute_data *execute_data)
641 {
642 	zend_execute_data *ex = execute_data;
643 	php_printf("%*s<!--\n", 2 * ZT_G(observer_nesting_depth), "");
644 	do {
645 		zend_function *fbc = ex->func;
646 		int indent = 2 * ZT_G(observer_nesting_depth) + 4;
647 		if (fbc->common.function_name) {
648 			if (fbc->common.scope) {
649 				php_printf("%*s%s::%s()\n", indent, "", ZSTR_VAL(fbc->common.scope->name), ZSTR_VAL(fbc->common.function_name));
650 			} else {
651 				php_printf("%*s%s()\n", indent, "", ZSTR_VAL(fbc->common.function_name));
652 			}
653 		} else {
654 			php_printf("%*s{main} %s\n", indent, "", ZSTR_VAL(fbc->op_array.filename));
655 		}
656 	} while ((ex = ex->prev_execute_data) != NULL);
657 	php_printf("%*s-->\n", 2 * ZT_G(observer_nesting_depth), "");
658 }
659 
observer_fcall_init(zend_execute_data * execute_data)660 static zend_observer_fcall_handlers observer_fcall_init(zend_execute_data *execute_data)
661 {
662 	zend_function *fbc = execute_data->func;
663 	if (ZT_G(observer_show_output)) {
664 		observer_show_init(fbc);
665 		if (ZT_G(observer_show_init_backtrace)) {
666 			observer_show_init_backtrace(execute_data);
667 		}
668 		observer_show_opcode(execute_data);
669 	}
670 
671 	if (ZT_G(observer_observe_all)) {
672 		return (zend_observer_fcall_handlers){observer_begin, observer_end};
673 	} else if (fbc->common.function_name) {
674 		if (ZT_G(observer_observe_functions)) {
675 			return (zend_observer_fcall_handlers){observer_begin, observer_end};
676 		} else if (ZT_G(observer_observe_function_names) && zend_hash_exists(ZT_G(observer_observe_function_names), fbc->common.function_name)) {
677 			return (zend_observer_fcall_handlers){observer_begin, observer_end};
678 		}
679 	} else {
680 		if (ZT_G(observer_observe_includes)) {
681 			return (zend_observer_fcall_handlers){observer_begin, observer_end};
682 		}
683 	}
684 	return (zend_observer_fcall_handlers){NULL, NULL};
685 }
686 
PHP_RINIT_FUNCTION(zend_test)687 PHP_RINIT_FUNCTION(zend_test)
688 {
689 	zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
690 	return SUCCESS;
691 }
692 
PHP_RSHUTDOWN_FUNCTION(zend_test)693 PHP_RSHUTDOWN_FUNCTION(zend_test)
694 {
695 	zend_ulong objptr;
696 	ZEND_HASH_FOREACH_NUM_KEY(&ZT_G(global_weakmap), objptr) {
697 		zend_weakrefs_hash_del(&ZT_G(global_weakmap), (zend_object *)(uintptr_t)objptr);
698 	} ZEND_HASH_FOREACH_END();
699 	zend_hash_destroy(&ZT_G(global_weakmap));
700 	return SUCCESS;
701 }
702 
PHP_GINIT_FUNCTION(zend_test)703 static PHP_GINIT_FUNCTION(zend_test)
704 {
705 #if defined(COMPILE_DL_ZEND_TEST) && defined(ZTS)
706 	ZEND_TSRMLS_CACHE_UPDATE();
707 #endif
708 	memset(zend_test_globals, 0, sizeof(*zend_test_globals));
709 }
710 
PHP_MINFO_FUNCTION(zend_test)711 PHP_MINFO_FUNCTION(zend_test)
712 {
713 	php_info_print_table_start();
714 	php_info_print_table_header(2, "zend-test extension", "enabled");
715 	php_info_print_table_end();
716 
717 	DISPLAY_INI_ENTRIES();
718 }
719 
720 zend_module_entry zend_test_module_entry = {
721 	STANDARD_MODULE_HEADER,
722 	"zend-test",
723 	ext_functions,
724 	PHP_MINIT(zend_test),
725 	PHP_MSHUTDOWN(zend_test),
726 	PHP_RINIT(zend_test),
727 	PHP_RSHUTDOWN(zend_test),
728 	PHP_MINFO(zend_test),
729 	PHP_ZEND_TEST_VERSION,
730 	PHP_MODULE_GLOBALS(zend_test),
731 	PHP_GINIT(zend_test),
732 	NULL,
733 	NULL,
734 	STANDARD_MODULE_PROPERTIES_EX
735 };
736 
737 #ifdef COMPILE_DL_ZEND_TEST
738 #ifdef ZTS
739 ZEND_TSRMLS_CACHE_DEFINE()
740 #endif
ZEND_GET_MODULE(zend_test)741 ZEND_GET_MODULE(zend_test)
742 #endif
743 
744 PHP_ZEND_TEST_API struct bug79096 bug79096(void)
745 {
746   struct bug79096 b;
747 
748   b.a = 1;
749   b.b = 1;
750   return b;
751 }
752 
bug79532(off_t * array,size_t elems)753 PHP_ZEND_TEST_API void bug79532(off_t *array, size_t elems)
754 {
755 	int i;
756 	for (i = 0; i < elems; i++) {
757 		array[i] = i;
758 	}
759 }
760 
761 PHP_ZEND_TEST_API int *(*bug79177_cb)(void);
bug79177(void)762 void bug79177(void)
763 {
764 	bug79177_cb();
765 }
766 
767 typedef struct bug80847_01 {
768 	uint64_t b;
769 	double c;
770 } bug80847_01;
771 typedef struct bug80847_02 {
772 	bug80847_01 a;
773 } bug80847_02;
774 
ffi_bug80847(bug80847_02 s)775 PHP_ZEND_TEST_API bug80847_02 ffi_bug80847(bug80847_02 s) {
776 	s.a.b += 10;
777 	s.a.c -= 10.0;
778     return s;
779 }
780