xref: /PHP-8.4/ext/zend_test/test.c (revision e643129b)
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 #include "zend_modules.h"
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21 
22 #include "php.h"
23 #include "php_ini.h"
24 #include "ext/standard/info.h"
25 #include "php_test.h"
26 #include "observer.h"
27 #include "fiber.h"
28 #include "iterators.h"
29 #include "object_handlers.h"
30 #include "zend_attributes.h"
31 #include "zend_enum.h"
32 #include "zend_interfaces.h"
33 #include "zend_weakrefs.h"
34 #include "Zend/Optimizer/zend_optimizer.h"
35 #include "Zend/zend_alloc.h"
36 #include "test_arginfo.h"
37 #include "zend_call_stack.h"
38 #include "zend_exceptions.h"
39 #include "zend_mm_custom_handlers.h"
40 
41 // `php.h` sets `NDEBUG` when not `PHP_DEBUG` which will make `assert()` from
42 // assert.h a no-op. In order to have `assert()` working on NDEBUG builds, we
43 // undefine `NDEBUG` and re-include assert.h
44 #undef NDEBUG
45 #include "assert.h"
46 
47 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
48 # include <libxml/globals.h>
49 # include <libxml/parser.h>
50 #endif
51 
52 ZEND_DECLARE_MODULE_GLOBALS(zend_test)
53 
54 static zend_class_entry *zend_test_interface;
55 static zend_class_entry *zend_test_class;
56 static zend_class_entry *zend_test_child_class;
57 static zend_class_entry *zend_attribute_test_class;
58 static zend_class_entry *zend_test_trait;
59 static zend_class_entry *zend_test_attribute;
60 static zend_class_entry *zend_test_repeatable_attribute;
61 static zend_class_entry *zend_test_parameter_attribute;
62 static zend_class_entry *zend_test_property_attribute;
63 static zend_class_entry *zend_test_attribute_with_arguments;
64 static zend_class_entry *zend_test_class_with_method_with_parameter_attribute;
65 static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute;
66 static zend_class_entry *zend_test_class_with_property_attribute;
67 static zend_class_entry *zend_test_forbid_dynamic_call;
68 static zend_class_entry *zend_test_ns_foo_class;
69 static zend_class_entry *zend_test_ns_unlikely_compile_error_class;
70 static zend_class_entry *zend_test_ns_not_unlikely_compile_error_class;
71 static zend_class_entry *zend_test_ns2_foo_class;
72 static zend_class_entry *zend_test_ns2_ns_foo_class;
73 static zend_class_entry *zend_test_unit_enum;
74 static zend_class_entry *zend_test_string_enum;
75 static zend_class_entry *zend_test_int_enum;
76 static zend_class_entry *zend_test_magic_call;
77 static zend_object_handlers zend_test_class_handlers;
78 
79 static int le_throwing_resource;
80 
ZEND_FUNCTION(zend_test_func)81 static ZEND_FUNCTION(zend_test_func)
82 {
83 	RETVAL_STR_COPY(EX(func)->common.function_name);
84 
85 	/* Cleanup trampoline */
86 	ZEND_ASSERT(EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE);
87 	zend_string_release(EX(func)->common.function_name);
88 	zend_free_trampoline(EX(func));
89 	EX(func) = NULL;
90 }
91 
ZEND_FUNCTION(zend_test_array_return)92 static ZEND_FUNCTION(zend_test_array_return)
93 {
94 	ZEND_PARSE_PARAMETERS_NONE();
95 }
96 
ZEND_FUNCTION(zend_test_nullable_array_return)97 static ZEND_FUNCTION(zend_test_nullable_array_return)
98 {
99 	ZEND_PARSE_PARAMETERS_NONE();
100 
101 	RETURN_NULL();
102 }
103 
ZEND_FUNCTION(zend_test_void_return)104 static ZEND_FUNCTION(zend_test_void_return)
105 {
106 	/* dummy */
107 	ZEND_PARSE_PARAMETERS_NONE();
108 }
109 
pass1(zend_script * script,void * context)110 static void pass1(zend_script *script, void *context)
111 {
112 	php_printf("pass1\n");
113 }
114 
pass2(zend_script * script,void * context)115 static void pass2(zend_script *script, void *context)
116 {
117 	php_printf("pass2\n");
118 }
119 
ZEND_FUNCTION(zend_test_deprecated)120 static ZEND_FUNCTION(zend_test_deprecated)
121 {
122 	zval *arg1;
123 
124 	zend_parse_parameters(ZEND_NUM_ARGS(), "|z", &arg1);
125 }
126 
ZEND_FUNCTION(zend_test_deprecated_attr)127 static ZEND_FUNCTION(zend_test_deprecated_attr)
128 {
129 	ZEND_PARSE_PARAMETERS_NONE();
130 }
131 
132 /* Create a string without terminating null byte. Must be terminated with
133  * zend_terminate_string() before destruction, otherwise a warning is issued
134  * in debug builds. */
ZEND_FUNCTION(zend_create_unterminated_string)135 static ZEND_FUNCTION(zend_create_unterminated_string)
136 {
137 	zend_string *str, *res;
138 
139 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
140 		RETURN_THROWS();
141 	}
142 
143 	res = zend_string_alloc(ZSTR_LEN(str), 0);
144 	memcpy(ZSTR_VAL(res), ZSTR_VAL(str), ZSTR_LEN(str));
145 	/* No trailing null byte */
146 
147 	RETURN_STR(res);
148 }
149 
150 /* Enforce terminate null byte on string. This avoids a warning in debug builds. */
ZEND_FUNCTION(zend_terminate_string)151 static ZEND_FUNCTION(zend_terminate_string)
152 {
153 	zend_string *str;
154 
155 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
156 		RETURN_THROWS();
157 	}
158 
159 	ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
160 }
161 
162 /* Cause an intentional memory leak, for testing/debugging purposes */
ZEND_FUNCTION(zend_leak_bytes)163 static ZEND_FUNCTION(zend_leak_bytes)
164 {
165 	zend_long leakbytes = 3;
166 
167 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &leakbytes) == FAILURE) {
168 		RETURN_THROWS();
169 	}
170 
171 	emalloc(leakbytes);
172 }
173 
174 /* Leak a refcounted variable */
ZEND_FUNCTION(zend_leak_variable)175 static ZEND_FUNCTION(zend_leak_variable)
176 {
177 	zval *zv;
178 
179 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
180 		RETURN_THROWS();
181 	}
182 
183 	if (!Z_REFCOUNTED_P(zv)) {
184 		zend_error(E_WARNING, "Cannot leak variable that is not refcounted");
185 		return;
186 	}
187 
188 	Z_ADDREF_P(zv);
189 }
190 
191 /* Tests Z_PARAM_OBJ_OR_STR */
ZEND_FUNCTION(zend_string_or_object)192 static ZEND_FUNCTION(zend_string_or_object)
193 {
194 	zend_string *str;
195 	zend_object *object;
196 
197 	ZEND_PARSE_PARAMETERS_START(1, 1)
198 		Z_PARAM_OBJ_OR_STR(object, str)
199 	ZEND_PARSE_PARAMETERS_END();
200 
201 	if (str) {
202 		RETURN_STR_COPY(str);
203 	} else {
204 		RETURN_OBJ_COPY(object);
205 	}
206 }
207 
208 /* Tests Z_PARAM_OBJ_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_object_or_null)209 static ZEND_FUNCTION(zend_string_or_object_or_null)
210 {
211 	zend_string *str;
212 	zend_object *object;
213 
214 	ZEND_PARSE_PARAMETERS_START(1, 1)
215 		Z_PARAM_OBJ_OR_STR_OR_NULL(object, str)
216 	ZEND_PARSE_PARAMETERS_END();
217 
218 	if (str) {
219 		RETURN_STR_COPY(str);
220 	} else if (object) {
221 		RETURN_OBJ_COPY(object);
222 	} else {
223 		RETURN_NULL();
224 	}
225 }
226 
227 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR */
ZEND_FUNCTION(zend_string_or_stdclass)228 static ZEND_FUNCTION(zend_string_or_stdclass)
229 {
230 	zend_string *str;
231 	zend_object *object;
232 
233 	ZEND_PARSE_PARAMETERS_START(1, 1)
234 		Z_PARAM_OBJ_OF_CLASS_OR_STR(object, zend_standard_class_def, str)
235 	ZEND_PARSE_PARAMETERS_END();
236 
237 	if (str) {
238 		RETURN_STR_COPY(str);
239 	} else {
240 		RETURN_OBJ_COPY(object);
241 	}
242 }
243 
ZEND_FUNCTION(zend_test_compile_string)244 static ZEND_FUNCTION(zend_test_compile_string)
245 {
246 	zend_string *source_string = NULL;
247 	zend_string *filename = NULL;
248 	zend_long position = ZEND_COMPILE_POSITION_AT_OPEN_TAG;
249 
250 	ZEND_PARSE_PARAMETERS_START(3, 3)
251 		Z_PARAM_STR(source_string)
252 		Z_PARAM_STR(filename)
253 		Z_PARAM_LONG(position)
254 	ZEND_PARSE_PARAMETERS_END();
255 
256 	zend_op_array *op_array = NULL;
257 
258 	op_array = compile_string(source_string, ZSTR_VAL(filename), position);
259 
260 	if (op_array) {
261 		zval retval;
262 
263 		zend_try {
264 			ZVAL_UNDEF(&retval);
265 			zend_execute(op_array, &retval);
266 		} zend_catch {
267 			destroy_op_array(op_array);
268 			efree_size(op_array, sizeof(zend_op_array));
269 			zend_bailout();
270 		} zend_end_try();
271 
272 		destroy_op_array(op_array);
273 		efree_size(op_array, sizeof(zend_op_array));
274 	}
275 
276 	return;
277 }
278 
279 /* Tests Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_string_or_stdclass_or_null)280 static ZEND_FUNCTION(zend_string_or_stdclass_or_null)
281 {
282 	zend_string *str;
283 	zend_object *object;
284 
285 	ZEND_PARSE_PARAMETERS_START(1, 1)
286 		Z_PARAM_OBJ_OF_CLASS_OR_STR_OR_NULL(object, zend_standard_class_def, str)
287 	ZEND_PARSE_PARAMETERS_END();
288 
289 	if (str) {
290 		RETURN_STR_COPY(str);
291 	} else if (object) {
292 		RETURN_OBJ_COPY(object);
293 	} else {
294 		RETURN_NULL();
295 	}
296 }
297 
298 /* Tests Z_PARAM_NUMBER_OR_STR */
ZEND_FUNCTION(zend_number_or_string)299 static ZEND_FUNCTION(zend_number_or_string)
300 {
301 	zval *input;
302 
303 	ZEND_PARSE_PARAMETERS_START(1, 1)
304 		Z_PARAM_NUMBER_OR_STR(input)
305 	ZEND_PARSE_PARAMETERS_END();
306 
307 	switch (Z_TYPE_P(input)) {
308 		case IS_LONG:
309 			RETURN_LONG(Z_LVAL_P(input));
310 		case IS_DOUBLE:
311 			RETURN_DOUBLE(Z_DVAL_P(input));
312 		case IS_STRING:
313 			RETURN_STR_COPY(Z_STR_P(input));
314 		EMPTY_SWITCH_DEFAULT_CASE();
315 	}
316 }
317 
318 /* Tests Z_PARAM_NUMBER_OR_STR_OR_NULL */
ZEND_FUNCTION(zend_number_or_string_or_null)319 static ZEND_FUNCTION(zend_number_or_string_or_null)
320 {
321 	zval *input;
322 
323 	ZEND_PARSE_PARAMETERS_START(1, 1)
324 		Z_PARAM_NUMBER_OR_STR_OR_NULL(input)
325 	ZEND_PARSE_PARAMETERS_END();
326 
327 	if (!input) {
328 		RETURN_NULL();
329 	}
330 
331 	switch (Z_TYPE_P(input)) {
332 		case IS_LONG:
333 			RETURN_LONG(Z_LVAL_P(input));
334 		case IS_DOUBLE:
335 			RETURN_DOUBLE(Z_DVAL_P(input));
336 		case IS_STRING:
337 			RETURN_STR_COPY(Z_STR_P(input));
338 		EMPTY_SWITCH_DEFAULT_CASE();
339 	}
340 }
341 
ZEND_FUNCTION(zend_weakmap_attach)342 static ZEND_FUNCTION(zend_weakmap_attach)
343 {
344 	zval *value;
345 	zend_object *obj;
346 
347 	ZEND_PARSE_PARAMETERS_START(2, 2)
348 			Z_PARAM_OBJ(obj)
349 			Z_PARAM_ZVAL(value)
350 	ZEND_PARSE_PARAMETERS_END();
351 
352 	if (zend_weakrefs_hash_add(&ZT_G(global_weakmap), obj, value)) {
353 		Z_TRY_ADDREF_P(value);
354 		RETURN_TRUE;
355 	}
356 	RETURN_FALSE;
357 }
358 
ZEND_FUNCTION(zend_weakmap_remove)359 static ZEND_FUNCTION(zend_weakmap_remove)
360 {
361 	zend_object *obj;
362 
363 	ZEND_PARSE_PARAMETERS_START(1, 1)
364 			Z_PARAM_OBJ(obj)
365 	ZEND_PARSE_PARAMETERS_END();
366 
367 	RETURN_BOOL(zend_weakrefs_hash_del(&ZT_G(global_weakmap), obj) == SUCCESS);
368 }
369 
ZEND_FUNCTION(zend_weakmap_dump)370 static ZEND_FUNCTION(zend_weakmap_dump)
371 {
372 	ZEND_PARSE_PARAMETERS_NONE();
373 	RETURN_ARR(zend_array_dup(&ZT_G(global_weakmap)));
374 }
375 
ZEND_FUNCTION(zend_get_current_func_name)376 static ZEND_FUNCTION(zend_get_current_func_name)
377 {
378     ZEND_PARSE_PARAMETERS_NONE();
379 
380     zend_string *function_name = get_function_or_method_name(EG(current_execute_data)->prev_execute_data->func);
381 
382     RETURN_STR(function_name);
383 }
384 
385 #if defined(HAVE_LIBXML) && !defined(PHP_WIN32)
ZEND_FUNCTION(zend_test_override_libxml_global_state)386 static ZEND_FUNCTION(zend_test_override_libxml_global_state)
387 {
388 	ZEND_PARSE_PARAMETERS_NONE();
389 
390 	ZEND_DIAGNOSTIC_IGNORED_START("-Wdeprecated-declarations")
391 	xmlLoadExtDtdDefaultValue = 1;
392 	xmlDoValidityCheckingDefaultValue = 1;
393 	(void) xmlPedanticParserDefault(1);
394 	(void) xmlSubstituteEntitiesDefault(1);
395 	(void) xmlLineNumbersDefault(1);
396 	(void) xmlKeepBlanksDefault(0);
397 	ZEND_DIAGNOSTIC_IGNORED_END
398 }
399 #endif
400 
401 /* TESTS Z_PARAM_ITERABLE and Z_PARAM_ITERABLE_OR_NULL */
ZEND_FUNCTION(zend_iterable)402 static ZEND_FUNCTION(zend_iterable)
403 {
404 	zval *arg1, *arg2;
405 
406 	ZEND_PARSE_PARAMETERS_START(1, 2)
407 		Z_PARAM_ITERABLE(arg1)
408 		Z_PARAM_OPTIONAL
409 		Z_PARAM_ITERABLE_OR_NULL(arg2)
410 	ZEND_PARSE_PARAMETERS_END();
411 }
412 
ZEND_FUNCTION(zend_iterable_legacy)413 static ZEND_FUNCTION(zend_iterable_legacy)
414 {
415 	zval *arg1, *arg2;
416 
417 	ZEND_PARSE_PARAMETERS_START(1, 2)
418 		Z_PARAM_ITERABLE(arg1)
419 		Z_PARAM_OPTIONAL
420 		Z_PARAM_ITERABLE_OR_NULL(arg2)
421 	ZEND_PARSE_PARAMETERS_END();
422 
423 	RETURN_COPY(arg1);
424 }
425 
426 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_iterable_legacy, 0, 1, IS_ITERABLE, 0)
427 	ZEND_ARG_TYPE_INFO(0, arg1, IS_ITERABLE, 0)
428 	ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, arg2, IS_ITERABLE, 1, "null")
429 ZEND_END_ARG_INFO()
430 
431 static const zend_function_entry ext_function_legacy[] = {
432 	ZEND_FE(zend_iterable_legacy, arginfo_zend_iterable_legacy)
433 	ZEND_FE_END
434 };
435 
436 /* Call a method on a class or object using zend_call_method() */
ZEND_FUNCTION(zend_call_method)437 static ZEND_FUNCTION(zend_call_method)
438 {
439 	zend_string *method_name;
440 	zval *class_or_object, *arg1 = NULL, *arg2 = NULL;
441 	zend_object *obj = NULL;
442 	zend_class_entry *ce = NULL;
443 	int argc = ZEND_NUM_ARGS();
444 
445 	ZEND_PARSE_PARAMETERS_START(2, 4)
446 		Z_PARAM_ZVAL(class_or_object)
447 		Z_PARAM_STR(method_name)
448 		Z_PARAM_OPTIONAL
449 		Z_PARAM_ZVAL(arg1)
450 		Z_PARAM_ZVAL(arg2)
451 	ZEND_PARSE_PARAMETERS_END();
452 
453 	if (Z_TYPE_P(class_or_object) == IS_OBJECT) {
454 		obj = Z_OBJ_P(class_or_object);
455 		ce = obj->ce;
456 	} else if (Z_TYPE_P(class_or_object) == IS_STRING) {
457 		ce = zend_lookup_class(Z_STR_P(class_or_object));
458 		if (!ce) {
459 			zend_error_noreturn(E_ERROR, "Unknown class '%s'", Z_STRVAL_P(class_or_object));
460 			return;
461 		}
462 	} else {
463 		zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(class_or_object));
464 		return;
465 	}
466 
467 	ZEND_ASSERT((argc >= 2) && (argc <= 4));
468 	zend_call_method(obj, ce, NULL, ZSTR_VAL(method_name), ZSTR_LEN(method_name), return_value, argc - 2, arg1, arg2);
469 }
470 
471 /* Instantiate a class and run the constructor via object_init_with_constructor */
ZEND_FUNCTION(zend_object_init_with_constructor)472 static ZEND_FUNCTION(zend_object_init_with_constructor)
473 {
474 	zend_class_entry *ce = NULL;
475 	zval *args;
476 	uint32_t num_args;
477 	HashTable *named_args;
478 
479 	ZEND_PARSE_PARAMETERS_START(1, -1)
480 		Z_PARAM_CLASS(ce)
481 		Z_PARAM_VARIADIC_WITH_NAMED(args, num_args, named_args)
482 	ZEND_PARSE_PARAMETERS_END();
483 
484 	zval obj;
485 	/* We don't use return_value directly to check for memory leaks of the API on failure */
486 	zend_result status = object_init_with_constructor(&obj, ce, num_args, args, named_args);
487 	if (status == FAILURE) {
488 		RETURN_THROWS();
489 	}
490 	ZEND_ASSERT(!EG(exception));
491 	ZVAL_COPY_VALUE(return_value, &obj);
492 }
493 
ZEND_FUNCTION(zend_get_unit_enum)494 static ZEND_FUNCTION(zend_get_unit_enum)
495 {
496 	ZEND_PARSE_PARAMETERS_NONE();
497 
498 	RETURN_OBJ_COPY(zend_enum_get_case_cstr(zend_test_unit_enum, "Foo"));
499 }
500 
ZEND_FUNCTION(zend_test_zend_ini_parse_quantity)501 static ZEND_FUNCTION(zend_test_zend_ini_parse_quantity)
502 {
503 	zend_string *str;
504 	zend_string *errstr;
505 
506 	ZEND_PARSE_PARAMETERS_START(1, 1)
507 		Z_PARAM_STR(str)
508 	ZEND_PARSE_PARAMETERS_END();
509 
510 	RETVAL_LONG(zend_ini_parse_quantity(str, &errstr));
511 
512 	if (errstr) {
513 		zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
514 		zend_string_release(errstr);
515 	}
516 }
517 
ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity)518 static ZEND_FUNCTION(zend_test_zend_ini_parse_uquantity)
519 {
520 	zend_string *str;
521 	zend_string *errstr;
522 
523 	ZEND_PARSE_PARAMETERS_START(1, 1)
524 		Z_PARAM_STR(str)
525 	ZEND_PARSE_PARAMETERS_END();
526 
527 	RETVAL_LONG((zend_long)zend_ini_parse_uquantity(str, &errstr));
528 
529 	if (errstr) {
530 		zend_error(E_WARNING, "%s", ZSTR_VAL(errstr));
531 		zend_string_release(errstr);
532 	}
533 }
534 
ZEND_FUNCTION(zend_test_zend_ini_str)535 static ZEND_FUNCTION(zend_test_zend_ini_str)
536 {
537 	ZEND_PARSE_PARAMETERS_NONE();
538 
539 	RETURN_STR(ZT_G(str_test));
540 }
541 
ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8)542 static ZEND_FUNCTION(zend_test_is_string_marked_as_valid_utf8)
543 {
544 	zend_string *str;
545 
546 	ZEND_PARSE_PARAMETERS_START(1, 1)
547 		Z_PARAM_STR(str)
548 	ZEND_PARSE_PARAMETERS_END();
549 
550 	RETURN_BOOL(ZSTR_IS_VALID_UTF8(str));
551 }
552 
ZEND_FUNCTION(ZendTestNS2_namespaced_func)553 static ZEND_FUNCTION(ZendTestNS2_namespaced_func)
554 {
555 	ZEND_PARSE_PARAMETERS_NONE();
556 	RETURN_TRUE;
557 }
558 
ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func)559 static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func)
560 {
561 	ZEND_PARSE_PARAMETERS_NONE();
562 }
563 
ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func)564 static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func)
565 {
566 	ZEND_PARSE_PARAMETERS_NONE();
567 	RETURN_TRUE;
568 }
569 
ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_deprecated_func)570 static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_deprecated_func)
571 {
572 	ZEND_PARSE_PARAMETERS_NONE();
573 }
574 
ZEND_FUNCTION(zend_test_parameter_with_attribute)575 static ZEND_FUNCTION(zend_test_parameter_with_attribute)
576 {
577 	zend_string *parameter;
578 
579 	ZEND_PARSE_PARAMETERS_START(1, 1)
580 		Z_PARAM_STR(parameter)
581 	ZEND_PARSE_PARAMETERS_END();
582 
583 	RETURN_LONG(1);
584 }
585 
ZEND_FUNCTION(zend_test_attribute_with_named_argument)586 static ZEND_FUNCTION(zend_test_attribute_with_named_argument)
587 {
588 	ZEND_PARSE_PARAMETERS_NONE();
589 }
590 
591 #ifdef ZEND_CHECK_STACK_LIMIT
ZEND_FUNCTION(zend_test_zend_call_stack_get)592 static ZEND_FUNCTION(zend_test_zend_call_stack_get)
593 {
594 	zend_call_stack stack;
595 
596 	ZEND_PARSE_PARAMETERS_NONE();
597 
598 	if (zend_call_stack_get(&stack)) {
599 		zend_string *str;
600 
601 		array_init(return_value);
602 
603 		str = strpprintf(0, "%p", stack.base);
604 		add_assoc_str(return_value, "base", str);
605 
606 		str = strpprintf(0, "0x%zx", stack.max_size);
607 		add_assoc_str(return_value, "max_size", str);
608 
609 		str = strpprintf(0, "%p", zend_call_stack_position());
610 		add_assoc_str(return_value, "position", str);
611 
612 		str = strpprintf(0, "%p", EG(stack_limit));
613 		add_assoc_str(return_value, "EG(stack_limit)", str);
614 
615 		return;
616 	}
617 
618 	RETURN_NULL();
619 }
620 
621 zend_long (*volatile zend_call_stack_use_all_fun)(void *limit);
622 
zend_call_stack_use_all(void * limit)623 static zend_long zend_call_stack_use_all(void *limit)
624 {
625 	if (zend_call_stack_overflowed(limit)) {
626 		return 1;
627 	}
628 
629 	return 1 + zend_call_stack_use_all_fun(limit);
630 }
631 
ZEND_FUNCTION(zend_test_zend_call_stack_use_all)632 static ZEND_FUNCTION(zend_test_zend_call_stack_use_all)
633 {
634 	zend_call_stack stack;
635 
636 	ZEND_PARSE_PARAMETERS_NONE();
637 
638 	if (!zend_call_stack_get(&stack)) {
639 		return;
640 	}
641 
642 	zend_call_stack_use_all_fun = zend_call_stack_use_all;
643 
644 	void *limit = zend_call_stack_limit(stack.base, stack.max_size, 4096);
645 
646 	RETURN_LONG(zend_call_stack_use_all(limit));
647 }
648 #endif /* ZEND_CHECK_STACK_LIMIT */
649 
ZEND_FUNCTION(zend_get_map_ptr_last)650 static ZEND_FUNCTION(zend_get_map_ptr_last)
651 {
652 	ZEND_PARSE_PARAMETERS_NONE();
653 	RETURN_LONG(CG(map_ptr_last));
654 }
655 
ZEND_FUNCTION(zend_test_crash)656 static ZEND_FUNCTION(zend_test_crash)
657 {
658 	zend_string *message = NULL;
659 
660 	ZEND_PARSE_PARAMETERS_START(0, 1)
661 		Z_PARAM_OPTIONAL
662 		Z_PARAM_STR_OR_NULL(message)
663 	ZEND_PARSE_PARAMETERS_END();
664 
665 	if (message) {
666 		php_printf("%s", ZSTR_VAL(message));
667 	}
668 
669 	char *invalid = (char *) 1;
670 	php_printf("%s", invalid);
671 }
672 
has_opline(zend_execute_data * execute_data)673 static bool has_opline(zend_execute_data *execute_data)
674 {
675 	return execute_data
676 		&& execute_data->func
677 		&& ZEND_USER_CODE(execute_data->func->type)
678 		&& execute_data->opline
679 	;
680 }
681 
zend_test_custom_malloc(size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)682 void * zend_test_custom_malloc(size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
683 {
684 	if (has_opline(EG(current_execute_data))) {
685 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
686 	}
687 	return _zend_mm_alloc(ZT_G(zend_orig_heap), len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
688 }
689 
zend_test_custom_free(void * ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)690 void zend_test_custom_free(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
691 {
692 	if (has_opline(EG(current_execute_data))) {
693 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
694 	}
695 	_zend_mm_free(ZT_G(zend_orig_heap), ptr ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
696 }
697 
zend_test_custom_realloc(void * ptr,size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)698 void * zend_test_custom_realloc(void * ptr, size_t len ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
699 {
700 	if (has_opline(EG(current_execute_data))) {
701 		assert(EG(current_execute_data)->opline->lineno != (uint32_t)-1);
702 	}
703 	return _zend_mm_realloc(ZT_G(zend_orig_heap), ptr, len ZEND_FILE_LINE_EMPTY_CC ZEND_FILE_LINE_EMPTY_CC);
704 }
705 
PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)706 static PHP_INI_MH(OnUpdateZendTestObserveOplineInZendMM)
707 {
708 	if (new_value == NULL) {
709 		return FAILURE;
710 	}
711 
712 	int int_value = zend_ini_parse_bool(new_value);
713 
714 	if (int_value == 1) {
715 		// `zend_mm_heap` is a private struct, so we have not way to find the
716 		// actual size, but 4096 bytes should be enough
717 		ZT_G(zend_test_heap) = malloc(4096);
718 		memset(ZT_G(zend_test_heap), 0, 4096);
719 		zend_mm_set_custom_handlers(
720 			ZT_G(zend_test_heap),
721 			zend_test_custom_malloc,
722 			zend_test_custom_free,
723 			zend_test_custom_realloc
724 		);
725 		ZT_G(zend_orig_heap) = zend_mm_get_heap();
726 		zend_mm_set_heap(ZT_G(zend_test_heap));
727 	} else if (ZT_G(zend_test_heap))  {
728 		free(ZT_G(zend_test_heap));
729 		ZT_G(zend_test_heap) = NULL;
730 		zend_mm_set_heap(ZT_G(zend_orig_heap));
731 	}
732 	return OnUpdateBool(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
733 }
734 
ZEND_FUNCTION(zend_test_fill_packed_array)735 static ZEND_FUNCTION(zend_test_fill_packed_array)
736 {
737 	HashTable *parameter;
738 
739 	ZEND_PARSE_PARAMETERS_START(1, 1)
740 		Z_PARAM_ARRAY_HT_EX(parameter, 0, 1)
741 	ZEND_PARSE_PARAMETERS_END();
742 
743 	if (!HT_IS_PACKED(parameter)) {
744 		zend_argument_value_error(1, "must be a packed array");
745 		RETURN_THROWS();
746 	}
747 
748 	zend_hash_extend(parameter, parameter->nNumUsed + 10, true);
749 	ZEND_HASH_FILL_PACKED(parameter) {
750 		for (int i = 0; i < 10; i++) {
751 			zval value;
752 			ZVAL_LONG(&value, i);
753 			ZEND_HASH_FILL_ADD(&value);
754 		}
755 	} ZEND_HASH_FILL_END();
756 }
757 
ZEND_FUNCTION(get_open_basedir)758 static ZEND_FUNCTION(get_open_basedir)
759 {
760 	ZEND_PARSE_PARAMETERS_NONE();
761 	if (PG(open_basedir)) {
762 		RETURN_STRING(PG(open_basedir));
763 	} else {
764 		RETURN_NULL();
765 	}
766 }
767 
ZEND_FUNCTION(zend_test_is_pcre_bundled)768 static ZEND_FUNCTION(zend_test_is_pcre_bundled)
769 {
770 	ZEND_PARSE_PARAMETERS_NONE();
771 #ifdef HAVE_BUNDLED_PCRE
772 	RETURN_TRUE;
773 #else
774 	RETURN_FALSE;
775 #endif
776 }
777 
778 #ifdef PHP_WIN32
ZEND_FUNCTION(zend_test_set_fmode)779 static ZEND_FUNCTION(zend_test_set_fmode)
780 {
781 	bool binary;
782 	ZEND_PARSE_PARAMETERS_START(1, 1)
783 		Z_PARAM_BOOL(binary)
784 	ZEND_PARSE_PARAMETERS_END();
785 
786 	_fmode = binary ? _O_BINARY : _O_TEXT;
787 }
788 #endif
789 
ZEND_FUNCTION(zend_test_cast_fread)790 static ZEND_FUNCTION(zend_test_cast_fread)
791 {
792 	zval *stream_zv;
793 	php_stream *stream;
794 	FILE *fp;
795 
796 	ZEND_PARSE_PARAMETERS_START(1, 1)
797 		Z_PARAM_RESOURCE(stream_zv);
798 	ZEND_PARSE_PARAMETERS_END();
799 
800 	php_stream_from_zval(stream, stream_zv);
801 
802 	if (php_stream_cast(stream, PHP_STREAM_AS_STDIO, (void *) &fp, REPORT_ERRORS) == FAILURE) {
803 		return;
804 	}
805 
806 	size_t size = 10240; /* Must be large enough to trigger the issue */
807 	char *buf = malloc(size);
808 	bool bail = false;
809 	zend_try {
810 		(void) !fread(buf, 1, size, fp);
811 	} zend_catch {
812 		bail = true;
813 	} zend_end_try();
814 
815 	free(buf);
816 
817 	if (bail) {
818 		zend_bailout();
819 	}
820 }
821 
ZEND_FUNCTION(zend_test_is_zend_ptr)822 static ZEND_FUNCTION(zend_test_is_zend_ptr)
823 {
824 	zend_long addr;
825 
826 	ZEND_PARSE_PARAMETERS_START(1, 1)
827 		Z_PARAM_LONG(addr);
828 	ZEND_PARSE_PARAMETERS_END();
829 
830 	RETURN_BOOL(is_zend_ptr((void*)addr));
831 }
832 
ZEND_FUNCTION(zend_test_log_err_debug)833 static ZEND_FUNCTION(zend_test_log_err_debug)
834 {
835 	zend_string *str;
836 
837 	ZEND_PARSE_PARAMETERS_START(1, 1)
838 		Z_PARAM_STR(str);
839 	ZEND_PARSE_PARAMETERS_END();
840 
841 	php_log_err_with_severity(ZSTR_VAL(str), LOG_DEBUG);
842 }
843 
zend_test_class_new(zend_class_entry * class_type)844 static zend_object *zend_test_class_new(zend_class_entry *class_type)
845 {
846 	zend_object *obj = zend_objects_new(class_type);
847 	object_properties_init(obj, class_type);
848 	obj->handlers = &zend_test_class_handlers;
849 	return obj;
850 }
851 
zend_test_class_method_get(zend_object ** object,zend_string * name,const zval * key)852 static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key)
853 {
854 	if (zend_string_equals_literal_ci(name, "test")) {
855 		zend_internal_function *fptr;
856 
857 		if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
858 			fptr = (zend_internal_function *) &EG(trampoline);
859 		} else {
860 			fptr = emalloc(sizeof(zend_internal_function));
861 	    }
862 		memset(fptr, 0, sizeof(zend_internal_function));
863 		fptr->type = ZEND_INTERNAL_FUNCTION;
864 		fptr->num_args = 0;
865 		fptr->scope = (*object)->ce;
866 		fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
867 		fptr->function_name = zend_string_copy(name);
868 		fptr->handler = ZEND_FN(zend_test_func);
869 		fptr->doc_comment = NULL;
870 
871 		return (zend_function*)fptr;
872 	}
873 	return zend_std_get_method(object, name, key);
874 }
875 
zend_test_class_static_method_get(zend_class_entry * ce,zend_string * name)876 static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name)
877 {
878 	if (zend_string_equals_literal_ci(name, "test")) {
879 		zend_internal_function *fptr;
880 
881 		if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
882 			fptr = (zend_internal_function *) &EG(trampoline);
883 		} else {
884 			fptr = emalloc(sizeof(zend_internal_function));
885 		}
886 		memset(fptr, 0, sizeof(zend_internal_function));
887 		fptr->type = ZEND_INTERNAL_FUNCTION;
888 		fptr->num_args = 0;
889 		fptr->scope = ce;
890 		fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC;
891 		fptr->function_name = zend_string_copy(name);
892 		fptr->handler = ZEND_FN(zend_test_func);
893 		fptr->doc_comment = NULL;
894 
895 		return (zend_function*)fptr;
896 	}
897 	return zend_std_get_static_method(ce, name, NULL);
898 }
899 
zend_attribute_validate_zendtestattribute(zend_attribute * attr,uint32_t target,zend_class_entry * scope)900 void zend_attribute_validate_zendtestattribute(zend_attribute *attr, uint32_t target, zend_class_entry *scope)
901 {
902 	if (target != ZEND_ATTRIBUTE_TARGET_CLASS) {
903 		zend_error(E_COMPILE_ERROR, "Only classes can be marked with #[ZendTestAttribute]");
904 	}
905 }
906 
ZEND_METHOD(_ZendTestClass,__toString)907 static ZEND_METHOD(_ZendTestClass, __toString)
908 {
909 	ZEND_PARSE_PARAMETERS_NONE();
910 	RETURN_EMPTY_STRING();
911 }
912 
913 /* Internal function returns bool, we return int. */
ZEND_METHOD(_ZendTestClass,is_object)914 static ZEND_METHOD(_ZendTestClass, is_object)
915 {
916 	ZEND_PARSE_PARAMETERS_NONE();
917 	RETURN_LONG(42);
918 }
919 
ZEND_METHOD(_ZendTestClass,returnsStatic)920 static ZEND_METHOD(_ZendTestClass, returnsStatic) {
921 	ZEND_PARSE_PARAMETERS_NONE();
922 	object_init_ex(return_value, zend_get_called_scope(execute_data));
923 }
924 
ZEND_METHOD(_ZendTestClass,returnsThrowable)925 static ZEND_METHOD(_ZendTestClass, returnsThrowable)
926 {
927 	ZEND_PARSE_PARAMETERS_NONE();
928 	zend_throw_error(NULL, "Dummy");
929 }
930 
ZEND_METHOD(_ZendTestClass,variadicTest)931 static ZEND_METHOD(_ZendTestClass, variadicTest) {
932 	int      argc, i;
933 	zval    *args = NULL;
934 
935 	ZEND_PARSE_PARAMETERS_START(0, -1)
936 		Z_PARAM_VARIADIC('*', args, argc)
937 	ZEND_PARSE_PARAMETERS_END();
938 
939 	for (i = 0; i < argc; i++) {
940 		zval *arg = args + i;
941 
942 		if (Z_TYPE_P(arg) == IS_STRING) {
943 			continue;
944 		}
945 		if (Z_TYPE_P(arg) == IS_OBJECT && instanceof_function(Z_OBJ_P(arg)->ce, zend_ce_iterator)) {
946 			continue;
947 		}
948 
949 		zend_argument_type_error(i + 1, "must be of class Iterator or a string, %s given", zend_zval_type_name(arg));
950 		RETURN_THROWS();
951 	}
952 
953 	object_init_ex(return_value, zend_get_called_scope(execute_data));
954 }
955 
ZEND_METHOD(_ZendTestChildClass,returnsThrowable)956 static ZEND_METHOD(_ZendTestChildClass, returnsThrowable)
957 {
958 	ZEND_PARSE_PARAMETERS_NONE();
959 	zend_throw_error(NULL, "Dummy");
960 }
961 
ZEND_METHOD(ZendAttributeTest,testMethod)962 static ZEND_METHOD(ZendAttributeTest, testMethod)
963 {
964 	ZEND_PARSE_PARAMETERS_NONE();
965 	RETURN_TRUE;
966 }
967 
ZEND_METHOD(_ZendTestTrait,testMethod)968 static ZEND_METHOD(_ZendTestTrait, testMethod)
969 {
970 	ZEND_PARSE_PARAMETERS_NONE();
971 	RETURN_TRUE;
972 }
973 
ZEND_METHOD(ZendTestNS_Foo,method)974 static ZEND_METHOD(ZendTestNS_Foo, method)
975 {
976 	ZEND_PARSE_PARAMETERS_NONE();
977 
978 	RETURN_LONG(0);
979 }
980 
ZEND_METHOD(ZendTestNS_UnlikelyCompileError,method)981 static ZEND_METHOD(ZendTestNS_UnlikelyCompileError, method)
982 {
983 	ZEND_PARSE_PARAMETERS_NONE();
984 
985 	RETURN_NULL();
986 }
987 
ZEND_METHOD(ZendTestNS_NotUnlikelyCompileError,method)988 static ZEND_METHOD(ZendTestNS_NotUnlikelyCompileError, method)
989 {
990 	ZEND_PARSE_PARAMETERS_NONE();
991 
992 	RETURN_NULL();
993 }
994 
ZEND_METHOD(ZendTestNS2_Foo,method)995 static ZEND_METHOD(ZendTestNS2_Foo, method)
996 {
997 	ZEND_PARSE_PARAMETERS_NONE();
998 }
999 
ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo,method)1000 static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method)
1001 {
1002 	ZEND_PARSE_PARAMETERS_NONE();
1003 }
1004 
ZEND_METHOD(ZendTestParameterAttribute,__construct)1005 static ZEND_METHOD(ZendTestParameterAttribute, __construct)
1006 {
1007 	zend_string *parameter;
1008 
1009 	ZEND_PARSE_PARAMETERS_START(1, 1)
1010 		Z_PARAM_STR(parameter)
1011 	ZEND_PARSE_PARAMETERS_END();
1012 
1013 	ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter);
1014 }
1015 
ZEND_METHOD(ZendTestPropertyAttribute,__construct)1016 static ZEND_METHOD(ZendTestPropertyAttribute, __construct)
1017 {
1018 	zend_string *parameter;
1019 
1020 	ZEND_PARSE_PARAMETERS_START(1, 1)
1021 		Z_PARAM_STR(parameter)
1022 	ZEND_PARSE_PARAMETERS_END();
1023 
1024 	ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter);
1025 }
1026 
ZEND_METHOD(ZendTestAttributeWithArguments,__construct)1027 static ZEND_METHOD(ZendTestAttributeWithArguments, __construct)
1028 {
1029 	zval *arg;
1030 
1031 	ZEND_PARSE_PARAMETERS_START(1, 1)
1032 		Z_PARAM_ZVAL(arg)
1033 	ZEND_PARSE_PARAMETERS_END();
1034 
1035 	zend_string *property_name = zend_string_init("arg", strlen("arg"), 0);
1036 	zend_update_property_ex(zend_test_attribute_with_arguments, Z_OBJ_P(ZEND_THIS), property_name, arg);
1037 	zend_string_release(property_name);
1038 }
1039 
ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute,no_override)1040 static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override)
1041 {
1042 	zend_string *parameter;
1043 
1044 	ZEND_PARSE_PARAMETERS_START(1, 1)
1045 		Z_PARAM_STR(parameter)
1046 	ZEND_PARSE_PARAMETERS_END();
1047 
1048 	RETURN_LONG(2);
1049 }
1050 
ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute,override)1051 static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override)
1052 {
1053 	zend_string *parameter;
1054 
1055 	ZEND_PARSE_PARAMETERS_START(1, 1)
1056 		Z_PARAM_STR(parameter)
1057 	ZEND_PARSE_PARAMETERS_END();
1058 
1059 	RETURN_LONG(3);
1060 }
1061 
ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute,override)1062 static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override)
1063 {
1064 	zend_string *parameter;
1065 
1066 	ZEND_PARSE_PARAMETERS_START(1, 1)
1067 		Z_PARAM_STR(parameter)
1068 	ZEND_PARSE_PARAMETERS_END();
1069 
1070 	RETURN_LONG(4);
1071 }
1072 
ZEND_METHOD(ZendTestForbidDynamicCall,call)1073 static ZEND_METHOD(ZendTestForbidDynamicCall, call)
1074 {
1075 	ZEND_PARSE_PARAMETERS_NONE();
1076 
1077 	zend_forbid_dynamic_call();
1078 }
1079 
ZEND_METHOD(ZendTestForbidDynamicCall,callStatic)1080 static ZEND_METHOD(ZendTestForbidDynamicCall, callStatic)
1081 {
1082 	ZEND_PARSE_PARAMETERS_NONE();
1083 
1084 	zend_forbid_dynamic_call();
1085 }
1086 
ZEND_METHOD(_ZendTestMagicCall,__call)1087 static ZEND_METHOD(_ZendTestMagicCall, __call)
1088 {
1089 	zend_string *name;
1090 	zval *arguments;
1091 
1092 	ZEND_PARSE_PARAMETERS_START(2, 2)
1093 		Z_PARAM_STR(name)
1094 		Z_PARAM_ARRAY(arguments)
1095 	ZEND_PARSE_PARAMETERS_END();
1096 
1097 	zval name_zv;
1098 	ZVAL_STR(&name_zv, name);
1099 
1100 	zend_string_addref(name);
1101 	Z_TRY_ADDREF_P(arguments);
1102 	RETURN_ARR(zend_new_pair(&name_zv, arguments));
1103 }
1104 
ZEND_METHOD(_ZendTestMagicCallForward,__call)1105 static ZEND_METHOD(_ZendTestMagicCallForward, __call)
1106 {
1107 	zend_string *name;
1108 	zval *arguments;
1109 
1110 	ZEND_PARSE_PARAMETERS_START(2, 2)
1111 		Z_PARAM_STR(name)
1112 		Z_PARAM_ARRAY(arguments)
1113 	ZEND_PARSE_PARAMETERS_END();
1114 
1115 	ZEND_IGNORE_VALUE(arguments);
1116 
1117 	zval func;
1118 	ZVAL_STR(&func, name);
1119 	call_user_function(NULL, NULL, &func, return_value, 0, NULL);
1120 }
1121 
1122 PHP_INI_BEGIN()
1123 	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)
1124 	STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals)
1125 	STD_PHP_INI_BOOLEAN("zend_test.print_stderr_mshutdown", "0", PHP_INI_SYSTEM, OnUpdateBool, print_stderr_mshutdown, zend_zend_test_globals, zend_test_globals)
1126 #ifdef HAVE_COPY_FILE_RANGE
1127 	STD_PHP_INI_ENTRY("zend_test.limit_copy_file_range", "-1", PHP_INI_ALL, OnUpdateLong, limit_copy_file_range, zend_zend_test_globals, zend_test_globals)
1128 #endif
1129 	STD_PHP_INI_ENTRY("zend_test.quantity_value", "0", PHP_INI_ALL, OnUpdateLong, quantity_value, zend_zend_test_globals, zend_test_globals)
1130 	STD_PHP_INI_ENTRY("zend_test.str_test", "", PHP_INI_ALL, OnUpdateStr, str_test, zend_zend_test_globals, zend_test_globals)
1131 	STD_PHP_INI_ENTRY("zend_test.not_empty_str_test", "val", PHP_INI_ALL, OnUpdateStrNotEmpty, not_empty_str_test, zend_zend_test_globals, zend_test_globals)
1132 	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)
1133 PHP_INI_END()
1134 
1135 void (*old_zend_execute_ex)(zend_execute_data *execute_data);
custom_zend_execute_ex(zend_execute_data * execute_data)1136 static void custom_zend_execute_ex(zend_execute_data *execute_data)
1137 {
1138 	old_zend_execute_ex(execute_data);
1139 }
1140 
le_throwing_resource_dtor(zend_resource * rsrc)1141 static void le_throwing_resource_dtor(zend_resource *rsrc)
1142 {
1143 	zend_throw_exception(NULL, "Throwing resource destructor called", 0);
1144 }
1145 
ZEND_METHOD(_ZendTestClass,takesUnionType)1146 static ZEND_METHOD(_ZendTestClass, takesUnionType)
1147 {
1148 	zend_object *obj;
1149 	ZEND_PARSE_PARAMETERS_START(1, 1);
1150 		Z_PARAM_OBJ(obj)
1151 	ZEND_PARSE_PARAMETERS_END();
1152 	// we have to perform type-checking to avoid arginfo/zpp mismatch error
1153 	bool type_matches = (
1154 		instanceof_function(obj->ce, zend_standard_class_def)
1155 		||
1156 		instanceof_function(obj->ce, zend_ce_iterator)
1157 	);
1158 	if (!type_matches) {
1159 		zend_string *ty = zend_type_to_string(execute_data->func->internal_function.arg_info->type);
1160 		zend_argument_type_error(1, "must be of type %s, %s given", ty->val, obj->ce->name->val);
1161 		zend_string_release(ty);
1162 		RETURN_THROWS();
1163 	}
1164 
1165 	RETURN_NULL();
1166 }
1167 
1168 // Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`.
1169 //
1170 // We need to generate it "manually" because gen_stubs.php does not support codegen for DNF types ATM.
create_test_dnf_type(void)1171 static zend_type create_test_dnf_type(void) {
1172 	zend_string *class_Iterator = zend_string_init_interned("Iterator", sizeof("Iterator") - 1, true);
1173 	zend_alloc_ce_cache(class_Iterator);
1174 	zend_string *class_Traversable = ZSTR_KNOWN(ZEND_STR_TRAVERSABLE);
1175 	zend_string *class_Countable = zend_string_init_interned("Countable", sizeof("Countable") - 1, true);
1176 	zend_alloc_ce_cache(class_Countable);
1177 	//
1178 	zend_type_list *intersection_list = malloc(ZEND_TYPE_LIST_SIZE(2));
1179 	intersection_list->num_types = 2;
1180 	intersection_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Traversable, 0, 0);
1181 	intersection_list->types[1] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Countable, 0, 0);
1182 	zend_type_list *union_list = malloc(ZEND_TYPE_LIST_SIZE(2));
1183 	union_list->num_types = 2;
1184 	union_list->types[0] = (zend_type) ZEND_TYPE_INIT_CLASS(class_Iterator, 0, 0);
1185 	union_list->types[1] = (zend_type) ZEND_TYPE_INIT_INTERSECTION(intersection_list, 0);
1186 	return (zend_type) ZEND_TYPE_INIT_UNION(union_list, 0);
1187 }
1188 
register_ZendTestClass_dnf_property(zend_class_entry * ce)1189 static void register_ZendTestClass_dnf_property(zend_class_entry *ce) {
1190 	zend_string *prop_name = zend_string_init_interned("dnfProperty", sizeof("dnfProperty") - 1, true);
1191 	zval default_value;
1192 	ZVAL_UNDEF(&default_value);
1193 	zend_type type = create_test_dnf_type();
1194 	zend_declare_typed_property(ce, prop_name, &default_value, ZEND_ACC_PUBLIC, NULL, type);
1195 }
1196 
1197 // arg_info for `zend_test_internal_dnf_arguments`
1198 // The types are upgraded to DNF types in `register_dynamic_function_entries()`
1199 static zend_internal_arg_info arginfo_zend_test_internal_dnf_arguments[] = {
1200 	// first entry is a zend_internal_function_info (see zend_compile.h): {argument_count, return_type, unused}
1201 	{(const char*)(uintptr_t)(1), {0}, NULL},
1202 	{"arg", {0}, NULL}
1203 };
1204 
ZEND_NAMED_FUNCTION(zend_test_internal_dnf_arguments)1205 static ZEND_NAMED_FUNCTION(zend_test_internal_dnf_arguments)
1206 {
1207 	zend_object *obj;
1208 	ZEND_PARSE_PARAMETERS_START(1, 1);
1209 		Z_PARAM_OBJ(obj)
1210 	ZEND_PARSE_PARAMETERS_END();
1211 	// we have to perform type-checking to avoid arginfo/zpp mismatch error
1212 	bool type_matches = (
1213 		instanceof_function(obj->ce, zend_ce_iterator)
1214 		|| (
1215 			instanceof_function(obj->ce, zend_ce_traversable)
1216 			&& instanceof_function(obj->ce, zend_ce_countable)
1217 		)
1218 	);
1219 	if (!type_matches) {
1220 		zend_string *ty = zend_type_to_string(arginfo_zend_test_internal_dnf_arguments[1].type);
1221 		zend_argument_type_error(1, "must be of type %s, %s given", ty->val, obj->ce->name->val);
1222 		zend_string_release(ty);
1223 		RETURN_THROWS();
1224 	}
1225 
1226 	RETURN_OBJ_COPY(obj);
1227 }
1228 
1229 static const zend_function_entry dynamic_function_entries[] = {
1230 	{
1231 		.fname = "zend_test_internal_dnf_arguments",
1232 		.handler = zend_test_internal_dnf_arguments,
1233 		.arg_info = arginfo_zend_test_internal_dnf_arguments,
1234 		.num_args = 1,
1235 		.flags = 0,
1236 	},
1237 	ZEND_FE_END,
1238 };
1239 
register_dynamic_function_entries(int module_type)1240 static void register_dynamic_function_entries(int module_type) {
1241 	// return-type is at index 0
1242 	arginfo_zend_test_internal_dnf_arguments[0].type = create_test_dnf_type();
1243 	arginfo_zend_test_internal_dnf_arguments[1].type = create_test_dnf_type();
1244 	//
1245 	zend_register_functions(NULL, dynamic_function_entries, NULL, module_type);
1246 }
1247 
PHP_MINIT_FUNCTION(zend_test)1248 PHP_MINIT_FUNCTION(zend_test)
1249 {
1250 	register_dynamic_function_entries(type);
1251 
1252 	zend_test_interface = register_class__ZendTestInterface();
1253 
1254 	zend_test_class = register_class__ZendTestClass(zend_test_interface);
1255 	register_ZendTestClass_dnf_property(zend_test_class);
1256 	zend_test_class->create_object = zend_test_class_new;
1257 	zend_test_class->get_static_method = zend_test_class_static_method_get;
1258 
1259 	zend_test_child_class = register_class__ZendTestChildClass(zend_test_class);
1260 
1261 	memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1262 	zend_test_class_handlers.get_method = zend_test_class_method_get;
1263 
1264 	zend_attribute_test_class = register_class_ZendAttributeTest();
1265 
1266 	zend_test_trait = register_class__ZendTestTrait();
1267 
1268 	register_test_symbols(module_number);
1269 
1270 	zend_test_attribute = register_class_ZendTestAttribute();
1271 	{
1272 		zend_internal_attribute *attr = zend_mark_internal_attribute(zend_test_attribute);
1273 		attr->validator = zend_attribute_validate_zendtestattribute;
1274 	}
1275 
1276 	zend_test_repeatable_attribute = register_class_ZendTestRepeatableAttribute();
1277 	zend_mark_internal_attribute(zend_test_repeatable_attribute);
1278 
1279 	zend_test_parameter_attribute = register_class_ZendTestParameterAttribute();
1280 	zend_mark_internal_attribute(zend_test_parameter_attribute);
1281 
1282 	zend_test_property_attribute = register_class_ZendTestPropertyAttribute();
1283 	zend_mark_internal_attribute(zend_test_property_attribute);
1284 
1285 	zend_test_attribute_with_arguments = register_class_ZendTestAttributeWithArguments();
1286 	zend_mark_internal_attribute(zend_test_attribute_with_arguments);
1287 
1288 	zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute();
1289 	zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute);
1290 
1291 	zend_test_class_with_property_attribute = register_class_ZendTestClassWithPropertyAttribute();
1292 	{
1293 		zend_property_info *prop_info = zend_hash_str_find_ptr(&zend_test_class_with_property_attribute->properties_info, "attributed", sizeof("attributed") - 1);
1294 		zend_add_property_attribute(zend_test_class_with_property_attribute, prop_info, zend_test_attribute->name, 0);
1295 	}
1296 
1297 	zend_test_forbid_dynamic_call = register_class_ZendTestForbidDynamicCall();
1298 
1299 	zend_test_ns_foo_class = register_class_ZendTestNS_Foo();
1300 	zend_test_ns_unlikely_compile_error_class = register_class_ZendTestNS_UnlikelyCompileError();
1301 	zend_test_ns_not_unlikely_compile_error_class = register_class_ZendTestNS_NotUnlikelyCompileError();
1302 	zend_test_ns2_foo_class = register_class_ZendTestNS2_Foo();
1303 	zend_test_ns2_ns_foo_class = register_class_ZendTestNS2_ZendSubNS_Foo();
1304 
1305 	zend_test_unit_enum = register_class_ZendTestUnitEnum();
1306 	zend_test_string_enum = register_class_ZendTestStringEnum();
1307 	zend_test_int_enum = register_class_ZendTestIntEnum();
1308 
1309 	zend_test_magic_call = register_class__ZendTestMagicCall();
1310 
1311 	register_class__ZendTestMagicCallForward();
1312 
1313 	zend_register_functions(NULL, ext_function_legacy, NULL, EG(current_module)->type);
1314 
1315 	// Loading via dl() not supported with the observer API
1316 	if (type != MODULE_TEMPORARY) {
1317 		REGISTER_INI_ENTRIES();
1318 	} else {
1319 		(void)ini_entries;
1320 	}
1321 
1322 	if (ZT_G(replace_zend_execute_ex)) {
1323 		old_zend_execute_ex = zend_execute_ex;
1324 		zend_execute_ex = custom_zend_execute_ex;
1325 	}
1326 
1327 	if (ZT_G(register_passes)) {
1328 		zend_optimizer_register_pass(pass1);
1329 		zend_optimizer_register_pass(pass2);
1330 	}
1331 
1332 	zend_test_observer_init(INIT_FUNC_ARGS_PASSTHRU);
1333 	zend_test_mm_custom_handlers_minit(INIT_FUNC_ARGS_PASSTHRU);
1334 	zend_test_fiber_init();
1335 	zend_test_iterators_init();
1336 	zend_test_object_handlers_init();
1337 
1338 	le_throwing_resource = zend_register_list_destructors_ex(le_throwing_resource_dtor, NULL, "throwing resource", module_number);
1339 
1340 	return SUCCESS;
1341 }
1342 
PHP_MSHUTDOWN_FUNCTION(zend_test)1343 PHP_MSHUTDOWN_FUNCTION(zend_test)
1344 {
1345 	if (type != MODULE_TEMPORARY) {
1346 		UNREGISTER_INI_ENTRIES();
1347 	}
1348 
1349 	zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS_PASSTHRU);
1350 
1351 	if (ZT_G(print_stderr_mshutdown)) {
1352 		fprintf(stderr, "[zend_test] MSHUTDOWN\n");
1353 	}
1354 
1355 	return SUCCESS;
1356 }
1357 
PHP_RINIT_FUNCTION(zend_test)1358 PHP_RINIT_FUNCTION(zend_test)
1359 {
1360 	zend_hash_init(&ZT_G(global_weakmap), 8, NULL, ZVAL_PTR_DTOR, 0);
1361 	ZT_G(observer_nesting_depth) = 0;
1362 	zend_test_mm_custom_handlers_rinit();
1363 	return SUCCESS;
1364 }
1365 
PHP_RSHUTDOWN_FUNCTION(zend_test)1366 PHP_RSHUTDOWN_FUNCTION(zend_test)
1367 {
1368 	zend_ulong obj_key;
1369 	ZEND_HASH_FOREACH_NUM_KEY(&ZT_G(global_weakmap), obj_key) {
1370 		zend_weakrefs_hash_del(&ZT_G(global_weakmap), zend_weakref_key_to_object(obj_key));
1371 	} ZEND_HASH_FOREACH_END();
1372 	zend_hash_destroy(&ZT_G(global_weakmap));
1373 
1374 	if (ZT_G(zend_test_heap))  {
1375 		free(ZT_G(zend_test_heap));
1376 		ZT_G(zend_test_heap) = NULL;
1377 		zend_mm_set_heap(ZT_G(zend_orig_heap));
1378 	}
1379 
1380 	zend_test_mm_custom_handlers_rshutdown();
1381 	return SUCCESS;
1382 }
1383 
PHP_GINIT_FUNCTION(zend_test)1384 static PHP_GINIT_FUNCTION(zend_test)
1385 {
1386 #if defined(COMPILE_DL_ZEND_TEST) && defined(ZTS)
1387 	ZEND_TSRMLS_CACHE_UPDATE();
1388 #endif
1389 	memset(zend_test_globals, 0, sizeof(*zend_test_globals));
1390 
1391 	zend_test_observer_ginit(zend_test_globals);
1392 }
1393 
PHP_GSHUTDOWN_FUNCTION(zend_test)1394 static PHP_GSHUTDOWN_FUNCTION(zend_test)
1395 {
1396 	zend_test_observer_gshutdown(zend_test_globals);
1397 }
1398 
PHP_MINFO_FUNCTION(zend_test)1399 PHP_MINFO_FUNCTION(zend_test)
1400 {
1401 	php_info_print_table_start();
1402 	php_info_print_table_row(2, "zend_test extension", "enabled");
1403 	php_info_print_table_end();
1404 
1405 	DISPLAY_INI_ENTRIES();
1406 }
1407 
1408 zend_module_entry zend_test_module_entry = {
1409 	STANDARD_MODULE_HEADER,
1410 	"zend_test",
1411 	ext_functions,
1412 	PHP_MINIT(zend_test),
1413 	PHP_MSHUTDOWN(zend_test),
1414 	PHP_RINIT(zend_test),
1415 	PHP_RSHUTDOWN(zend_test),
1416 	PHP_MINFO(zend_test),
1417 	PHP_ZEND_TEST_VERSION,
1418 	PHP_MODULE_GLOBALS(zend_test),
1419 	PHP_GINIT(zend_test),
1420 	PHP_GSHUTDOWN(zend_test),
1421 	NULL,
1422 	STANDARD_MODULE_PROPERTIES_EX
1423 };
1424 
1425 #ifdef COMPILE_DL_ZEND_TEST
1426 # ifdef ZTS
1427 ZEND_TSRMLS_CACHE_DEFINE()
1428 # endif
ZEND_GET_MODULE(zend_test)1429 ZEND_GET_MODULE(zend_test)
1430 #endif
1431 
1432 /* The important part here is the ZEND_FASTCALL. */
1433 PHP_ZEND_TEST_API int ZEND_FASTCALL bug78270(const char *str, size_t str_len)
1434 {
1435 	char * copy = zend_strndup(str, str_len);
1436 	int r = (int) ZEND_ATOL(copy);
1437 	free(copy);
1438 	return r;
1439 }
1440 
bug79096(void)1441 PHP_ZEND_TEST_API struct bug79096 bug79096(void)
1442 {
1443 	struct bug79096 b;
1444 
1445 	b.a = 1;
1446 	b.b = 1;
1447 	return b;
1448 }
1449 
bug79532(off_t * array,size_t elems)1450 PHP_ZEND_TEST_API void bug79532(off_t *array, size_t elems)
1451 {
1452 	for (size_t i = 0; i < elems; i++) {
1453 		array[i] = i;
1454 	}
1455 }
1456 
1457 PHP_ZEND_TEST_API int *(*bug79177_cb)(void);
bug79177(void)1458 void bug79177(void)
1459 {
1460 	bug79177_cb();
1461 }
1462 
1463 typedef struct bug80847_01 {
1464 	uint64_t b;
1465 	double c;
1466 } bug80847_01;
1467 typedef struct bug80847_02 {
1468 	bug80847_01 a;
1469 } bug80847_02;
1470 
ffi_bug80847(bug80847_02 s)1471 PHP_ZEND_TEST_API bug80847_02 ffi_bug80847(bug80847_02 s) {
1472 	s.a.b += 10;
1473 	s.a.c -= 10.0;
1474 	return s;
1475 }
1476 
1477 PHP_ZEND_TEST_API void (*bug_gh9090_void_none_ptr)(void) = NULL;
1478 PHP_ZEND_TEST_API void (*bug_gh9090_void_int_char_ptr)(int, char *) = NULL;
1479 PHP_ZEND_TEST_API void (*bug_gh9090_void_int_char_var_ptr)(int, char *, ...) = NULL;
1480 PHP_ZEND_TEST_API void (*bug_gh9090_void_char_int_ptr)(char *, int) = NULL;
1481 PHP_ZEND_TEST_API int (*bug_gh9090_int_int_char_ptr)(int, char *) = NULL;
1482 
bug_gh9090_void_none(void)1483 PHP_ZEND_TEST_API void bug_gh9090_void_none(void) {
1484     php_printf("bug_gh9090_none\n");
1485 }
1486 
bug_gh9090_void_int_char(int i,char * s)1487 PHP_ZEND_TEST_API void bug_gh9090_void_int_char(int i, char *s) {
1488     php_printf("bug_gh9090_int_char %d %s\n", i, s);
1489 }
1490 
bug_gh9090_void_int_char_var(int i,char * fmt,...)1491 PHP_ZEND_TEST_API void bug_gh9090_void_int_char_var(int i, char *fmt, ...) {
1492     va_list args;
1493     char *buffer;
1494 
1495     va_start(args, fmt);
1496 
1497     zend_vspprintf(&buffer, 0, fmt, args);
1498     php_printf("bug_gh9090_void_int_char_var %s\n", buffer);
1499     efree(buffer);
1500 
1501     va_end(args);
1502 }
1503 
1504 PHP_ZEND_TEST_API int gh11934b_ffi_var_test_cdata;
1505 
1506 #ifdef HAVE_COPY_FILE_RANGE
1507 /**
1508  * This function allows us to simulate early return of copy_file_range by setting the limit_copy_file_range ini setting.
1509  */
1510 #ifdef __MUSL__
1511 typedef off_t off64_t;
1512 #endif
copy_file_range(int fd_in,off64_t * off_in,int fd_out,off64_t * off_out,size_t len,unsigned int flags)1513 PHP_ZEND_TEST_API ssize_t copy_file_range(int fd_in, off64_t *off_in, int fd_out, off64_t *off_out, size_t len, unsigned int flags)
1514 {
1515 	ssize_t (*original_copy_file_range)(int, off64_t *, int, off64_t *, size_t, unsigned int) = dlsym(RTLD_NEXT, "copy_file_range");
1516 	if (ZT_G(limit_copy_file_range) >= Z_L(0)) {
1517 		len = ZT_G(limit_copy_file_range);
1518 	}
1519 	return original_copy_file_range(fd_in, off_in, fd_out, off_out, len, flags);
1520 }
1521 #endif
1522 
1523 
PHP_FUNCTION(zend_test_create_throwing_resource)1524 static PHP_FUNCTION(zend_test_create_throwing_resource)
1525 {
1526 	ZEND_PARSE_PARAMETERS_NONE();
1527 	zend_resource *res = zend_register_resource(NULL, le_throwing_resource);
1528 	ZVAL_RES(return_value, res);
1529 }
1530