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