xref: /PHP-8.4/ext/zend_test/object_handlers.c (revision a479ed7c)
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   | Authors: George Peter Banyard <girgias@php.net>                      |
14   +----------------------------------------------------------------------+
15 */
16 
17 #include "object_handlers.h"
18 #include "zend_API.h"
19 #include "object_handlers_arginfo.h"
20 
21 /* donc refers to DoOperationNoCast */
22 static zend_class_entry *donc_ce;
23 static zend_object_handlers donc_object_handlers;
24 
donc_object_create_ex(zend_class_entry * ce,zend_long l)25 static zend_object* donc_object_create_ex(zend_class_entry* ce, zend_long l) {
26 	zend_object *obj = zend_objects_new(ce);
27 	object_properties_init(obj, ce);
28 	obj->handlers = &donc_object_handlers;
29 	ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l);
30 	return obj;
31 }
donc_object_create(zend_class_entry * ce)32 static zend_object *donc_object_create(zend_class_entry *ce) /* {{{ */
33 {
34 	return donc_object_create_ex(ce, 0);
35 }
36 /* }}} */
37 
donc_create(zval * target,zend_long l)38 static inline void donc_create(zval *target, zend_long l) /* {{{ */
39 {
40 	ZVAL_OBJ(target, donc_object_create_ex(donc_ce, l));
41 }
42 
43 #define IS_DONC(zval) \
44 	(Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), donc_ce))
45 
donc_add(zval * result,zval * op1,zval * op2)46 static void donc_add(zval *result, zval *op1, zval *op2)
47 {
48 	zend_long val_1;
49 	zend_long val_2;
50 	if (IS_DONC(op1)) {
51 		val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0));
52 	} else {
53 		val_1 = zval_get_long(op1);
54 	}
55 	if (IS_DONC(op2)) {
56 		val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0));
57 	} else {
58 		val_2 = zval_get_long(op2);
59 	}
60 
61 	donc_create(result, val_1 + val_2);
62 }
donc_mul(zval * result,zval * op1,zval * op2)63 static void donc_mul(zval *result, zval *op1, zval *op2)
64 {
65 	zend_long val_1;
66 	zend_long val_2;
67 	if (IS_DONC(op1)) {
68 		val_1 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op1), 0));
69 	} else {
70 		val_1 = zval_get_long(op1);
71 	}
72 	if (IS_DONC(op2)) {
73 		val_2 = Z_LVAL_P(OBJ_PROP_NUM(Z_OBJ_P(op2), 0));
74 	} else {
75 		val_2 = zval_get_long(op2);
76 	}
77 
78 	donc_create(result, val_1 * val_2);
79 }
80 
donc_do_operation(zend_uchar opcode,zval * result,zval * op1,zval * op2)81 static zend_result donc_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2)
82 {
83 	zval op1_copy;
84 	zend_result status;
85 
86 	if (result == op1) {
87 		ZVAL_COPY_VALUE(&op1_copy, op1);
88 		op1 = &op1_copy;
89 	}
90 
91 	switch (opcode) {
92 		case ZEND_ADD:
93 			donc_add(result, op1, op2);
94 			if (UNEXPECTED(EG(exception))) { status = FAILURE; }
95 			status = SUCCESS;
96 			break;
97 		case ZEND_MUL:
98 			donc_mul(result, op1, op2);
99 			if (UNEXPECTED(EG(exception))) { status = FAILURE; }
100 			status = SUCCESS;
101 			break;
102 		default:
103 			status = FAILURE;
104 			break;
105 	}
106 
107 	if (status == SUCCESS && op1 == &op1_copy) {
108 		zval_ptr_dtor(op1);
109 	}
110 
111 	return status;
112 }
113 
ZEND_METHOD(DoOperationNoCast,__construct)114 ZEND_METHOD(DoOperationNoCast, __construct)
115 {
116 	zend_long l;
117 
118 	ZEND_PARSE_PARAMETERS_START(1, 1)
119 		Z_PARAM_LONG(l)
120 	ZEND_PARSE_PARAMETERS_END();
121 
122 	ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l);
123 }
124 
125 static zend_class_entry *long_castable_no_operation_ce;
126 static zend_object_handlers long_castable_no_operation_object_handlers;
127 
long_castable_no_operation_object_create_ex(zend_class_entry * ce,zend_long l)128 static zend_object* long_castable_no_operation_object_create_ex(zend_class_entry* ce, zend_long l) {
129 	zend_object *obj = zend_objects_new(ce);
130 	object_properties_init(obj, ce);
131 	obj->handlers = &long_castable_no_operation_object_handlers;
132 	ZVAL_LONG(OBJ_PROP_NUM(obj, 0), l);
133 	return obj;
134 }
135 
long_castable_no_operation_object_create(zend_class_entry * ce)136 static zend_object *long_castable_no_operation_object_create(zend_class_entry *ce)
137 {
138 	return long_castable_no_operation_object_create_ex(ce, 0);
139 }
140 
long_castable_no_operation_cast_object(zend_object * obj,zval * result,int type)141 static zend_result long_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
142 {
143 	if (type == IS_LONG) {
144 		ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
145 		return SUCCESS;
146 	}
147 	return FAILURE;
148 }
149 
ZEND_METHOD(LongCastableNoOperations,__construct)150 ZEND_METHOD(LongCastableNoOperations, __construct)
151 {
152 	zend_long l;
153 
154 	ZEND_PARSE_PARAMETERS_START(1, 1)
155 		Z_PARAM_LONG(l)
156 	ZEND_PARSE_PARAMETERS_END();
157 
158 	ZVAL_LONG(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), l);
159 }
160 
161 static zend_class_entry *float_castable_no_operation_ce;
162 static zend_object_handlers float_castable_no_operation_object_handlers;
163 
float_castable_no_operation_object_create_ex(zend_class_entry * ce,double d)164 static zend_object* float_castable_no_operation_object_create_ex(zend_class_entry* ce, double d) {
165 	zend_object *obj = zend_objects_new(ce);
166 	object_properties_init(obj, ce);
167 	obj->handlers = &float_castable_no_operation_object_handlers;
168 	ZVAL_DOUBLE(OBJ_PROP_NUM(obj, 0), d);
169 	return obj;
170 }
171 
float_castable_no_operation_object_create(zend_class_entry * ce)172 static zend_object *float_castable_no_operation_object_create(zend_class_entry *ce)
173 {
174 	return float_castable_no_operation_object_create_ex(ce, 0.0);
175 }
176 
float_castable_no_operation_cast_object(zend_object * obj,zval * result,int type)177 static zend_result float_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
178 {
179 	if (type == IS_DOUBLE) {
180 		ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
181 		return SUCCESS;
182 	}
183 	return FAILURE;
184 }
185 
ZEND_METHOD(FloatCastableNoOperations,__construct)186 ZEND_METHOD(FloatCastableNoOperations, __construct)
187 {
188 	double d;
189 
190 	ZEND_PARSE_PARAMETERS_START(1, 1)
191 		Z_PARAM_DOUBLE(d)
192 	ZEND_PARSE_PARAMETERS_END();
193 
194 	ZVAL_DOUBLE(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), d);
195 }
196 
197 static zend_class_entry *numeric_castable_no_operation_ce;
198 static zend_object_handlers numeric_castable_no_operation_object_handlers;
199 
numeric_castable_no_operation_object_create_ex(zend_class_entry * ce,const zval * n)200 static zend_object* numeric_castable_no_operation_object_create_ex(zend_class_entry* ce, const zval *n) {
201 	zend_object *obj = zend_objects_new(ce);
202 	object_properties_init(obj, ce);
203 	obj->handlers = &numeric_castable_no_operation_object_handlers;
204 	ZVAL_COPY(OBJ_PROP_NUM(obj, 0), n);
205 	return obj;
206 }
207 
numeric_castable_no_operation_object_create(zend_class_entry * ce)208 static zend_object *numeric_castable_no_operation_object_create(zend_class_entry *ce)
209 {
210 	zval tmp;
211 	ZVAL_LONG(&tmp, 0);
212 	return numeric_castable_no_operation_object_create_ex(ce, &tmp);
213 }
214 
numeric_castable_no_operation_cast_object(zend_object * obj,zval * result,int type)215 static zend_result numeric_castable_no_operation_cast_object(zend_object *obj, zval *result, int type)
216 {
217 	if (type == _IS_NUMBER) {
218 		ZVAL_COPY(result, OBJ_PROP_NUM(obj, 0));
219 		return SUCCESS;
220 	}
221 	return FAILURE;
222 }
223 
ZEND_METHOD(NumericCastableNoOperations,__construct)224 ZEND_METHOD(NumericCastableNoOperations, __construct)
225 {
226 	zval *n;
227 
228 	ZEND_PARSE_PARAMETERS_START(1, 1)
229 		Z_PARAM_NUMBER(n)
230 	ZEND_PARSE_PARAMETERS_END();
231 
232 	ZVAL_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), n);
233 }
234 
235 static zend_class_entry *dimension_handlers_no_ArrayAccess_ce;
236 static zend_object_handlers dimension_handlers_no_ArrayAccess_object_handlers;
237 
dimension_handlers_no_ArrayAccess_object_create(zend_class_entry * ce)238 static zend_object* dimension_handlers_no_ArrayAccess_object_create(zend_class_entry* ce) {
239 	zend_object *object = zend_objects_new(ce);
240 	object_properties_init(object, ce);
241 	object->handlers = &dimension_handlers_no_ArrayAccess_object_handlers;
242 	return object;
243 }
244 
dimension_common_helper(zend_object * object,zval * offset,int prop_access_type)245 static void dimension_common_helper(zend_object *object, zval *offset, int prop_access_type) {
246 	ZVAL_BOOL(OBJ_PROP_NUM(object, prop_access_type), true);
247 	/* hasOffset */
248 	ZVAL_BOOL(OBJ_PROP_NUM(object, 5), offset != NULL);
249 	if (offset) {
250 		ZVAL_COPY(OBJ_PROP_NUM(object, 7), offset);
251 	}
252 }
253 
dimension_handlers_no_ArrayAccess_read_dimension(zend_object * object,zval * offset,int type,zval * rv)254 static zval* dimension_handlers_no_ArrayAccess_read_dimension(zend_object *object, zval *offset, int type, zval *rv) {
255 	dimension_common_helper(object, offset, 0);
256 	/* ReadType */
257 	ZVAL_LONG(OBJ_PROP_NUM(object, 4), type);
258 
259 	/* Normal logic */
260 	ZVAL_BOOL(rv, true);
261 	return rv;
262 }
263 
dimension_handlers_no_ArrayAccess_write_dimension(zend_object * object,zval * offset,zval * value)264 static void dimension_handlers_no_ArrayAccess_write_dimension(zend_object *object, zval *offset, zval *value) {
265 	dimension_common_helper(object, offset, 1);
266 }
267 
dimension_handlers_no_ArrayAccess_has_dimension(zend_object * object,zval * offset,int check_empty)268 static int dimension_handlers_no_ArrayAccess_has_dimension(zend_object *object, zval *offset, int check_empty) {
269 	/* checkEmpty */
270 	ZVAL_LONG(OBJ_PROP_NUM(object, 6), check_empty);
271 	dimension_common_helper(object, offset, 2);
272 
273 	/* Normal logic */
274 	return 1;
275 }
276 
dimension_handlers_no_ArrayAccess_unset_dimension(zend_object * object,zval * offset)277 static void dimension_handlers_no_ArrayAccess_unset_dimension(zend_object *object, zval *offset) {
278 	dimension_common_helper(object, offset, 3);
279 }
280 
zend_test_object_handlers_init(void)281 void zend_test_object_handlers_init(void)
282 {
283 	/* DoOperationNoCast class */
284 	donc_ce = register_class_DoOperationNoCast();
285 	donc_ce->create_object = donc_object_create;
286 	memcpy(&donc_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
287 	donc_object_handlers.do_operation = donc_do_operation;
288 
289 	/* CastableNoOperation classes */
290 	long_castable_no_operation_ce = register_class_LongCastableNoOperations();
291 	long_castable_no_operation_ce->create_object = long_castable_no_operation_object_create;
292 	memcpy(&long_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
293 	long_castable_no_operation_object_handlers.cast_object = long_castable_no_operation_cast_object;
294 
295 	float_castable_no_operation_ce = register_class_FloatCastableNoOperations();
296 	float_castable_no_operation_ce->create_object = float_castable_no_operation_object_create;
297 	memcpy(&float_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
298 	float_castable_no_operation_object_handlers.cast_object = float_castable_no_operation_cast_object;
299 
300 	numeric_castable_no_operation_ce = register_class_NumericCastableNoOperations();
301 	numeric_castable_no_operation_ce->create_object = numeric_castable_no_operation_object_create;
302 	memcpy(&numeric_castable_no_operation_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
303 	numeric_castable_no_operation_object_handlers.cast_object = numeric_castable_no_operation_cast_object;
304 
305 	dimension_handlers_no_ArrayAccess_ce = register_class_DimensionHandlersNoArrayAccess();
306 	dimension_handlers_no_ArrayAccess_ce->create_object = dimension_handlers_no_ArrayAccess_object_create;
307 	memcpy(&dimension_handlers_no_ArrayAccess_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
308 	dimension_handlers_no_ArrayAccess_object_handlers.read_dimension = dimension_handlers_no_ArrayAccess_read_dimension;
309 	dimension_handlers_no_ArrayAccess_object_handlers.write_dimension = dimension_handlers_no_ArrayAccess_write_dimension;
310 	dimension_handlers_no_ArrayAccess_object_handlers.has_dimension = dimension_handlers_no_ArrayAccess_has_dimension;
311 	dimension_handlers_no_ArrayAccess_object_handlers.unset_dimension = dimension_handlers_no_ArrayAccess_unset_dimension;
312 }
313