xref: /PHP-8.1/ext/zend_test/test.c (revision 5bd04acf)
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   | https://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 "php_test.h"
25 #include "observer.h"
26 #include "fiber.h"
27 #include "iterators.h"
28 #include "zend_attributes.h"
29 #include "zend_enum.h"
30 #include "zend_interfaces.h"
31 #include "zend_weakrefs.h"
32 #include "Zend/Optimizer/zend_optimizer.h"
33 #include "Zend/zend_alloc.h"
34 #include "test_arginfo.h"
35 
36 // `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
37 // assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
38 // undefine `NDEBUG` and re-include assert.h
39 #undef NDEBUG
40 #include "assert.h"
41 
42 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
43 # include <libxml/globals.h>
44 # include <libxml/parser.h>
45 #endif
46 
47 ZEND_DECLARE_MODULE_GLOBALS(zend_test)
48 
49 static zend_class_entry *zend_test_interface;
50 static zend_class_entry *zend_test_class;
51 static zend_class_entry *zend_test_child_class;
52 static zend_class_entry *zend_test_trait;
53 static zend_class_entry *zend_test_attribute;
54 static zend_class_entry *zend_test_parameter_attribute;
55 static zend_class_entry *zend_test_class_with_method_with_parameter_attribute;
56 static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute;
57 static zend_class_entry *zend_test_ns_foo_class;
58 static zend_class_entry *zend_test_ns2_foo_class;
59 static zend_class_entry *zend_test_ns2_ns_foo_class;
60 static zend_class_entry *zend_test_unit_enum;
61 static zend_class_entry *zend_test_string_enum;
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 
pass1(zend_script * script,void * context)91 static void pass1(zend_script *script, void *context)
92 {
93 	php_printf("pass1\n");
94 }
95 
pass2(zend_script * script,void * context)96 static void pass2(zend_script *script, void *context)
97 {
98 	php_printf("pass2\n");
99 }
100 
ZEND_FUNCTION(zend_test_deprecated)101 static ZEND_FUNCTION(zend_test_deprecated)
102 {
103 	zval *arg1;
104 
105 	zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1);
106 }
107 
108 /* Create a string without terminating null byte. Must be terminated with
109  * zend_terminate_string() before destruction, otherwise a warning is issued
110  * in debug builds. */
ZEND_FUNCTION(zend_create_unterminated_string)111 static ZEND_FUNCTION(zend_create_unterminated_string)
112 {
113 	zend_string *str, *res;
114 
115 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
116 		RETURN_THROWS();
117 	}
118 
119 	res = zend_string_alloc(ZSTR_LEN(str), 0);
120 	memcpy(ZSTR_VAL(res), ZSTR_VAL(str), ZSTR_LEN(str));
121 	/* No trailing null byte */
122 
123 	RETURN_STR(res);
124 }
125 
126 /* Enforce terminate null byte on string. This avoids a warning in debug builds. */
ZEND_FUNCTION(zend_terminate_string)127 static ZEND_FUNCTION(zend_terminate_string)
128 {
129 	zend_string *str;
130 
131 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
132 		RETURN_THROWS();
133 	}
134 
135 	ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
136 }
137 
138 /* Cause an intentional memory leak, for testing/debugging purposes */
ZEND_FUNCTION(zend_leak_bytes)139 static ZEND_FUNCTION(zend_leak_bytes)
140 {
141 	zend_long leakbytes = 3;
142 
143 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &leakbytes) == FAILURE) {
144 		RETURN_THROWS();
145 	}
146 
147 	emalloc(leakbytes);
148 }
149 
150 /* Leak a refcounted variable */
ZEND_FUNCTION(zend_leak_variable)151 static ZEND_FUNCTION(zend_leak_variable)
152 {
153 	zval *zv;
154 
155 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
156 		RETURN_THROWS();
157 	}
158 
159 	if (!Z_REFCOUNTED_P(zv)) {
160 		zend_error(E_WARNING, "Cannot leak variable that is not refcounted");
161 		return;
162 	}
163 
164 	Z_ADDREF_P(zv);
165 }
166 
167 /* Tests Z_PARAM_OBJ_OR_STR */
ZEND_FUNCTION(zend_string_or_object)168 static ZEND_FUNCTION(zend_string_or_object)
169 {
170 	zend_string *str;
171 	zend_object *object;
172 
173 	ZEND_PARSE_PARAMETERS_START(1, 1)
174 		Z_PARAM_OBJ_OR_STR(object, str)
175 	ZEND_PARSE_PARAMETERS_END();
176 
177 	if (str) {
178 		RETURN_STR_COPY(str);
179 	} else {
180 		RETURN_OBJ_COPY(object);
181 	}
182 }
183 
184 /* Tests Z_PARAM_OBJ_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_object_or_null)185 static ZEND_FUNCTION(zend_string_or_object_or_null)
186 {
187 	zend_string *str;
188 	zend_object *object;
189 
190 	ZEND_PARSE_PARAMETERS_START(1, 1)
191 		Z_PARAM_OBJ_OR_STR_OR_NULL(object, str)
192 	ZEND_PARSE_PARAMETERS_END();
193 
194 	if (str) {
195 		RETURN_STR_COPY(str);
196 	} else if (object) {
197 		RETURN_OBJ_COPY(object);
198 	} else {
199 		RETURN_NULL();
200 	}
201 }
202 
203 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR */
ZEND_FUNCTION(zend_string_or_stdclass)204 static ZEND_FUNCTION(zend_string_or_stdclass)
205 {
206 	zend_string *str;
207 	zend_object *object;
208 
209 	ZEND_PARSE_PARAMETERS_START(1, 1)
210 		Z_PARAM_OBJ_OF_CLASS_OR_STR(object, zend_standard_class_def, str)
211 	ZEND_PARSE_PARAMETERS_END();
212 
213 	if (str) {
214 		RETURN_STR_COPY(str);
215 	} else {
216 		RETURN_OBJ_COPY(object);
217 	}
218 }
219 
220 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_stdclass_or_null)221 static ZEND_FUNCTION(zend_string_or_stdclass_or_null)
222 {
223 	zend_string *str;
224 	zend_object *object;
225 
226 	ZEND_PARSE_PARAMETERS_START(1, 1)
227 		Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(object, zend_standard_class_def, str)
228 	ZEND_PARSE_PARAMETERS_END();
229 
230 	if (str) {
231 		RETURN_STR_COPY(str);
232 	} else if (object) {
233 		RETURN_OBJ_COPY(object);
234 	} else {
235 		RETURN_NULL();
236 	}
237 }
238 
ZEND_FUNCTION(zend_weakmap_attach)239 static ZEND_FUNCTION(zend_weakmap_attach)
240 {
241 	zval *value;
242 	zend_object *obj;
243 
244 	ZEND_PARSE_PARAMETERS_START(2, 2)
245 			Z_PARAM_OBJ(obj)
246 			Z_PARAM_ZVAL(value)
247 	ZEND_PARSE_PARAMETERS_END();
248 
249 	if (zend_weakrefs_hash_add(&ZT_G(global_weakmap), obj, value)) {
250 		Z_TRY_ADDREF_P(value);
251 		RETURN_TRUE;
252 	}
253 	RETURN_FALSE;
254 }
255 
ZEND_FUNCTION(zend_weakmap_remove)256 static ZEND_FUNCTION(zend_weakmap_remove)
257 {
258 	zend_object *obj;
259 
260 	ZEND_PARSE_PARAMETERS_START(1, 1)
261 			Z_PARAM_OBJ(obj)
262 	ZEND_PARSE_PARAMETERS_END();
263 
264 	RETURN_BOOL(zend_weakrefs_hash_del(&ZT_G(global_weakmap), obj) == SUCCESS);
265 }
266 
ZEND_FUNCTION(zend_weakmap_dump)267 static ZEND_FUNCTION(zend_weakmap_dump)
268 {
269 	ZEND_PARSE_PARAMETERS_NONE();
270 	RETURN_ARR(zend_array_dup(&ZT_G(global_weakmap)));
271 }
272 
ZEND_FUNCTION(zend_get_current_func_name)273 static ZEND_FUNCTION(zend_get_current_func_name)
274 {
275     ZEND_PARSE_PARAMETERS_NONE();
276 
277     zend_string *function_name = get_function_or_method_name(EG(current_execute_data)->prev_execute_data->func);
278 
279     RETURN_STR(function_name);
280 }
281 
282 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
283 
284 /* This test relies on deprecated code to modify the global state of libxml.
285  * We cannot include the libxml header here as that would create a dependency on libxml from zend_test.
286  * On 8.2+ this uses ZEND_DIAGNOSTIC_IGNORED_START, but this doesn't exist on 8.1 */
287 #if defined(__clang__)
288 # define PHP_LIBXML_IGNORE_DEPRECATIONS_START \
289 	_Pragma("clang diagnostic push") \
290 	_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
291 # define PHP_LIBXML_IGNORE_DEPRECATIONS_END \
292 	_Pragma("clang diagnostic pop")
293 #elif defined(__GNUC__)
294 # define PHP_LIBXML_IGNORE_DEPRECATIONS_START \
295 	_Pragma("GCC diagnostic push") \
296 	_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
297 # define PHP_LIBXML_IGNORE_DEPRECATIONS_END \
298 	_Pragma("GCC diagnostic pop")
299 #else
300 # define PHP_LIBXML_IGNORE_DEPRECATIONS_START
301 # define PHP_LIBXML_IGNORE_DEPRECATIONS_END
302 #endif
303 
ZEND_FUNCTION(zend_test_override_libxml_global_state)304 static ZEND_FUNCTION(zend_test_override_libxml_global_state)
305 {
306 	ZEND_PARSE_PARAMETERS_NONE();
307 
308 	PHP_LIBXML_IGNORE_DEPRECATIONS_START
309 	xmlLoadExtDtdDefaultValue = 1;
310 	xmlDoValidityCheckingDefaultValue = 1;
311 	(void) xmlPedanticParserDefault(1);
312 	(void) xmlSubstituteEntitiesDefault(1);
313 	(void) xmlLineNumbersDefault(1);
314 	(void) xmlKeepBlanksDefault(0);
315 	PHP_LIBXML_IGNORE_DEPRECATIONS_END
316 }
317 #endif
318 
319 /* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */
ZEND_FUNCTION(zend_iterable)320 static ZEND_FUNCTION(zend_iterable)
321 {
322 	zval *arg1, *arg2;
323 
324 	ZEND_PARSE_PARAMETERS_START(1, 2)
325 		Z_PARAM_ITERABLE(arg1)
326 		Z_PARAM_OPTIONAL
327 		Z_PARAM_ITERABLE_OR_NULL(arg2)
328 	ZEND_PARSE_PARAMETERS_END();
329 }
330 
331 /* Call a method on a class or object using zend_call_method() */
ZEND_FUNCTION(zend_call_method)332 static ZEND_FUNCTION(zend_call_method)
333 {
334 	zend_class_entry *ce = NULL;
335 	zend_string *method_name = NULL;
336 	zval *arg1 = NULL, *arg2 = NULL;
337 	int argc = ZEND_NUM_ARGS();
338 
339 	ZEND_PARSE_PARAMETERS_START(2, 4)
340 		Z_PARAM_CLASS(ce)
341 		Z_PARAM_STR(method_name)
342 		Z_PARAM_OPTIONAL
343 		Z_PARAM_ZVAL(arg1)
344 		Z_PARAM_ZVAL(arg2)
345 	ZEND_PARSE_PARAMETERS_END();
346 
347 	zend_call_method(NULL, ce, NULL, ZSTR_VAL(method_name), ZSTR_LEN(method_name), return_value, argc - 2, arg1, arg2);
348 }
349 
ZEND_FUNCTION(zend_get_unit_enum)350 static ZEND_FUNCTION(zend_get_unit_enum)
351 {
352 	ZEND_PARSE_PARAMETERS_NONE();
353 
354 	RETURN_OBJ_COPY(zend_enum_get_case_cstr(zend_test_unit_enum, "Foo"));
355 }
356 
ZEND_FUNCTION(namespaced_func)357 static ZEND_FUNCTION(namespaced_func)
358 {
359 	ZEND_PARSE_PARAMETERS_NONE();
360 	RETURN_TRUE;
361 }
362 
ZEND_FUNCTION(zend_test_parameter_with_attribute)363 static ZEND_FUNCTION(zend_test_parameter_with_attribute)
364 {
365 	zend_string *parameter;
366 
367 	ZEND_PARSE_PARAMETERS_START(1, 1)
368 		Z_PARAM_STR(parameter)
369 	ZEND_PARSE_PARAMETERS_END();
370 
371 	RETURN_LONG(1);
372 }
373 
ZEND_FUNCTION(zend_get_map_ptr_last)374 static ZEND_FUNCTION(zend_get_map_ptr_last)
375 {
376 	ZEND_PARSE_PARAMETERS_NONE();
377 	RETURN_LONG(CG(map_ptr_last));
378 }
379 
ZEND_FUNCTION(zend_test_crash)380 static ZEND_FUNCTION(zend_test_crash)
381 {
382 	zend_string *message = NULL;
383 
384 	ZEND_PARSE_PARAMETERS_START(0, 1)
385 		Z_PARAM_OPTIONAL
386 		Z_PARAM_STR_OR_NULL(message)
387 	ZEND_PARSE_PARAMETERS_END();
388 
389 	if (message) {
390 		php_printf("%s", ZSTR_VAL(message));
391 	}
392 
393 	char *invalid = (char *) 1;
394 	php_printf("%s", invalid);
395 }
396 
has_opline(zend_execute_data * execute_data)397 static bool has_opline(zend_execute_data *execute_data)
398 {
399 	return execute_data
400 		&& execute_data->func
401 		&& ZEND_USER_CODE(execute_data->func->type)
402 		&& execute_data->opline
403 	;
404 }
405 
zend_test_custom_malloc(size_t len)406 void * zend_test_custom_malloc(size_t len)
407 {
408 	if (has_opline(EG(current_execute_data))) {
409 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
410 	}
411 	return _zend_mm_alloc(ZT_G(zend_orig_heap), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
412 }
413 
zend_test_custom_free(void * ptr)414 void zend_test_custom_free(void *ptr)
415 {
416 	if (has_opline(EG(current_execute_data))) {
417 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
418 	}
419 	_zend_mm_free(ZT_G(zend_orig_heap), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
420 }
421 
zend_test_custom_realloc(void * ptr,size_t len)422 void * zend_test_custom_realloc(void * ptr, size_t len)
423 {
424 	if (has_opline(EG(current_execute_data))) {
425 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
426 	}
427 	return _zend_mm_realloc(ZT_G(zend_orig_heap), ptr, len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
428 }
429 
PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)430 static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
431 {
432 	if (new_value == NULL) {
433 		return FAILURE;
434 	}
435 
436 	int int_value = zend_ini_parse_bool(new_value);
437 
438 	if (int_value == 1) {
439 		// `zend_mm_heap` is a private struct, so we have not way to find the
440 		// actual size, but 4096 bytes should be enough
441 		ZT_G(zend_test_heap) = malloc(4096);
442 		memset(ZT_G(zend_test_heap), 0, 4096);
443 		zend_mm_set_custom_handlers(
444 			ZT_G(zend_test_heap),
445 			zend_test_custom_malloc,
446 			zend_test_custom_free,
447 			zend_test_custom_realloc
448 		);
449 		ZT_G(zend_orig_heap) = zend_mm_get_heap();
450 		zend_mm_set_heap(ZT_G(zend_test_heap));
451 	} else if (ZT_G(zend_test_heap))  {
452 		free(ZT_G(zend_test_heap));
453 		ZT_G(zend_test_heap) = NULL;
454 		zend_mm_set_heap(ZT_G(zend_orig_heap));
455 	}
456 	return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
457 }
458 
ZEND_FUNCTION(zend_test_is_pcre_bundled)459 static ZEND_FUNCTION(zend_test_is_pcre_bundled)
460 {
461 	ZEND_PARSE_PARAMETERS_NONE();
462 #if HAVE_BUNDLED_PCRE
463 	RETURN_TRUE;
464 #else
465 	RETURN_FALSE;
466 #endif
467 }
468 
zend_test_class_new(zend_class_entry * class_type)469 static zend_object *zend_test_class_new(zend_class_entry *class_type)
470 {
471 	zend_object *obj = zend_objects_new(class_type);
472 	object_properties_init(obj, class_type);
473 	obj->handlers = &zend_test_class_handlers;
474 	return obj;
475 }
476 
zend_test_class_method_get(zend_object ** object,zend_string * name,const zval * key)477 static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key)
478 {
479 	if (zend_string_equals_literal_ci(name, "test")) {
480 	    zend_internal_function *fptr;
481 
482 	    if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
483 		    fptr = (zend_internal_function *) &EG(trampoline);
484 	    } else {
485 		    fptr = emalloc(sizeof(zend_internal_function));
486 	    }
487 	    memset(fptr, 0, sizeof(zend_internal_function));
488 	    fptr->type = ZEND_INTERNAL_FUNCTION;
489 	    fptr->num_args = 1;
490 	    fptr->scope = (*object)->ce;
491 	    fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
492 	    fptr->function_name = zend_string_copy(name);
493 	    fptr->handler = ZEND_FN(zend_test_func);
494 
495 	    return (zend_function*)fptr;
496 	}
497 	return zend_std_get_method(object, name, key);
498 }
499 
zend_test_class_static_method_get(zend_class_entry * ce,zend_string * name)500 static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name)
501 {
502 	if (zend_string_equals_literal_ci(name, "test")) {
503 		zend_internal_function *fptr;
504 
505 		if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
506 			fptr = (zend_internal_function *) &EG(trampoline);
507 		} else {
508 			fptr = emalloc(sizeof(zend_internal_function));
509 		}
510 		memset(fptr, 0, sizeof(zend_internal_function));
511 		fptr->type = ZEND_INTERNAL_FUNCTION;
512 		fptr->num_args = 1;
513 		fptr->scope = ce;
514 		fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC;
515 		fptr->function_name = zend_string_copy(name);
516 		fptr->handler = ZEND_FN(zend_test_func);
517 
518 		return (zend_function*)fptr;
519 	}
520 	return zend_std_get_static_method(ce, name, NULL);
521 }
522 
zend_attribute_validate_zendtestattribute(zend_attribute * attr,uint32_t target,zend_class_entry * scope)523 void zend_attribute_validate_zendtestattribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
524 {
525 	if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
526 		zend_error(E_COMPILE_ERROR, "Only classes can be marked with #[ZendTestAttribute]");
527 	}
528 }
529 
ZEND_METHOD(_ZendTestClass,__toString)530 static ZEND_METHOD(_ZendTestClass, __toString)
531 {
532 	ZEND_PARSE_PARAMETERS_NONE();
533 	RETURN_EMPTY_STRING();
534 }
535 
536 /* Internal function returns bool, we return int. */
ZEND_METHOD(_ZendTestClass,is_object)537 static ZEND_METHOD(_ZendTestClass, is_object)
538 {
539 	ZEND_PARSE_PARAMETERS_NONE();
540 	RETURN_LONG(42);
541 }
542 
ZEND_METHOD(_ZendTestClass,returnsStatic)543 static ZEND_METHOD(_ZendTestClass, returnsStatic) {
544 	ZEND_PARSE_PARAMETERS_NONE();
545 	object_init_ex(return_value, zend_get_called_scope(execute_data));
546 }
547 
ZEND_METHOD(_ZendTestClass,returnsThrowable)548 static ZEND_METHOD(_ZendTestClass, returnsThrowable)
549 {
550 	ZEND_PARSE_PARAMETERS_NONE();
551 	zend_throw_error(NULL, "Dummy");
552 }
553 
ZEND_METHOD(_ZendTestClass,variadicTest)554 static ZEND_METHOD(_ZendTestClass, variadicTest) {
555 	int      argc, i;
556 	zval    *args = NULL;
557 
558 	ZEND_PARSE_PARAMETERS_START(0, -1)
559 		Z_PARAM_VARIADIC('*', args, argc)
560 	ZEND_PARSE_PARAMETERS_END();
561 
562 	for (i = 0; i < argc; i++) {
563 		zval *arg = args + i;
564 
565 		if (Z_TYPE_P(arg) == IS_STRING) {
566 			continue;
567 		}
568 		if (Z_TYPE_P(arg) == IS_OBJECT && instanceof_function(Z_OBJ_P(arg)->ce, zend_ce_iterator)) {
569 			continue;
570 		}
571 
572 		zend_argument_type_error(i + 1, "must be of class Iterator or a string, %s given", zend_zval_type_name(arg));
573 		RETURN_THROWS();
574 	}
575 
576 	object_init_ex(return_value, zend_get_called_scope(execute_data));
577 }
578 
ZEND_METHOD(_ZendTestChildClass,returnsThrowable)579 static ZEND_METHOD(_ZendTestChildClass, returnsThrowable)
580 {
581 	ZEND_PARSE_PARAMETERS_NONE();
582 	zend_throw_error(NULL, "Dummy");
583 }
584 
ZEND_METHOD(_ZendTestTrait,testMethod)585 static ZEND_METHOD(_ZendTestTrait, testMethod)
586 {
587 	ZEND_PARSE_PARAMETERS_NONE();
588 	RETURN_TRUE;
589 }
590 
ZEND_METHOD(ZendTestNS_Foo,method)591 static ZEND_METHOD(ZendTestNS_Foo, method)
592 {
593 	ZEND_PARSE_PARAMETERS_NONE();
594 }
595 
ZEND_METHOD(ZendTestNS2_Foo,method)596 static ZEND_METHOD(ZendTestNS2_Foo, method)
597 {
598 	ZEND_PARSE_PARAMETERS_NONE();
599 }
600 
ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo,method)601 static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method)
602 {
603 	ZEND_PARSE_PARAMETERS_NONE();
604 }
605 
ZEND_METHOD(ZendTestParameterAttribute,__construct)606 static ZEND_METHOD(ZendTestParameterAttribute, __construct)
607 {
608 	zend_string *parameter;
609 
610 	ZEND_PARSE_PARAMETERS_START(1, 1)
611 		Z_PARAM_STR(parameter)
612 	ZEND_PARSE_PARAMETERS_END();
613 
614 	ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter);
615 }
616 
ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute,no_override)617 static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override)
618 {
619 	zend_string *parameter;
620 
621 	ZEND_PARSE_PARAMETERS_START(1, 1)
622 		Z_PARAM_STR(parameter)
623 	ZEND_PARSE_PARAMETERS_END();
624 
625 	RETURN_LONG(2);
626 }
627 
ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute,override)628 static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override)
629 {
630 	zend_string *parameter;
631 
632 	ZEND_PARSE_PARAMETERS_START(1, 1)
633 		Z_PARAM_STR(parameter)
634 	ZEND_PARSE_PARAMETERS_END();
635 
636 	RETURN_LONG(3);
637 }
638 
ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute,override)639 static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override)
640 {
641 	zend_string *parameter;
642 
643 	ZEND_PARSE_PARAMETERS_START(1, 1)
644 		Z_PARAM_STR(parameter)
645 	ZEND_PARSE_PARAMETERS_END();
646 
647 	RETURN_LONG(4);
648 }
649 
650 PHP_INI_BEGIN()
651 	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)
652 	STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals)
653 	STD_PHP_INI_BOOLEAN("zend_test.observe_opline_in_zendmm", "0", PHP_INI_ALL, OnUpdateZendTestObserveOplineInZendMM, observe_opline_in_zendmm, zend_zend_test_globals, zend_test_globals)
654 PHP_INI_END()
655 
656 void (*old_zend_execute_ex)(zend_execute_data *execute_data);
custom_zend_execute_ex(zend_execute_data * execute_data)657 static void custom_zend_execute_ex(zend_execute_data *execute_data)
658 {
659 	old_zend_execute_ex(execute_data);
660 }
661 
PHP_MINIT_FUNCTION(zend_test)662 PHP_MINIT_FUNCTION(zend_test)
663 {
664 	zend_test_interface = register_class__ZendTestInterface();
665 	zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0);
666 
667 	zend_test_class = register_class__ZendTestClass(zend_test_interface);
668 	zend_test_class->create_object = zend_test_class_new;
669 	zend_test_class->get_static_method = zend_test_class_static_method_get;
670 
671 	zend_test_child_class = register_class__ZendTestChildClass(zend_test_class);
672 
673 	memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
674 	zend_test_class_handlers.get_method = zend_test_class_method_get;
675 
676 	zend_test_trait = register_class__ZendTestTrait();
677 
678 	REGISTER_LONG_CONSTANT("ZEND_TEST_DEPRECATED", 42, CONST_PERSISTENT | CONST_DEPRECATED);
679 
680 	zend_test_attribute = register_class_ZendTestAttribute();
681 	{
682 		zend_internal_attribute *attr = zend_internal_attribute_register(zend_test_attribute, ZEND_ATTRIBUTE_TARGET_ALL);
683 		attr->validator = zend_attribute_validate_zendtestattribute;
684 	}
685 
686 	zend_test_parameter_attribute = register_class_ZendTestParameterAttribute();
687 	zend_internal_attribute_register(zend_test_parameter_attribute, ZEND_ATTRIBUTE_TARGET_PARAMETER);
688 
689 	{
690 		zend_attribute *attr;
691 
692 		attr = zend_add_parameter_attribute(
693 			zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1),
694 			0,
695 			zend_test_parameter_attribute->name,
696 			1
697 		);
698 
699 		ZVAL_PSTRING(&attr->args[0].value, "value1");
700 	}
701 
702 	zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute();
703 
704 	{
705 		zend_attribute *attr;
706 
707 		attr = zend_add_parameter_attribute(
708 			zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "no_override", sizeof("no_override") - 1),
709 			0,
710 			zend_test_parameter_attribute->name,
711 			1
712 		);
713 
714 		ZVAL_PSTRING(&attr->args[0].value, "value2");
715 
716 		attr = zend_add_parameter_attribute(
717 			zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1),
718 			0,
719 			zend_test_parameter_attribute->name,
720 			1
721 		);
722 
723 		ZVAL_PSTRING(&attr->args[0].value, "value3");
724 	}
725 
726 	zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute);
727 
728 	{
729 		zend_attribute *attr;
730 
731 		attr = zend_add_parameter_attribute(
732 			zend_hash_str_find_ptr(&zend_test_child_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1),
733 			0,
734 			zend_test_parameter_attribute->name,
735 			1
736 		);
737 
738 		ZVAL_PSTRING(&attr->args[0].value, "value4");
739 	}
740 
741 	zend_test_ns_foo_class = register_class_ZendTestNS_Foo();
742 	zend_test_ns2_foo_class = register_class_ZendTestNS2_Foo();
743 	zend_test_ns2_ns_foo_class = register_class_ZendTestNS2_ZendSubNS_Foo();
744 
745 	zend_test_unit_enum = register_class_ZendTestUnitEnum();
746 	zend_test_string_enum = register_class_ZendTestStringEnum();
747 
748 	// Loading via dl() not supported with the observer API
749 	if (type != MODULE_TEMPORARY) {
750 		REGISTER_INI_ENTRIES();
751 	} else {
752 		(void)ini_entries;
753 	}
754 
755 	if (ZT_G(replace_zend_execute_ex)) {
756 		old_zend_execute_ex = zend_execute_ex;
757 		zend_execute_ex = custom_zend_execute_ex;
758 	}
759 
760 	if (ZT_G(register_passes)) {
761 		zend_optimizer_register_pass(pass1);
762 		zend_optimizer_register_pass(pass2);
763 	}
764 
765 	zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
766 	zend_test_fiber_init();
767 	zend_test_iterators_init();
768 
769 	return SUCCESS;
770 }
771 
PHP_MSHUTDOWN_FUNCTION(zend_test)772 PHP_MSHUTDOWN_FUNCTION(zend_test)
773 {
774 	if (type != MODULE_TEMPORARY) {
775 		UNREGISTER_INI_ENTRIES();
776 	}
777 
778 	zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
779 
780 	return SUCCESS;
781 }
782 
PHP_RINIT_FUNCTION(zend_test)783 PHP_RINIT_FUNCTION(zend_test)
784 {
785 	zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
786 	return SUCCESS;
787 }
788 
PHP_RSHUTDOWN_FUNCTION(zend_test)789 PHP_RSHUTDOWN_FUNCTION(zend_test)
790 {
791 	zend_ulong objptr;
792 	ZEND_HASH_FOREACH_NUM_KEY(&ZT_G(global_weakmap), objptr) {
793 		zend_weakrefs_hash_del(&ZT_G(global_weakmap), (zend_object *)(uintptr_t)objptr);
794 	} ZEND_HASH_FOREACH_END();
795 	zend_hash_destroy(&ZT_G(global_weakmap));
796 
797 	if (ZT_G(zend_test_heap))  {
798 		free(ZT_G(zend_test_heap));
799 		ZT_G(zend_test_heap) = NULL;
800 		zend_mm_set_heap(ZT_G(zend_orig_heap));
801 	}
802 
803 	return SUCCESS;
804 }
805 
PHP_GINIT_FUNCTION(zend_test)806 static PHP_GINIT_FUNCTION(zend_test)
807 {
808 #if defined(COMPILE_DL_ZEND_TEST) && defined(ZTS)
809 	ZEND_TSRMLS_CACHE_UPDATE();
810 #endif
811 	memset(zend_test_globals, 0, sizeof(*zend_test_globals));
812 }
813 
PHP_MINFO_FUNCTION(zend_test)814 PHP_MINFO_FUNCTION(zend_test)
815 {
816 	php_info_print_table_start();
817 	php_info_print_table_header(2, "zend_test extension", "enabled");
818 	php_info_print_table_end();
819 
820 	DISPLAY_INI_ENTRIES();
821 }
822 
823 zend_module_entry zend_test_module_entry = {
824 	STANDARD_MODULE_HEADER,
825 	"zend_test",
826 	ext_functions,
827 	PHP_MINIT(zend_test),
828 	PHP_MSHUTDOWN(zend_test),
829 	PHP_RINIT(zend_test),
830 	PHP_RSHUTDOWN(zend_test),
831 	PHP_MINFO(zend_test),
832 	PHP_ZEND_TEST_VERSION,
833 	PHP_MODULE_GLOBALS(zend_test),
834 	PHP_GINIT(zend_test),
835 	NULL,
836 	NULL,
837 	STANDARD_MODULE_PROPERTIES_EX
838 };
839 
840 #ifdef COMPILE_DL_ZEND_TEST
841 # ifdef ZTS
842 ZEND_TSRMLS_CACHE_DEFINE()
843 # endif
ZEND_GET_MODULE(zend_test)844 ZEND_GET_MODULE(zend_test)
845 #endif
846 
847 /* The important part here is the ZEND_FASTCALL. */
848 PHP_ZEND_TEST_API int ZEND_FASTCALL bug78270(const char *str, size_t str_len)
849 {
850 	return (int) zend_atol(str, str_len);
851 }
852 
bug79096(void)853 PHP_ZEND_TEST_API struct bug79096 bug79096(void)
854 {
855 	struct bug79096 b;
856 
857 	b.a = 1;
858 	b.b = 1;
859 	return b;
860 }
861 
bug79532(off_t * array,size_t elems)862 PHP_ZEND_TEST_API void bug79532(off_t *array, size_t elems)
863 {
864 	int i;
865 	for (i = 0; i < elems; i++) {
866 		array[i] = i;
867 	}
868 }
869 
870 PHP_ZEND_TEST_API int *(*bug79177_cb)(void);
bug79177(void)871 void bug79177(void)
872 {
873 	bug79177_cb();
874 }
875 
876 typedef struct bug80847_01 {
877 	uint64_t b;
878 	double c;
879 } bug80847_01;
880 typedef struct bug80847_02 {
881 	bug80847_01 a;
882 } bug80847_02;
883 
ffi_bug80847(bug80847_02 s)884 PHP_ZEND_TEST_API bug80847_02 ffi_bug80847(bug80847_02 s) {
885 	s.a.b += 10;
886 	s.a.c -= 10.0;
887 	return s;
888 }
889