1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2018 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: |
16 +----------------------------------------------------------------------+
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "php.h"
24 #include "php_ini.h"
25 #include "ext/standard/info.h"
26 #include "php_test.h"
27
28 static zend_class_entry *zend_test_interface;
29 static zend_class_entry *zend_test_class;
30 static zend_class_entry *zend_test_child_class;
31 static zend_class_entry *zend_test_trait;
32 static zend_object_handlers zend_test_class_handlers;
33
34 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_array_return, IS_ARRAY, 0)
ZEND_END_ARG_INFO()35 ZEND_END_ARG_INFO()
36
37 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_nullable_array_return, IS_ARRAY, 1)
38 ZEND_END_ARG_INFO()
39
40 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO(arginfo_zend_test_void_return, IS_VOID, 0)
41 ZEND_END_ARG_INFO()
42
43 ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_terminate_string, 0, 0, 1)
44 ZEND_ARG_INFO(1, str)
45 ZEND_END_ARG_INFO()
46
47 ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_leak_variable, 0, 0, 1)
48 ZEND_ARG_INFO(0, variable)
49 ZEND_END_ARG_INFO()
50
51 ZEND_FUNCTION(zend_test_func)
52 {
53 /* dummy */
54 }
55
ZEND_FUNCTION(zend_test_array_return)56 ZEND_FUNCTION(zend_test_array_return)
57 {
58 zval *arg1, *arg2;
59
60 zend_parse_parameters(ZEND_NUM_ARGS(), "|zz", &arg1, &arg2);
61 }
62
ZEND_FUNCTION(zend_test_nullable_array_return)63 ZEND_FUNCTION(zend_test_nullable_array_return)
64 {
65 zval *arg1, *arg2;
66
67 zend_parse_parameters(ZEND_NUM_ARGS(), "|zz", &arg1, &arg2);
68 }
69
ZEND_FUNCTION(zend_test_void_return)70 ZEND_FUNCTION(zend_test_void_return)
71 {
72 /* dummy */
73 }
74
75 /* Create a string without terminating null byte. Must be termined with
76 * zend_terminate_string() before destruction, otherwise a warning is issued
77 * in debug builds. */
ZEND_FUNCTION(zend_create_unterminated_string)78 ZEND_FUNCTION(zend_create_unterminated_string)
79 {
80 zend_string *str, *res;
81
82 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
83 return;
84 }
85
86 res = zend_string_alloc(ZSTR_LEN(str), 0);
87 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), ZSTR_LEN(str));
88 /* No trailing null byte */
89
90 RETURN_STR(res);
91 }
92
93 /* Enforce terminate null byte on string. This avoids a warning in debug builds. */
ZEND_FUNCTION(zend_terminate_string)94 ZEND_FUNCTION(zend_terminate_string)
95 {
96 zend_string *str;
97
98 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
99 return;
100 }
101
102 ZSTR_VAL(str)[ZSTR_LEN(str)] = '\0';
103 }
104
105 /* {{{ proto void zend_leak_bytes([int num_bytes])
106 Cause an intentional memory leak, for testing/debugging purposes */
ZEND_FUNCTION(zend_leak_bytes)107 ZEND_FUNCTION(zend_leak_bytes)
108 {
109 zend_long leakbytes = 3;
110
111 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &leakbytes) == FAILURE) {
112 return;
113 }
114
115 emalloc(leakbytes);
116 }
117 /* }}} */
118
119 /* {{{ proto void zend_leak_variable(mixed variable)
120 Leak a refcounted variable */
ZEND_FUNCTION(zend_leak_variable)121 ZEND_FUNCTION(zend_leak_variable)
122 {
123 zval *zv;
124
125 if (zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zv) == FAILURE) {
126 return;
127 }
128
129 if (!Z_REFCOUNTED_P(zv)) {
130 zend_error(E_WARNING, "Cannot leak variable that is not refcounted");
131 return;
132 }
133
134 Z_ADDREF_P(zv);
135 }
136 /* }}} */
137
zend_test_class_new(zend_class_entry * class_type)138 static zend_object *zend_test_class_new(zend_class_entry *class_type) /* {{{ */ {
139 zend_object *obj = zend_objects_new(class_type);
140 obj->handlers = &zend_test_class_handlers;
141 return obj;
142 }
143 /* }}} */
144
zend_test_class_method_get(zend_object ** object,zend_string * name,const zval * key)145 static zend_function *zend_test_class_method_get(zend_object **object, zend_string *name, const zval *key) /* {{{ */ {
146 zend_internal_function *fptr = emalloc(sizeof(zend_internal_function));
147 fptr->type = ZEND_OVERLOADED_FUNCTION_TEMPORARY;
148 fptr->num_args = 1;
149 fptr->arg_info = NULL;
150 fptr->scope = (*object)->ce;
151 fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER;
152 fptr->function_name = zend_string_copy(name);
153 fptr->handler = ZEND_FN(zend_test_func);
154 zend_set_function_arg_flags((zend_function*)fptr);
155
156 return (zend_function*)fptr;
157 }
158 /* }}} */
159
zend_test_class_static_method_get(zend_class_entry * ce,zend_string * name)160 static zend_function *zend_test_class_static_method_get(zend_class_entry *ce, zend_string *name) /* {{{ */ {
161 if (zend_string_equals_literal_ci(name, "test")) {
162 zend_internal_function *fptr = emalloc(sizeof(zend_internal_function));
163 fptr->type = ZEND_OVERLOADED_FUNCTION;
164 fptr->num_args = 1;
165 fptr->arg_info = NULL;
166 fptr->scope = ce;
167 fptr->fn_flags = ZEND_ACC_CALL_VIA_HANDLER|ZEND_ACC_STATIC;
168 fptr->function_name = name;
169 fptr->handler = ZEND_FN(zend_test_func);
170 zend_set_function_arg_flags((zend_function*)fptr);
171
172 return (zend_function*)fptr;
173 }
174 return zend_std_get_static_method(ce, name, NULL);
175 }
176 /* }}} */
177
zend_test_class_call_method(zend_string * method,zend_object * object,INTERNAL_FUNCTION_PARAMETERS)178 static int zend_test_class_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS) /* {{{ */ {
179 RETVAL_STR(zend_string_copy(method));
180 return 0;
181 }
182 /* }}} */
183
184 /* Internal function returns bool, we return int. */
ZEND_METHOD(_ZendTestClass,is_object)185 static ZEND_METHOD(_ZendTestClass, is_object) /* {{{ */ {
186 RETURN_LONG(42);
187 }
188 /* }}} */
189
ZEND_METHOD(_ZendTestTrait,testMethod)190 static ZEND_METHOD(_ZendTestTrait, testMethod) /* {{{ */ {
191 RETURN_TRUE;
192 }
193 /* }}} */
194
195 static const zend_function_entry zend_test_class_methods[] = {
196 ZEND_ME(_ZendTestClass, is_object, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
197 ZEND_FE_END
198 };
199
200 static const zend_function_entry zend_test_trait_methods[] = {
201 ZEND_ME(_ZendTestTrait, testMethod, NULL, ZEND_ACC_PUBLIC)
202 ZEND_FE_END
203 };
204
PHP_MINIT_FUNCTION(zend_test)205 PHP_MINIT_FUNCTION(zend_test)
206 {
207 zend_class_entry class_entry;
208
209 INIT_CLASS_ENTRY(class_entry, "_ZendTestInterface", NULL);
210 zend_test_interface = zend_register_internal_interface(&class_entry);
211 zend_declare_class_constant_long(zend_test_interface, ZEND_STRL("DUMMY"), 0);
212 INIT_CLASS_ENTRY(class_entry, "_ZendTestClass", zend_test_class_methods);
213 zend_test_class = zend_register_internal_class_ex(&class_entry, NULL);
214 zend_class_implements(zend_test_class, 1, zend_test_interface);
215 zend_test_class->create_object = zend_test_class_new;
216 zend_test_class->get_static_method = zend_test_class_static_method_get;
217
218 zend_declare_property_null(zend_test_class, "_StaticProp", sizeof("_StaticProp") - 1, ZEND_ACC_STATIC);
219
220 INIT_CLASS_ENTRY(class_entry, "_ZendTestChildClass", NULL);
221 zend_test_child_class = zend_register_internal_class_ex(&class_entry, zend_test_class);
222
223 memcpy(&zend_test_class_handlers, &std_object_handlers, sizeof(zend_object_handlers));
224 zend_test_class_handlers.get_method = zend_test_class_method_get;
225 zend_test_class_handlers.call_method = zend_test_class_call_method;
226
227 INIT_CLASS_ENTRY(class_entry, "_ZendTestTrait", zend_test_trait_methods);
228 zend_test_trait = zend_register_internal_class(&class_entry);
229 zend_test_trait->ce_flags |= ZEND_ACC_TRAIT;
230 zend_declare_property_null(zend_test_trait, "testProp", sizeof("testProp")-1, ZEND_ACC_PUBLIC);
231
232 zend_register_class_alias("_ZendTestClassAlias", zend_test_class);
233 return SUCCESS;
234 }
235
PHP_MSHUTDOWN_FUNCTION(zend_test)236 PHP_MSHUTDOWN_FUNCTION(zend_test)
237 {
238 return SUCCESS;
239 }
240
PHP_RINIT_FUNCTION(zend_test)241 PHP_RINIT_FUNCTION(zend_test)
242 {
243 #if defined(COMPILE_DL_ZEND_TEST) && defined(ZTS)
244 ZEND_TSRMLS_CACHE_UPDATE();
245 #endif
246 return SUCCESS;
247 }
248
PHP_RSHUTDOWN_FUNCTION(zend_test)249 PHP_RSHUTDOWN_FUNCTION(zend_test)
250 {
251 return SUCCESS;
252 }
253
PHP_MINFO_FUNCTION(zend_test)254 PHP_MINFO_FUNCTION(zend_test)
255 {
256 php_info_print_table_start();
257 php_info_print_table_header(2, "zend-test extension", "enabled");
258 php_info_print_table_end();
259 }
260
261 static const zend_function_entry zend_test_functions[] = {
262 ZEND_FE(zend_test_array_return, arginfo_zend_test_array_return)
263 ZEND_FE(zend_test_nullable_array_return, arginfo_zend_test_nullable_array_return)
264 ZEND_FE(zend_test_void_return, arginfo_zend_test_void_return)
265 ZEND_FE(zend_create_unterminated_string, NULL)
266 ZEND_FE(zend_terminate_string, arginfo_zend_terminate_string)
267 ZEND_FE(zend_leak_bytes, NULL)
268 ZEND_FE(zend_leak_variable, arginfo_zend_leak_variable)
269 ZEND_FE_END
270 };
271
272 zend_module_entry zend_test_module_entry = {
273 STANDARD_MODULE_HEADER,
274 "zend-test",
275 zend_test_functions,
276 PHP_MINIT(zend_test),
277 PHP_MSHUTDOWN(zend_test),
278 PHP_RINIT(zend_test),
279 PHP_RSHUTDOWN(zend_test),
280 PHP_MINFO(zend_test),
281 PHP_ZEND_TEST_VERSION,
282 STANDARD_MODULE_PROPERTIES
283 };
284
285 #ifdef COMPILE_DL_ZEND_TEST
286 #ifdef ZTS
287 ZEND_TSRMLS_CACHE_DEFINE()
288 #endif
289 ZEND_GET_MODULE(zend_test)
290 #endif
291