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