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