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