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: Dmitry Stogov <dmitry@zend.com>                              |
14    +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 
21 #include "php.h"
22 #include "php_ffi.h"
23 #include "ext/standard/info.h"
24 #include "php_scandir.h"
25 #include "zend_exceptions.h"
26 #include "zend_interfaces.h"
27 #include "zend_closures.h"
28 #include "main/SAPI.h"
29 #include "ffi_arginfo.h"
30 
31 #include <ffi.h>
32 
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 
37 #ifdef HAVE_GLOB
38 #ifdef PHP_WIN32
39 #include "win32/glob.h"
40 #else
41 #include <glob.h>
42 #endif
43 #endif
44 
45 #ifndef __BIGGEST_ALIGNMENT__
46 /* XXX need something better, perhaps with regard to SIMD, etc. */
47 # define __BIGGEST_ALIGNMENT__ sizeof(size_t)
48 #endif
49 
50 ZEND_DECLARE_MODULE_GLOBALS(ffi)
51 
52 typedef enum _zend_ffi_tag_kind {
53 	ZEND_FFI_TAG_ENUM,
54 	ZEND_FFI_TAG_STRUCT,
55 	ZEND_FFI_TAG_UNION
56 } zend_ffi_tag_kind;
57 
58 static const char *zend_ffi_tag_kind_name[3] = {"enum", "struct", "union"};
59 
60 
61 typedef struct _zend_ffi_tag {
62 	zend_ffi_tag_kind      kind;
63 	zend_ffi_type         *type;
64 } zend_ffi_tag;
65 
66 typedef enum _zend_ffi_type_kind {
67 	ZEND_FFI_TYPE_VOID,
68 	ZEND_FFI_TYPE_FLOAT,
69 	ZEND_FFI_TYPE_DOUBLE,
70 #ifdef HAVE_LONG_DOUBLE
71 	ZEND_FFI_TYPE_LONGDOUBLE,
72 #endif
73 	ZEND_FFI_TYPE_UINT8,
74 	ZEND_FFI_TYPE_SINT8,
75 	ZEND_FFI_TYPE_UINT16,
76 	ZEND_FFI_TYPE_SINT16,
77 	ZEND_FFI_TYPE_UINT32,
78 	ZEND_FFI_TYPE_SINT32,
79 	ZEND_FFI_TYPE_UINT64,
80 	ZEND_FFI_TYPE_SINT64,
81 	ZEND_FFI_TYPE_ENUM,
82 	ZEND_FFI_TYPE_BOOL,
83 	ZEND_FFI_TYPE_CHAR,
84 	ZEND_FFI_TYPE_POINTER,
85 	ZEND_FFI_TYPE_FUNC,
86 	ZEND_FFI_TYPE_ARRAY,
87 	ZEND_FFI_TYPE_STRUCT,
88 } zend_ffi_type_kind;
89 
90 typedef enum _zend_ffi_flags {
91 	ZEND_FFI_FLAG_CONST      = (1 << 0),
92 	ZEND_FFI_FLAG_OWNED      = (1 << 1),
93 	ZEND_FFI_FLAG_PERSISTENT = (1 << 2),
94 } zend_ffi_flags;
95 
96 struct _zend_ffi_type {
97 	zend_ffi_type_kind     kind;
98 	size_t                 size;
99 	uint32_t               align;
100 	uint32_t               attr;
101 	union {
102 		struct {
103 			zend_string        *tag_name;
104 			zend_ffi_type_kind  kind;
105 		} enumeration;
106 		struct {
107 			zend_ffi_type *type;
108 			zend_long      length;
109 		} array;
110 		struct {
111 			zend_ffi_type *type;
112 		} pointer;
113 		struct {
114 			zend_string   *tag_name;
115 			HashTable      fields;
116 		} record;
117 		struct {
118 			zend_ffi_type *ret_type;
119 			HashTable     *args;
120 			ffi_abi        abi;
121 		} func;
122 	};
123 };
124 
125 typedef struct _zend_ffi_field {
126 	size_t                 offset;
127 	zend_bool              is_const;
128 	zend_bool              is_nested; /* part of nested anonymous struct */
129 	uint8_t                first_bit;
130 	uint8_t                bits;
131 	zend_ffi_type         *type;
132 } zend_ffi_field;
133 
134 typedef enum _zend_ffi_symbol_kind {
135 	ZEND_FFI_SYM_TYPE,
136 	ZEND_FFI_SYM_CONST,
137 	ZEND_FFI_SYM_VAR,
138 	ZEND_FFI_SYM_FUNC
139 } zend_ffi_symbol_kind;
140 
141 typedef struct _zend_ffi_symbol {
142 	zend_ffi_symbol_kind   kind;
143 	zend_bool              is_const;
144 	zend_ffi_type         *type;
145 	union {
146 		void *addr;
147 		int64_t value;
148 	};
149 } zend_ffi_symbol;
150 
151 typedef struct _zend_ffi_scope {
152 	HashTable             *symbols;
153 	HashTable             *tags;
154 } zend_ffi_scope;
155 
156 typedef struct _zend_ffi {
157 	zend_object            std;
158 	DL_HANDLE              lib;
159 	HashTable             *symbols;
160 	HashTable             *tags;
161 	zend_bool              persistent;
162 } zend_ffi;
163 
164 #define ZEND_FFI_TYPE_OWNED        (1<<0)
165 
166 #define ZEND_FFI_TYPE(t) \
167 	((zend_ffi_type*)(((uintptr_t)(t)) & ~ZEND_FFI_TYPE_OWNED))
168 
169 #define ZEND_FFI_TYPE_IS_OWNED(t) \
170 	(((uintptr_t)(t)) & ZEND_FFI_TYPE_OWNED)
171 
172 #define ZEND_FFI_TYPE_MAKE_OWNED(t) \
173 	((zend_ffi_type*)(((uintptr_t)(t)) | ZEND_FFI_TYPE_OWNED))
174 
175 #define ZEND_FFI_SIZEOF_ARG \
176 	MAX(FFI_SIZEOF_ARG, sizeof(double))
177 
178 typedef struct _zend_ffi_cdata {
179 	zend_object            std;
180 	zend_ffi_type         *type;
181 	void                  *ptr;
182 	void                  *ptr_holder;
183 	zend_ffi_flags         flags;
184 } zend_ffi_cdata;
185 
186 typedef struct _zend_ffi_ctype {
187 	zend_object            std;
188 	zend_ffi_type         *type;
189 } zend_ffi_ctype;
190 
191 static zend_class_entry *zend_ffi_exception_ce;
192 static zend_class_entry *zend_ffi_parser_exception_ce;
193 static zend_class_entry *zend_ffi_ce;
194 static zend_class_entry *zend_ffi_cdata_ce;
195 static zend_class_entry *zend_ffi_ctype_ce;
196 
197 static zend_object_handlers zend_ffi_handlers;
198 static zend_object_handlers zend_ffi_cdata_handlers;
199 static zend_object_handlers zend_ffi_cdata_value_handlers;
200 static zend_object_handlers zend_ffi_cdata_free_handlers;
201 static zend_object_handlers zend_ffi_ctype_handlers;
202 
203 static zend_internal_function zend_ffi_new_fn;
204 static zend_internal_function zend_ffi_cast_fn;
205 static zend_internal_function zend_ffi_type_fn;
206 
207 /* forward declarations */
208 static void _zend_ffi_type_dtor(zend_ffi_type *type);
209 static void zend_ffi_finalize_type(zend_ffi_dcl *dcl);
210 static int zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2);
211 static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type);
212 static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, zend_bool preload);
213 static ZEND_FUNCTION(ffi_trampoline);
214 static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type);
215 static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type);
216 static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type);
217 
218 #if FFI_CLOSURES
219 static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value);
220 #endif
221 
zend_ffi_type_dtor(zend_ffi_type * type)222 static zend_always_inline void zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
223 {
224 	if (UNEXPECTED(ZEND_FFI_TYPE_IS_OWNED(type))) {
225 		_zend_ffi_type_dtor(type);
226 		return;
227 	}
228 }
229 /* }}} */
230 
zend_ffi_object_init(zend_object * object,zend_class_entry * ce)231 static zend_always_inline void zend_ffi_object_init(zend_object *object, zend_class_entry *ce) /* {{{ */
232 {
233 	GC_SET_REFCOUNT(object, 1);
234 	GC_TYPE_INFO(object) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT);
235 	object->ce = ce;
236 	object->properties = NULL;
237 	zend_objects_store_put(object);
238 }
239 /* }}} */
240 
zend_ffi_cdata_new(zend_class_entry * class_type)241 static zend_object *zend_ffi_cdata_new(zend_class_entry *class_type) /* {{{ */
242 {
243 	zend_ffi_cdata *cdata;
244 
245 	cdata = emalloc(sizeof(zend_ffi_cdata));
246 
247 	zend_ffi_object_init(&cdata->std, class_type);
248 	cdata->std.handlers = &zend_ffi_cdata_handlers;
249 
250 	cdata->type = NULL;
251 	cdata->ptr = NULL;
252 	cdata->flags = 0;
253 
254 	return &cdata->std;
255 }
256 /* }}} */
257 
zend_ffi_is_compatible_type(zend_ffi_type * dst_type,zend_ffi_type * src_type)258 static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
259 {
260 	while (1) {
261 		if (dst_type == src_type) {
262 			return 1;
263 		} else if (dst_type->kind == src_type->kind) {
264 			if (dst_type->kind < ZEND_FFI_TYPE_POINTER) {
265 				return 1;
266 			} else if (dst_type->kind == ZEND_FFI_TYPE_POINTER) {
267 				dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
268 				src_type = ZEND_FFI_TYPE(src_type->pointer.type);
269 				if (dst_type->kind == ZEND_FFI_TYPE_VOID ||
270 				    src_type->kind == ZEND_FFI_TYPE_VOID) {
271 				    return 1;
272 				}
273 			} else if (dst_type->kind == ZEND_FFI_TYPE_ARRAY &&
274 			           (dst_type->array.length == src_type->array.length ||
275 			            dst_type->array.length == 0)) {
276 				dst_type = ZEND_FFI_TYPE(dst_type->array.type);
277 				src_type = ZEND_FFI_TYPE(src_type->array.type);
278 			} else {
279 				break;
280 			}
281 		} else if (dst_type->kind == ZEND_FFI_TYPE_POINTER &&
282 		           src_type->kind == ZEND_FFI_TYPE_ARRAY) {
283 			dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
284 			src_type = ZEND_FFI_TYPE(src_type->array.type);
285 			if (dst_type->kind == ZEND_FFI_TYPE_VOID) {
286 			    return 1;
287 			}
288 		} else {
289 			break;
290 		}
291 	}
292 	return 0;
293 }
294 /* }}} */
295 
zend_ffi_face_struct_add_fields(ffi_type * t,zend_ffi_type * type,int * i,size_t size)296 static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size)
297 {
298 	zend_ffi_field *field;
299 
300 	ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
301 		switch (ZEND_FFI_TYPE(field->type)->kind) {
302 			case ZEND_FFI_TYPE_FLOAT:
303 				t->elements[(*i)++] = &ffi_type_float;
304 				break;
305 			case ZEND_FFI_TYPE_DOUBLE:
306 				t->elements[(*i)++] = &ffi_type_double;
307 				break;
308 #ifdef HAVE_LONG_DOUBLE
309 			case ZEND_FFI_TYPE_LONGDOUBLE:
310 				t->elements[(*i)++] = &ffi_type_longdouble;
311 				break;
312 #endif
313 			case ZEND_FFI_TYPE_SINT8:
314 			case ZEND_FFI_TYPE_UINT8:
315 			case ZEND_FFI_TYPE_BOOL:
316 			case ZEND_FFI_TYPE_CHAR:
317 				t->elements[(*i)++] = &ffi_type_uint8;
318 				break;
319 			case ZEND_FFI_TYPE_SINT16:
320 			case ZEND_FFI_TYPE_UINT16:
321 				t->elements[(*i)++] = &ffi_type_uint16;
322 				break;
323 			case ZEND_FFI_TYPE_SINT32:
324 			case ZEND_FFI_TYPE_UINT32:
325 				t->elements[(*i)++] = &ffi_type_uint32;
326 				break;
327 			case ZEND_FFI_TYPE_SINT64:
328 			case ZEND_FFI_TYPE_UINT64:
329 				t->elements[(*i)++] = &ffi_type_uint64;
330 				break;
331 			case ZEND_FFI_TYPE_POINTER:
332 				t->elements[(*i)++] = &ffi_type_pointer;
333 				break;
334 			case ZEND_FFI_TYPE_STRUCT: {
335 				zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
336 				/* for unions we use only the first field */
337 				int num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ?
338 					zend_hash_num_elements(&field_type->record.fields) : 1;
339 
340 				if (num_fields > 1) {
341 					size += sizeof(ffi_type*) * (num_fields - 1);
342 					t = erealloc(t, size);
343 					t->elements = (ffi_type**)(t + 1);
344 				}
345 				t = zend_ffi_face_struct_add_fields(t, field_type, i, size);
346 				break;
347 			}
348 			default:
349 				t->elements[(*i)++] = &ffi_type_void;
350 				break;
351 		}
352 		if (type->attr & ZEND_FFI_ATTR_UNION) {
353 			/* for unions we use only the first field */
354 			break;
355 		}
356 	} ZEND_HASH_FOREACH_END();
357 	return t;
358 }
359 
zend_ffi_make_fake_struct_type(zend_ffi_type * type)360 static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
361 {
362 	/* for unions we use only the first field */
363 	int num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ?
364 		zend_hash_num_elements(&type->record.fields) : 1;
365 	size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1);
366 	ffi_type *t = emalloc(size);
367 	int i;
368 
369 	t->size = type->size;
370 	t->alignment = type->align;
371 	t->type = FFI_TYPE_STRUCT;
372 	t->elements = (ffi_type**)(t + 1);
373 	i = 0;
374 	t = zend_ffi_face_struct_add_fields(t, type, &i, size);
375 	t->elements[i] = NULL;
376 	return t;
377 }
378 /* }}} */
379 
zend_ffi_get_type(zend_ffi_type * type)380 static ffi_type *zend_ffi_get_type(zend_ffi_type *type) /* {{{ */
381 {
382 	zend_ffi_type_kind kind = type->kind;
383 
384 again:
385     switch (kind) {
386 		case ZEND_FFI_TYPE_FLOAT:
387 			return &ffi_type_float;
388 		case ZEND_FFI_TYPE_DOUBLE:
389 			return &ffi_type_double;
390 #ifdef HAVE_LONG_DOUBLE
391 		case ZEND_FFI_TYPE_LONGDOUBLE:
392 			return &ffi_type_longdouble;
393 #endif
394 		case ZEND_FFI_TYPE_UINT8:
395 			return &ffi_type_uint8;
396 		case ZEND_FFI_TYPE_SINT8:
397 			return &ffi_type_sint8;
398 		case ZEND_FFI_TYPE_UINT16:
399 			return &ffi_type_uint16;
400 		case ZEND_FFI_TYPE_SINT16:
401 			return &ffi_type_sint16;
402 		case ZEND_FFI_TYPE_UINT32:
403 			return &ffi_type_uint32;
404 		case ZEND_FFI_TYPE_SINT32:
405 			return &ffi_type_sint32;
406 		case ZEND_FFI_TYPE_UINT64:
407 			return &ffi_type_uint64;
408 		case ZEND_FFI_TYPE_SINT64:
409 			return &ffi_type_sint64;
410 		case ZEND_FFI_TYPE_POINTER:
411 			return &ffi_type_pointer;
412 		case ZEND_FFI_TYPE_VOID:
413 			return &ffi_type_void;
414 		case ZEND_FFI_TYPE_BOOL:
415 			return &ffi_type_uint8;
416 		case ZEND_FFI_TYPE_CHAR:
417 			return &ffi_type_sint8;
418 		case ZEND_FFI_TYPE_ENUM:
419 			kind = type->enumeration.kind;
420 			goto again;
421 		case ZEND_FFI_TYPE_STRUCT:
422 			return zend_ffi_make_fake_struct_type(type);
423 		default:
424 			break;
425 	}
426 	return NULL;
427 }
428 /* }}} */
429 
zend_ffi_cdata_to_zval_slow(void * ptr,zend_ffi_type * type,zend_ffi_flags flags)430 static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
431 {
432 	zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
433 
434 	zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
435 	cdata->std.handlers =
436 		(type->kind < ZEND_FFI_TYPE_POINTER) ?
437 		&zend_ffi_cdata_value_handlers :
438 		&zend_ffi_cdata_handlers;
439 	cdata->type = type;
440 	cdata->flags = flags;
441 	cdata->ptr = ptr;
442 	return cdata;
443 }
444 /* }}} */
445 
zend_ffi_cdata_to_zval_slow_ptr(void * ptr,zend_ffi_type * type,zend_ffi_flags flags)446 static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ptr(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
447 {
448 	zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
449 
450 	zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
451 	cdata->std.handlers = &zend_ffi_cdata_handlers;
452 	cdata->type = type;
453 	cdata->flags = flags;
454 	cdata->ptr = (void*)&cdata->ptr_holder;
455 	*(void**)cdata->ptr = *(void**)ptr;
456 	return cdata;
457 }
458 /* }}} */
459 
zend_ffi_cdata_to_zval_slow_ret(void * ptr,zend_ffi_type * type,zend_ffi_flags flags)460 static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ret(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
461 {
462 	zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
463 
464 	zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
465 	cdata->std.handlers =
466 		(type->kind < ZEND_FFI_TYPE_POINTER) ?
467 		&zend_ffi_cdata_value_handlers :
468 		&zend_ffi_cdata_handlers;
469 	cdata->type = type;
470 	cdata->flags = flags;
471 	if (type->kind == ZEND_FFI_TYPE_POINTER) {
472 		cdata->ptr = (void*)&cdata->ptr_holder;
473 		*(void**)cdata->ptr = *(void**)ptr;
474 	} else if (type->kind == ZEND_FFI_TYPE_STRUCT) {
475 		cdata->ptr = emalloc(type->size);
476 		cdata->flags |= ZEND_FFI_FLAG_OWNED;
477 		memcpy(cdata->ptr, ptr, type->size);
478 	} else {
479 		cdata->ptr = ptr;
480 	}
481 	return cdata;
482 }
483 /* }}} */
484 
zend_ffi_cdata_to_zval(zend_ffi_cdata * cdata,void * ptr,zend_ffi_type * type,int read_type,zval * rv,zend_ffi_flags flags,zend_bool is_ret,zend_bool debug_union)485 static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, void *ptr, zend_ffi_type *type, int read_type, zval *rv, zend_ffi_flags flags, zend_bool is_ret, zend_bool debug_union) /* {{{ */
486 {
487 	if (read_type == BP_VAR_R) {
488 		zend_ffi_type_kind kind = type->kind;
489 
490 again:
491 	    switch (kind) {
492 			case ZEND_FFI_TYPE_FLOAT:
493 				ZVAL_DOUBLE(rv, *(float*)ptr);
494 				return;
495 			case ZEND_FFI_TYPE_DOUBLE:
496 				ZVAL_DOUBLE(rv, *(double*)ptr);
497 				return;
498 #ifdef HAVE_LONG_DOUBLE
499 			case ZEND_FFI_TYPE_LONGDOUBLE:
500 				ZVAL_DOUBLE(rv, *(long double*)ptr);
501 				return;
502 #endif
503 			case ZEND_FFI_TYPE_UINT8:
504 				ZVAL_LONG(rv, *(uint8_t*)ptr);
505 				return;
506 			case ZEND_FFI_TYPE_SINT8:
507 				ZVAL_LONG(rv, *(int8_t*)ptr);
508 				return;
509 			case ZEND_FFI_TYPE_UINT16:
510 				ZVAL_LONG(rv, *(uint16_t*)ptr);
511 				return;
512 			case ZEND_FFI_TYPE_SINT16:
513 				ZVAL_LONG(rv, *(int16_t*)ptr);
514 				return;
515 			case ZEND_FFI_TYPE_UINT32:
516 				ZVAL_LONG(rv, *(uint32_t*)ptr);
517 				return;
518 			case ZEND_FFI_TYPE_SINT32:
519 				ZVAL_LONG(rv, *(int32_t*)ptr);
520 				return;
521 			case ZEND_FFI_TYPE_UINT64:
522 				ZVAL_LONG(rv, *(uint64_t*)ptr);
523 				return;
524 			case ZEND_FFI_TYPE_SINT64:
525 				ZVAL_LONG(rv, *(int64_t*)ptr);
526 				return;
527 			case ZEND_FFI_TYPE_BOOL:
528 				ZVAL_BOOL(rv, *(uint8_t*)ptr);
529 				return;
530 			case ZEND_FFI_TYPE_CHAR:
531 				ZVAL_CHAR(rv, *(char*)ptr);
532 				return;
533 			case ZEND_FFI_TYPE_ENUM:
534 				kind = type->enumeration.kind;
535 				goto again;
536 			case ZEND_FFI_TYPE_POINTER:
537 				if (*(void**)ptr == NULL) {
538 					ZVAL_NULL(rv);
539 					return;
540 				} else if (debug_union) {
541 					ZVAL_STR(rv, zend_strpprintf(0, "%p", *(void**)ptr));
542 					return;
543 				} else if ((type->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
544 					ZVAL_STRING(rv, *(char**)ptr);
545 					return;
546 				}
547 				if (!cdata) {
548 					if (is_ret) {
549 						cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
550 					} else {
551 						cdata = zend_ffi_cdata_to_zval_slow_ptr(ptr, type, flags);
552 					}
553 				} else {
554 					GC_ADDREF(&cdata->std);
555 				}
556 				ZVAL_OBJ(rv, &cdata->std);
557 				return;
558 			default:
559 				break;
560 		}
561 	}
562 
563 	if (!cdata) {
564 		if (is_ret) {
565 			cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
566 		} else {
567 			cdata = zend_ffi_cdata_to_zval_slow(ptr, type, flags);
568 		}
569 	} else {
570 		GC_ADDREF(&cdata->std);
571 	}
572 	ZVAL_OBJ(rv, &cdata->std);
573 }
574 /* }}} */
575 
zend_ffi_bit_field_read(void * ptr,zend_ffi_field * field)576 static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ */
577 {
578 	size_t bit = field->first_bit;
579 	size_t last_bit = bit + field->bits - 1;
580 	uint8_t *p = (uint8_t *) ptr + bit / 8;
581 	uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
582 	size_t pos = bit % 8;
583 	size_t insert_pos = 0;
584 	uint8_t mask;
585 	uint64_t val = 0;
586 
587 	/* Bitfield fits into a single byte */
588 	if (p == last_p) {
589 		mask = (1U << field->bits) - 1U;
590 		return (*p >> pos) & mask;
591 	}
592 
593 	/* Read partial prefix byte */
594 	if (pos != 0) {
595 		size_t num_bits = 8 - pos;
596 		mask = ((1U << num_bits) - 1U) << pos;
597 		val = (*p++ >> pos) & mask;
598 		insert_pos += num_bits;
599 	}
600 
601 	/* Read full bytes */
602 	while (p < last_p) {
603 		val |= *p++ << insert_pos;
604 		insert_pos += 8;
605 	}
606 
607 	/* Read partial suffix byte */
608 	if (p == last_p) {
609 		size_t num_bits = last_bit % 8 + 1;
610 		mask = (1U << num_bits) - 1U;
611 		val |= (*p & mask) << insert_pos;
612 	}
613 
614 	return val;
615 }
616 /* }}} */
617 
zend_ffi_bit_field_to_zval(void * ptr,zend_ffi_field * field,zval * rv)618 static void zend_ffi_bit_field_to_zval(void *ptr, zend_ffi_field *field, zval *rv) /* {{{ */
619 {
620 	uint64_t val = zend_ffi_bit_field_read(ptr, field);
621 	if (ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_CHAR
622 	 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT8
623 	 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT16
624 	 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT32
625 	 || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT64) {
626 		/* Sign extend */
627 		uint64_t shift = 64 - (field->bits % 64);
628 		if (shift != 0) {
629 			val = (int64_t)(val << shift) >> shift;
630 		}
631 	}
632 	ZVAL_LONG(rv, val);
633 }
634 /* }}} */
635 
zend_ffi_zval_to_bit_field(void * ptr,zend_ffi_field * field,zval * value)636 static int zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *value) /* {{{ */
637 {
638 	uint64_t val = zval_get_long(value);
639 	size_t bit = field->first_bit;
640 	size_t last_bit = bit + field->bits - 1;
641 	uint8_t *p = (uint8_t *) ptr + bit / 8;
642 	uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
643 	size_t pos = bit % 8;
644 	uint8_t mask;
645 
646 	/* Bitfield fits into a single byte */
647 	if (p == last_p) {
648 		mask = ((1U << field->bits) - 1U) << pos;
649 		*p = (*p & ~mask) | ((val << pos) & mask);
650 		return SUCCESS;
651 	}
652 
653 	/* Write partial prefix byte */
654 	if (pos != 0) {
655 		size_t num_bits = 8 - pos;
656 		mask = ((1U << num_bits) - 1U) << pos;
657 		*p = (*p & ~mask) | ((val << pos) & mask);
658 		p++;
659 		val >>= num_bits;
660 	}
661 
662 	/* Write full bytes */
663 	while (p < last_p) {
664 		*p++ = val;
665 		val >>= 8;
666 	}
667 
668 	/* Write partial suffix byte */
669 	if (p == last_p) {
670 		size_t num_bits = last_bit % 8 + 1;
671 		mask = (1U << num_bits) - 1U;
672 		*p = (*p & ~mask) | (val & mask);
673 	}
674 
675 	return SUCCESS;
676 }
677 /* }}} */
678 
zend_ffi_zval_to_cdata(void * ptr,zend_ffi_type * type,zval * value)679 static zend_always_inline int zend_ffi_zval_to_cdata(void *ptr, zend_ffi_type *type, zval *value) /* {{{ */
680 {
681 	zend_long lval;
682 	double dval;
683 	zend_string *tmp_str;
684 	zend_string *str;
685 	zend_ffi_type_kind kind = type->kind;
686 
687 again:
688     switch (kind) {
689 		case ZEND_FFI_TYPE_FLOAT:
690 			dval = zval_get_double(value);
691 			*(float*)ptr = dval;
692 			break;
693 		case ZEND_FFI_TYPE_DOUBLE:
694 			dval = zval_get_double(value);
695 			*(double*)ptr = dval;
696 			break;
697 #ifdef HAVE_LONG_DOUBLE
698 		case ZEND_FFI_TYPE_LONGDOUBLE:
699 			dval = zval_get_double(value);
700 			*(long double*)ptr = dval;
701 			break;
702 #endif
703 		case ZEND_FFI_TYPE_UINT8:
704 			lval = zval_get_long(value);
705 			*(uint8_t*)ptr = lval;
706 			break;
707 		case ZEND_FFI_TYPE_SINT8:
708 			lval = zval_get_long(value);
709 			*(int8_t*)ptr = lval;
710 			break;
711 		case ZEND_FFI_TYPE_UINT16:
712 			lval = zval_get_long(value);
713 			*(uint16_t*)ptr = lval;
714 			break;
715 		case ZEND_FFI_TYPE_SINT16:
716 			lval = zval_get_long(value);
717 			*(int16_t*)ptr = lval;
718 			break;
719 		case ZEND_FFI_TYPE_UINT32:
720 			lval = zval_get_long(value);
721 			*(uint32_t*)ptr = lval;
722 			break;
723 		case ZEND_FFI_TYPE_SINT32:
724 			lval = zval_get_long(value);
725 			*(int32_t*)ptr = lval;
726 			break;
727 		case ZEND_FFI_TYPE_UINT64:
728 			lval = zval_get_long(value);
729 			*(uint64_t*)ptr = lval;
730 			break;
731 		case ZEND_FFI_TYPE_SINT64:
732 			lval = zval_get_long(value);
733 			*(int64_t*)ptr = lval;
734 			break;
735 		case ZEND_FFI_TYPE_BOOL:
736 			*(uint8_t*)ptr = zend_is_true(value);
737 			break;
738 		case ZEND_FFI_TYPE_CHAR:
739 			str = zval_get_tmp_string(value, &tmp_str);
740 			if (ZSTR_LEN(str) == 1) {
741 				*(char*)ptr = ZSTR_VAL(str)[0];
742 			} else {
743 				zend_ffi_assign_incompatible(value, type);
744 				return FAILURE;
745 			}
746 			zend_tmp_string_release(tmp_str);
747 			break;
748 		case ZEND_FFI_TYPE_ENUM:
749 			kind = type->enumeration.kind;
750 			goto again;
751 		case ZEND_FFI_TYPE_POINTER:
752 			if (Z_TYPE_P(value) == IS_NULL) {
753 				*(void**)ptr = NULL;
754 				break;
755 			} else if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
756 				zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value);
757 
758 				if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
759 					if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
760 						*(void**)ptr = *(void**)cdata->ptr;
761 					} else {
762 						if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
763 							zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign of owned C pointer");
764 							return FAILURE;
765 						}
766 						*(void**)ptr = cdata->ptr;
767 					}
768 					return SUCCESS;
769 				/* Allow transparent assignment of not-owned CData to compatible pointers */
770 				} else if (ZEND_FFI_TYPE(cdata->type)->kind != ZEND_FFI_TYPE_POINTER
771 				 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(type->pointer.type), ZEND_FFI_TYPE(cdata->type))) {
772 					if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
773 						zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign pointer to owned C data");
774 						return FAILURE;
775 					}
776 					*(void**)ptr = cdata->ptr;
777 					return SUCCESS;
778 				}
779 #if FFI_CLOSURES
780 			} else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
781 				void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), value);
782 
783 				if (callback) {
784 					*(void**)ptr = callback;
785 					break;
786 				} else {
787 					return FAILURE;
788 				}
789 #endif
790 			}
791 			zend_ffi_assign_incompatible(value, type);
792 			return FAILURE;
793 		case ZEND_FFI_TYPE_STRUCT:
794 		case ZEND_FFI_TYPE_ARRAY:
795 		default:
796 			if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
797 				zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value);
798 				if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type)) &&
799 				    type->size == ZEND_FFI_TYPE(cdata->type)->size) {
800 					memcpy(ptr, cdata->ptr, type->size);
801 					return SUCCESS;
802 				}
803 			}
804 			zend_ffi_assign_incompatible(value, type);
805 			return FAILURE;
806 	}
807 	return SUCCESS;
808 }
809 /* }}} */
810 
811 #if defined(ZEND_WIN32) && (defined(HAVE_FFI_FASTCALL) || defined(HAVE_FFI_STDCALL) || defined(HAVE_FFI_VECTORCALL_PARTIAL))
zend_ffi_arg_size(zend_ffi_type * type)812 static size_t zend_ffi_arg_size(zend_ffi_type *type) /* {{{ */
813 {
814 	zend_ffi_type *arg_type;
815 	size_t arg_size = 0;
816 
817 	ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
818 		arg_size += MAX(ZEND_FFI_TYPE(arg_type)->size, sizeof(size_t));
819 	} ZEND_HASH_FOREACH_END();
820 	return arg_size;
821 }
822 /* }}} */
823 #endif
824 
zend_ffi_mangled_func_name(zend_string * name,zend_ffi_type * type)825 static zend_always_inline zend_string *zend_ffi_mangled_func_name(zend_string *name, zend_ffi_type *type) /* {{{ */
826 {
827 #ifdef ZEND_WIN32
828 	switch (type->func.abi) {
829 # ifdef HAVE_FFI_FASTCALL
830 		case FFI_FASTCALL:
831 			return strpprintf(0, "@%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
832 # endif
833 # ifdef HAVE_FFI_STDCALL
834 		case FFI_STDCALL:
835 			return strpprintf(0, "_%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
836 # endif
837 # ifdef HAVE_FFI_VECTORCALL_PARTIAL
838 		case FFI_VECTORCALL_PARTIAL:
839 			return strpprintf(0, "%s@@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
840 # endif
841 	}
842 #endif
843 	return zend_string_copy(name);
844 }
845 /* }}} */
846 
847 #if FFI_CLOSURES
848 typedef struct _zend_ffi_callback_data {
849 	zend_fcall_info_cache  fcc;
850 	zend_ffi_type         *type;
851 	void                  *code;
852 	void                  *callback;
853 	ffi_cif                cif;
854 	uint32_t               arg_count;
855 	ffi_type              *ret_type;
856 	ffi_type              *arg_types[0];
857 } zend_ffi_callback_data;
858 
zend_ffi_callback_hash_dtor(zval * zv)859 static void zend_ffi_callback_hash_dtor(zval *zv) /* {{{ */
860 {
861 	zend_ffi_callback_data *callback_data = Z_PTR_P(zv);
862 
863 	ffi_closure_free(callback_data->callback);
864 	if (callback_data->fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) {
865 		OBJ_RELEASE(ZEND_CLOSURE_OBJECT(callback_data->fcc.function_handler));
866 	}
867 	efree(callback_data);
868 }
869 /* }}} */
870 
zend_ffi_callback_trampoline(ffi_cif * cif,void * ret,void ** args,void * data)871 static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, void* data) /* {{{ */
872 {
873 	zend_ffi_callback_data *callback_data = (zend_ffi_callback_data*)data;
874 	zend_fcall_info fci;
875 	zend_ffi_type *ret_type;
876 	zval retval;
877 	ALLOCA_FLAG(use_heap)
878 
879 	fci.size = sizeof(zend_fcall_info);
880 	ZVAL_UNDEF(&fci.function_name);
881 	fci.retval = &retval;
882 	fci.params = do_alloca(sizeof(zval) *callback_data->arg_count, use_heap);
883 	fci.object = NULL;
884 	fci.param_count = callback_data->arg_count;
885 	fci.named_params = NULL;
886 
887 	if (callback_data->type->func.args) {
888 		int n = 0;
889 		zend_ffi_type *arg_type;
890 
891 		ZEND_HASH_FOREACH_PTR(callback_data->type->func.args, arg_type) {
892 			arg_type = ZEND_FFI_TYPE(arg_type);
893 			zend_ffi_cdata_to_zval(NULL, args[n], arg_type, BP_VAR_R, &fci.params[n], (zend_ffi_flags)(arg_type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
894 			n++;
895 		} ZEND_HASH_FOREACH_END();
896 	}
897 
898 	ZVAL_UNDEF(&retval);
899 	if (zend_call_function(&fci, &callback_data->fcc) != SUCCESS) {
900 		zend_throw_error(zend_ffi_exception_ce, "Cannot call callback");
901 	}
902 
903 	if (callback_data->arg_count) {
904 		int n = 0;
905 
906 		for (n = 0; n < callback_data->arg_count; n++) {
907 			zval_ptr_dtor(&fci.params[n]);
908 		}
909 	}
910 	free_alloca(fci.params, use_heap);
911 
912 	if (EG(exception)) {
913 		zend_error(E_ERROR, "Throwing from FFI callbacks is not allowed");
914 	}
915 
916 	ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
917 	if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
918 		zend_ffi_zval_to_cdata(ret, ret_type, &retval);
919 	}
920 }
921 /* }}} */
922 
zend_ffi_create_callback(zend_ffi_type * type,zval * value)923 static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value) /* {{{ */
924 {
925 	zend_fcall_info_cache fcc;
926 	char *error = NULL;
927 	uint32_t arg_count;
928 	void *code;
929 	void *callback;
930 	zend_ffi_callback_data *callback_data;
931 
932 	if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
933 		zend_throw_error(zend_ffi_exception_ce, "Variadic function closures are not supported");
934 		return NULL;
935 	}
936 
937 	if (!zend_is_callable_ex(value, NULL, 0, NULL, &fcc, &error)) {
938 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, %s", error);
939 		return NULL;
940 	}
941 
942 	arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
943 	if (arg_count < fcc.function_handler->common.required_num_args) {
944 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, insufficient number of arguments");
945 		return NULL;
946 	}
947 
948 	callback = ffi_closure_alloc(sizeof(ffi_closure), &code);
949 	if (!callback) {
950 		zend_throw_error(zend_ffi_exception_ce, "Cannot allocate callback");
951 		return NULL;
952 	}
953 
954 	callback_data = emalloc(sizeof(zend_ffi_callback_data) + sizeof(ffi_type*) * arg_count);
955 	memcpy(&callback_data->fcc, &fcc, sizeof(zend_fcall_info_cache));
956 	callback_data->type = type;
957 	callback_data->callback = callback;
958 	callback_data->code = code;
959 	callback_data->arg_count = arg_count;
960 
961 	if (type->func.args) {
962 		int n = 0;
963 		zend_ffi_type *arg_type;
964 
965 		ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
966 			arg_type = ZEND_FFI_TYPE(arg_type);
967 			callback_data->arg_types[n] = zend_ffi_get_type(arg_type);
968 			if (!callback_data->arg_types[n]) {
969 				zend_ffi_pass_unsupported(arg_type);
970 				efree(callback_data);
971 				ffi_closure_free(callback);
972 				return NULL;
973 			}
974 			n++;
975 		} ZEND_HASH_FOREACH_END();
976 	}
977 	callback_data->ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
978 	if (!callback_data->ret_type) {
979 		zend_ffi_return_unsupported(type->func.ret_type);
980 		efree(callback_data);
981 		ffi_closure_free(callback);
982 		return NULL;
983 	}
984 
985 	if (ffi_prep_cif(&callback_data->cif, type->func.abi, callback_data->arg_count, callback_data->ret_type, callback_data->arg_types) != FFI_OK) {
986 		zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
987 		efree(callback_data);
988 		ffi_closure_free(callback);
989 		return NULL;
990 	}
991 
992 	if (ffi_prep_closure_loc(callback, &callback_data->cif, zend_ffi_callback_trampoline, callback_data, code) != FFI_OK) {
993 		zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback");
994 		efree(callback_data);
995 		ffi_closure_free(callback);
996 		return NULL;
997 	}
998 
999 	if (!FFI_G(callbacks)) {
1000 		FFI_G(callbacks) = emalloc(sizeof(HashTable));
1001 		zend_hash_init(FFI_G(callbacks), 0, NULL, zend_ffi_callback_hash_dtor, 0);
1002 	}
1003 	zend_hash_next_index_insert_ptr(FFI_G(callbacks), callback_data);
1004 
1005 	if (fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) {
1006 		GC_ADDREF(ZEND_CLOSURE_OBJECT(fcc.function_handler));
1007 	}
1008 
1009 	return code;
1010 }
1011 /* }}} */
1012 #endif
1013 
zend_ffi_cdata_get(zend_object * obj,zend_string * member,int read_type,void ** cache_slot,zval * rv)1014 static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_type, void **cache_slot, zval *rv) /* {{{ */
1015 {
1016 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1017 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1018 
1019 #if 0
1020 	if (UNEXPECTED(!cdata->ptr)) {
1021 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1022 		return &EG(uninitialized_zval);
1023 	}
1024 #endif
1025 
1026 	if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
1027 		zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be read");
1028 		return &EG(uninitialized_zval);;
1029 	}
1030 
1031 	zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0);
1032 	return rv;
1033 }
1034 /* }}} */
1035 
zend_ffi_cdata_set(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)1036 static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
1037 {
1038 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1039 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1040 
1041 #if 0
1042 	if (UNEXPECTED(!cdata->ptr)) {
1043 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1044 		return &EG(uninitialized_zval);;
1045 	}
1046 #endif
1047 
1048 	if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
1049 		zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be set");
1050 		return &EG(uninitialized_zval);;
1051 	}
1052 
1053 	zend_ffi_zval_to_cdata(cdata->ptr, type, value);
1054 
1055 	return value;
1056 }
1057 /* }}} */
1058 
zend_ffi_cdata_cast_object(zend_object * readobj,zval * writeobj,int type)1059 static int zend_ffi_cdata_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */
1060 {
1061 	if (type == IS_STRING) {
1062 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)readobj;
1063 		zend_ffi_type  *ctype = ZEND_FFI_TYPE(cdata->type);
1064 		void           *ptr = cdata->ptr;
1065 		zend_ffi_type_kind kind = ctype->kind;
1066 
1067 again:
1068 	    switch (kind) {
1069 			case ZEND_FFI_TYPE_FLOAT:
1070 				ZVAL_DOUBLE(writeobj, *(float*)ptr);
1071 				break;
1072 			case ZEND_FFI_TYPE_DOUBLE:
1073 				ZVAL_DOUBLE(writeobj, *(double*)ptr);
1074 				break;
1075 #ifdef HAVE_LONG_DOUBLE
1076 			case ZEND_FFI_TYPE_LONGDOUBLE:
1077 				ZVAL_DOUBLE(writeobj, *(long double*)ptr);
1078 				break;
1079 #endif
1080 			case ZEND_FFI_TYPE_UINT8:
1081 				ZVAL_LONG(writeobj, *(uint8_t*)ptr);
1082 				break;
1083 			case ZEND_FFI_TYPE_SINT8:
1084 				ZVAL_LONG(writeobj, *(int8_t*)ptr);
1085 				break;
1086 			case ZEND_FFI_TYPE_UINT16:
1087 				ZVAL_LONG(writeobj, *(uint16_t*)ptr);
1088 				break;
1089 			case ZEND_FFI_TYPE_SINT16:
1090 				ZVAL_LONG(writeobj, *(int16_t*)ptr);
1091 				break;
1092 			case ZEND_FFI_TYPE_UINT32:
1093 				ZVAL_LONG(writeobj, *(uint32_t*)ptr);
1094 				break;
1095 			case ZEND_FFI_TYPE_SINT32:
1096 				ZVAL_LONG(writeobj, *(int32_t*)ptr);
1097 				break;
1098 			case ZEND_FFI_TYPE_UINT64:
1099 				ZVAL_LONG(writeobj, *(uint64_t*)ptr);
1100 				break;
1101 			case ZEND_FFI_TYPE_SINT64:
1102 				ZVAL_LONG(writeobj, *(int64_t*)ptr);
1103 				break;
1104 			case ZEND_FFI_TYPE_BOOL:
1105 				ZVAL_BOOL(writeobj, *(uint8_t*)ptr);
1106 				break;
1107 			case ZEND_FFI_TYPE_CHAR:
1108 				ZVAL_CHAR(writeobj, *(char*)ptr);
1109 				return SUCCESS;
1110 			case ZEND_FFI_TYPE_ENUM:
1111 				kind = ctype->enumeration.kind;
1112 				goto again;
1113 			case ZEND_FFI_TYPE_POINTER:
1114 				if (*(void**)ptr == NULL) {
1115 					ZVAL_NULL(writeobj);
1116 					break;
1117 				} else if ((ctype->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(ctype->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
1118 					ZVAL_STRING(writeobj, *(char**)ptr);
1119 					return SUCCESS;
1120 				}
1121 				return FAILURE;
1122 			default:
1123 				return FAILURE;
1124 		}
1125 		convert_to_string(writeobj);
1126 		return SUCCESS;
1127 	} else if (type == _IS_BOOL) {
1128 		ZVAL_TRUE(writeobj);
1129 		return SUCCESS;
1130 	}
1131 
1132 	return FAILURE;
1133 }
1134 /* }}} */
1135 
zend_ffi_cdata_read_field(zend_object * obj,zend_string * field_name,int read_type,void ** cache_slot,zval * rv)1136 static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
1137 {
1138 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1139 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1140 	void           *ptr = cdata->ptr;
1141 	zend_ffi_field *field;
1142 
1143 	if (cache_slot && *cache_slot == type) {
1144 		field = *(cache_slot + 1);
1145 	} else {
1146 		if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1147 			if (type->kind == ZEND_FFI_TYPE_POINTER) {
1148 				/* transparently dereference the pointer */
1149 				if (UNEXPECTED(!ptr)) {
1150 					zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1151 					return &EG(uninitialized_zval);
1152 				}
1153 				ptr = (void*)(*(char**)ptr);
1154 				if (UNEXPECTED(!ptr)) {
1155 					zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1156 					return &EG(uninitialized_zval);
1157 				}
1158 				type = ZEND_FFI_TYPE(type->pointer.type);
1159 			}
1160 			if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1161 				zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
1162 				return &EG(uninitialized_zval);
1163 			}
1164 		}
1165 
1166 		field = zend_hash_find_ptr(&type->record.fields, field_name);
1167 		if (UNEXPECTED(!field)) {
1168 			zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
1169 			return &EG(uninitialized_zval);
1170 		}
1171 
1172 		if (cache_slot) {
1173 			*cache_slot = type;
1174 			*(cache_slot + 1) = field;
1175 		}
1176 	}
1177 
1178 #if 0
1179 	if (UNEXPECTED(!ptr)) {
1180 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1181 		return &EG(uninitialized_zval);
1182 	}
1183 #endif
1184 
1185 	if (EXPECTED(!field->bits)) {
1186 		zend_ffi_type *field_type = field->type;
1187 
1188 		if (ZEND_FFI_TYPE_IS_OWNED(field_type)) {
1189 			field_type = ZEND_FFI_TYPE(field_type);
1190 			if (!(field_type->attr & ZEND_FFI_ATTR_STORED)
1191 			 && field_type->kind == ZEND_FFI_TYPE_POINTER) {
1192 				field->type = field_type = zend_ffi_remember_type(field_type);
1193 			}
1194 		}
1195 		ptr = (void*)(((char*)ptr) + field->offset);
1196 		zend_ffi_cdata_to_zval(NULL, ptr, field_type, read_type, rv, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)field->is_const, 0, 0);
1197 	} else {
1198 		zend_ffi_bit_field_to_zval(ptr, field, rv);
1199 	}
1200 
1201 	return rv;
1202 }
1203 /* }}} */
1204 
zend_ffi_cdata_write_field(zend_object * obj,zend_string * field_name,zval * value,void ** cache_slot)1205 static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_name, zval *value, void **cache_slot) /* {{{ */
1206 {
1207 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1208 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1209 	void           *ptr = cdata->ptr;
1210 	zend_ffi_field *field;
1211 
1212 	if (cache_slot && *cache_slot == type) {
1213 		field = *(cache_slot + 1);
1214 	} else {
1215 		if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1216 			if (type->kind == ZEND_FFI_TYPE_POINTER) {
1217 				/* transparently dereference the pointer */
1218 				if (UNEXPECTED(!ptr)) {
1219 					zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1220 					return value;
1221 				}
1222 				ptr = (void*)(*(char**)ptr);
1223 				if (UNEXPECTED(!ptr)) {
1224 					zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1225 					return value;
1226 				}
1227 				type = ZEND_FFI_TYPE(type->pointer.type);
1228 			}
1229 			if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
1230 				zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
1231 				return value;
1232 			}
1233 		}
1234 
1235 		field = zend_hash_find_ptr(&type->record.fields, field_name);
1236 		if (UNEXPECTED(!field)) {
1237 			zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
1238 			return value;
1239 		}
1240 
1241 		if (cache_slot) {
1242 			*cache_slot = type;
1243 			*(cache_slot + 1) = field;
1244 		}
1245 	}
1246 
1247 #if 0
1248 	if (UNEXPECTED(!ptr)) {
1249 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1250 		return value;
1251 	}
1252 #endif
1253 
1254 	if (UNEXPECTED(cdata->flags & ZEND_FFI_FLAG_CONST)) {
1255 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
1256 		return value;
1257 	} else if (UNEXPECTED(field->is_const)) {
1258 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only field '%s'", ZSTR_VAL(field_name));
1259 		return value;
1260 	}
1261 
1262 	if (EXPECTED(!field->bits)) {
1263 		ptr = (void*)(((char*)ptr) + field->offset);
1264 		zend_ffi_zval_to_cdata(ptr, ZEND_FFI_TYPE(field->type), value);
1265 	} else {
1266 		zend_ffi_zval_to_bit_field(ptr, field, value);
1267 	}
1268 	return value;
1269 }
1270 /* }}} */
1271 
zend_ffi_cdata_read_dim(zend_object * obj,zval * offset,int read_type,zval * rv)1272 static zval *zend_ffi_cdata_read_dim(zend_object *obj, zval *offset, int read_type, zval *rv) /* {{{ */
1273 {
1274 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1275 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1276 	zend_long       dim = zval_get_long(offset);
1277 	zend_ffi_type  *dim_type;
1278 	void           *ptr;
1279 	zend_ffi_flags  is_const;
1280 
1281 	if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
1282 		if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
1283 		 && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
1284 			zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
1285 			return &EG(uninitialized_zval);
1286 		}
1287 
1288 		is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
1289 
1290 		dim_type = type->array.type;
1291 		if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1292 			dim_type = ZEND_FFI_TYPE(dim_type);
1293 			if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1294 			 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1295 				type->array.type = dim_type = zend_ffi_remember_type(dim_type);
1296 			}
1297 		}
1298 #if 0
1299 		if (UNEXPECTED(!cdata->ptr)) {
1300 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1301 			return &EG(uninitialized_zval);
1302 		}
1303 #endif
1304 		ptr = (void*)(((char*)cdata->ptr) + dim_type->size * dim);
1305 	} else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
1306 		is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
1307 		dim_type = type->pointer.type;
1308 		if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1309 			dim_type = ZEND_FFI_TYPE(dim_type);
1310 			if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1311 			 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1312 				type->pointer.type = dim_type = zend_ffi_remember_type(dim_type);
1313 			}
1314 		}
1315 		if (UNEXPECTED(!cdata->ptr)) {
1316 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1317 			return &EG(uninitialized_zval);
1318 		}
1319 		ptr = (void*)((*(char**)cdata->ptr) + dim_type->size * dim);
1320 	} else {
1321 		zend_throw_error(zend_ffi_exception_ce, "Attempt to read element of non C array");
1322 		return &EG(uninitialized_zval);
1323 	}
1324 
1325 	zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0, 0);
1326 	return rv;
1327 }
1328 /* }}} */
1329 
zend_ffi_cdata_write_dim(zend_object * obj,zval * offset,zval * value)1330 static void zend_ffi_cdata_write_dim(zend_object *obj, zval *offset, zval *value) /* {{{ */
1331 {
1332 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1333 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1334 	zend_long       dim;
1335 	void           *ptr;
1336 	zend_ffi_flags  is_const;
1337 
1338 	if (offset == NULL) {
1339 		zend_throw_error(zend_ffi_exception_ce, "Cannot add next element to object of type FFI\\CData");
1340 		return;
1341 	}
1342 
1343 	dim = zval_get_long(offset);
1344 	if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
1345 		if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
1346 		 && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
1347 			zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
1348 			return;
1349 		}
1350 
1351 		is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
1352 		type = ZEND_FFI_TYPE(type->array.type);
1353 #if 0
1354 		if (UNEXPECTED(!cdata->ptr)) {
1355 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1356 			return;
1357 		}
1358 #endif
1359 		ptr = (void*)(((char*)cdata->ptr) + type->size * dim);
1360 	} else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
1361 		is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
1362 		type = ZEND_FFI_TYPE(type->pointer.type);
1363 		if (UNEXPECTED(!cdata->ptr)) {
1364 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1365 			return;
1366 		}
1367 		ptr = (void*)((*(char**)cdata->ptr) + type->size * dim);
1368 	} else {
1369 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign element of non C array");
1370 		return;
1371 	}
1372 
1373 	if (UNEXPECTED(is_const)) {
1374 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
1375 		return;
1376 	}
1377 
1378 	zend_ffi_zval_to_cdata(ptr, type, value);
1379 }
1380 /* }}} */
1381 
1382 #define MAX_TYPE_NAME_LEN 256
1383 
1384 typedef struct _zend_ffi_ctype_name_buf {
1385 	char *start;
1386 	char *end;
1387 	char buf[MAX_TYPE_NAME_LEN];
1388 } zend_ffi_ctype_name_buf;
1389 
zend_ffi_ctype_name_prepend(zend_ffi_ctype_name_buf * buf,const char * str,size_t len)1390 static int zend_ffi_ctype_name_prepend(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
1391 {
1392 	buf->start -= len;
1393 	if (buf->start < buf->buf) {
1394 		return 0;
1395 	}
1396 	memcpy(buf->start, str, len);
1397 	return 1;
1398 }
1399 /* }}} */
1400 
zend_ffi_ctype_name_append(zend_ffi_ctype_name_buf * buf,const char * str,size_t len)1401 static int zend_ffi_ctype_name_append(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
1402 {
1403 	if (buf->end + len > buf->buf + MAX_TYPE_NAME_LEN) {
1404 		return 0;
1405 	}
1406 	memcpy(buf->end, str, len);
1407 	buf->end += len;
1408 	return 1;
1409 }
1410 /* }}} */
1411 
zend_ffi_ctype_name(zend_ffi_ctype_name_buf * buf,const zend_ffi_type * type)1412 static int zend_ffi_ctype_name(zend_ffi_ctype_name_buf *buf, const zend_ffi_type *type) /* {{{ */
1413 {
1414 	const char *name = NULL;
1415 	int is_ptr = 0;
1416 
1417 	while (1) {
1418 		switch (type->kind) {
1419 			case ZEND_FFI_TYPE_VOID:
1420 				name = "void";
1421 				break;
1422 			case ZEND_FFI_TYPE_FLOAT:
1423 				name = "float";
1424 				break;
1425 			case ZEND_FFI_TYPE_DOUBLE:
1426 				name = "double";
1427 				break;
1428 #ifdef HAVE_LONG_DOUBLE
1429 			case ZEND_FFI_TYPE_LONGDOUBLE:
1430 				name = "long double";
1431 				break;
1432 #endif
1433 			case ZEND_FFI_TYPE_UINT8:
1434 				name = "uint8_t";
1435 				break;
1436 			case ZEND_FFI_TYPE_SINT8:
1437 				name = "int8_t";
1438 				break;
1439 			case ZEND_FFI_TYPE_UINT16:
1440 				name = "uint16_t";
1441 				break;
1442 			case ZEND_FFI_TYPE_SINT16:
1443 				name = "int16_t";
1444 				break;
1445 			case ZEND_FFI_TYPE_UINT32:
1446 				name = "uint32_t";
1447 				break;
1448 			case ZEND_FFI_TYPE_SINT32:
1449 				name = "int32_t";
1450 				break;
1451 			case ZEND_FFI_TYPE_UINT64:
1452 				name = "uint64_t";
1453 				break;
1454 			case ZEND_FFI_TYPE_SINT64:
1455 				name = "int64_t";
1456 				break;
1457 			case ZEND_FFI_TYPE_ENUM:
1458 				if (type->enumeration.tag_name) {
1459 					zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->enumeration.tag_name), ZSTR_LEN(type->enumeration.tag_name));
1460 				} else {
1461 					zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1462 				}
1463 				name = "enum ";
1464 				break;
1465 			case ZEND_FFI_TYPE_BOOL:
1466 				name = "bool";
1467 				break;
1468 			case ZEND_FFI_TYPE_CHAR:
1469 				name = "char";
1470 				break;
1471 			case ZEND_FFI_TYPE_POINTER:
1472 				if (!zend_ffi_ctype_name_prepend(buf, "*", 1)) {
1473 					return 0;
1474 				}
1475 				is_ptr = 1;
1476 				type = ZEND_FFI_TYPE(type->pointer.type);
1477 				break;
1478 			case ZEND_FFI_TYPE_FUNC:
1479 				if (is_ptr) {
1480 					is_ptr = 0;
1481 					if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
1482 					 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1483 						return 0;
1484 					}
1485 				}
1486 				if (!zend_ffi_ctype_name_append(buf, "(", 1)
1487 				 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1488 					return 0;
1489 				}
1490 				type = ZEND_FFI_TYPE(type->func.ret_type);
1491 				break;
1492 			case ZEND_FFI_TYPE_ARRAY:
1493 				if (is_ptr) {
1494 					is_ptr = 0;
1495 					if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
1496 					 || !zend_ffi_ctype_name_append(buf, ")", 1)) {
1497 						return 0;
1498 					}
1499 				}
1500 				if (!zend_ffi_ctype_name_append(buf, "[", 1)) {
1501 					return 0;
1502 				}
1503 				if (type->attr & ZEND_FFI_ATTR_VLA) {
1504 					if (!zend_ffi_ctype_name_append(buf, "*", 1)) {
1505 						return 0;
1506 					}
1507 				} else if (!(type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
1508 					char str[MAX_LENGTH_OF_LONG + 1];
1509 					char *s = zend_print_long_to_buf(str + sizeof(str) - 1, type->array.length);
1510 
1511 					if (!zend_ffi_ctype_name_append(buf, s, strlen(s))) {
1512 						return 0;
1513 					}
1514 				}
1515 				if (!zend_ffi_ctype_name_append(buf, "]", 1)) {
1516 					return 0;
1517 				}
1518 				type = ZEND_FFI_TYPE(type->array.type);
1519 				break;
1520 			case ZEND_FFI_TYPE_STRUCT:
1521 				if (type->attr & ZEND_FFI_ATTR_UNION) {
1522 					if (type->record.tag_name) {
1523 						zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
1524 					} else {
1525 						zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1526 					}
1527 					name = "union ";
1528 				} else {
1529 					if (type->record.tag_name) {
1530 						zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
1531 					} else {
1532 						zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
1533 					}
1534 					name = "struct ";
1535 				}
1536 				break;
1537 			default:
1538 				ZEND_UNREACHABLE();
1539 		}
1540 		if (name) {
1541 			break;
1542 		}
1543 	}
1544 
1545 //	if (buf->start != buf->end && *buf->start != '[') {
1546 //		if (!zend_ffi_ctype_name_prepend(buf, " ", 1)) {
1547 //			return 0;
1548 //		}
1549 //	}
1550 	return zend_ffi_ctype_name_prepend(buf, name, strlen(name));
1551 }
1552 /* }}} */
1553 
zend_ffi_return_unsupported(zend_ffi_type * type)1554 static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type) /* {{{ */
1555 {
1556 	type = ZEND_FFI_TYPE(type);
1557 	if (type->kind == ZEND_FFI_TYPE_STRUCT) {
1558 		zend_throw_error(zend_ffi_exception_ce, "FFI return struct/union is not implemented");
1559 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
1560 		zend_throw_error(zend_ffi_exception_ce, "FFI return array is not implemented");
1561 	} else {
1562 		zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported return type");
1563 	}
1564 }
1565 /* }}} */
1566 
zend_ffi_pass_unsupported(zend_ffi_type * type)1567 static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type) /* {{{ */
1568 {
1569 	type = ZEND_FFI_TYPE(type);
1570 	if (type->kind == ZEND_FFI_TYPE_STRUCT) {
1571 		zend_throw_error(zend_ffi_exception_ce, "FFI passing struct/union is not implemented");
1572 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
1573 		zend_throw_error(zend_ffi_exception_ce, "FFI passing array is not implemented");
1574 	} else {
1575 		zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported parameter type");
1576 	}
1577 }
1578 /* }}} */
1579 
zend_ffi_pass_incompatible(zval * arg,zend_ffi_type * type,uint32_t n,zend_execute_data * execute_data)1580 static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, uint32_t n, zend_execute_data *execute_data) /* {{{ */
1581 {
1582 	zend_ffi_ctype_name_buf buf1, buf2;
1583 
1584 	buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1585 	if (!zend_ffi_ctype_name(&buf1, type)) {
1586 		zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name));
1587 	} else {
1588 		*buf1.end = 0;
1589 		if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
1590 			zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
1591 
1592 			type = ZEND_FFI_TYPE(cdata->type);
1593 			buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1594 			if (!zend_ffi_ctype_name(&buf2, type)) {
1595 				zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start);
1596 			} else {
1597 				*buf2.end = 0;
1598 				zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, buf2.start);
1599 			}
1600 		} else {
1601 			zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found PHP '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, zend_zval_type_name(arg));
1602 		}
1603 	}
1604 }
1605 /* }}} */
1606 
zend_ffi_assign_incompatible(zval * arg,zend_ffi_type * type)1607 static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type) /* {{{ */
1608 {
1609 	zend_ffi_ctype_name_buf buf1, buf2;
1610 
1611 	buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1612 	if (!zend_ffi_ctype_name(&buf1, type)) {
1613 		zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning");
1614 	} else {
1615 		*buf1.end = 0;
1616 		if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
1617 			zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
1618 
1619 			type = ZEND_FFI_TYPE(cdata->type);
1620 			buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1621 			if (!zend_ffi_ctype_name(&buf2, type)) {
1622 				zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s'", buf1.start);
1623 			} else {
1624 				*buf2.end = 0;
1625 				zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from type '%s'", buf1.start, buf2.start);
1626 			}
1627 		} else {
1628 			zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from PHP '%s'", buf1.start, zend_zval_type_name(arg));
1629 		}
1630 	}
1631 }
1632 /* }}} */
1633 
zend_ffi_get_class_name(zend_string * prefix,const zend_ffi_type * type)1634 static zend_string *zend_ffi_get_class_name(zend_string *prefix, const zend_ffi_type *type) /* {{{ */
1635 {
1636 	zend_ffi_ctype_name_buf buf;
1637 
1638 	buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
1639 	if (!zend_ffi_ctype_name(&buf, type)) {
1640 		return zend_string_copy(prefix);
1641 	} else {
1642 		return zend_string_concat3(
1643 			ZSTR_VAL(prefix), ZSTR_LEN(prefix), ":", 1, buf.start, buf.end - buf.start);
1644 	}
1645 }
1646 /* }}} */
1647 
zend_ffi_cdata_get_class_name(const zend_object * zobj)1648 static zend_string *zend_ffi_cdata_get_class_name(const zend_object *zobj) /* {{{ */
1649 {
1650 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)zobj;
1651 
1652 	return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(cdata->type));
1653 }
1654 /* }}} */
1655 
zend_ffi_cdata_compare_objects(zval * o1,zval * o2)1656 static int zend_ffi_cdata_compare_objects(zval *o1, zval *o2) /* {{{ */
1657 {
1658 	if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_cdata_ce &&
1659 	    Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_cdata_ce) {
1660 		zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(o1);
1661 		zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(o2);
1662 		zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type);
1663 		zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
1664 
1665 		if (type1->kind == ZEND_FFI_TYPE_POINTER && type2->kind == ZEND_FFI_TYPE_POINTER) {
1666 			void *ptr1 = *(void**)cdata1->ptr;
1667 			void *ptr2 = *(void**)cdata2->ptr;
1668 
1669 			if (!ptr1 || !ptr2) {
1670 				zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1671 				return 0;
1672 			}
1673 			return ptr1 == ptr2 ? 0 : (ptr1 < ptr2 ? -1 : 1);
1674 		}
1675 	}
1676 	zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
1677 	return 0;
1678 }
1679 /* }}} */
1680 
zend_ffi_cdata_count_elements(zend_object * obj,zend_long * count)1681 static int zend_ffi_cdata_count_elements(zend_object *obj, zend_long *count) /* {{{ */
1682 {
1683 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1684 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1685 
1686 	if (type->kind != ZEND_FFI_TYPE_ARRAY) {
1687 		zend_throw_error(zend_ffi_exception_ce, "Attempt to count() on non C array");
1688 		return FAILURE;
1689 	} else {
1690 		*count = type->array.length;
1691 		return SUCCESS;
1692 	}
1693 }
1694 /* }}} */
1695 
zend_ffi_add(zend_ffi_cdata * base_cdata,zend_ffi_type * base_type,zend_long offset)1696 static zend_object* zend_ffi_add(zend_ffi_cdata *base_cdata, zend_ffi_type *base_type, zend_long offset) /* {{{ */
1697 {
1698 	char *ptr;
1699 	zend_ffi_type *ptr_type;
1700 	zend_ffi_cdata *cdata =
1701 		(zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
1702 
1703 	if (base_type->kind == ZEND_FFI_TYPE_POINTER) {
1704 		if (ZEND_FFI_TYPE_IS_OWNED(base_cdata->type)) {
1705 			if (!(base_type->attr & ZEND_FFI_ATTR_STORED)) {
1706 				if (GC_REFCOUNT(&base_cdata->std) == 1) {
1707 					/* transfer type ownership */
1708 					base_cdata->type = base_type;
1709 					base_type = ZEND_FFI_TYPE_MAKE_OWNED(base_type);
1710 				} else {
1711 					base_cdata->type = base_type = zend_ffi_remember_type(base_type);
1712 				}
1713 			}
1714 		}
1715 		cdata->type = base_type;
1716 		ptr = (char*)(*(void**)base_cdata->ptr);
1717 		ptr_type = ZEND_FFI_TYPE(base_type)->pointer.type;
1718 	} else {
1719 		zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
1720 
1721 		new_type->kind = ZEND_FFI_TYPE_POINTER;
1722 		new_type->attr = 0;
1723 		new_type->size = sizeof(void*);
1724 		new_type->align = _Alignof(void*);
1725 
1726 		ptr_type = base_type->array.type;
1727 		if (ZEND_FFI_TYPE_IS_OWNED(ptr_type)) {
1728 			ptr_type = ZEND_FFI_TYPE(ptr_type);
1729 			if (!(ptr_type->attr & ZEND_FFI_ATTR_STORED)) {
1730 				if (GC_REFCOUNT(&base_cdata->std) == 1) {
1731 					/* transfer type ownership */
1732 					base_type->array.type = ptr_type;
1733 					ptr_type = ZEND_FFI_TYPE_MAKE_OWNED(ptr_type);
1734 				} else {
1735 					base_type->array.type = ptr_type = zend_ffi_remember_type(ptr_type);
1736 				}
1737 			}
1738 		}
1739 		new_type->pointer.type = ptr_type;
1740 
1741 		cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
1742 		ptr = (char*)base_cdata->ptr;
1743 	}
1744 	cdata->ptr = &cdata->ptr_holder;
1745 	cdata->ptr_holder = ptr +
1746 		(ptrdiff_t) (offset * ZEND_FFI_TYPE(ptr_type)->size);
1747 	cdata->flags = base_cdata->flags & ZEND_FFI_FLAG_CONST;
1748 	return &cdata->std;
1749 }
1750 /* }}} */
1751 
zend_ffi_cdata_do_operation(zend_uchar opcode,zval * result,zval * op1,zval * op2)1752 static int zend_ffi_cdata_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
1753 {
1754 	zend_long offset;
1755 
1756 	ZVAL_DEREF(op1);
1757 	ZVAL_DEREF(op2);
1758 	if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJCE_P(op1) == zend_ffi_cdata_ce) {
1759 		zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(op1);
1760 		zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type);
1761 
1762 		if (type1->kind == ZEND_FFI_TYPE_POINTER || type1->kind == ZEND_FFI_TYPE_ARRAY) {
1763 			if (opcode == ZEND_ADD) {
1764 				offset = zval_get_long(op2);
1765 				ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, offset));
1766 				if (result == op1) {
1767 					OBJ_RELEASE(&cdata1->std);
1768 				}
1769 				return SUCCESS;
1770 			} else if (opcode == ZEND_SUB) {
1771 				if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
1772 					zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2);
1773 					zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
1774 
1775 					if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
1776 						zend_ffi_type *t1, *t2;
1777 						char *p1, *p2;
1778 
1779 						if (type1->kind == ZEND_FFI_TYPE_POINTER) {
1780 							t1 = ZEND_FFI_TYPE(type1->pointer.type);
1781 							p1 = (char*)(*(void**)cdata1->ptr);
1782 						} else {
1783 							t1 = ZEND_FFI_TYPE(type1->array.type);
1784 							p1 = cdata1->ptr;
1785 						}
1786 						if (type2->kind == ZEND_FFI_TYPE_POINTER) {
1787 							t2 = ZEND_FFI_TYPE(type2->pointer.type);
1788 							p2 = (char*)(*(void**)cdata2->ptr);
1789 						} else {
1790 							t2 = ZEND_FFI_TYPE(type2->array.type);
1791 							p2 = cdata2->ptr;
1792 						}
1793 						if (zend_ffi_is_same_type(t1, t2)) {
1794 							ZVAL_LONG(result,
1795 								(zend_long)(p1 - p2) / (zend_long)t1->size);
1796 							return SUCCESS;
1797 						}
1798 					}
1799 				}
1800 				offset = zval_get_long(op2);
1801 				ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, -offset));
1802 				if (result == op1) {
1803 					OBJ_RELEASE(&cdata1->std);
1804 				}
1805 				return SUCCESS;
1806 			}
1807 		}
1808 	} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
1809 		zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2);
1810 		zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
1811 
1812 		if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
1813 			if (opcode == ZEND_ADD) {
1814 				offset = zval_get_long(op1);
1815 				ZVAL_OBJ(result, zend_ffi_add(cdata2, type2, offset));
1816 				return SUCCESS;
1817 			}
1818 		}
1819 	}
1820 
1821 	return FAILURE;
1822 }
1823 /* }}} */
1824 
1825 typedef struct _zend_ffi_cdata_iterator {
1826 	zend_object_iterator it;
1827 	zend_long key;
1828 	zval value;
1829 	zend_bool by_ref;
1830 } zend_ffi_cdata_iterator;
1831 
zend_ffi_cdata_it_dtor(zend_object_iterator * iter)1832 static void zend_ffi_cdata_it_dtor(zend_object_iterator *iter) /* {{{ */
1833 {
1834 	zval_ptr_dtor(&((zend_ffi_cdata_iterator*)iter)->value);
1835 	zval_ptr_dtor(&iter->data);
1836 }
1837 /* }}} */
1838 
zend_ffi_cdata_it_valid(zend_object_iterator * it)1839 static int zend_ffi_cdata_it_valid(zend_object_iterator *it) /* {{{ */
1840 {
1841 	zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
1842 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data);
1843 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1844 
1845 	return (iter->key >= 0 && iter->key < type->array.length) ? SUCCESS : FAILURE;
1846 }
1847 /* }}} */
1848 
zend_ffi_cdata_it_get_current_data(zend_object_iterator * it)1849 static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{ */
1850 {
1851 	zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
1852 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data);
1853 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1854 	zend_ffi_type  *dim_type;
1855 	void *ptr;
1856 
1857 	if (!cdata->ptr) {
1858 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1859 		return &EG(uninitialized_zval);
1860 	}
1861 	dim_type = type->array.type;
1862 	if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
1863 		dim_type = ZEND_FFI_TYPE(dim_type);
1864 		if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
1865 		 && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
1866 			type->array.type = dim_type = zend_ffi_remember_type(dim_type);
1867 		}
1868 	}
1869 	ptr = (void*)((char*)cdata->ptr + dim_type->size * iter->it.index);
1870 
1871 	zval_ptr_dtor(&iter->value);
1872 	zend_ffi_cdata_to_zval(NULL, ptr, dim_type, iter->by_ref ? BP_VAR_RW : BP_VAR_R, &iter->value, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
1873 	return &iter->value;
1874 }
1875 /* }}} */
1876 
zend_ffi_cdata_it_get_current_key(zend_object_iterator * it,zval * key)1877 static void zend_ffi_cdata_it_get_current_key(zend_object_iterator *it, zval *key) /* {{{ */
1878 {
1879 	zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
1880 	ZVAL_LONG(key, iter->key);
1881 }
1882 /* }}} */
1883 
zend_ffi_cdata_it_move_forward(zend_object_iterator * it)1884 static void zend_ffi_cdata_it_move_forward(zend_object_iterator *it) /* {{{ */
1885 {
1886 	zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
1887 	iter->key++;
1888 }
1889 /* }}} */
1890 
zend_ffi_cdata_it_rewind(zend_object_iterator * it)1891 static void zend_ffi_cdata_it_rewind(zend_object_iterator *it) /* {{{ */
1892 {
1893 	zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
1894 	iter->key = 0;
1895 }
1896 /* }}} */
1897 
1898 static const zend_object_iterator_funcs zend_ffi_cdata_it_funcs = {
1899 	zend_ffi_cdata_it_dtor,
1900 	zend_ffi_cdata_it_valid,
1901 	zend_ffi_cdata_it_get_current_data,
1902 	zend_ffi_cdata_it_get_current_key,
1903 	zend_ffi_cdata_it_move_forward,
1904 	zend_ffi_cdata_it_rewind,
1905 	NULL,
1906 	NULL, /* get_gc */
1907 };
1908 
zend_ffi_cdata_get_iterator(zend_class_entry * ce,zval * object,int by_ref)1909 static zend_object_iterator *zend_ffi_cdata_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
1910 {
1911 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(object);
1912 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1913 	zend_ffi_cdata_iterator *iter;
1914 
1915 	if (type->kind != ZEND_FFI_TYPE_ARRAY) {
1916 		zend_throw_error(zend_ffi_exception_ce, "Attempt to iterate on non C array");
1917 		return NULL;
1918 	}
1919 
1920 	iter = emalloc(sizeof(zend_ffi_cdata_iterator));
1921 
1922 	zend_iterator_init(&iter->it);
1923 
1924 	Z_ADDREF_P(object);
1925 	ZVAL_OBJ(&iter->it.data, Z_OBJ_P(object));
1926 	iter->it.funcs = &zend_ffi_cdata_it_funcs;
1927 	iter->key = 0;
1928 	iter->by_ref = by_ref;
1929 	ZVAL_UNDEF(&iter->value);
1930 
1931 	return &iter->it;
1932 }
1933 /* }}} */
1934 
zend_ffi_cdata_get_debug_info(zend_object * obj,int * is_temp)1935 static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
1936 {
1937 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
1938 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
1939 	void           *ptr = cdata->ptr;
1940 	HashTable      *ht = NULL;
1941 	zend_string    *key;
1942 	zend_ffi_field *f;
1943 	zend_long       n;
1944 	zval            tmp;
1945 
1946 	if (!cdata->ptr) {
1947 		zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
1948 		return NULL;
1949 	}
1950 
1951     switch (type->kind) {
1952 		case ZEND_FFI_TYPE_BOOL:
1953 		case ZEND_FFI_TYPE_CHAR:
1954 		case ZEND_FFI_TYPE_ENUM:
1955 		case ZEND_FFI_TYPE_FLOAT:
1956 		case ZEND_FFI_TYPE_DOUBLE:
1957 #ifdef HAVE_LONG_DOUBLE
1958 		case ZEND_FFI_TYPE_LONGDOUBLE:
1959 #endif
1960 		case ZEND_FFI_TYPE_UINT8:
1961 		case ZEND_FFI_TYPE_SINT8:
1962 		case ZEND_FFI_TYPE_UINT16:
1963 		case ZEND_FFI_TYPE_SINT16:
1964 		case ZEND_FFI_TYPE_UINT32:
1965 		case ZEND_FFI_TYPE_SINT32:
1966 		case ZEND_FFI_TYPE_UINT64:
1967 		case ZEND_FFI_TYPE_SINT64:
1968 			zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
1969 			ht = zend_new_array(1);
1970 			zend_hash_str_add(ht, "cdata", sizeof("cdata")-1, &tmp);
1971 			*is_temp = 1;
1972 			return ht;
1973 			break;
1974 		case ZEND_FFI_TYPE_POINTER:
1975 			if (*(void**)ptr == NULL) {
1976 				ZVAL_NULL(&tmp);
1977 				ht = zend_new_array(1);
1978 				zend_hash_index_add_new(ht, 0, &tmp);
1979 				*is_temp = 1;
1980 				return ht;
1981 			} else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
1982 				ZVAL_LONG(&tmp, (uintptr_t)*(void**)ptr);
1983 				ht = zend_new_array(1);
1984 				zend_hash_index_add_new(ht, 0, &tmp);
1985 				*is_temp = 1;
1986 				return ht;
1987 			} else {
1988 				zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
1989 				ht = zend_new_array(1);
1990 				zend_hash_index_add_new(ht, 0, &tmp);
1991 				*is_temp = 1;
1992 				return ht;
1993 			}
1994 			break;
1995 		case ZEND_FFI_TYPE_STRUCT:
1996 			ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
1997 			ZEND_HASH_FOREACH_STR_KEY_PTR(&type->record.fields, key, f) {
1998 				if (key) {
1999 					if (!f->bits) {
2000 						void *f_ptr = (void*)(((char*)ptr) + f->offset);
2001 						zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, type->attr & ZEND_FFI_ATTR_UNION);
2002 						zend_hash_add(ht, key, &tmp);
2003 					} else {
2004 						zend_ffi_bit_field_to_zval(ptr, f, &tmp);
2005 						zend_hash_add(ht, key, &tmp);
2006 					}
2007 				}
2008 			} ZEND_HASH_FOREACH_END();
2009 			*is_temp = 1;
2010 			return ht;
2011 		case ZEND_FFI_TYPE_ARRAY:
2012 			ht = zend_new_array(type->array.length);
2013 			for (n = 0; n < type->array.length; n++) {
2014 				zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
2015 				zend_hash_index_add(ht, n, &tmp);
2016 				ptr = (void*)(((char*)ptr) + ZEND_FFI_TYPE(type->array.type)->size);
2017 			}
2018 			*is_temp = 1;
2019 			return ht;
2020 		case ZEND_FFI_TYPE_FUNC:
2021 			ht = zend_new_array(0);
2022 			// TODO: function name ???
2023 			*is_temp = 1;
2024 			return ht;
2025 			break;
2026 		default:
2027 			ZEND_UNREACHABLE();
2028 			break;
2029 	}
2030 	return NULL;
2031 }
2032 /* }}} */
2033 
zend_ffi_cdata_get_closure(zend_object * obj,zend_class_entry ** ce_ptr,zend_function ** fptr_ptr,zend_object ** obj_ptr,zend_bool check_only)2034 static int zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, zend_bool check_only) /* {{{ */
2035 {
2036 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
2037 	zend_ffi_type  *type = ZEND_FFI_TYPE(cdata->type);
2038 	zend_function  *func;
2039 
2040 	if (type->kind != ZEND_FFI_TYPE_POINTER) {
2041 		if (!check_only) {
2042 			zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
2043 		}
2044 		return FAILURE;
2045 	}
2046 	type = ZEND_FFI_TYPE(type->pointer.type);
2047 	if (type->kind != ZEND_FFI_TYPE_FUNC) {
2048 		if (!check_only) {
2049 			zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
2050 		}
2051 		return FAILURE;
2052 	}
2053 	if (!cdata->ptr) {
2054 		if (!check_only) {
2055 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
2056 		}
2057 		return FAILURE;
2058 	}
2059 
2060 	if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
2061 		func = &EG(trampoline);
2062 	} else {
2063 		func = ecalloc(sizeof(zend_internal_function), 1);
2064 	}
2065 	func->type = ZEND_INTERNAL_FUNCTION;
2066 	func->common.arg_flags[0] = 0;
2067 	func->common.arg_flags[1] = 0;
2068 	func->common.arg_flags[2] = 0;
2069 	func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
2070 	func->common.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE);
2071 	/* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
2072 	func->common.num_args = 0;
2073 	func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2074 	func->common.scope = NULL;
2075 	func->common.prototype = NULL;
2076 	func->common.arg_info = NULL;
2077 	func->internal_function.handler = ZEND_FN(ffi_trampoline);
2078 	func->internal_function.module = NULL;
2079 
2080 	func->internal_function.reserved[0] = type;
2081 	func->internal_function.reserved[1] = *(void**)cdata->ptr;
2082 
2083 	*ce_ptr = NULL;
2084 	*fptr_ptr= func;
2085 	*obj_ptr = NULL;
2086 
2087 	return SUCCESS;
2088 }
2089 /* }}} */
2090 
zend_ffi_ctype_new(zend_class_entry * class_type)2091 static zend_object *zend_ffi_ctype_new(zend_class_entry *class_type) /* {{{ */
2092 {
2093 	zend_ffi_ctype *ctype;
2094 
2095 	ctype = emalloc(sizeof(zend_ffi_ctype));
2096 
2097 	zend_ffi_object_init(&ctype->std, class_type);
2098 	ctype->std.handlers = &zend_ffi_ctype_handlers;
2099 
2100 	ctype->type = NULL;
2101 
2102 	return &ctype->std;
2103 }
2104 /* }}} */
2105 
zend_ffi_ctype_free_obj(zend_object * object)2106 static void zend_ffi_ctype_free_obj(zend_object *object) /* {{{ */
2107 {
2108 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)object;
2109 
2110 	zend_ffi_type_dtor(ctype->type);
2111 }
2112 /* }}} */
2113 
zend_ffi_is_same_type(zend_ffi_type * type1,zend_ffi_type * type2)2114 static int zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2) /* {{{ */
2115 {
2116 	while (1) {
2117 		if (type1 == type2) {
2118 			return 1;
2119 		} else if (type1->kind == type2->kind) {
2120 			if (type1->kind < ZEND_FFI_TYPE_POINTER) {
2121 				return 1;
2122 			} else if (type1->kind == ZEND_FFI_TYPE_POINTER) {
2123 				type1 = ZEND_FFI_TYPE(type1->pointer.type);
2124 				type2 = ZEND_FFI_TYPE(type2->pointer.type);
2125 				if (type1->kind == ZEND_FFI_TYPE_VOID ||
2126 				    type2->kind == ZEND_FFI_TYPE_VOID) {
2127 				    return 1;
2128 				}
2129 			} else if (type1->kind == ZEND_FFI_TYPE_ARRAY &&
2130 			           type1->array.length == type2->array.length) {
2131 				type1 = ZEND_FFI_TYPE(type1->array.type);
2132 				type2 = ZEND_FFI_TYPE(type2->array.type);
2133 			} else {
2134 				break;
2135 			}
2136 		} else {
2137 			break;
2138 		}
2139 	}
2140 	return 0;
2141 }
2142 /* }}} */
2143 
zend_ffi_ctype_get_class_name(const zend_object * zobj)2144 static zend_string *zend_ffi_ctype_get_class_name(const zend_object *zobj) /* {{{ */
2145 {
2146 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)zobj;
2147 
2148 	return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(ctype->type));
2149 }
2150 /* }}} */
2151 
zend_ffi_ctype_compare_objects(zval * o1,zval * o2)2152 static int zend_ffi_ctype_compare_objects(zval *o1, zval *o2) /* {{{ */
2153 {
2154 	if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_ctype_ce &&
2155 	    Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_ctype_ce) {
2156 		zend_ffi_ctype *ctype1 = (zend_ffi_ctype*)Z_OBJ_P(o1);
2157 		zend_ffi_ctype *ctype2 = (zend_ffi_ctype*)Z_OBJ_P(o2);
2158 		zend_ffi_type *type1 = ZEND_FFI_TYPE(ctype1->type);
2159 		zend_ffi_type *type2 = ZEND_FFI_TYPE(ctype2->type);
2160 
2161 		if (zend_ffi_is_same_type(type1, type2)) {
2162 			return 0;
2163 		} else {
2164 			return 1;
2165 		}
2166 	}
2167 	zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
2168 	return 0;
2169 }
2170 /* }}} */
2171 
zend_ffi_ctype_get_debug_info(zend_object * obj,int * is_temp)2172 static HashTable *zend_ffi_ctype_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
2173 {
2174 	return NULL;
2175 }
2176 /* }}} */
2177 
zend_ffi_new(zend_class_entry * class_type)2178 static zend_object *zend_ffi_new(zend_class_entry *class_type) /* {{{ */
2179 {
2180 	zend_ffi *ffi;
2181 
2182 	ffi = emalloc(sizeof(zend_ffi));
2183 
2184 	zend_ffi_object_init(&ffi->std, class_type);
2185 	ffi->std.handlers = &zend_ffi_handlers;
2186 
2187 	ffi->lib = NULL;
2188 	ffi->symbols = NULL;
2189 	ffi->tags = NULL;
2190 	ffi->persistent = 0;
2191 
2192 	return &ffi->std;
2193 }
2194 /* }}} */
2195 
_zend_ffi_type_dtor(zend_ffi_type * type)2196 static void _zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
2197 {
2198 	type = ZEND_FFI_TYPE(type);
2199 
2200 	switch (type->kind) {
2201 		case ZEND_FFI_TYPE_ENUM:
2202 			if (type->enumeration.tag_name) {
2203 				zend_string_release(type->enumeration.tag_name);
2204 			}
2205 			break;
2206 		case ZEND_FFI_TYPE_STRUCT:
2207 			if (type->record.tag_name) {
2208 				zend_string_release(type->record.tag_name);
2209 			}
2210 			zend_hash_destroy(&type->record.fields);
2211 			break;
2212 		case ZEND_FFI_TYPE_POINTER:
2213 			zend_ffi_type_dtor(type->pointer.type);
2214 			break;
2215 		case ZEND_FFI_TYPE_ARRAY:
2216 			zend_ffi_type_dtor(type->array.type);
2217 			break;
2218 		case ZEND_FFI_TYPE_FUNC:
2219 			if (type->func.args) {
2220 				zend_hash_destroy(type->func.args);
2221 				pefree(type->func.args, type->attr & ZEND_FFI_ATTR_PERSISTENT);
2222 			}
2223 			zend_ffi_type_dtor(type->func.ret_type);
2224 			break;
2225 		default:
2226 			break;
2227 	}
2228 	pefree(type, type->attr & ZEND_FFI_ATTR_PERSISTENT);
2229 }
2230 /* }}} */
2231 
zend_ffi_type_hash_dtor(zval * zv)2232 static void zend_ffi_type_hash_dtor(zval *zv) /* {{{ */
2233 {
2234 	zend_ffi_type *type = Z_PTR_P(zv);
2235 	zend_ffi_type_dtor(type);
2236 }
2237 /* }}} */
2238 
zend_ffi_field_hash_dtor(zval * zv)2239 static void zend_ffi_field_hash_dtor(zval *zv) /* {{{ */
2240 {
2241 	zend_ffi_field *field = Z_PTR_P(zv);
2242 	zend_ffi_type_dtor(field->type);
2243 	efree(field);
2244 }
2245 /* }}} */
2246 
zend_ffi_field_hash_persistent_dtor(zval * zv)2247 static void zend_ffi_field_hash_persistent_dtor(zval *zv) /* {{{ */
2248 {
2249 	zend_ffi_field *field = Z_PTR_P(zv);
2250 	zend_ffi_type_dtor(field->type);
2251 	free(field);
2252 }
2253 /* }}} */
2254 
zend_ffi_symbol_hash_dtor(zval * zv)2255 static void zend_ffi_symbol_hash_dtor(zval *zv) /* {{{ */
2256 {
2257 	zend_ffi_symbol *sym = Z_PTR_P(zv);
2258 	zend_ffi_type_dtor(sym->type);
2259 	efree(sym);
2260 }
2261 /* }}} */
2262 
zend_ffi_symbol_hash_persistent_dtor(zval * zv)2263 static void zend_ffi_symbol_hash_persistent_dtor(zval *zv) /* {{{ */
2264 {
2265 	zend_ffi_symbol *sym = Z_PTR_P(zv);
2266 	zend_ffi_type_dtor(sym->type);
2267 	free(sym);
2268 }
2269 /* }}} */
2270 
zend_ffi_tag_hash_dtor(zval * zv)2271 static void zend_ffi_tag_hash_dtor(zval *zv) /* {{{ */
2272 {
2273 	zend_ffi_tag *tag = Z_PTR_P(zv);
2274 	zend_ffi_type_dtor(tag->type);
2275 	efree(tag);
2276 }
2277 /* }}} */
2278 
zend_ffi_tag_hash_persistent_dtor(zval * zv)2279 static void zend_ffi_tag_hash_persistent_dtor(zval *zv) /* {{{ */
2280 {
2281 	zend_ffi_tag *tag = Z_PTR_P(zv);
2282 	zend_ffi_type_dtor(tag->type);
2283 	free(tag);
2284 }
2285 /* }}} */
2286 
zend_ffi_cdata_dtor(zend_ffi_cdata * cdata)2287 static void zend_ffi_cdata_dtor(zend_ffi_cdata *cdata) /* {{{ */
2288 {
2289 	zend_ffi_type_dtor(cdata->type);
2290 	if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
2291 		if (cdata->ptr != (void*)&cdata->ptr_holder) {
2292 			pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
2293 		} else {
2294 			pefree(cdata->ptr_holder, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
2295 		}
2296 	}
2297 }
2298 /* }}} */
2299 
zend_ffi_scope_hash_dtor(zval * zv)2300 static void zend_ffi_scope_hash_dtor(zval *zv) /* {{{ */
2301 {
2302 	zend_ffi_scope *scope = Z_PTR_P(zv);
2303 	if (scope->symbols) {
2304 		zend_hash_destroy(scope->symbols);
2305 		free(scope->symbols);
2306 	}
2307 	if (scope->tags) {
2308 		zend_hash_destroy(scope->tags);
2309 		free(scope->tags);
2310 	}
2311 	free(scope);
2312 }
2313 /* }}} */
2314 
zend_ffi_free_obj(zend_object * object)2315 static void zend_ffi_free_obj(zend_object *object) /* {{{ */
2316 {
2317 	zend_ffi *ffi = (zend_ffi*)object;
2318 
2319 	if (ffi->persistent) {
2320 		return;
2321 	}
2322 
2323 	if (ffi->lib) {
2324 		DL_UNLOAD(ffi->lib);
2325 		ffi->lib = NULL;
2326 	}
2327 
2328 	if (ffi->symbols) {
2329 		zend_hash_destroy(ffi->symbols);
2330 		efree(ffi->symbols);
2331 	}
2332 
2333 	if (ffi->tags) {
2334 		zend_hash_destroy(ffi->tags);
2335 		efree(ffi->tags);
2336 	}
2337 }
2338 /* }}} */
2339 
zend_ffi_cdata_free_obj(zend_object * object)2340 static void zend_ffi_cdata_free_obj(zend_object *object) /* {{{ */
2341 {
2342 	zend_ffi_cdata *cdata = (zend_ffi_cdata*)object;
2343 
2344 	zend_ffi_cdata_dtor(cdata);
2345 }
2346 /* }}} */
2347 
zend_ffi_cdata_clone_obj(zend_object * obj)2348 static zend_object *zend_ffi_cdata_clone_obj(zend_object *obj) /* {{{ */
2349 {
2350 	zend_ffi_cdata *old_cdata = (zend_ffi_cdata*)obj;
2351 	zend_ffi_type *type = ZEND_FFI_TYPE(old_cdata->type);
2352 	zend_ffi_cdata *new_cdata;
2353 
2354 	new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
2355 	if (type->kind < ZEND_FFI_TYPE_POINTER) {
2356 		new_cdata->std.handlers = &zend_ffi_cdata_value_handlers;
2357 	}
2358 	new_cdata->type = type;
2359 	new_cdata->ptr = emalloc(type->size);
2360 	memcpy(new_cdata->ptr, old_cdata->ptr, type->size);
2361 	new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
2362 
2363 	return &new_cdata->std;
2364 }
2365 /* }}} */
2366 
zend_ffi_read_var(zend_object * obj,zend_string * var_name,int read_type,void ** cache_slot,zval * rv)2367 static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
2368 {
2369 	zend_ffi        *ffi = (zend_ffi*)obj;
2370 	zend_ffi_symbol *sym = NULL;
2371 
2372 	if (ffi->symbols) {
2373 		sym = zend_hash_find_ptr(ffi->symbols, var_name);
2374 		if (sym && sym->kind != ZEND_FFI_SYM_VAR && sym->kind != ZEND_FFI_SYM_CONST && sym->kind != ZEND_FFI_SYM_FUNC) {
2375 			sym = NULL;
2376 		}
2377 	}
2378 	if (!sym) {
2379 		zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined C variable '%s'", ZSTR_VAL(var_name));
2380 		return &EG(uninitialized_zval);
2381 	}
2382 
2383 	if (sym->kind == ZEND_FFI_SYM_VAR) {
2384 		zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0, 0);
2385 	} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
2386 		zend_ffi_cdata *cdata;
2387 		zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
2388 
2389 		new_type->kind = ZEND_FFI_TYPE_POINTER;
2390 		new_type->attr = 0;
2391 		new_type->size = sizeof(void*);
2392 		new_type->align = _Alignof(void*);
2393 		new_type->pointer.type = ZEND_FFI_TYPE(sym->type);
2394 
2395 		cdata = emalloc(sizeof(zend_ffi_cdata));
2396 		zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
2397 		cdata->std.handlers = &zend_ffi_cdata_handlers;
2398 		cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
2399 		cdata->flags = ZEND_FFI_FLAG_CONST;
2400 		cdata->ptr_holder = sym->addr;
2401 		cdata->ptr = &cdata->ptr_holder;
2402 		ZVAL_OBJ(rv, &cdata->std);
2403 	} else {
2404 		ZVAL_LONG(rv, sym->value);
2405 	}
2406 
2407 	return rv;
2408 }
2409 /* }}} */
2410 
zend_ffi_write_var(zend_object * obj,zend_string * var_name,zval * value,void ** cache_slot)2411 static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *value, void **cache_slot) /* {{{ */
2412 {
2413 	zend_ffi        *ffi = (zend_ffi*)obj;
2414 	zend_ffi_symbol *sym = NULL;
2415 
2416 	if (ffi->symbols) {
2417 		sym = zend_hash_find_ptr(ffi->symbols, var_name);
2418 		if (sym && sym->kind != ZEND_FFI_SYM_VAR) {
2419 			sym = NULL;
2420 		}
2421 	}
2422 	if (!sym) {
2423 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined C variable '%s'", ZSTR_VAL(var_name));
2424 		return value;
2425 	}
2426 
2427 	if (sym->is_const) {
2428 		zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only C variable '%s'", ZSTR_VAL(var_name));
2429 		return value;
2430 	}
2431 
2432 	zend_ffi_zval_to_cdata(sym->addr, ZEND_FFI_TYPE(sym->type), value);
2433 	return value;
2434 }
2435 /* }}} */
2436 
zend_ffi_pass_arg(zval * arg,zend_ffi_type * type,ffi_type ** pass_type,void ** arg_values,uint32_t n,zend_execute_data * execute_data)2437 static int zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
2438 {
2439 	zend_long lval;
2440 	double dval;
2441 	zend_string *str, *tmp_str;
2442 	zend_ffi_type_kind kind = type->kind;
2443 
2444 	ZVAL_DEREF(arg);
2445 
2446 again:
2447     switch (kind) {
2448 		case ZEND_FFI_TYPE_FLOAT:
2449 			dval = zval_get_double(arg);
2450 			*pass_type = &ffi_type_float;
2451 			*(float*)arg_values[n] = (float)dval;
2452 			break;
2453 		case ZEND_FFI_TYPE_DOUBLE:
2454 			dval = zval_get_double(arg);
2455 			*pass_type = &ffi_type_double;
2456 			*(double*)arg_values[n] = dval;
2457 			break;
2458 #ifdef HAVE_LONG_DOUBLE
2459 		case ZEND_FFI_TYPE_LONGDOUBLE:
2460 			dval = zval_get_double(arg);
2461 			*pass_type = &ffi_type_double;
2462 			*(long double*)arg_values[n] = (long double)dval;
2463 			break;
2464 #endif
2465 		case ZEND_FFI_TYPE_UINT8:
2466 			lval = zval_get_long(arg);
2467 			*pass_type = &ffi_type_uint8;
2468 			*(uint8_t*)arg_values[n] = (uint8_t)lval;
2469 			break;
2470 		case ZEND_FFI_TYPE_SINT8:
2471 			lval = zval_get_long(arg);
2472 			*pass_type = &ffi_type_sint8;
2473 			*(int8_t*)arg_values[n] = (int8_t)lval;
2474 			break;
2475 		case ZEND_FFI_TYPE_UINT16:
2476 			lval = zval_get_long(arg);
2477 			*pass_type = &ffi_type_uint16;
2478 			*(uint16_t*)arg_values[n] = (uint16_t)lval;
2479 			break;
2480 		case ZEND_FFI_TYPE_SINT16:
2481 			lval = zval_get_long(arg);
2482 			*pass_type = &ffi_type_sint16;
2483 			*(int16_t*)arg_values[n] = (int16_t)lval;
2484 			break;
2485 		case ZEND_FFI_TYPE_UINT32:
2486 			lval = zval_get_long(arg);
2487 			*pass_type = &ffi_type_uint32;
2488 			*(uint32_t*)arg_values[n] = (uint32_t)lval;
2489 			break;
2490 		case ZEND_FFI_TYPE_SINT32:
2491 			lval = zval_get_long(arg);
2492 			*pass_type = &ffi_type_sint32;
2493 			*(int32_t*)arg_values[n] = (int32_t)lval;
2494 			break;
2495 		case ZEND_FFI_TYPE_UINT64:
2496 			lval = zval_get_long(arg);
2497 			*pass_type = &ffi_type_uint64;
2498 			*(uint64_t*)arg_values[n] = (uint64_t)lval;
2499 			break;
2500 		case ZEND_FFI_TYPE_SINT64:
2501 			lval = zval_get_long(arg);
2502 			*pass_type = &ffi_type_sint64;
2503 			*(int64_t*)arg_values[n] = (int64_t)lval;
2504 			break;
2505 		case ZEND_FFI_TYPE_POINTER:
2506 			*pass_type = &ffi_type_pointer;
2507 			if (Z_TYPE_P(arg) == IS_NULL) {
2508 				*(void**)arg_values[n] = NULL;
2509 				return SUCCESS;
2510 			} else if (Z_TYPE_P(arg) == IS_STRING
2511 			        && ((ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR)
2512 			         || (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID))) {
2513 				*(void**)arg_values[n] = Z_STRVAL_P(arg);
2514 				return SUCCESS;
2515 			} else if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2516 				zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
2517 
2518 				if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
2519 					if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
2520 						if (!cdata->ptr) {
2521 							zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
2522 							return FAILURE;
2523 						}
2524 						*(void**)arg_values[n] = *(void**)cdata->ptr;
2525 					} else {
2526 						*(void**)arg_values[n] = cdata->ptr;
2527 					}
2528 					return SUCCESS;
2529 				}
2530 #if FFI_CLOSURES
2531 			} else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
2532 				void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), arg);
2533 
2534 				if (callback) {
2535 					*(void**)arg_values[n] = callback;
2536 					break;
2537 				} else {
2538 					return FAILURE;
2539 				}
2540 #endif
2541 			}
2542 			zend_ffi_pass_incompatible(arg, type, n, execute_data);
2543 			return FAILURE;
2544 		case ZEND_FFI_TYPE_BOOL:
2545 			*pass_type = &ffi_type_uint8;
2546 			*(uint8_t*)arg_values[n] = zend_is_true(arg);
2547 			break;
2548 		case ZEND_FFI_TYPE_CHAR:
2549 			str = zval_get_tmp_string(arg, &tmp_str);
2550 			*pass_type = &ffi_type_sint8;
2551 			*(char*)arg_values[n] = ZSTR_VAL(str)[0];
2552 			if (ZSTR_LEN(str) != 1) {
2553 				zend_ffi_pass_incompatible(arg, type, n, execute_data);
2554 			}
2555 			zend_tmp_string_release(tmp_str);
2556 			break;
2557 		case ZEND_FFI_TYPE_ENUM:
2558 			kind = type->enumeration.kind;
2559 			goto again;
2560 		case ZEND_FFI_TYPE_STRUCT:
2561 			if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2562 				zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
2563 
2564 				if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
2565 					*pass_type = zend_ffi_make_fake_struct_type(type);;
2566 					arg_values[n] = cdata->ptr;
2567 					break;
2568 				}
2569 			}
2570 			zend_ffi_pass_incompatible(arg, type, n, execute_data);
2571 			return FAILURE;
2572 		default:
2573 			zend_ffi_pass_unsupported(type);
2574 			return FAILURE;
2575 	}
2576 	return SUCCESS;
2577 }
2578 /* }}} */
2579 
zend_ffi_pass_var_arg(zval * arg,ffi_type ** pass_type,void ** arg_values,uint32_t n,zend_execute_data * execute_data)2580 static int zend_ffi_pass_var_arg(zval *arg, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
2581 {
2582 	ZVAL_DEREF(arg);
2583 	switch (Z_TYPE_P(arg)) {
2584 		case IS_NULL:
2585 			*pass_type = &ffi_type_pointer;
2586 			*(void**)arg_values[n] = NULL;
2587 			break;
2588 		case IS_FALSE:
2589 			*pass_type = &ffi_type_uint8;
2590 			*(uint8_t*)arg_values[n] = 0;
2591 			break;
2592 		case IS_TRUE:
2593 			*pass_type = &ffi_type_uint8;
2594 			*(uint8_t*)arg_values[n] = 1;
2595 			break;
2596 		case IS_LONG:
2597 			if (sizeof(zend_long) == 4) {
2598 				*pass_type = &ffi_type_sint32;
2599 				*(int32_t*)arg_values[n] = Z_LVAL_P(arg);
2600 			} else {
2601 				*pass_type = &ffi_type_sint64;
2602 				*(int64_t*)arg_values[n] = Z_LVAL_P(arg);
2603 			}
2604 			break;
2605 		case IS_DOUBLE:
2606 			*pass_type = &ffi_type_double;
2607 			*(double*)arg_values[n] = Z_DVAL_P(arg);
2608 			break;
2609 		case IS_STRING:
2610 			*pass_type = &ffi_type_pointer;
2611 			*(char**)arg_values[n] = Z_STRVAL_P(arg);
2612 			break;
2613 		case IS_OBJECT:
2614 			if (Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
2615 				zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
2616 				zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
2617 
2618 				return zend_ffi_pass_arg(arg, type, pass_type, arg_values, n, execute_data);
2619 			}
2620 			/* break missing intentionally */
2621 		default:
2622 			zend_throw_error(zend_ffi_exception_ce, "Unsupported argument type");
2623 			return FAILURE;
2624 	}
2625 	return SUCCESS;
2626 }
2627 /* }}} */
2628 
ZEND_FUNCTION(ffi_trampoline)2629 static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
2630 {
2631 	zend_ffi_type *type = EX(func)->internal_function.reserved[0];
2632 	void *addr = EX(func)->internal_function.reserved[1];
2633 	ffi_cif cif;
2634 	ffi_type *ret_type = NULL;
2635 	ffi_type **arg_types = NULL;
2636 	void **arg_values = NULL;
2637 	uint32_t n, arg_count;
2638 	void *ret;
2639 	zend_ffi_type *arg_type;
2640 	ALLOCA_FLAG(arg_types_use_heap = 0)
2641 	ALLOCA_FLAG(arg_values_use_heap = 0)
2642 	ALLOCA_FLAG(ret_use_heap = 0)
2643 
2644 	ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
2645 	arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2646 	if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
2647 		if (arg_count > EX_NUM_ARGS()) {
2648 			zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting at least %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
2649 			goto exit;
2650 		}
2651 		if (EX_NUM_ARGS()) {
2652 			arg_types = do_alloca(
2653 				sizeof(ffi_type*) * EX_NUM_ARGS(), arg_types_use_heap);
2654 			arg_values = do_alloca(
2655 				(sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
2656 			n = 0;
2657 			if (type->func.args) {
2658 				ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
2659 					arg_type = ZEND_FFI_TYPE(arg_type);
2660 					arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2661 					if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
2662 						free_alloca(arg_types, arg_types_use_heap);
2663 						free_alloca(arg_values, arg_values_use_heap);
2664 						goto exit;
2665 					}
2666 					n++;
2667 				} ZEND_HASH_FOREACH_END();
2668 			}
2669 			for (; n < EX_NUM_ARGS(); n++) {
2670 				arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2671 				if (zend_ffi_pass_var_arg(EX_VAR_NUM(n), &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
2672 					free_alloca(arg_types, arg_types_use_heap);
2673 					free_alloca(arg_values, arg_values_use_heap);
2674 					goto exit;
2675 				}
2676 			}
2677 		}
2678 		ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
2679 		if (!ret_type) {
2680 			zend_ffi_return_unsupported(type->func.ret_type);
2681 			free_alloca(arg_types, arg_types_use_heap);
2682 			free_alloca(arg_values, arg_values_use_heap);
2683 			goto exit;
2684 		}
2685 		if (ffi_prep_cif_var(&cif, type->func.abi, arg_count, EX_NUM_ARGS(), ret_type, arg_types) != FFI_OK) {
2686 			zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
2687 			free_alloca(arg_types, arg_types_use_heap);
2688 			free_alloca(arg_values, arg_values_use_heap);
2689 			goto exit;
2690 		}
2691 	} else {
2692 		if (arg_count != EX_NUM_ARGS()) {
2693 			zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting exactly %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
2694 			goto exit;
2695 		}
2696 		if (EX_NUM_ARGS()) {
2697 			arg_types = do_alloca(
2698 				(sizeof(ffi_type*) + sizeof(ffi_type)) * EX_NUM_ARGS(), arg_types_use_heap);
2699 			arg_values = do_alloca(
2700 				(sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
2701 			n = 0;
2702 			if (type->func.args) {
2703 				ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
2704 					arg_type = ZEND_FFI_TYPE(arg_type);
2705 					arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
2706 					if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
2707 						free_alloca(arg_types, arg_types_use_heap);
2708 						free_alloca(arg_values, arg_values_use_heap);
2709 						goto exit;
2710 					}
2711 					n++;
2712 				} ZEND_HASH_FOREACH_END();
2713 			}
2714 		}
2715 		ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
2716 		if (!ret_type) {
2717 			zend_ffi_return_unsupported(type->func.ret_type);
2718 			free_alloca(arg_types, arg_types_use_heap);
2719 			free_alloca(arg_values, arg_values_use_heap);
2720 			goto exit;
2721 		}
2722 		if (ffi_prep_cif(&cif, type->func.abi, arg_count, ret_type, arg_types) != FFI_OK) {
2723 			zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
2724 			free_alloca(arg_types, arg_types_use_heap);
2725 			free_alloca(arg_values, arg_values_use_heap);
2726 			goto exit;
2727 		}
2728 	}
2729 
2730 	ret = do_alloca(MAX(ret_type->size, sizeof(ffi_arg)), ret_use_heap);
2731 	ffi_call(&cif, addr, ret, arg_values);
2732 
2733 	for (n = 0; n < arg_count; n++) {
2734 		if (arg_types[n]->type == FFI_TYPE_STRUCT) {
2735 			efree(arg_types[n]);
2736 		}
2737 	}
2738 	if (ret_type->type == FFI_TYPE_STRUCT) {
2739 		efree(ret_type);
2740 	}
2741 
2742 	if (EX_NUM_ARGS()) {
2743 		free_alloca(arg_types, arg_types_use_heap);
2744 		free_alloca(arg_values, arg_values_use_heap);
2745 	}
2746 
2747 	zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0);
2748 	free_alloca(ret, ret_use_heap);
2749 
2750 exit:
2751 	zend_string_release(EX(func)->common.function_name);
2752 	if (EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2753 		zend_free_trampoline(EX(func));
2754 		EX(func) = NULL;
2755 	}
2756 }
2757 /* }}} */
2758 
zend_ffi_get_func(zend_object ** obj,zend_string * name,const zval * key)2759 static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */
2760 {
2761 	zend_ffi        *ffi = (zend_ffi*)*obj;
2762 	zend_ffi_symbol *sym = NULL;
2763 	zend_function   *func;
2764 	zend_ffi_type   *type;
2765 
2766 	if (ZSTR_LEN(name) == sizeof("new") -1
2767 	 && (ZSTR_VAL(name)[0] == 'n' || ZSTR_VAL(name)[0] == 'N')
2768 	 && (ZSTR_VAL(name)[1] == 'e' || ZSTR_VAL(name)[1] == 'E')
2769 	 && (ZSTR_VAL(name)[2] == 'w' || ZSTR_VAL(name)[2] == 'W')) {
2770 		return (zend_function*)&zend_ffi_new_fn;
2771 	} else if (ZSTR_LEN(name) == sizeof("cast") -1
2772 	 && (ZSTR_VAL(name)[0] == 'c' || ZSTR_VAL(name)[0] == 'C')
2773 	 && (ZSTR_VAL(name)[1] == 'a' || ZSTR_VAL(name)[1] == 'A')
2774 	 && (ZSTR_VAL(name)[2] == 's' || ZSTR_VAL(name)[2] == 'S')
2775 	 && (ZSTR_VAL(name)[3] == 't' || ZSTR_VAL(name)[3] == 'T')) {
2776 		return (zend_function*)&zend_ffi_cast_fn;
2777 	} else if (ZSTR_LEN(name) == sizeof("type") -1
2778 	 && (ZSTR_VAL(name)[0] == 't' || ZSTR_VAL(name)[0] == 'T')
2779 	 && (ZSTR_VAL(name)[1] == 'y' || ZSTR_VAL(name)[1] == 'Y')
2780 	 && (ZSTR_VAL(name)[2] == 'p' || ZSTR_VAL(name)[2] == 'P')
2781 	 && (ZSTR_VAL(name)[3] == 'e' || ZSTR_VAL(name)[3] == 'E')) {
2782 		return (zend_function*)&zend_ffi_type_fn;
2783 	}
2784 
2785 	if (ffi->symbols) {
2786 		sym = zend_hash_find_ptr(ffi->symbols, name);
2787 		if (sym && sym->kind != ZEND_FFI_SYM_FUNC) {
2788 			sym = NULL;
2789 		}
2790 	}
2791 	if (!sym) {
2792 		zend_throw_error(zend_ffi_exception_ce, "Attempt to call undefined C function '%s'", ZSTR_VAL(name));
2793 		return NULL;
2794 	}
2795 
2796 	type = ZEND_FFI_TYPE(sym->type);
2797 	ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
2798 
2799 	if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
2800 		func = &EG(trampoline);
2801 	} else {
2802 		func = ecalloc(sizeof(zend_internal_function), 1);
2803 	}
2804 	func->common.type = ZEND_INTERNAL_FUNCTION;
2805 	func->common.arg_flags[0] = 0;
2806 	func->common.arg_flags[1] = 0;
2807 	func->common.arg_flags[2] = 0;
2808 	func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
2809 	func->common.function_name = zend_string_copy(name);
2810 	/* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
2811 	func->common.num_args = 0;
2812 	func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
2813 	func->common.scope = NULL;
2814 	func->common.prototype = NULL;
2815 	func->common.arg_info = NULL;
2816 	func->internal_function.handler = ZEND_FN(ffi_trampoline);
2817 	func->internal_function.module = NULL;
2818 
2819 	func->internal_function.reserved[0] = type;
2820 	func->internal_function.reserved[1] = sym->addr;
2821 
2822 	return func;
2823 }
2824 /* }}} */
2825 
zend_ffi_disabled(void)2826 static zend_never_inline int zend_ffi_disabled(void) /* {{{ */
2827 {
2828 	zend_throw_error(zend_ffi_exception_ce, "FFI API is restricted by \"ffi.enable\" configuration directive");
2829 	return 0;
2830 }
2831 /* }}} */
2832 
zend_ffi_validate_api_restriction(zend_execute_data * execute_data)2833 static zend_always_inline int zend_ffi_validate_api_restriction(zend_execute_data *execute_data) /* {{{ */
2834 {
2835 	if (EXPECTED(FFI_G(restriction) > ZEND_FFI_ENABLED)) {
2836 		ZEND_ASSERT(FFI_G(restriction) == ZEND_FFI_PRELOAD);
2837 		if (FFI_G(is_cli)
2838 		 || (execute_data->prev_execute_data
2839 		  && (execute_data->prev_execute_data->func->common.fn_flags & ZEND_ACC_PRELOADED))
2840 		 || (CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
2841 			return 1;
2842 		}
2843 	} else if (EXPECTED(FFI_G(restriction) == ZEND_FFI_ENABLED)) {
2844 		return 1;
2845 	}
2846 	return zend_ffi_disabled();
2847 }
2848 /* }}} */
2849 
2850 #define ZEND_FFI_VALIDATE_API_RESTRICTION() do { \
2851 		if (UNEXPECTED(!zend_ffi_validate_api_restriction(execute_data))) { \
2852 			RETURN_THROWS(); \
2853 		} \
2854 	} while (0)
2855 
ZEND_METHOD(FFI,cdef)2856 ZEND_METHOD(FFI, cdef) /* {{{ */
2857 {
2858 	zend_string *code = NULL;
2859 	zend_string *lib = NULL;
2860 	zend_ffi *ffi = NULL;
2861 	DL_HANDLE handle = NULL;
2862 	void *addr;
2863 
2864 	ZEND_FFI_VALIDATE_API_RESTRICTION();
2865 	ZEND_PARSE_PARAMETERS_START(0, 2)
2866 		Z_PARAM_OPTIONAL
2867 		Z_PARAM_STR(code)
2868 		Z_PARAM_STR_OR_NULL(lib)
2869 	ZEND_PARSE_PARAMETERS_END();
2870 
2871 	if (lib) {
2872 		handle = DL_LOAD(ZSTR_VAL(lib));
2873 		if (!handle) {
2874 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", ZSTR_VAL(lib));
2875 			RETURN_THROWS();
2876 		}
2877 #ifdef RTLD_DEFAULT
2878 	} else if (1) {
2879 		// TODO: this might need to be disabled or protected ???
2880 		handle = RTLD_DEFAULT;
2881 #endif
2882 	}
2883 
2884 	FFI_G(symbols) = NULL;
2885 	FFI_G(tags) = NULL;
2886 
2887 	if (code && ZSTR_LEN(code)) {
2888 		/* Parse C definitions */
2889 		FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED;
2890 
2891 		if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) != SUCCESS) {
2892 			if (FFI_G(symbols)) {
2893 				zend_hash_destroy(FFI_G(symbols));
2894 				efree(FFI_G(symbols));
2895 				FFI_G(symbols) = NULL;
2896 			}
2897 			if (FFI_G(tags)) {
2898 				zend_hash_destroy(FFI_G(tags));
2899 				efree(FFI_G(tags));
2900 				FFI_G(tags) = NULL;
2901 			}
2902 			RETURN_THROWS();
2903 		}
2904 
2905 		if (FFI_G(symbols)) {
2906 			zend_string *name;
2907 			zend_ffi_symbol *sym;
2908 
2909 			ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
2910 				if (sym->kind == ZEND_FFI_SYM_VAR) {
2911 					addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
2912 					if (!addr) {
2913 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
2914 						RETURN_THROWS();
2915 					}
2916 					sym->addr = addr;
2917 				} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
2918 					zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
2919 
2920 					addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
2921 					zend_string_release(mangled_name);
2922 					if (!addr) {
2923 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
2924 						RETURN_THROWS();
2925 					}
2926 					sym->addr = addr;
2927 				}
2928 			} ZEND_HASH_FOREACH_END();
2929 		}
2930 	}
2931 
2932 	ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
2933 	ffi->lib = handle;
2934 	ffi->symbols = FFI_G(symbols);
2935 	ffi->tags = FFI_G(tags);
2936 
2937 	FFI_G(symbols) = NULL;
2938 	FFI_G(tags) = NULL;
2939 
2940 	RETURN_OBJ(&ffi->std);
2941 }
2942 /* }}} */
2943 
zend_ffi_same_types(zend_ffi_type * old,zend_ffi_type * type)2944 static int zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
2945 {
2946 	if (old == type) {
2947 		return 1;
2948 	}
2949 
2950 	if (old->kind != type->kind
2951 	 || old->size != type->size
2952 	 || old->align != type->align
2953 	 || old->attr != type->attr) {
2954 		return 0;
2955 	}
2956 
2957 	switch (old->kind) {
2958 		case ZEND_FFI_TYPE_ENUM:
2959 			return old->enumeration.kind == type->enumeration.kind;
2960 		case ZEND_FFI_TYPE_ARRAY:
2961 			return old->array.length == type->array.length
2962 			 &&	zend_ffi_same_types(ZEND_FFI_TYPE(old->array.type), ZEND_FFI_TYPE(type->array.type));
2963 		case ZEND_FFI_TYPE_POINTER:
2964 			return zend_ffi_same_types(ZEND_FFI_TYPE(old->pointer.type), ZEND_FFI_TYPE(type->pointer.type));
2965 		case ZEND_FFI_TYPE_STRUCT:
2966 			if (zend_hash_num_elements(&old->record.fields) != zend_hash_num_elements(&type->record.fields)) {
2967 				return 0;
2968 			} else {
2969 				zend_ffi_field *old_field, *field;
2970 				zend_string *key;
2971 				Bucket *b = type->record.fields.arData;
2972 
2973 				ZEND_HASH_FOREACH_STR_KEY_PTR(&old->record.fields, key, old_field) {
2974 					while (Z_TYPE(b->val) == IS_UNDEF) {
2975 						b++;
2976 					}
2977 					if (key) {
2978 						if (!b->key
2979 						 || !zend_string_equals(key, b->key)) {
2980 							return 0;
2981 						}
2982 					} else if (b->key) {
2983 						return 0;
2984 					}
2985 					field = Z_PTR(b->val);
2986 					if (old_field->offset != field->offset
2987 					 || old_field->is_const != field->is_const
2988 					 || old_field->is_nested != field->is_nested
2989 					 || old_field->first_bit != field->first_bit
2990 					 || old_field->bits != field->bits
2991 					 || !zend_ffi_same_types(ZEND_FFI_TYPE(old_field->type), ZEND_FFI_TYPE(field->type))) {
2992 						return 0;
2993 					}
2994 					b++;
2995 				} ZEND_HASH_FOREACH_END();
2996 			}
2997 			break;
2998 		case ZEND_FFI_TYPE_FUNC:
2999 			if (old->func.abi != type->func.abi
3000 			 || ((old->func.args ? zend_hash_num_elements(old->func.args) : 0) != (type->func.args ? zend_hash_num_elements(type->func.args) : 0))
3001 			 || !zend_ffi_same_types(ZEND_FFI_TYPE(old->func.ret_type), ZEND_FFI_TYPE(type->func.ret_type))) {
3002 				return 0;
3003 			} else if (old->func.args) {
3004 				zend_ffi_type *arg_type;
3005 				Bucket *b = type->func.args->arData;
3006 
3007 				ZEND_HASH_FOREACH_PTR(old->func.args, arg_type) {
3008 					while (Z_TYPE(b->val) == IS_UNDEF) {
3009 						b++;
3010 					}
3011 					if (!zend_ffi_same_types(ZEND_FFI_TYPE(arg_type), ZEND_FFI_TYPE(Z_PTR(b->val)))) {
3012 						return 0;
3013 					}
3014 					b++;
3015 				} ZEND_HASH_FOREACH_END();
3016 			}
3017 			break;
3018 		default:
3019 			break;
3020 	}
3021 
3022 	return 1;
3023 }
3024 /* }}} */
3025 
zend_ffi_same_symbols(zend_ffi_symbol * old,zend_ffi_symbol * sym)3026 static int zend_ffi_same_symbols(zend_ffi_symbol *old, zend_ffi_symbol *sym) /* {{{ */
3027 {
3028 	if (old->kind != sym->kind || old->is_const != sym->is_const) {
3029 		return 0;
3030 	}
3031 
3032 	if (old->kind == ZEND_FFI_SYM_CONST) {
3033 		if (old->value != sym->value) {
3034 			return 0;
3035 		}
3036 	}
3037 
3038 	return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(sym->type));
3039 }
3040 /* }}} */
3041 
zend_ffi_same_tags(zend_ffi_tag * old,zend_ffi_tag * tag)3042 static int zend_ffi_same_tags(zend_ffi_tag *old, zend_ffi_tag *tag) /* {{{ */
3043 {
3044 	if (old->kind != tag->kind) {
3045 		return 0;
3046 	}
3047 
3048 	return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(tag->type));
3049 }
3050 /* }}} */
3051 
zend_ffi_subst_old_type(zend_ffi_type ** dcl,zend_ffi_type * old,zend_ffi_type * type)3052 static int zend_ffi_subst_old_type(zend_ffi_type **dcl, zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
3053 {
3054 	zend_ffi_type *dcl_type;
3055 	zend_ffi_field *field;
3056 
3057 	if (ZEND_FFI_TYPE(*dcl) == type) {
3058 		*dcl = old;
3059 		return 1;
3060 	}
3061 	dcl_type = *dcl;
3062 	switch (dcl_type->kind) {
3063 		case ZEND_FFI_TYPE_POINTER:
3064 			return zend_ffi_subst_old_type(&dcl_type->pointer.type, old, type);
3065 		case ZEND_FFI_TYPE_ARRAY:
3066 			return zend_ffi_subst_old_type(&dcl_type->array.type, old, type);
3067 		case ZEND_FFI_TYPE_FUNC:
3068 			if (zend_ffi_subst_old_type(&dcl_type->func.ret_type, old, type)) {
3069 				return 1;
3070 			}
3071 			if (dcl_type->func.args) {
3072 				zval *zv;
3073 
3074 				ZEND_HASH_FOREACH_VAL(dcl_type->func.args, zv) {
3075 					if (zend_ffi_subst_old_type((zend_ffi_type**)&Z_PTR_P(zv), old, type)) {
3076 						return 1;
3077 					}
3078 				} ZEND_HASH_FOREACH_END();
3079 			}
3080 			break;
3081 		case ZEND_FFI_TYPE_STRUCT:
3082 			ZEND_HASH_FOREACH_PTR(&dcl_type->record.fields, field) {
3083 				if (zend_ffi_subst_old_type(&field->type, old, type)) {
3084 					return 1;
3085 				}
3086 			} ZEND_HASH_FOREACH_END();
3087 			break;
3088 		default:
3089 			break;
3090 	}
3091 	return 0;
3092 } /* }}} */
3093 
zend_ffi_cleanup_type(zend_ffi_type * old,zend_ffi_type * type)3094 static void zend_ffi_cleanup_type(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
3095 {
3096 	zend_ffi_symbol *sym;
3097 	zend_ffi_tag *tag;
3098 
3099 	if (FFI_G(symbols)) {
3100 		ZEND_HASH_FOREACH_PTR(FFI_G(symbols), sym) {
3101 			zend_ffi_subst_old_type(&sym->type, old, type);
3102 		} ZEND_HASH_FOREACH_END();
3103 	}
3104 	if (FFI_G(tags)) {
3105 		ZEND_HASH_FOREACH_PTR(FFI_G(tags), tag) {
3106 			zend_ffi_subst_old_type(&tag->type, old, type);
3107 		} ZEND_HASH_FOREACH_END();
3108 	}
3109 }
3110 /* }}} */
3111 
zend_ffi_remember_type(zend_ffi_type * type)3112 static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type) /* {{{ */
3113 {
3114 	if (!FFI_G(weak_types)) {
3115 		FFI_G(weak_types) = emalloc(sizeof(HashTable));
3116 		zend_hash_init(FFI_G(weak_types), 0, NULL, zend_ffi_type_hash_dtor, 0);
3117 	}
3118 	// TODO: avoid dups ???
3119 	type->attr |= ZEND_FFI_ATTR_STORED;
3120 	zend_hash_next_index_insert_ptr(FFI_G(weak_types), ZEND_FFI_TYPE_MAKE_OWNED(type));
3121 	return type;
3122 }
3123 /* }}} */
3124 
zend_ffi_load(const char * filename,zend_bool preload)3125 static zend_ffi *zend_ffi_load(const char *filename, zend_bool preload) /* {{{ */
3126 {
3127 	struct stat buf;
3128 	int fd;
3129 	char *code, *code_pos, *scope_name, *lib;
3130 	size_t code_size, scope_name_len;
3131 	zend_ffi *ffi;
3132 	DL_HANDLE handle = NULL;
3133 	zend_ffi_scope *scope = NULL;
3134 	zend_string *name;
3135 	zend_ffi_symbol *sym;
3136 	zend_ffi_tag *tag;
3137 	void *addr;
3138 
3139 	if (stat(filename, &buf) != 0) {
3140 		if (preload) {
3141 			zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
3142 		} else {
3143 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', file doesn't exist", filename);
3144 		}
3145 		return NULL;
3146 	}
3147 
3148 	if ((buf.st_mode & S_IFMT) != S_IFREG) {
3149 		if (preload) {
3150 			zend_error(E_WARNING, "FFI: failed pre-loading '%s', not a regular file", filename);
3151 		} else {
3152 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
3153 		}
3154 		return NULL;
3155 	}
3156 
3157 	code_size = buf.st_size;
3158 	code = emalloc(code_size + 1);
3159 	fd = open(filename, O_RDONLY, 0);
3160 	if (fd < 0 || read(fd, code, code_size) != code_size) {
3161 		if (preload) {
3162 			zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);
3163         } else {
3164 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', cannot read_file", filename);
3165 		}
3166 		efree(code);
3167 		close(fd);
3168 		return NULL;
3169 	}
3170 	close(fd);
3171 	code[code_size] = 0;
3172 
3173 	FFI_G(symbols) = NULL;
3174 	FFI_G(tags) = NULL;
3175 	FFI_G(persistent) = preload;
3176 	FFI_G(default_type_attr) = preload ?
3177 		ZEND_FFI_ATTR_STORED | ZEND_FFI_ATTR_PERSISTENT :
3178 		ZEND_FFI_ATTR_STORED;
3179 
3180 	scope_name = NULL;
3181 	scope_name_len = 0;
3182 	lib = NULL;
3183 	code_pos = zend_ffi_parse_directives(filename, code, &scope_name, &lib, preload);
3184 	if (!code_pos) {
3185 		efree(code);
3186 		FFI_G(persistent) = 0;
3187 		return NULL;
3188 	}
3189 	code_size -= code_pos - code;
3190 
3191 	if (zend_ffi_parse_decl(code_pos, code_size) != SUCCESS) {
3192 		if (preload) {
3193 			zend_error(E_WARNING, "FFI: failed pre-loading '%s'", filename);
3194 		} else {
3195 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", filename);
3196 		}
3197 		goto cleanup;
3198 	}
3199 
3200 	if (lib) {
3201 		handle = DL_LOAD(lib);
3202 		if (!handle) {
3203 			if (preload) {
3204 				zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
3205 			} else {
3206 				zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", lib);
3207 			}
3208 			goto cleanup;
3209 		}
3210 #ifdef RTLD_DEFAULT
3211 	} else if (1) {
3212 		// TODO: this might need to be disabled or protected ???
3213 		handle = RTLD_DEFAULT;
3214 #endif
3215 	}
3216 
3217 	if (preload) {
3218 		if (!scope_name) {
3219 			scope_name = "C";
3220 		}
3221 		scope_name_len = strlen(scope_name);
3222 		if (FFI_G(scopes)) {
3223 			scope = zend_hash_str_find_ptr(FFI_G(scopes), scope_name, scope_name_len);
3224 		}
3225 	}
3226 
3227 	if (FFI_G(symbols)) {
3228 		ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3229 			if (sym->kind == ZEND_FFI_SYM_VAR) {
3230 				addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
3231 				if (!addr) {
3232 					if (preload) {
3233 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', cannot resolve C variable '%s'", filename, ZSTR_VAL(name));
3234 					} else {
3235 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3236 					}
3237 					if (lib) {
3238 						DL_UNLOAD(handle);
3239 					}
3240 					goto cleanup;
3241 				}
3242 				sym->addr = addr;
3243 			} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
3244 				zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
3245 
3246 				addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
3247 				zend_string_release(mangled_name);
3248 				if (!addr) {
3249 					if (preload) {
3250 						zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
3251 					} else {
3252 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3253 					}
3254 					if (lib) {
3255 						DL_UNLOAD(handle);
3256 					}
3257 					goto cleanup;
3258 				}
3259 				sym->addr = addr;
3260 			}
3261 			if (scope && scope->symbols) {
3262 				zend_ffi_symbol *old_sym = zend_hash_find_ptr(scope->symbols, name);
3263 
3264 				if (old_sym) {
3265 					if (zend_ffi_same_symbols(old_sym, sym)) {
3266 						if (ZEND_FFI_TYPE_IS_OWNED(sym->type)
3267 						 && ZEND_FFI_TYPE(old_sym->type) != ZEND_FFI_TYPE(sym->type)) {
3268 							zend_ffi_type *type = ZEND_FFI_TYPE(sym->type);
3269 							zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_sym->type), ZEND_FFI_TYPE(type));
3270 							zend_ffi_type_dtor(type);
3271 						}
3272 					} else {
3273 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s'", filename, ZSTR_VAL(name));
3274 						if (lib) {
3275 							DL_UNLOAD(handle);
3276 						}
3277 						goto cleanup;
3278 					}
3279 				}
3280 			}
3281 		} ZEND_HASH_FOREACH_END();
3282 	}
3283 
3284 	if (preload) {
3285 		if (scope && scope->tags && FFI_G(tags)) {
3286 			ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3287 				zend_ffi_tag *old_tag = zend_hash_find_ptr(scope->tags, name);
3288 
3289 				if (old_tag) {
3290 					if (zend_ffi_same_tags(old_tag, tag)) {
3291 						if (ZEND_FFI_TYPE_IS_OWNED(tag->type)
3292 						 && ZEND_FFI_TYPE(old_tag->type) != ZEND_FFI_TYPE(tag->type)) {
3293 							zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3294 							zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_tag->type), ZEND_FFI_TYPE(type));
3295 							zend_ffi_type_dtor(type);
3296 						}
3297 					} else {
3298 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s %s'", filename, zend_ffi_tag_kind_name[tag->kind], ZSTR_VAL(name));
3299 						if (lib) {
3300 							DL_UNLOAD(handle);
3301 						}
3302 						goto cleanup;
3303 					}
3304 				}
3305 			} ZEND_HASH_FOREACH_END();
3306 		}
3307 
3308 		if (!scope) {
3309 			scope = malloc(sizeof(zend_ffi_scope));
3310 			scope->symbols = FFI_G(symbols);
3311 			scope->tags = FFI_G(tags);
3312 
3313 			if (!FFI_G(scopes)) {
3314 				FFI_G(scopes) = malloc(sizeof(HashTable));
3315 				zend_hash_init(FFI_G(scopes), 0, NULL, zend_ffi_scope_hash_dtor, 1);
3316 			}
3317 
3318 			zend_hash_str_add_ptr(FFI_G(scopes), scope_name, scope_name_len, scope);
3319 		} else {
3320 			if (FFI_G(symbols)) {
3321 				if (!scope->symbols) {
3322 					scope->symbols = FFI_G(symbols);
3323 					FFI_G(symbols) = NULL;
3324 				} else {
3325 					ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3326 						if (!zend_hash_add_ptr(scope->symbols, name, sym)) {
3327 							zend_ffi_type_dtor(sym->type);
3328 							free(sym);
3329 						}
3330 					} ZEND_HASH_FOREACH_END();
3331 					FFI_G(symbols)->pDestructor = NULL;
3332 					zend_hash_destroy(FFI_G(symbols));
3333 				}
3334 			}
3335 			if (FFI_G(tags)) {
3336 				if (!scope->tags) {
3337 					scope->tags = FFI_G(tags);
3338 					FFI_G(tags) = NULL;
3339 				} else {
3340 					ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3341 						if (!zend_hash_add_ptr(scope->tags, name, tag)) {
3342 							zend_ffi_type_dtor(tag->type);
3343 							free(tag);
3344 						}
3345 					} ZEND_HASH_FOREACH_END();
3346 					FFI_G(tags)->pDestructor = NULL;
3347 					zend_hash_destroy(FFI_G(tags));
3348 				}
3349 			}
3350 		}
3351 
3352 		if (EG(objects_store).object_buckets) {
3353 			ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3354 		} else {
3355 			ffi = ecalloc(1, sizeof(zend_ffi));
3356 		}
3357 		ffi->symbols = scope->symbols;
3358 		ffi->tags = scope->tags;
3359 		ffi->persistent = 1;
3360 	} else {
3361 		ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3362 		ffi->lib = handle;
3363 		ffi->symbols = FFI_G(symbols);
3364 		ffi->tags = FFI_G(tags);
3365 	}
3366 
3367 	efree(code);
3368 	FFI_G(symbols) = NULL;
3369 	FFI_G(tags) = NULL;
3370 	FFI_G(persistent) = 0;
3371 
3372 	return ffi;
3373 
3374 cleanup:
3375 	efree(code);
3376 	if (FFI_G(symbols)) {
3377 		zend_hash_destroy(FFI_G(symbols));
3378 		pefree(FFI_G(symbols), preload);
3379 		FFI_G(symbols) = NULL;
3380 	}
3381 	if (FFI_G(tags)) {
3382 		zend_hash_destroy(FFI_G(tags));
3383 		pefree(FFI_G(tags), preload);
3384 		FFI_G(tags) = NULL;
3385 	}
3386 	FFI_G(persistent) = 0;
3387 	return NULL;
3388 }
3389 /* }}} */
3390 
ZEND_METHOD(FFI,load)3391 ZEND_METHOD(FFI, load) /* {{{ */
3392 {
3393 	zend_string *fn;
3394 	zend_ffi *ffi;
3395 
3396 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3397 	ZEND_PARSE_PARAMETERS_START(1, 1)
3398 		Z_PARAM_STR(fn)
3399 	ZEND_PARSE_PARAMETERS_END();
3400 
3401 	if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
3402 		zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.preload_user\". Use \"ffi.preload\" instead.");
3403 		RETURN_THROWS();
3404 	}
3405 
3406 	ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
3407 
3408 	if (ffi) {
3409 		RETURN_OBJ(&ffi->std);
3410 	}
3411 }
3412 /* }}} */
3413 
ZEND_METHOD(FFI,scope)3414 ZEND_METHOD(FFI, scope) /* {{{ */
3415 {
3416 	zend_string *scope_name;
3417 	zend_ffi_scope *scope = NULL;
3418 	zend_ffi *ffi;
3419 
3420 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3421 	ZEND_PARSE_PARAMETERS_START(1, 1)
3422 		Z_PARAM_STR(scope_name)
3423 	ZEND_PARSE_PARAMETERS_END();
3424 
3425 	if (FFI_G(scopes)) {
3426 		scope = zend_hash_find_ptr(FFI_G(scopes), scope_name);
3427 	}
3428 
3429 	if (!scope) {
3430 		zend_throw_error(zend_ffi_exception_ce, "Failed loading scope '%s'", ZSTR_VAL(scope_name));
3431 		RETURN_THROWS();
3432 	}
3433 
3434 	ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3435 
3436 	ffi->symbols = scope->symbols;
3437 	ffi->tags = scope->tags;
3438 	ffi->persistent = 1;
3439 
3440 	RETURN_OBJ(&ffi->std);
3441 }
3442 /* }}} */
3443 
zend_ffi_cleanup_dcl(zend_ffi_dcl * dcl)3444 static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
3445 {
3446 	if (dcl) {
3447 		zend_ffi_type_dtor(dcl->type);
3448 		dcl->type = NULL;
3449 	}
3450 }
3451 /* }}} */
3452 
zend_ffi_throw_parser_error(const char * format,...)3453 static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */
3454 {
3455 	va_list va;
3456 	char *message = NULL;
3457 
3458 	va_start(va, format);
3459 	zend_vspprintf(&message, 0, format, va);
3460 
3461 	if (EG(current_execute_data)) {
3462 		zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
3463 	} else {
3464 		zend_error(E_WARNING, "FFI Parser: %s", message);
3465 	}
3466 
3467 	efree(message);
3468 	va_end(va);
3469 }
3470 /* }}} */
3471 
zend_ffi_validate_vla(zend_ffi_type * type)3472 static int zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */
3473 {
3474 	if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3475 		zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3476 		return FAILURE;
3477 	}
3478 	return SUCCESS;
3479 }
3480 /* }}} */
3481 
zend_ffi_validate_incomplete_type(zend_ffi_type * type,zend_bool allow_incomplete_tag,zend_bool allow_incomplete_array)3482 static int zend_ffi_validate_incomplete_type(zend_ffi_type *type, zend_bool allow_incomplete_tag, zend_bool allow_incomplete_array) /* {{{ */
3483 {
3484 	if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
3485 		if (FFI_G(tags)) {
3486 			zend_string *key;
3487 			zend_ffi_tag *tag;
3488 
3489 			ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), key, tag) {
3490 				if (ZEND_FFI_TYPE(tag->type) == type) {
3491 					if (type->kind == ZEND_FFI_TYPE_ENUM) {
3492 						zend_ffi_throw_parser_error("Incomplete enum \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3493 					} else if (type->attr & ZEND_FFI_ATTR_UNION) {
3494 						zend_ffi_throw_parser_error("Incomplete union \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3495 					} else {
3496 						zend_ffi_throw_parser_error("Incomplete struct \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3497 					}
3498 					return FAILURE;
3499 				}
3500 			} ZEND_HASH_FOREACH_END();
3501 		}
3502 		if (FFI_G(symbols)) {
3503 			zend_string *key;
3504 			zend_ffi_symbol *sym;
3505 
3506 			ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), key, sym) {
3507 				if (type == ZEND_FFI_TYPE(sym->type)) {
3508 					zend_ffi_throw_parser_error("Incomplete C type %s at line %d", ZSTR_VAL(key), FFI_G(line));
3509 					return FAILURE;
3510 				}
3511 			} ZEND_HASH_FOREACH_END();
3512 		}
3513 		zend_ffi_throw_parser_error("Incomplete type at line %d", FFI_G(line));
3514 		return FAILURE;
3515 	} else if (!allow_incomplete_array && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
3516 		zend_ffi_throw_parser_error("\"[]\" is not allowed at line %d", FFI_G(line));
3517 		return FAILURE;
3518 	} else if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3519 		zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3520 		return FAILURE;
3521 	}
3522 	return SUCCESS;
3523 }
3524 /* }}} */
3525 
zend_ffi_validate_type(zend_ffi_type * type,zend_bool allow_incomplete_tag,zend_bool allow_incomplete_array)3526 static int zend_ffi_validate_type(zend_ffi_type *type, zend_bool allow_incomplete_tag, zend_bool allow_incomplete_array) /* {{{ */
3527 {
3528 	if (type->kind == ZEND_FFI_TYPE_VOID) {
3529 		zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line));
3530 		return FAILURE;
3531 	}
3532 	return zend_ffi_validate_incomplete_type(type, allow_incomplete_tag, allow_incomplete_array);
3533 }
3534 /* }}} */
3535 
zend_ffi_validate_var_type(zend_ffi_type * type,zend_bool allow_incomplete_array)3536 static int zend_ffi_validate_var_type(zend_ffi_type *type, zend_bool allow_incomplete_array) /* {{{ */
3537 {
3538 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
3539 		zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line));
3540 		return FAILURE;
3541 	}
3542 	return zend_ffi_validate_type(type, 0, allow_incomplete_array);
3543 }
3544 /* }}} */
3545 
zend_ffi_validate_type_name(zend_ffi_dcl * dcl)3546 void zend_ffi_validate_type_name(zend_ffi_dcl *dcl) /* {{{ */
3547 {
3548 	zend_ffi_finalize_type(dcl);
3549 	if (zend_ffi_validate_var_type(ZEND_FFI_TYPE(dcl->type), 0) != SUCCESS) {
3550 		zend_ffi_cleanup_dcl(dcl);
3551 		LONGJMP(FFI_G(bailout), FAILURE);
3552 	}
3553 }
3554 /* }}} */
3555 
zend_ffi_subst_type(zend_ffi_type ** dcl,zend_ffi_type * type)3556 static int zend_ffi_subst_type(zend_ffi_type **dcl, zend_ffi_type *type) /* {{{ */
3557 {
3558 	zend_ffi_type *dcl_type;
3559 	zend_ffi_field *field;
3560 
3561 	if (*dcl == type) {
3562 		*dcl = ZEND_FFI_TYPE_MAKE_OWNED(type);
3563 		return 1;
3564 	}
3565 	dcl_type = *dcl;
3566 	switch (dcl_type->kind) {
3567 		case ZEND_FFI_TYPE_POINTER:
3568 			return zend_ffi_subst_type(&dcl_type->pointer.type, type);
3569 		case ZEND_FFI_TYPE_ARRAY:
3570 			return zend_ffi_subst_type(&dcl_type->array.type, type);
3571 		case ZEND_FFI_TYPE_FUNC:
3572 			if (zend_ffi_subst_type(&dcl_type->func.ret_type, type)) {
3573 				return 1;
3574 			}
3575 			if (dcl_type->func.args) {
3576 				zval *zv;
3577 
3578 				ZEND_HASH_FOREACH_VAL(dcl_type->func.args, zv) {
3579 					if (zend_ffi_subst_type((zend_ffi_type**)&Z_PTR_P(zv), type)) {
3580 						return 1;
3581 					}
3582 				} ZEND_HASH_FOREACH_END();
3583 			}
3584 			break;
3585 		case ZEND_FFI_TYPE_STRUCT:
3586 			ZEND_HASH_FOREACH_PTR(&dcl_type->record.fields, field) {
3587 				if (zend_ffi_subst_type(&field->type, type)) {
3588 					return 1;
3589 				}
3590 			} ZEND_HASH_FOREACH_END();
3591 			break;
3592 		default:
3593 			break;
3594 	}
3595 	return 0;
3596 } /* }}} */
3597 
zend_ffi_tags_cleanup(zend_ffi_dcl * dcl)3598 static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
3599 {
3600 	zend_ffi_tag *tag;
3601 	ZEND_HASH_FOREACH_PTR(FFI_G(tags), tag) {
3602 		if (ZEND_FFI_TYPE_IS_OWNED(tag->type)) {
3603 			zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3604 			zend_ffi_subst_type(&dcl->type, type);
3605 			tag->type = type;
3606 		}
3607 	} ZEND_HASH_FOREACH_END();
3608 	zend_hash_destroy(FFI_G(tags));
3609 	efree(FFI_G(tags));
3610 }
3611 /* }}} */
3612 
ZEND_METHOD(FFI,new)3613 ZEND_METHOD(FFI, new) /* {{{ */
3614 {
3615 	zend_string *type_def = NULL;
3616 	zend_object *type_obj = NULL;
3617 	zend_ffi_type *type, *type_ptr;
3618 	zend_ffi_cdata *cdata;
3619 	void *ptr;
3620 	zend_bool owned = 1;
3621 	zend_bool persistent = 0;
3622 	zend_bool is_const = 0;
3623 	zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
3624 
3625 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3626 	ZEND_PARSE_PARAMETERS_START(1, 3)
3627 		Z_PARAM_OBJ_OF_CLASS_OR_STR(type_obj, zend_ffi_ctype_ce, type_def)
3628 		Z_PARAM_OPTIONAL
3629 		Z_PARAM_BOOL(owned)
3630 		Z_PARAM_BOOL(persistent)
3631 	ZEND_PARSE_PARAMETERS_END();
3632 
3633 	if (!owned) {
3634 		flags &= ~ZEND_FFI_FLAG_OWNED;
3635 	}
3636 
3637 	if (persistent) {
3638 		flags |= ZEND_FFI_FLAG_PERSISTENT;
3639 	}
3640 
3641 	if (type_def) {
3642 		zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3643 
3644 		if (Z_TYPE(EX(This)) == IS_OBJECT) {
3645 			zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3646 			FFI_G(symbols) = ffi->symbols;
3647 			FFI_G(tags) = ffi->tags;
3648 		} else {
3649 			FFI_G(symbols) = NULL;
3650 			FFI_G(tags) = NULL;
3651 		}
3652 
3653 		FFI_G(default_type_attr) = 0;
3654 
3655 		if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
3656 			zend_ffi_type_dtor(dcl.type);
3657 			if (Z_TYPE(EX(This)) != IS_OBJECT) {
3658 				if (FFI_G(tags)) {
3659 					zend_hash_destroy(FFI_G(tags));
3660 					efree(FFI_G(tags));
3661 					FFI_G(tags) = NULL;
3662 				}
3663 				if (FFI_G(symbols)) {
3664 					zend_hash_destroy(FFI_G(symbols));
3665 					efree(FFI_G(symbols));
3666 					FFI_G(symbols) = NULL;
3667 				}
3668 			}
3669 			return;
3670 		}
3671 
3672 		type = ZEND_FFI_TYPE(dcl.type);
3673 		if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3674 			is_const = 1;
3675 		}
3676 
3677 		if (Z_TYPE(EX(This)) != IS_OBJECT) {
3678 			if (FFI_G(tags)) {
3679 				zend_ffi_tags_cleanup(&dcl);
3680 			}
3681 			if (FFI_G(symbols)) {
3682 				zend_hash_destroy(FFI_G(symbols));
3683 				efree(FFI_G(symbols));
3684 				FFI_G(symbols) = NULL;
3685 			}
3686 		}
3687 		FFI_G(symbols) = NULL;
3688 		FFI_G(tags) = NULL;
3689 
3690 		type_ptr = dcl.type;
3691 	} else {
3692 		zend_ffi_ctype *ctype = (zend_ffi_ctype*) type_obj;
3693 
3694 		type_ptr = type = ctype->type;
3695 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3696 			type = ZEND_FFI_TYPE(type);
3697 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3698 				if (GC_REFCOUNT(&ctype->std) == 1) {
3699 					/* transfer type ownership */
3700 					ctype->type = type;
3701 				} else {
3702 					ctype->type = type_ptr = type = zend_ffi_remember_type(type);
3703 				}
3704 			}
3705 		}
3706 	}
3707 
3708 	if (type->size == 0) {
3709 		zend_throw_error(zend_ffi_exception_ce, "Cannot instantiate FFI\\CData of zero size");
3710 		zend_ffi_type_dtor(type_ptr);
3711 		return;
3712 	}
3713 
3714 	ptr = pemalloc(type->size, flags & ZEND_FFI_FLAG_PERSISTENT);
3715 	memset(ptr, 0, type->size);
3716 
3717 	cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3718 	if (type->kind < ZEND_FFI_TYPE_POINTER) {
3719 		cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3720 	}
3721 	cdata->type = type_ptr;
3722 	cdata->ptr = ptr;
3723 	cdata->flags = flags;
3724 	if (is_const) {
3725 		cdata->flags |= ZEND_FFI_FLAG_CONST;
3726 	}
3727 
3728 	RETURN_OBJ(&cdata->std);
3729 }
3730 /* }}} */
3731 
ZEND_METHOD(FFI,free)3732 ZEND_METHOD(FFI, free) /* {{{ */
3733 {
3734 	zval *zv;
3735 	zend_ffi_cdata *cdata;
3736 
3737 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3738 	ZEND_PARSE_PARAMETERS_START(1, 1)
3739 		Z_PARAM_OBJECT_OF_CLASS_EX2(zv, zend_ffi_cdata_ce, 0, 1, 0);
3740 	ZEND_PARSE_PARAMETERS_END();
3741 
3742 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3743 
3744 	if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
3745 		if (!cdata->ptr) {
3746 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
3747 			RETURN_THROWS();
3748 		}
3749 		if (cdata->ptr != (void*)&cdata->ptr_holder) {
3750 			pefree(*(void**)cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3751 		} else {
3752 			pefree(cdata->ptr_holder, (cdata->flags & ZEND_FFI_FLAG_PERSISTENT) || !is_zend_ptr(cdata->ptr_holder));
3753 		}
3754 		*(void**)cdata->ptr = NULL;
3755 	} else if (!(cdata->flags & ZEND_FFI_FLAG_OWNED)) {
3756 		pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3757 		cdata->ptr = NULL;
3758 		cdata->flags &= ~(ZEND_FFI_FLAG_OWNED|ZEND_FFI_FLAG_PERSISTENT);
3759 		cdata->std.handlers = &zend_ffi_cdata_free_handlers;
3760 	} else {
3761 		zend_throw_error(zend_ffi_exception_ce, "free() non a C pointer");
3762 	}
3763 }
3764 /* }}} */
3765 
ZEND_METHOD(FFI,cast)3766 ZEND_METHOD(FFI, cast) /* {{{ */
3767 {
3768 	zend_string *type_def = NULL;
3769 	zend_object *ztype = NULL;
3770 	zend_ffi_type *old_type, *type, *type_ptr;
3771 	zend_ffi_cdata *old_cdata, *cdata;
3772 	zend_bool is_const = 0;
3773 	zval *zv, *arg;
3774 	void *ptr;
3775 
3776 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3777 	ZEND_PARSE_PARAMETERS_START(2, 2)
3778 		Z_PARAM_OBJ_OF_CLASS_OR_STR(ztype, zend_ffi_ctype_ce, type_def)
3779 		Z_PARAM_ZVAL(zv)
3780 	ZEND_PARSE_PARAMETERS_END();
3781 
3782 	arg = zv;
3783 	ZVAL_DEREF(zv);
3784 
3785 	if (type_def) {
3786 		zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3787 
3788 		if (Z_TYPE(EX(This)) == IS_OBJECT) {
3789 			zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3790 			FFI_G(symbols) = ffi->symbols;
3791 			FFI_G(tags) = ffi->tags;
3792 		} else {
3793 			FFI_G(symbols) = NULL;
3794 			FFI_G(tags) = NULL;
3795 		}
3796 
3797 		FFI_G(default_type_attr) = 0;
3798 
3799 		if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
3800 			zend_ffi_type_dtor(dcl.type);
3801 			if (Z_TYPE(EX(This)) != IS_OBJECT) {
3802 				if (FFI_G(tags)) {
3803 					zend_hash_destroy(FFI_G(tags));
3804 					efree(FFI_G(tags));
3805 					FFI_G(tags) = NULL;
3806 				}
3807 				if (FFI_G(symbols)) {
3808 					zend_hash_destroy(FFI_G(symbols));
3809 					efree(FFI_G(symbols));
3810 					FFI_G(symbols) = NULL;
3811 				}
3812 			}
3813 			return;
3814 		}
3815 
3816 		type = ZEND_FFI_TYPE(dcl.type);
3817 		if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3818 			is_const = 1;
3819 		}
3820 
3821 		if (Z_TYPE(EX(This)) != IS_OBJECT) {
3822 			if (FFI_G(tags)) {
3823 				zend_ffi_tags_cleanup(&dcl);
3824 			}
3825 			if (FFI_G(symbols)) {
3826 				zend_hash_destroy(FFI_G(symbols));
3827 				efree(FFI_G(symbols));
3828 				FFI_G(symbols) = NULL;
3829 			}
3830 		}
3831 		FFI_G(symbols) = NULL;
3832 		FFI_G(tags) = NULL;
3833 
3834 		type_ptr = dcl.type;
3835 	} else {
3836 		zend_ffi_ctype *ctype = (zend_ffi_ctype*) ztype;
3837 
3838 		type_ptr = type = ctype->type;
3839 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3840 			type = ZEND_FFI_TYPE(type);
3841 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3842 				if (GC_REFCOUNT(&ctype->std) == 1) {
3843 					/* transfer type ownership */
3844 					ctype->type = type;
3845 				} else {
3846 					ctype->type = type_ptr = type = zend_ffi_remember_type(type);
3847 				}
3848 			}
3849 		}
3850 	}
3851 
3852 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
3853 		if (type->kind < ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) < IS_STRING) {
3854 			/* numeric conversion */
3855 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3856 			cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3857 			cdata->type = type_ptr;
3858 			cdata->ptr = emalloc(type->size);
3859 			zend_ffi_zval_to_cdata(cdata->ptr, type, zv);
3860 			cdata->flags = ZEND_FFI_FLAG_OWNED;
3861 			if (is_const) {
3862 				cdata->flags |= ZEND_FFI_FLAG_CONST;
3863 			}
3864 			RETURN_OBJ(&cdata->std);
3865 		} else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_LONG) {
3866 			/* number to pointer conversion */
3867 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3868 			cdata->type = type_ptr;
3869 			cdata->ptr = &cdata->ptr_holder;
3870 			cdata->ptr_holder = (void*)(intptr_t)Z_LVAL_P(zv);
3871 			if (is_const) {
3872 				cdata->flags |= ZEND_FFI_FLAG_CONST;
3873 			}
3874 			RETURN_OBJ(&cdata->std);
3875 		} else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_NULL) {
3876 			/* null -> pointer */
3877 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3878 			cdata->type = type_ptr;
3879 			cdata->ptr = &cdata->ptr_holder;
3880 			cdata->ptr_holder = NULL;
3881 			if (is_const) {
3882 				cdata->flags |= ZEND_FFI_FLAG_CONST;
3883 			}
3884 			RETURN_OBJ(&cdata->std);
3885 		} else {
3886 			zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
3887 			RETURN_THROWS();
3888 		}
3889 	}
3890 
3891 	old_cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3892 	old_type = ZEND_FFI_TYPE(old_cdata->type);
3893 	ptr = old_cdata->ptr;
3894 
3895 	cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3896 	if (type->kind < ZEND_FFI_TYPE_POINTER) {
3897 		cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3898 	}
3899 	cdata->type = type_ptr;
3900 
3901 	if (old_type->kind == ZEND_FFI_TYPE_POINTER
3902 	 && type->kind != ZEND_FFI_TYPE_POINTER
3903 	 && ZEND_FFI_TYPE(old_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
3904 		/* automatically dereference void* pointers ??? */
3905 		cdata->ptr = *(void**)ptr;
3906 	} else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
3907 	 && type->kind == ZEND_FFI_TYPE_POINTER) {
3908 		cdata->ptr = &cdata->ptr_holder;
3909 		cdata->ptr_holder = old_cdata->ptr;
3910 	} else if (type->size > old_type->size) {
3911 		zend_object_release(&cdata->std);
3912 		zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");
3913 		RETURN_THROWS();
3914 	} else if (ptr != &old_cdata->ptr_holder) {
3915 		cdata->ptr = ptr;
3916 	} else {
3917 		cdata->ptr = &cdata->ptr_holder;
3918 		cdata->ptr_holder = old_cdata->ptr_holder;
3919 	}
3920 	if (is_const) {
3921 		cdata->flags |= ZEND_FFI_FLAG_CONST;
3922 	}
3923 
3924 	if (old_cdata->flags & ZEND_FFI_FLAG_OWNED) {
3925 		if (GC_REFCOUNT(&old_cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
3926 			/* transfer ownership */
3927 			old_cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
3928 			cdata->flags |= ZEND_FFI_FLAG_OWNED;
3929 		} else {
3930 			//???zend_throw_error(zend_ffi_exception_ce, "Attempt to cast owned C pointer");
3931 		}
3932 	}
3933 
3934 	RETURN_OBJ(&cdata->std);
3935 }
3936 /* }}} */
3937 
ZEND_METHOD(FFI,type)3938 ZEND_METHOD(FFI, type) /* {{{ */
3939 {
3940 	zend_ffi_ctype *ctype;
3941 	zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3942 	zend_string *type_def;
3943 
3944 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3945 	ZEND_PARSE_PARAMETERS_START(1, 1)
3946 		Z_PARAM_STR(type_def);
3947 	ZEND_PARSE_PARAMETERS_END();
3948 
3949 	if (Z_TYPE(EX(This)) == IS_OBJECT) {
3950 		zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3951 		FFI_G(symbols) = ffi->symbols;
3952 		FFI_G(tags) = ffi->tags;
3953 	} else {
3954 		FFI_G(symbols) = NULL;
3955 		FFI_G(tags) = NULL;
3956 	}
3957 
3958 	FFI_G(default_type_attr) = 0;
3959 
3960 	if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
3961 		zend_ffi_type_dtor(dcl.type);
3962 		if (Z_TYPE(EX(This)) != IS_OBJECT) {
3963 			if (FFI_G(tags)) {
3964 				zend_hash_destroy(FFI_G(tags));
3965 				efree(FFI_G(tags));
3966 				FFI_G(tags) = NULL;
3967 			}
3968 			if (FFI_G(symbols)) {
3969 				zend_hash_destroy(FFI_G(symbols));
3970 				efree(FFI_G(symbols));
3971 				FFI_G(symbols) = NULL;
3972 			}
3973 		}
3974 		return;
3975 	}
3976 
3977 	if (Z_TYPE(EX(This)) != IS_OBJECT) {
3978 		if (FFI_G(tags)) {
3979 			zend_ffi_tags_cleanup(&dcl);
3980 		}
3981 		if (FFI_G(symbols)) {
3982 			zend_hash_destroy(FFI_G(symbols));
3983 			efree(FFI_G(symbols));
3984 			FFI_G(symbols) = NULL;
3985 		}
3986 	}
3987 	FFI_G(symbols) = NULL;
3988 	FFI_G(tags) = NULL;
3989 
3990 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
3991 	ctype->type = dcl.type;
3992 
3993 	RETURN_OBJ(&ctype->std);
3994 }
3995 /* }}} */
3996 
ZEND_METHOD(FFI,typeof)3997 ZEND_METHOD(FFI, typeof) /* {{{ */
3998 {
3999 	zval *zv, *arg;
4000 	zend_ffi_ctype *ctype;
4001 	zend_ffi_type *type;
4002 
4003 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4004 	ZEND_PARSE_PARAMETERS_START(1, 1)
4005 		Z_PARAM_ZVAL(zv);
4006 	ZEND_PARSE_PARAMETERS_END();
4007 
4008 	arg = zv;
4009 	ZVAL_DEREF(zv);
4010 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4011 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4012 
4013 		type = cdata->type;
4014 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
4015 			type = ZEND_FFI_TYPE(type);
4016 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4017 				if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4018 					/* transfer type ownership */
4019 					cdata->type = type;
4020 					type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4021 				} else {
4022 					cdata->type = type = zend_ffi_remember_type(type);
4023 				}
4024 			}
4025 		}
4026 	} else {
4027 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4028 		RETURN_THROWS();
4029 	}
4030 
4031 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4032 	ctype->type = type;
4033 
4034 	RETURN_OBJ(&ctype->std);
4035 }
4036 /* }}} */
4037 
ZEND_METHOD(FFI,arrayType)4038 ZEND_METHOD(FFI, arrayType) /* {{{ */
4039 {
4040 	zval *ztype;
4041 	zend_ffi_ctype *ctype;
4042 	zend_ffi_type *type;
4043 	HashTable *dims;
4044 	zval *val;
4045 
4046 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4047 	ZEND_PARSE_PARAMETERS_START(2, 2)
4048 		Z_PARAM_OBJECT_OF_CLASS(ztype, zend_ffi_ctype_ce)
4049 		Z_PARAM_ARRAY_HT(dims)
4050 	ZEND_PARSE_PARAMETERS_END();
4051 
4052 	ctype = (zend_ffi_ctype*)Z_OBJ_P(ztype);
4053 	type = ZEND_FFI_TYPE(ctype->type);
4054 
4055 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
4056 		zend_throw_error(zend_ffi_exception_ce, "Array of functions is not allowed");
4057 		RETURN_THROWS();
4058 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4059 		zend_throw_error(zend_ffi_exception_ce, "Only the leftmost array can be undimensioned");
4060 		RETURN_THROWS();
4061 	} else if (type->kind == ZEND_FFI_TYPE_VOID) {
4062 		zend_throw_error(zend_ffi_exception_ce, "Array of void type is not allowed");
4063 		RETURN_THROWS();
4064 	} else if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG) {
4065 		zend_throw_error(zend_ffi_exception_ce, "Array of incomplete type is not allowed");
4066 		RETURN_THROWS();
4067 	}
4068 
4069 	if (ZEND_FFI_TYPE_IS_OWNED(ctype->type)) {
4070 		if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4071 			if (GC_REFCOUNT(&ctype->std) == 1) {
4072 				/* transfer type ownership */
4073 				ctype->type = type;
4074 				type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4075 			} else {
4076 				ctype->type = type = zend_ffi_remember_type(type);
4077 			}
4078 		}
4079 	}
4080 
4081 	ZEND_HASH_REVERSE_FOREACH_VAL(dims, val) {
4082 		zend_long n = zval_get_long(val);
4083 		zend_ffi_type *new_type;
4084 
4085 		if (n < 0) {
4086 			zend_throw_error(zend_ffi_exception_ce, "negative array index");
4087 			zend_ffi_type_dtor(type);
4088 			RETURN_THROWS();
4089 		} else if (ZEND_FFI_TYPE(type)->kind == ZEND_FFI_TYPE_ARRAY && (ZEND_FFI_TYPE(type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4090 			zend_throw_error(zend_ffi_exception_ce, "only the leftmost array can be undimensioned");
4091 			zend_ffi_type_dtor(type);
4092 			RETURN_THROWS();
4093 		}
4094 
4095 		new_type = emalloc(sizeof(zend_ffi_type));
4096 		new_type->kind = ZEND_FFI_TYPE_ARRAY;
4097 		new_type->attr = 0;
4098 		new_type->size = n * ZEND_FFI_TYPE(type)->size;
4099 		new_type->align = ZEND_FFI_TYPE(type)->align;
4100 		new_type->array.type = type;
4101 		new_type->array.length = n;
4102 
4103 		if (n == 0) {
4104 			new_type->attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;
4105 		}
4106 
4107 		type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4108 	} ZEND_HASH_FOREACH_END();
4109 
4110 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4111 	ctype->type = type;
4112 
4113 	RETURN_OBJ(&ctype->std);
4114 }
4115 /* }}} */
4116 
ZEND_METHOD(FFI,addr)4117 ZEND_METHOD(FFI, addr) /* {{{ */
4118 {
4119 	zend_ffi_type *type, *new_type;
4120 	zend_ffi_cdata *cdata, *new_cdata;
4121 	zval *zv, *arg;
4122 
4123 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4124 	ZEND_PARSE_PARAMETERS_START(1, 1)
4125 		Z_PARAM_ZVAL(zv)
4126 	ZEND_PARSE_PARAMETERS_END();
4127 
4128 	arg = zv;
4129 	ZVAL_DEREF(zv);
4130 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4131 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4132 		RETURN_THROWS();
4133 	}
4134 
4135 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4136 	type = ZEND_FFI_TYPE(cdata->type);
4137 
4138 	new_type = emalloc(sizeof(zend_ffi_type));
4139 	new_type->kind = ZEND_FFI_TYPE_POINTER;
4140 	new_type->attr = 0;
4141 	new_type->size = sizeof(void*);
4142 	new_type->align = _Alignof(void*);
4143 	/* life-time (source must relive the resulting pointer) ??? */
4144 	new_type->pointer.type = type;
4145 
4146 	new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4147 	new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4148 	new_cdata->ptr_holder = cdata->ptr;
4149 	new_cdata->ptr = &new_cdata->ptr_holder;
4150 
4151 	if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4152 		if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
4153 			/* transfer type ownership */
4154 			cdata->type = type;
4155 			new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4156 		}
4157 		if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
4158 			/* transfer ownership */
4159 			cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4160 			new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
4161 		}
4162 	}
4163 
4164 	RETURN_OBJ(&new_cdata->std);
4165 }
4166 /* }}} */
4167 
ZEND_METHOD(FFI,sizeof)4168 ZEND_METHOD(FFI, sizeof) /* {{{ */
4169 {
4170 	zval *zv;
4171 	zend_ffi_type *type;
4172 
4173 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4174 	ZEND_PARSE_PARAMETERS_START(1, 1)
4175 		Z_PARAM_ZVAL(zv);
4176 	ZEND_PARSE_PARAMETERS_END();
4177 
4178 	ZVAL_DEREF(zv);
4179 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4180 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4181 		type = ZEND_FFI_TYPE(cdata->type);
4182 	} else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4183 		zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4184 		type = ZEND_FFI_TYPE(ctype->type);
4185 	} else {
4186 		zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4187 		RETURN_THROWS();
4188 	}
4189 
4190 	RETURN_LONG(type->size);
4191 }
4192 /* }}} */
4193 
ZEND_METHOD(FFI,alignof)4194 ZEND_METHOD(FFI, alignof) /* {{{ */
4195 {
4196 	zval *zv;
4197 	zend_ffi_type *type;
4198 
4199 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4200 	ZEND_PARSE_PARAMETERS_START(1, 1)
4201 		Z_PARAM_ZVAL(zv);
4202 	ZEND_PARSE_PARAMETERS_END();
4203 
4204 	ZVAL_DEREF(zv);
4205 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4206 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4207 		type = ZEND_FFI_TYPE(cdata->type);
4208 	} else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4209 		zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4210 		type = ZEND_FFI_TYPE(ctype->type);
4211 	} else {
4212 		zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4213 		RETURN_THROWS();
4214 	}
4215 
4216 	RETURN_LONG(type->align);
4217 }
4218 /* }}} */
4219 
ZEND_METHOD(FFI,memcpy)4220 ZEND_METHOD(FFI, memcpy) /* {{{ */
4221 {
4222 	zval *zv1, *zv2;
4223 	zend_ffi_cdata *cdata1, *cdata2;
4224 	zend_ffi_type *type1, *type2;
4225 	void *ptr1, *ptr2;
4226 	zend_long size;
4227 
4228 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4229 	ZEND_PARSE_PARAMETERS_START(3, 3)
4230 		Z_PARAM_OBJECT_OF_CLASS_EX2(zv1, zend_ffi_cdata_ce, 0, 1, 0);
4231 		Z_PARAM_ZVAL(zv2)
4232 		Z_PARAM_LONG(size)
4233 	ZEND_PARSE_PARAMETERS_END();
4234 
4235 	cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4236 	type1 = ZEND_FFI_TYPE(cdata1->type);
4237 	if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4238 		ptr1 = *(void**)cdata1->ptr;
4239 	} else {
4240 		ptr1 = cdata1->ptr;
4241 		if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4242 			zend_throw_error(zend_ffi_exception_ce, "Attempt to write over data boundary");
4243 			RETURN_THROWS();
4244 		}
4245 	}
4246 
4247 	ZVAL_DEREF(zv2);
4248 	if (Z_TYPE_P(zv2) == IS_STRING) {
4249 		ptr2 = Z_STRVAL_P(zv2);
4250 		if (size > Z_STRLEN_P(zv2)) {
4251 			zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4252 			RETURN_THROWS();
4253 		}
4254 	} else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4255 		cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4256 		type2 = ZEND_FFI_TYPE(cdata2->type);
4257 		if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4258 			ptr2 = *(void**)cdata2->ptr;
4259 		} else {
4260 			ptr2 = cdata2->ptr;
4261 			if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4262 				zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4263 				RETURN_THROWS();
4264 			}
4265 		}
4266 	} else {
4267 		zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4268 		RETURN_THROWS();
4269 	}
4270 
4271 	memcpy(ptr1, ptr2, size);
4272 }
4273 /* }}} */
4274 
ZEND_METHOD(FFI,memcmp)4275 ZEND_METHOD(FFI, memcmp) /* {{{ */
4276 {
4277 	zval *zv1, *zv2;
4278 	zend_ffi_cdata *cdata1, *cdata2;
4279 	zend_ffi_type *type1, *type2;
4280 	void *ptr1, *ptr2;
4281 	zend_long size;
4282 	int ret;
4283 
4284 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4285 	ZEND_PARSE_PARAMETERS_START(3, 3)
4286 		Z_PARAM_ZVAL(zv1);
4287 		Z_PARAM_ZVAL(zv2);
4288 		Z_PARAM_LONG(size)
4289 	ZEND_PARSE_PARAMETERS_END();
4290 
4291 	ZVAL_DEREF(zv1);
4292 	if (Z_TYPE_P(zv1) == IS_STRING) {
4293 		ptr1 = Z_STRVAL_P(zv1);
4294 		if (size > Z_STRLEN_P(zv1)) {
4295 			zend_throw_error(zend_ffi_exception_ce, "attempt to read over string boundary");
4296 			RETURN_THROWS();
4297 		}
4298 	} else if (Z_TYPE_P(zv1) == IS_OBJECT && Z_OBJCE_P(zv1) == zend_ffi_cdata_ce) {
4299 		cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4300 		type1 = ZEND_FFI_TYPE(cdata1->type);
4301 		if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4302 			ptr1 = *(void**)cdata1->ptr;
4303 		} else {
4304 			ptr1 = cdata1->ptr;
4305 			if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4306 				zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4307 				RETURN_THROWS();
4308 			}
4309 		}
4310 	} else {
4311 		zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
4312 		RETURN_THROWS();
4313 	}
4314 
4315 	ZVAL_DEREF(zv2);
4316 	if (Z_TYPE_P(zv2) == IS_STRING) {
4317 		ptr2 = Z_STRVAL_P(zv2);
4318 		if (size > Z_STRLEN_P(zv2)) {
4319 			zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4320 			RETURN_THROWS();
4321 		}
4322 	} else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4323 		cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4324 		type2 = ZEND_FFI_TYPE(cdata2->type);
4325 		if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4326 			ptr2 = *(void**)cdata2->ptr;
4327 		} else {
4328 			ptr2 = cdata2->ptr;
4329 			if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4330 				zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4331 				RETURN_THROWS();
4332 			}
4333 		}
4334 	} else {
4335 		zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4336 		RETURN_THROWS();
4337 	}
4338 
4339 	ret = memcmp(ptr1, ptr2, size);
4340 	if (ret == 0) {
4341 		RETVAL_LONG(0);
4342 	} else if (ret < 0) {
4343 		RETVAL_LONG(-1);
4344 	} else {
4345 		RETVAL_LONG(1);
4346 	}
4347 }
4348 /* }}} */
4349 
ZEND_METHOD(FFI,memset)4350 ZEND_METHOD(FFI, memset) /* {{{ */
4351 {
4352 	zval *zv;
4353 	zend_ffi_cdata *cdata;
4354 	zend_ffi_type *type;
4355 	void *ptr;
4356 	zend_long ch, size;
4357 
4358 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4359 	ZEND_PARSE_PARAMETERS_START(3, 3)
4360 		Z_PARAM_OBJECT_OF_CLASS_EX2(zv, zend_ffi_cdata_ce, 0, 1, 0);
4361 		Z_PARAM_LONG(ch)
4362 		Z_PARAM_LONG(size)
4363 	ZEND_PARSE_PARAMETERS_END();
4364 
4365 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4366 	type = ZEND_FFI_TYPE(cdata->type);
4367 	if (type->kind == ZEND_FFI_TYPE_POINTER) {
4368 		ptr = *(void**)cdata->ptr;
4369 	} else {
4370 		ptr = cdata->ptr;
4371 		if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4372 			zend_throw_error(zend_ffi_exception_ce, "attempt to write over data boundary");
4373 			RETURN_THROWS();
4374 		}
4375 	}
4376 
4377 	memset(ptr, ch, size);
4378 }
4379 /* }}} */
4380 
ZEND_METHOD(FFI,string)4381 ZEND_METHOD(FFI, string) /* {{{ */
4382 {
4383 	zval *zv;
4384 	zend_ffi_cdata *cdata;
4385 	zend_ffi_type *type;
4386 	void *ptr;
4387 	zend_long size;
4388 	zend_bool size_is_null = 1;
4389 
4390 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4391 	ZEND_PARSE_PARAMETERS_START(1, 2)
4392 		Z_PARAM_OBJECT_OF_CLASS_EX2(zv, zend_ffi_cdata_ce, 0, 1, 0);
4393 		Z_PARAM_OPTIONAL
4394 		Z_PARAM_LONG_OR_NULL(size, size_is_null)
4395 	ZEND_PARSE_PARAMETERS_END();
4396 
4397 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4398 	type = ZEND_FFI_TYPE(cdata->type);
4399 	if (!size_is_null) {
4400 		if (type->kind == ZEND_FFI_TYPE_POINTER) {
4401 			ptr = *(void**)cdata->ptr;
4402 		} else {
4403 			ptr = cdata->ptr;
4404 			if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4405 				zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4406 				RETURN_THROWS();
4407 			}
4408 		}
4409 		RETURN_STRINGL((char*)ptr, size);
4410 	} else {
4411 		if (type->kind == ZEND_FFI_TYPE_POINTER && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
4412 			ptr = *(void**)cdata->ptr;
4413 		} else if (type->kind == ZEND_FFI_TYPE_ARRAY && ZEND_FFI_TYPE(type->array.type)->kind == ZEND_FFI_TYPE_CHAR) {
4414 			ptr = cdata->ptr;
4415 		} else {
4416 			zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a C string");
4417 			RETURN_THROWS();
4418 		}
4419 		RETURN_STRING((char*)ptr);
4420 	}
4421 }
4422 /* }}} */
4423 
ZEND_METHOD(FFI,isNull)4424 ZEND_METHOD(FFI, isNull) /* {{{ */
4425 {
4426 	zval *zv;
4427 	zend_ffi_cdata *cdata;
4428 	zend_ffi_type *type;
4429 
4430 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4431 	ZEND_PARSE_PARAMETERS_START(1, 1)
4432 		Z_PARAM_ZVAL(zv);
4433 	ZEND_PARSE_PARAMETERS_END();
4434 
4435 	ZVAL_DEREF(zv);
4436 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4437 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4438 		RETURN_THROWS();
4439 	}
4440 
4441 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4442 	type = ZEND_FFI_TYPE(cdata->type);
4443 
4444 	if (type->kind != ZEND_FFI_TYPE_POINTER){
4445 		zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a pointer");
4446 		RETURN_THROWS();
4447 	}
4448 
4449 	RETURN_BOOL(*(void**)cdata->ptr == NULL);
4450 }
4451 /* }}} */
4452 
4453 
ZEND_METHOD(FFI_CType,getName)4454 ZEND_METHOD(FFI_CType, getName) /* {{{ */
4455 {
4456 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4457 	if (zend_parse_parameters_none() == FAILURE) {
4458 		RETURN_THROWS();
4459 	}
4460 
4461 	zend_ffi_ctype_name_buf buf;
4462 
4463 	buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
4464 	if (!zend_ffi_ctype_name(&buf, ZEND_FFI_TYPE(ctype->type))) {
4465 		RETURN_STR_COPY(Z_OBJ_P(ZEND_THIS)->ce->name);
4466 	} else {
4467 		size_t len = buf.end - buf.start;
4468 		zend_string *res = zend_string_init(buf.start, len, 0);
4469 		RETURN_STR(res);
4470 	}
4471 }
4472 
zend_ffi_parse_directives(const char * filename,char * code_pos,char ** scope_name,char ** lib,zend_bool preload)4473 static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, zend_bool preload) /* {{{ */
4474 {
4475 	char *p;
4476 
4477 	*scope_name = NULL;
4478 	*lib = NULL;
4479 	while (*code_pos == '#') {
4480 		if (strncmp(code_pos, "#define FFI_SCOPE", sizeof("#define FFI_SCOPE") - 1) == 0
4481 		 && (code_pos[sizeof("#define FFI_SCOPE") - 1] == ' '
4482 		  || code_pos[sizeof("#define FFI_SCOPE") - 1] == '\t')) {
4483 			p = code_pos + sizeof("#define FFI_SCOPE");
4484 			while (*p == ' ' || *p == '\t') {
4485 				p++;
4486 			}
4487 			if (*p != '"') {
4488 				if (preload) {
4489 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4490 				} else {
4491 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4492 				}
4493 				return NULL;
4494 			}
4495 			p++;
4496 			if (*scope_name) {
4497 				if (preload) {
4498 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_SCOPE defined twice", filename);
4499 				} else {
4500 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_SCOPE defined twice", filename);
4501 				}
4502 				return NULL;
4503 			}
4504 			*scope_name = p;
4505 			while (1) {
4506 				if (*p == '\"') {
4507 					*p = 0;
4508 					p++;
4509 					break;
4510 				} else if (*p <= ' ') {
4511 					if (preload) {
4512 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4513 					} else {
4514 						zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4515 					}
4516 					return NULL;
4517 				}
4518 				p++;
4519 			}
4520 			while (*p == ' ' || *p == '\t') {
4521 				p++;
4522 			}
4523 			while (*p == '\r' || *p == '\n') {
4524 				p++;
4525 			}
4526 			code_pos = p;
4527 		} else if (strncmp(code_pos, "#define FFI_LIB", sizeof("#define FFI_LIB") - 1) == 0
4528 		 && (code_pos[sizeof("#define FFI_LIB") - 1] == ' '
4529 		  || code_pos[sizeof("#define FFI_LIB") - 1] == '\t')) {
4530 			p = code_pos + sizeof("#define FFI_LIB");
4531 			while (*p == ' ' || *p == '\t') {
4532 				p++;
4533 			}
4534 			if (*p != '"') {
4535 				if (preload) {
4536 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
4537 				} else {
4538 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
4539 				}
4540 				return NULL;
4541 			}
4542 			p++;
4543 			if (*lib) {
4544 				if (preload) {
4545 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_LIB defined twice", filename);
4546 				} else {
4547 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_LIB defined twice", filename);
4548 				}
4549 				return NULL;
4550 			}
4551 			*lib = p;
4552 			while (1) {
4553 				if (*p == '\"') {
4554 					*p = 0;
4555 					p++;
4556 					break;
4557 				} else if (*p <= ' ') {
4558 					if (preload) {
4559 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
4560 					} else {
4561 						zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
4562 					}
4563 					return NULL;
4564 				}
4565 				p++;
4566 			}
4567 			while (*p == ' ' || *p == '\t') {
4568 				p++;
4569 			}
4570 			while (*p == '\r' || *p == '\n') {
4571 				p++;
4572 			}
4573 			code_pos = p;
4574 		} else {
4575 			break;
4576 		}
4577 	}
4578 	return code_pos;
4579 }
4580 /* }}} */
4581 
zend_fake_get_constructor(zend_object * object)4582 static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */
4583 {
4584 	zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name));
4585 	return NULL;
4586 }
4587 /* }}} */
4588 
zend_bad_array_access(zend_class_entry * ce)4589 static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
4590 {
4591 	zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
4592 }
4593 /* }}} */
4594 
zend_fake_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)4595 static ZEND_COLD zval *zend_fake_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
4596 {
4597     zend_bad_array_access(obj->ce);
4598 	return NULL;
4599 }
4600 /* }}} */
4601 
zend_fake_write_dimension(zend_object * obj,zval * offset,zval * value)4602 static ZEND_COLD void zend_fake_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
4603 {
4604     zend_bad_array_access(obj->ce);
4605 }
4606 /* }}} */
4607 
zend_fake_has_dimension(zend_object * obj,zval * offset,int check_empty)4608 static ZEND_COLD int zend_fake_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
4609 {
4610     zend_bad_array_access(obj->ce);
4611 	return 0;
4612 }
4613 /* }}} */
4614 
zend_fake_unset_dimension(zend_object * obj,zval * offset)4615 static ZEND_COLD void zend_fake_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
4616 {
4617     zend_bad_array_access(obj->ce);
4618 }
4619 /* }}} */
4620 
zend_bad_property_access(zend_class_entry * ce)4621 static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_class_entry *ce) /* {{{ */
4622 {
4623 	zend_throw_error(NULL, "Cannot access property of object of type %s", ZSTR_VAL(ce->name));
4624 }
4625 /* }}} */
4626 
zend_fake_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)4627 static ZEND_COLD zval *zend_fake_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
4628 {
4629     zend_bad_property_access(obj->ce);
4630 	return &EG(uninitialized_zval);
4631 }
4632 /* }}} */
4633 
zend_fake_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)4634 static ZEND_COLD zval *zend_fake_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
4635 {
4636     zend_bad_array_access(obj->ce);
4637     return value;
4638 }
4639 /* }}} */
4640 
zend_fake_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)4641 static ZEND_COLD int zend_fake_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
4642 {
4643     zend_bad_array_access(obj->ce);
4644 	return 0;
4645 }
4646 /* }}} */
4647 
zend_fake_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)4648 static ZEND_COLD void zend_fake_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
4649 {
4650     zend_bad_array_access(obj->ce);
4651 }
4652 /* }}} */
4653 
zend_fake_get_property_ptr_ptr(zend_object * obj,zend_string * member,int type,void ** cache_slot)4654 static zval *zend_fake_get_property_ptr_ptr(zend_object *obj, zend_string *member, int type, void **cache_slot) /* {{{ */
4655 {
4656 	return NULL;
4657 }
4658 /* }}} */
4659 
zend_fake_get_method(zend_object ** obj_ptr,zend_string * method_name,const zval * key)4660 static ZEND_COLD zend_function *zend_fake_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
4661 {
4662 	zend_class_entry *ce = (*obj_ptr)->ce;
4663 	zend_throw_error(NULL, "Object of type %s does not support method calls", ZSTR_VAL(ce->name));
4664 	return NULL;
4665 }
4666 /* }}} */
4667 
zend_fake_get_properties(zend_object * obj)4668 static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
4669 {
4670 	return (HashTable*)&zend_empty_array;
4671 }
4672 /* }}} */
4673 
zend_fake_get_gc(zend_object * ob,zval ** table,int * n)4674 static HashTable *zend_fake_get_gc(zend_object *ob, zval **table, int *n) /* {{{ */
4675 {
4676 	*table = NULL;
4677 	*n = 0;
4678 	return NULL;
4679 }
4680 /* }}} */
4681 
zend_fake_cast_object(zend_object * obj,zval * result,int type)4682 static int zend_fake_cast_object(zend_object *obj, zval *result, int type)
4683 {
4684 	switch (type) {
4685 		case _IS_BOOL:
4686 			ZVAL_TRUE(result);
4687 			return SUCCESS;
4688 		default:
4689 			return FAILURE;
4690 	}
4691 }
4692 
zend_ffi_use_after_free(void)4693 static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
4694 {
4695 	zend_throw_error(zend_ffi_exception_ce, "Use after free()");
4696 }
4697 /* }}} */
4698 
zend_ffi_free_clone_obj(zend_object * obj)4699 static zend_object *zend_ffi_free_clone_obj(zend_object *obj) /* {{{ */
4700 {
4701 	zend_ffi_use_after_free();
4702 	return NULL;
4703 }
4704 /* }}} */
4705 
zend_ffi_free_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)4706 static ZEND_COLD zval *zend_ffi_free_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
4707 {
4708 	zend_ffi_use_after_free();
4709 	return NULL;
4710 }
4711 /* }}} */
4712 
zend_ffi_free_write_dimension(zend_object * obj,zval * offset,zval * value)4713 static ZEND_COLD void zend_ffi_free_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
4714 {
4715 	zend_ffi_use_after_free();
4716 }
4717 /* }}} */
4718 
zend_ffi_free_has_dimension(zend_object * obj,zval * offset,int check_empty)4719 static ZEND_COLD int zend_ffi_free_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
4720 {
4721 	zend_ffi_use_after_free();
4722 	return 0;
4723 }
4724 /* }}} */
4725 
zend_ffi_free_unset_dimension(zend_object * obj,zval * offset)4726 static ZEND_COLD void zend_ffi_free_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
4727 {
4728 	zend_ffi_use_after_free();
4729 }
4730 /* }}} */
4731 
zend_ffi_free_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)4732 static ZEND_COLD zval *zend_ffi_free_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
4733 {
4734 	zend_ffi_use_after_free();
4735 	return &EG(uninitialized_zval);
4736 }
4737 /* }}} */
4738 
zend_ffi_free_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)4739 static ZEND_COLD zval *zend_ffi_free_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
4740 {
4741 	zend_ffi_use_after_free();
4742 	return value;
4743 }
4744 /* }}} */
4745 
zend_ffi_free_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)4746 static ZEND_COLD int zend_ffi_free_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
4747 {
4748 	zend_ffi_use_after_free();
4749 	return 0;
4750 }
4751 /* }}} */
4752 
zend_ffi_free_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)4753 static ZEND_COLD void zend_ffi_free_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
4754 {
4755 	zend_ffi_use_after_free();
4756 }
4757 /* }}} */
4758 
zend_ffi_free_get_debug_info(zend_object * obj,int * is_temp)4759 static HashTable *zend_ffi_free_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
4760 {
4761 	zend_ffi_use_after_free();
4762 	return NULL;
4763 }
4764 /* }}} */
4765 
ZEND_INI_MH(OnUpdateFFIEnable)4766 static ZEND_INI_MH(OnUpdateFFIEnable) /* {{{ */
4767 {
4768 	if (zend_string_equals_literal_ci(new_value, "preload")) {
4769 		FFI_G(restriction) = ZEND_FFI_PRELOAD;
4770 	} else {
4771 		FFI_G(restriction) = (zend_ffi_api_restriction)zend_ini_parse_bool(new_value);
4772 	}
4773 	return SUCCESS;
4774 }
4775 /* }}} */
4776 
ZEND_INI_DISP(zend_ffi_enable_displayer_cb)4777 static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
4778 {
4779 	if (FFI_G(restriction) == ZEND_FFI_PRELOAD) {
4780 		ZEND_PUTS("preload");
4781 	} else if (FFI_G(restriction) == ZEND_FFI_ENABLED) {
4782 		ZEND_PUTS("On");
4783 	} else {
4784 		ZEND_PUTS("Off");
4785 	}
4786 }
4787 /* }}} */
4788 
4789 ZEND_INI_BEGIN()
4790 	ZEND_INI_ENTRY3_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, NULL, NULL, NULL, zend_ffi_enable_displayer_cb)
4791 	STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
ZEND_INI_END()4792 ZEND_INI_END()
4793 
4794 static int zend_ffi_preload_glob(const char *filename) /* {{{ */
4795 {
4796 #ifdef HAVE_GLOB
4797 	glob_t globbuf;
4798 	int    ret;
4799 	unsigned int i;
4800 
4801 	memset(&globbuf, 0, sizeof(glob_t));
4802 
4803 	ret = glob(filename, 0, NULL, &globbuf);
4804 #ifdef GLOB_NOMATCH
4805 	if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
4806 #else
4807 	if (!globbuf.gl_pathc) {
4808 #endif
4809 		/* pass */
4810 	} else {
4811 		for(i=0 ; i<globbuf.gl_pathc; i++) {
4812 			zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
4813 			if (!ffi) {
4814 				globfree(&globbuf);
4815 				return FAILURE;
4816 			}
4817 			efree(ffi);
4818 		}
4819 		globfree(&globbuf);
4820 	}
4821 #else
4822 	zend_ffi *ffi = zend_ffi_load(filename, 1);
4823 	if (!ffi) {
4824 		return FAILURE;
4825 	}
4826 	efree(ffi);
4827 #endif
4828 
4829 	return SUCCESS;
4830 }
4831 /* }}} */
4832 
4833 static int zend_ffi_preload(char *preload) /* {{{ */
4834 {
4835 	zend_ffi *ffi;
4836 	char *s = NULL, *e, *filename;
4837 	zend_bool is_glob = 0;
4838 
4839 	e = preload;
4840 	while (*e) {
4841 		switch (*e) {
4842 			case ZEND_PATHS_SEPARATOR:
4843 				if (s) {
4844 					filename = estrndup(s, e-s);
4845 					s = NULL;
4846 					if (!is_glob) {
4847 						ffi = zend_ffi_load(filename, 1);
4848 						efree(filename);
4849 						if (!ffi) {
4850 							return FAILURE;
4851 						}
4852 						efree(ffi);
4853 					} else {
4854 						int ret = zend_ffi_preload_glob(filename);
4855 
4856 						efree(filename);
4857 						if (ret != SUCCESS) {
4858 							return FAILURE;
4859 						}
4860 						is_glob = 0;
4861 					}
4862 				}
4863 				break;
4864 			case '*':
4865 			case '?':
4866 			case '[':
4867 				is_glob = 1;
4868 				break;
4869 			default:
4870 				if (!s) {
4871 					s = e;
4872 				}
4873 				break;
4874 		}
4875 		e++;
4876 	}
4877 	if (s) {
4878 		filename = estrndup(s, e-s);
4879 		if (!is_glob) {
4880 			ffi = zend_ffi_load(filename, 1);
4881 			efree(filename);
4882 			if (!ffi) {
4883 				return FAILURE;
4884 			}
4885 			efree(ffi);
4886 		} else {
4887 			int ret = zend_ffi_preload_glob(filename);
4888 			efree(filename);
4889 			if (ret != SUCCESS) {
4890 				return FAILURE;
4891 			}
4892 		}
4893 	}
4894 
4895 	return SUCCESS;
4896 }
4897 /* }}} */
4898 
4899 /* {{{ ZEND_MINIT_FUNCTION */
4900 ZEND_MINIT_FUNCTION(ffi)
4901 {
4902 	zend_class_entry ce;
4903 
4904 	REGISTER_INI_ENTRIES();
4905 
4906 	FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0;
4907 
4908 	INIT_NS_CLASS_ENTRY(ce, "FFI", "Exception", NULL);
4909 	zend_ffi_exception_ce = zend_register_internal_class_ex(&ce, zend_ce_error);
4910 
4911 	INIT_NS_CLASS_ENTRY(ce, "FFI", "ParserException", NULL);
4912 	zend_ffi_parser_exception_ce = zend_register_internal_class_ex(&ce, zend_ffi_exception_ce);
4913 	zend_ffi_parser_exception_ce->ce_flags |= ZEND_ACC_FINAL;
4914 
4915 	INIT_CLASS_ENTRY(ce, "FFI", class_FFI_methods);
4916 	zend_ffi_ce = zend_register_internal_class(&ce);
4917 	zend_ffi_ce->ce_flags |= ZEND_ACC_FINAL;
4918 	zend_ffi_ce->create_object = zend_ffi_new;
4919 	zend_ffi_ce->serialize = zend_class_serialize_deny;
4920 	zend_ffi_ce->unserialize = zend_class_unserialize_deny;
4921 
4922 	memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
4923 	zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
4924 	memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
4925 	zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
4926 	memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
4927 	zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
4928 
4929 	memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
4930 	zend_ffi_handlers.get_constructor      = zend_fake_get_constructor;
4931 	zend_ffi_handlers.free_obj             = zend_ffi_free_obj;
4932 	zend_ffi_handlers.clone_obj            = NULL;
4933 	zend_ffi_handlers.read_property        = zend_ffi_read_var;
4934 	zend_ffi_handlers.write_property       = zend_ffi_write_var;
4935 	zend_ffi_handlers.read_dimension       = zend_fake_read_dimension;
4936 	zend_ffi_handlers.write_dimension      = zend_fake_write_dimension;
4937 	zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
4938 	zend_ffi_handlers.has_property         = zend_fake_has_property;
4939 	zend_ffi_handlers.unset_property       = zend_fake_unset_property;
4940 	zend_ffi_handlers.has_dimension        = zend_fake_has_dimension;
4941 	zend_ffi_handlers.unset_dimension      = zend_fake_unset_dimension;
4942 	zend_ffi_handlers.get_method           = zend_ffi_get_func;
4943 	zend_ffi_handlers.compare              = NULL;
4944 	zend_ffi_handlers.cast_object          = zend_fake_cast_object;
4945 	zend_ffi_handlers.get_debug_info       = NULL;
4946 	zend_ffi_handlers.get_closure          = NULL;
4947 	zend_ffi_handlers.get_properties       = zend_fake_get_properties;
4948 	zend_ffi_handlers.get_gc               = zend_fake_get_gc;
4949 
4950 	zend_declare_class_constant_long(zend_ffi_ce, "__BIGGEST_ALIGNMENT__", sizeof("__BIGGEST_ALIGNMENT__")-1, __BIGGEST_ALIGNMENT__);
4951 
4952 	INIT_NS_CLASS_ENTRY(ce, "FFI", "CData", NULL);
4953 	zend_ffi_cdata_ce = zend_register_internal_class(&ce);
4954 	zend_ffi_cdata_ce->ce_flags |= ZEND_ACC_FINAL;
4955 	zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;
4956 	zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator;
4957 	zend_ffi_cdata_ce->serialize = zend_class_serialize_deny;
4958 	zend_ffi_cdata_ce->unserialize = zend_class_unserialize_deny;
4959 
4960 	memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
4961 	zend_ffi_cdata_handlers.get_constructor      = zend_fake_get_constructor;
4962 	zend_ffi_cdata_handlers.free_obj             = zend_ffi_cdata_free_obj;
4963 	zend_ffi_cdata_handlers.clone_obj            = zend_ffi_cdata_clone_obj;
4964 	zend_ffi_cdata_handlers.read_property        = zend_ffi_cdata_read_field;
4965 	zend_ffi_cdata_handlers.write_property       = zend_ffi_cdata_write_field;
4966 	zend_ffi_cdata_handlers.read_dimension       = zend_ffi_cdata_read_dim;
4967 	zend_ffi_cdata_handlers.write_dimension      = zend_ffi_cdata_write_dim;
4968 	zend_ffi_cdata_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
4969 	zend_ffi_cdata_handlers.has_property         = zend_fake_has_property;
4970 	zend_ffi_cdata_handlers.unset_property       = zend_fake_unset_property;
4971 	zend_ffi_cdata_handlers.has_dimension        = zend_fake_has_dimension;
4972 	zend_ffi_cdata_handlers.unset_dimension      = zend_fake_unset_dimension;
4973 	zend_ffi_cdata_handlers.get_method           = zend_fake_get_method;
4974 	zend_ffi_cdata_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
4975 	zend_ffi_cdata_handlers.do_operation         = zend_ffi_cdata_do_operation;
4976 	zend_ffi_cdata_handlers.compare              = zend_ffi_cdata_compare_objects;
4977 	zend_ffi_cdata_handlers.cast_object          = zend_ffi_cdata_cast_object;
4978 	zend_ffi_cdata_handlers.count_elements       = zend_ffi_cdata_count_elements;
4979 	zend_ffi_cdata_handlers.get_debug_info       = zend_ffi_cdata_get_debug_info;
4980 	zend_ffi_cdata_handlers.get_closure          = zend_ffi_cdata_get_closure;
4981 	zend_ffi_cdata_handlers.get_properties       = zend_fake_get_properties;
4982 	zend_ffi_cdata_handlers.get_gc               = zend_fake_get_gc;
4983 
4984 	memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
4985 	zend_ffi_cdata_value_handlers.get_constructor      = zend_fake_get_constructor;
4986 	zend_ffi_cdata_value_handlers.free_obj             = zend_ffi_cdata_free_obj;
4987 	zend_ffi_cdata_value_handlers.clone_obj            = zend_ffi_cdata_clone_obj;
4988 	zend_ffi_cdata_value_handlers.read_property        = zend_ffi_cdata_get;
4989 	zend_ffi_cdata_value_handlers.write_property       = zend_ffi_cdata_set;
4990 	zend_ffi_cdata_value_handlers.read_dimension       = zend_fake_read_dimension;
4991 	zend_ffi_cdata_value_handlers.write_dimension      = zend_fake_write_dimension;
4992 	zend_ffi_cdata_value_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
4993 	zend_ffi_cdata_value_handlers.has_property         = zend_fake_has_property;
4994 	zend_ffi_cdata_value_handlers.unset_property       = zend_fake_unset_property;
4995 	zend_ffi_cdata_value_handlers.has_dimension        = zend_fake_has_dimension;
4996 	zend_ffi_cdata_value_handlers.unset_dimension      = zend_fake_unset_dimension;
4997 	zend_ffi_cdata_value_handlers.get_method           = zend_fake_get_method;
4998 	zend_ffi_cdata_value_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
4999 	zend_ffi_cdata_value_handlers.compare              = zend_ffi_cdata_compare_objects;
5000 	zend_ffi_cdata_value_handlers.cast_object          = zend_ffi_cdata_cast_object;
5001 	zend_ffi_cdata_value_handlers.count_elements       = NULL;
5002 	zend_ffi_cdata_value_handlers.get_debug_info       = zend_ffi_cdata_get_debug_info;
5003 	zend_ffi_cdata_value_handlers.get_closure          = NULL;
5004 	zend_ffi_cdata_value_handlers.get_properties       = zend_fake_get_properties;
5005 	zend_ffi_cdata_value_handlers.get_gc               = zend_fake_get_gc;
5006 
5007 	memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5008 	zend_ffi_cdata_free_handlers.get_constructor      = zend_fake_get_constructor;
5009 	zend_ffi_cdata_free_handlers.free_obj             = zend_ffi_cdata_free_obj;
5010 	zend_ffi_cdata_free_handlers.clone_obj            = zend_ffi_free_clone_obj;
5011 	zend_ffi_cdata_free_handlers.read_property        = zend_ffi_free_read_property;
5012 	zend_ffi_cdata_free_handlers.write_property       = zend_ffi_free_write_property;
5013 	zend_ffi_cdata_free_handlers.read_dimension       = zend_ffi_free_read_dimension;
5014 	zend_ffi_cdata_free_handlers.write_dimension      = zend_ffi_free_write_dimension;
5015 	zend_ffi_cdata_free_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5016 	zend_ffi_cdata_free_handlers.has_property         = zend_ffi_free_has_property;
5017 	zend_ffi_cdata_free_handlers.unset_property       = zend_ffi_free_unset_property;
5018 	zend_ffi_cdata_free_handlers.has_dimension        = zend_ffi_free_has_dimension;
5019 	zend_ffi_cdata_free_handlers.unset_dimension      = zend_ffi_free_unset_dimension;
5020 	zend_ffi_cdata_free_handlers.get_method           = zend_fake_get_method;
5021 	zend_ffi_cdata_free_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
5022 	zend_ffi_cdata_free_handlers.compare              = zend_ffi_cdata_compare_objects;
5023 	zend_ffi_cdata_free_handlers.cast_object          = zend_fake_cast_object;
5024 	zend_ffi_cdata_free_handlers.count_elements       = NULL;
5025 	zend_ffi_cdata_free_handlers.get_debug_info       = zend_ffi_free_get_debug_info;
5026 	zend_ffi_cdata_free_handlers.get_closure          = NULL;
5027 	zend_ffi_cdata_free_handlers.get_properties       = zend_fake_get_properties;
5028 	zend_ffi_cdata_free_handlers.get_gc               = zend_fake_get_gc;
5029 
5030 	INIT_NS_CLASS_ENTRY(ce, "FFI", "CType", class_FFI_CType_methods);
5031 	zend_ffi_ctype_ce = zend_register_internal_class(&ce);
5032 	zend_ffi_ctype_ce->ce_flags |= ZEND_ACC_FINAL;
5033 	zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;
5034 	zend_ffi_ctype_ce->serialize = zend_class_serialize_deny;
5035 	zend_ffi_ctype_ce->unserialize = zend_class_unserialize_deny;
5036 
5037 	memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5038 	zend_ffi_ctype_handlers.get_constructor      = zend_fake_get_constructor;
5039 	zend_ffi_ctype_handlers.free_obj             = zend_ffi_ctype_free_obj;
5040 	zend_ffi_ctype_handlers.clone_obj            = NULL;
5041 	zend_ffi_ctype_handlers.read_property        = zend_fake_read_property;
5042 	zend_ffi_ctype_handlers.write_property       = zend_fake_write_property;
5043 	zend_ffi_ctype_handlers.read_dimension       = zend_fake_read_dimension;
5044 	zend_ffi_ctype_handlers.write_dimension      = zend_fake_write_dimension;
5045 	zend_ffi_ctype_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5046 	zend_ffi_ctype_handlers.has_property         = zend_fake_has_property;
5047 	zend_ffi_ctype_handlers.unset_property       = zend_fake_unset_property;
5048 	zend_ffi_ctype_handlers.has_dimension        = zend_fake_has_dimension;
5049 	zend_ffi_ctype_handlers.unset_dimension      = zend_fake_unset_dimension;
5050 	//zend_ffi_ctype_handlers.get_method           = zend_fake_get_method;
5051 	zend_ffi_ctype_handlers.get_class_name       = zend_ffi_ctype_get_class_name;
5052 	zend_ffi_ctype_handlers.compare              = zend_ffi_ctype_compare_objects;
5053 	zend_ffi_ctype_handlers.cast_object          = zend_fake_cast_object;
5054 	zend_ffi_ctype_handlers.count_elements       = NULL;
5055 	zend_ffi_ctype_handlers.get_debug_info       = zend_ffi_ctype_get_debug_info;
5056 	zend_ffi_ctype_handlers.get_closure          = NULL;
5057 	zend_ffi_ctype_handlers.get_properties       = zend_fake_get_properties;
5058 	zend_ffi_ctype_handlers.get_gc               = zend_fake_get_gc;
5059 
5060 	if (FFI_G(preload)) {
5061 		if (zend_ffi_preload(FFI_G(preload)) != SUCCESS) {
5062 			return FAILURE;
5063 		}
5064 	}
5065 
5066 	return SUCCESS;
5067 }
5068 /* }}} */
5069 
5070 /* {{{ ZEND_RSHUTDOWN_FUNCTION */
5071 ZEND_RSHUTDOWN_FUNCTION(ffi)
5072 {
5073 	if (FFI_G(callbacks)) {
5074 		zend_hash_destroy(FFI_G(callbacks));
5075 		efree(FFI_G(callbacks));
5076 		FFI_G(callbacks) = NULL;
5077 	}
5078 	if (FFI_G(weak_types)) {
5079 #if 0
5080 		fprintf(stderr, "WeakTypes: %d\n", zend_hash_num_elements(FFI_G(weak_types)));
5081 #endif
5082 		zend_hash_destroy(FFI_G(weak_types));
5083 		efree(FFI_G(weak_types));
5084 		FFI_G(weak_types) = NULL;
5085 	}
5086 	return SUCCESS;
5087 }
5088 /* }}} */
5089 
5090 /* {{{ ZEND_MINFO_FUNCTION */
5091 ZEND_MINFO_FUNCTION(ffi)
5092 {
5093 	php_info_print_table_start();
5094 	php_info_print_table_header(2, "FFI support", "enabled");
5095 	php_info_print_table_end();
5096 
5097 	DISPLAY_INI_ENTRIES();
5098 }
5099 /* }}} */
5100 
5101 static const zend_ffi_type zend_ffi_type_void = {.kind=ZEND_FFI_TYPE_VOID, .size=1, .align=1};
5102 static const zend_ffi_type zend_ffi_type_char = {.kind=ZEND_FFI_TYPE_CHAR, .size=1, .align=_Alignof(char)};
5103 static const zend_ffi_type zend_ffi_type_bool = {.kind=ZEND_FFI_TYPE_BOOL, .size=1, .align=_Alignof(uint8_t)};
5104 static const zend_ffi_type zend_ffi_type_sint8 = {.kind=ZEND_FFI_TYPE_SINT8, .size=1, .align=_Alignof(int8_t)};
5105 static const zend_ffi_type zend_ffi_type_uint8 = {.kind=ZEND_FFI_TYPE_UINT8, .size=1, .align=_Alignof(uint8_t)};
5106 static const zend_ffi_type zend_ffi_type_sint16 = {.kind=ZEND_FFI_TYPE_SINT16, .size=2, .align=_Alignof(int16_t)};
5107 static const zend_ffi_type zend_ffi_type_uint16 = {.kind=ZEND_FFI_TYPE_UINT16, .size=2, .align=_Alignof(uint16_t)};
5108 static const zend_ffi_type zend_ffi_type_sint32 = {.kind=ZEND_FFI_TYPE_SINT32, .size=4, .align=_Alignof(int32_t)};
5109 static const zend_ffi_type zend_ffi_type_uint32 = {.kind=ZEND_FFI_TYPE_UINT32, .size=4, .align=_Alignof(uint32_t)};
5110 static const zend_ffi_type zend_ffi_type_sint64 = {.kind=ZEND_FFI_TYPE_SINT64, .size=8, .align=_Alignof(int64_t)};
5111 static const zend_ffi_type zend_ffi_type_uint64 = {.kind=ZEND_FFI_TYPE_UINT64, .size=8, .align=_Alignof(uint64_t)};
5112 static const zend_ffi_type zend_ffi_type_float = {.kind=ZEND_FFI_TYPE_FLOAT, .size=sizeof(float), .align=_Alignof(float)};
5113 static const zend_ffi_type zend_ffi_type_double = {.kind=ZEND_FFI_TYPE_DOUBLE, .size=sizeof(double), .align=_Alignof(double)};
5114 
5115 #ifdef HAVE_LONG_DOUBLE
5116 static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONGDOUBLE, .size=sizeof(long double), .align=_Alignof(long double)};
5117 #endif
5118 
5119 static const zend_ffi_type zend_ffi_type_ptr = {.kind=ZEND_FFI_TYPE_POINTER, .size=sizeof(void*), .align=_Alignof(void*), .pointer.type = (zend_ffi_type*)&zend_ffi_type_void};
5120 
5121 const struct {
5122 	const char *name;
5123 	const zend_ffi_type *type;
5124 } zend_ffi_types[] = {
5125 	{"void",        &zend_ffi_type_void},
5126 	{"char",        &zend_ffi_type_char},
5127 	{"bool",        &zend_ffi_type_bool},
5128 	{"int8_t",      &zend_ffi_type_sint8},
5129 	{"uint8_t",     &zend_ffi_type_uint8},
5130 	{"int16_t",     &zend_ffi_type_sint16},
5131 	{"uint16_t",    &zend_ffi_type_uint16},
5132 	{"int32_t",     &zend_ffi_type_sint32},
5133 	{"uint32_t",    &zend_ffi_type_uint32},
5134 	{"int64_t",     &zend_ffi_type_sint64},
5135 	{"uint64_t",    &zend_ffi_type_uint64},
5136 	{"float",       &zend_ffi_type_float},
5137 	{"double",      &zend_ffi_type_double},
5138 #ifdef HAVE_LONG_DOUBLE
5139 	{"long double", &zend_ffi_type_long_double},
5140 #endif
5141 #if SIZEOF_SIZE_T == 4
5142 	{"uintptr_t",  &zend_ffi_type_uint32},
5143 	{"intptr_t",   &zend_ffi_type_sint32},
5144 	{"size_t",     &zend_ffi_type_uint32},
5145 	{"ssize_t",    &zend_ffi_type_sint32},
5146 	{"ptrdiff_t",  &zend_ffi_type_sint32},
5147 #else
5148 	{"uintptr_t",  &zend_ffi_type_uint64},
5149 	{"intptr_t",   &zend_ffi_type_sint64},
5150 	{"size_t",     &zend_ffi_type_uint64},
5151 	{"ssize_t",    &zend_ffi_type_sint64},
5152 	{"ptrdiff_t",  &zend_ffi_type_sint64},
5153 #endif
5154 #if SIZEOF_OFF_T == 4
5155 	{"off_t",      &zend_ffi_type_sint32},
5156 #else
5157 	{"off_t",      &zend_ffi_type_sint64},
5158 #endif
5159 
5160 	{"va_list",           &zend_ffi_type_ptr},
5161 	{"__builtin_va_list", &zend_ffi_type_ptr},
5162 	{"__gnuc_va_list",    &zend_ffi_type_ptr},
5163 };
5164 
5165 /* {{{ ZEND_GINIT_FUNCTION */
5166 static ZEND_GINIT_FUNCTION(ffi)
5167 {
5168 	size_t i;
5169 
5170 #if defined(COMPILE_DL_FFI) && defined(ZTS)
5171 	ZEND_TSRMLS_CACHE_UPDATE();
5172 #endif
5173 	memset(ffi_globals, 0, sizeof(*ffi_globals));
5174 	zend_hash_init(&ffi_globals->types, 0, NULL, NULL, 1);
5175 	for (i = 0; i < sizeof(zend_ffi_types)/sizeof(zend_ffi_types[0]); i++) {
5176 		zend_hash_str_add_new_ptr(&ffi_globals->types, zend_ffi_types[i].name, strlen(zend_ffi_types[i].name), (void*)zend_ffi_types[i].type);
5177 	}
5178 }
5179 /* }}} */
5180 
5181 /* {{{ ZEND_GINIT_FUNCTION */
5182 static ZEND_GSHUTDOWN_FUNCTION(ffi)
5183 {
5184 	if (ffi_globals->scopes) {
5185 		zend_hash_destroy(ffi_globals->scopes);
5186 		free(ffi_globals->scopes);
5187 	}
5188 	zend_hash_destroy(&ffi_globals->types);
5189 }
5190 /* }}} */
5191 
5192 /* {{{ ffi_module_entry */
5193 zend_module_entry ffi_module_entry = {
5194 	STANDARD_MODULE_HEADER,
5195 	"FFI",					/* Extension name */
5196 	NULL,					/* zend_function_entry */
5197 	ZEND_MINIT(ffi),		/* ZEND_MINIT - Module initialization */
5198 	NULL,					/* ZEND_MSHUTDOWN - Module shutdown */
5199 	NULL,					/* ZEND_RINIT - Request initialization */
5200 	ZEND_RSHUTDOWN(ffi),	/* ZEND_RSHUTDOWN - Request shutdown */
5201 	ZEND_MINFO(ffi),		/* ZEND_MINFO - Module info */
5202 	PHP_VERSION,			/* Version */
5203 	ZEND_MODULE_GLOBALS(ffi),
5204 	ZEND_GINIT(ffi),
5205 	ZEND_GSHUTDOWN(ffi),
5206 	NULL,
5207 	STANDARD_MODULE_PROPERTIES_EX
5208 };
5209 /* }}} */
5210 
5211 #ifdef COMPILE_DL_FFI
5212 # ifdef ZTS
5213 ZEND_TSRMLS_CACHE_DEFINE()
5214 # endif
5215 ZEND_GET_MODULE(ffi)
5216 #endif
5217 
5218 /* parser callbacks */
5219 void zend_ffi_parser_error(const char *format, ...) /* {{{ */
5220 {
5221 	va_list va;
5222 	char *message = NULL;
5223 
5224 	va_start(va, format);
5225 	zend_vspprintf(&message, 0, format, va);
5226 
5227 	if (EG(current_execute_data)) {
5228 		zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
5229 	} else {
5230 		zend_error(E_WARNING, "FFI Parser: %s", message);
5231 	}
5232 
5233 	efree(message);
5234 	va_end(va);
5235 
5236 	LONGJMP(FFI_G(bailout), FAILURE);
5237 }
5238 /* }}} */
5239 
5240 static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */
5241 {
5242 	if (!dcl->type) {
5243 		switch (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) {
5244 			case ZEND_FFI_DCL_VOID:
5245 				dcl->type = (zend_ffi_type*)&zend_ffi_type_void;
5246 				break;
5247 			case ZEND_FFI_DCL_CHAR:
5248 				dcl->type = (zend_ffi_type*)&zend_ffi_type_char;
5249 				break;
5250 			case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SIGNED:
5251 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint8;
5252 				break;
5253 			case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_UNSIGNED:
5254 			case ZEND_FFI_DCL_BOOL:
5255 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint8;
5256 				break;
5257 			case ZEND_FFI_DCL_SHORT:
5258 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED:
5259 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT:
5260 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5261 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint16;
5262 				break;
5263 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED:
5264 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5265 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint16;
5266 				break;
5267 			case ZEND_FFI_DCL_INT:
5268 			case ZEND_FFI_DCL_SIGNED:
5269 			case ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5270 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5271 				break;
5272 			case ZEND_FFI_DCL_UNSIGNED:
5273 			case ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5274 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5275 				break;
5276 			case ZEND_FFI_DCL_LONG:
5277 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5278 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5279 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5280 				if (sizeof(long) == 4) {
5281 					dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5282 				} else {
5283 					dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5284 				}
5285 				break;
5286 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5287 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5288 				if (sizeof(long) == 4) {
5289 					dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5290 				} else {
5291 					dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5292 				}
5293 				break;
5294 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG:
5295 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5296 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5297 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5298 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5299 				break;
5300 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5301 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5302 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5303 				break;
5304 			case ZEND_FFI_DCL_FLOAT:
5305 				dcl->type = (zend_ffi_type*)&zend_ffi_type_float;
5306 				break;
5307 			case ZEND_FFI_DCL_DOUBLE:
5308 				dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5309 				break;
5310 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_DOUBLE:
5311 #ifdef _WIN32
5312 				dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5313 #else
5314 				dcl->type = (zend_ffi_type*)&zend_ffi_type_long_double;
5315 #endif
5316 				break;
5317 			case ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_COMPLEX:
5318 			case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_COMPLEX:
5319 			case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_COMPLEX:
5320 				zend_ffi_parser_error("Unsupported type _Complex at line %d", FFI_G(line));
5321 				break;
5322 			default:
5323 				zend_ffi_parser_error("Unsupported type specifier combination at line %d", FFI_G(line));
5324 				break;
5325 		}
5326 		dcl->flags &= ~ZEND_FFI_DCL_TYPE_SPECIFIERS;
5327 		dcl->flags |= ZEND_FFI_DCL_TYPEDEF_NAME;
5328 	}
5329 }
5330 /* }}} */
5331 
5332 int zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */
5333 {
5334 	zend_ffi_symbol *sym;
5335 	zend_ffi_type *type;
5336 
5337 	if (FFI_G(symbols)) {
5338 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5339 		if (sym) {
5340 			return (sym->kind == ZEND_FFI_SYM_TYPE);
5341 		}
5342 	}
5343 	type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5344 	if (type) {
5345 		return 1;
5346 	}
5347 	return 0;
5348 }
5349 /* }}} */
5350 
5351 void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
5352 {
5353 	zend_ffi_symbol *sym;
5354 	zend_ffi_type *type;
5355 
5356 	if (FFI_G(symbols)) {
5357 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5358 		if (sym && sym->kind == ZEND_FFI_SYM_TYPE) {
5359 			dcl->type = ZEND_FFI_TYPE(sym->type);;
5360 			if (sym->is_const) {
5361 				dcl->attr |= ZEND_FFI_ATTR_CONST;
5362 			}
5363 			return;
5364 		}
5365 	}
5366 	type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5367 	if (type) {
5368 		dcl->type = type;
5369 		return;
5370 	}
5371 	zend_ffi_parser_error("Undefined C type \"%.*s\" at line %d", name_len, name, FFI_G(line));
5372 }
5373 /* }}} */
5374 
5375 void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
5376 {
5377 	zend_ffi_symbol *sym;
5378 
5379 	if (UNEXPECTED(FFI_G(attribute_parsing))) {
5380 		val->kind = ZEND_FFI_VAL_NAME;
5381 		val->str = name;
5382 		val->len = name_len;
5383 		return;
5384 	} else if (FFI_G(symbols)) {
5385 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5386 		if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
5387 			val->i64 = sym->value;
5388 			switch (sym->type->kind) {
5389 				case ZEND_FFI_TYPE_SINT8:
5390 				case ZEND_FFI_TYPE_SINT16:
5391 				case ZEND_FFI_TYPE_SINT32:
5392 					val->kind = ZEND_FFI_VAL_INT32;
5393 					break;
5394 				case ZEND_FFI_TYPE_SINT64:
5395 					val->kind = ZEND_FFI_VAL_INT64;
5396 					break;
5397 				case ZEND_FFI_TYPE_UINT8:
5398 				case ZEND_FFI_TYPE_UINT16:
5399 				case ZEND_FFI_TYPE_UINT32:
5400 					val->kind = ZEND_FFI_VAL_UINT32;
5401 					break;
5402 				case ZEND_FFI_TYPE_UINT64:
5403 					val->kind = ZEND_FFI_VAL_UINT64;
5404 					break;
5405 				default:
5406 					ZEND_UNREACHABLE();
5407 			}
5408 			return;
5409 		}
5410 	}
5411 	val->kind = ZEND_FFI_VAL_ERROR;
5412 }
5413 /* }}} */
5414 
5415 void zend_ffi_make_enum_type(zend_ffi_dcl *dcl) /* {{{ */
5416 {
5417 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5418 	type->kind = ZEND_FFI_TYPE_ENUM;
5419 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ENUM_ATTRS);
5420 	type->enumeration.tag_name = NULL;
5421 	if (type->attr & ZEND_FFI_ATTR_PACKED) {
5422 		type->size = zend_ffi_type_uint8.size;
5423 		type->align = zend_ffi_type_uint8.align;
5424 		type->enumeration.kind = ZEND_FFI_TYPE_UINT8;
5425 	} else {
5426 		type->size = zend_ffi_type_uint32.size;
5427 		type->align = zend_ffi_type_uint32.align;
5428 		type->enumeration.kind = ZEND_FFI_TYPE_UINT32;
5429 	}
5430 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5431 	dcl->attr &= ~ZEND_FFI_ENUM_ATTRS;
5432 }
5433 /* }}} */
5434 
5435 void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last) /* {{{ */
5436 {
5437 	zend_ffi_symbol *sym;
5438 	const zend_ffi_type *sym_type;
5439 	int64_t value;
5440 	zend_ffi_type *enum_type = ZEND_FFI_TYPE(enum_dcl->type);
5441 	zend_bool overflow = 0;
5442 	zend_bool is_signed =
5443 		(enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT8 ||
5444 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT16 ||
5445 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT32 ||
5446 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT64);
5447 
5448 	ZEND_ASSERT(enum_type && enum_type->kind == ZEND_FFI_TYPE_ENUM);
5449 	if (val->kind == ZEND_FFI_VAL_EMPTY) {
5450 		if (is_signed) {
5451 			if (*last == 0x7FFFFFFFFFFFFFFFLL) {
5452 				overflow = 1;
5453 			}
5454 		} else {
5455 			if ((*min != 0 || *max != 0)
5456 			 && (uint64_t)*last == 0xFFFFFFFFFFFFFFFFULL) {
5457 				overflow = 1;
5458 			}
5459 		}
5460 		value = *last + 1;
5461 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
5462 		if (!is_signed && val->ch < 0) {
5463 			if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5464 				overflow = 1;
5465 			} else {
5466 				is_signed = 1;
5467 			}
5468 		}
5469 		value = val->ch;
5470 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
5471 		if (!is_signed && val->i64 < 0) {
5472 			if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5473 				overflow = 1;
5474 			} else {
5475 				is_signed = 1;
5476 			}
5477 		}
5478 		value = val->i64;
5479 	} else if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
5480 		if (is_signed && val->u64 > 0x7FFFFFFFFFFFFFFFULL) {
5481 			overflow = 1;
5482 		}
5483 		value = val->u64;
5484 	} else {
5485 		zend_ffi_parser_error("Enumerator value \"%.*s\" must be an integer at line %d", name_len, name, FFI_G(line));
5486 		return;
5487 	}
5488 
5489 	if (overflow) {
5490 		zend_ffi_parser_error("Overflow in enumeration values \"%.*s\" at line %d", name_len, name, FFI_G(line));
5491 		return;
5492 	}
5493 
5494 	if (is_signed) {
5495 		*min = MIN(*min, value);
5496 		*max = MAX(*max, value);
5497 		if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5498 		 && *min >= -0x7FLL-1 && *max <= 0x7FLL) {
5499 			sym_type = &zend_ffi_type_sint8;
5500 		} else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5501 		 && *min >= -0x7FFFLL-1 && *max <= 0x7FFFLL) {
5502 			sym_type = &zend_ffi_type_sint16;
5503 		} else if (*min >= -0x7FFFFFFFLL-1 && *max <= 0x7FFFFFFFLL) {
5504 			sym_type = &zend_ffi_type_sint32;
5505 		} else {
5506 			sym_type = &zend_ffi_type_sint64;
5507 		}
5508 	} else {
5509 		*min = MIN((uint64_t)*min, (uint64_t)value);
5510 		*max = MAX((uint64_t)*max, (uint64_t)value);
5511 		if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5512 		 && (uint64_t)*max <= 0xFFULL) {
5513 			sym_type = &zend_ffi_type_uint8;
5514 		} else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5515 		 && (uint64_t)*max <= 0xFFFFULL) {
5516 			sym_type = &zend_ffi_type_uint16;
5517 		} else if ((uint64_t)*max <= 0xFFFFFFFFULL) {
5518 			sym_type = &zend_ffi_type_uint32;
5519 		} else {
5520 			sym_type = &zend_ffi_type_uint64;
5521 		}
5522 	}
5523 	enum_type->enumeration.kind = sym_type->kind;
5524 	enum_type->size = sym_type->size;
5525 	enum_type->align = sym_type->align;
5526 	*last = value;
5527 
5528 	if (!FFI_G(symbols)) {
5529 		FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
5530 		zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
5531 	}
5532 	sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5533 	if (sym) {
5534 		zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
5535 	} else {
5536 		sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
5537 		sym->kind  = ZEND_FFI_SYM_CONST;
5538 		sym->type  = (zend_ffi_type*)sym_type;
5539 		sym->value = value;
5540 		zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
5541 	}
5542 }
5543 /* }}} */
5544 
5545 void zend_ffi_make_struct_type(zend_ffi_dcl *dcl) /* {{{ */
5546 {
5547 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5548 	type->kind = ZEND_FFI_TYPE_STRUCT;
5549 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_STRUCT_ATTRS);
5550 	type->size = 0;
5551 	type->align = dcl->align > 1 ? dcl->align : 1;
5552 	if (dcl->flags & ZEND_FFI_DCL_UNION) {
5553 		type->attr |= ZEND_FFI_ATTR_UNION;
5554 	}
5555 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5556 	type->record.tag_name = NULL;
5557 	zend_hash_init(&type->record.fields, 0, NULL, FFI_G(persistent) ? zend_ffi_field_hash_persistent_dtor :zend_ffi_field_hash_dtor, FFI_G(persistent));
5558 	dcl->attr &= ~ZEND_FFI_STRUCT_ATTRS;
5559 	dcl->align = 0;
5560 }
5561 /* }}} */
5562 
5563 static int zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */
5564 {
5565 	if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
5566 		zend_ffi_field *field = NULL;
5567 
5568 		ZEND_HASH_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) {
5569 			break;
5570 		} ZEND_HASH_FOREACH_END();
5571 		if (ZEND_FFI_TYPE(field->type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
5572 			zend_ffi_throw_parser_error("Flexible array member not at end of struct at line %d", FFI_G(line));
5573 			return FAILURE;
5574 		}
5575 	}
5576 	return SUCCESS;
5577 }
5578 /* }}} */
5579 
5580 static int zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */
5581 {
5582 	if (type == struct_type) {
5583 		zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line));
5584 		return FAILURE;
5585 	} else if (zend_ffi_validate_var_type(type, 1) != SUCCESS) {
5586 		return FAILURE;
5587 	} else if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
5588 		if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
5589 			zend_ffi_throw_parser_error("Flexible array member in union at line %d", FFI_G(line));
5590 			return FAILURE;
5591 		}
5592 	}
5593 	return zend_ffi_validate_prev_field_type(struct_type);
5594 }
5595 /* }}} */
5596 
5597 void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl) /* {{{ */
5598 {
5599 	zend_ffi_field *field;
5600 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
5601 	zend_ffi_type *field_type;
5602 
5603 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
5604 	zend_ffi_finalize_type(field_dcl);
5605 	field_type = ZEND_FFI_TYPE(field_dcl->type);
5606 	if (zend_ffi_validate_field_type(field_type, struct_type) != SUCCESS) {
5607 		zend_ffi_cleanup_dcl(field_dcl);
5608 		LONGJMP(FFI_G(bailout), FAILURE);
5609 	}
5610 
5611 	field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
5612 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
5613 		struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
5614 	}
5615 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
5616 		field->offset = 0;
5617 		struct_type->size = MAX(struct_type->size, field_type->size);
5618 	} else {
5619 		if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
5620 			uint32_t field_align = MAX(field_type->align, field_dcl->align);
5621 			struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
5622 		}
5623 		field->offset = struct_type->size;
5624 		struct_type->size += field_type->size;
5625 	}
5626 	field->type = field_dcl->type;
5627 	field->is_const = (zend_bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
5628 	field->is_nested = 0;
5629 	field->first_bit = 0;
5630 	field->bits = 0;
5631 	field_dcl->type = field_type; /* reset "owned" flag */
5632 
5633 	if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
5634 		zend_ffi_type_dtor(field->type);
5635 		pefree(field, FFI_G(persistent));
5636 		zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
5637 	}
5638 }
5639 /* }}} */
5640 
5641 void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl) /* {{{ */
5642 {
5643 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
5644 	zend_ffi_type *field_type;
5645 	zend_ffi_field *field;
5646 	zend_string *key;
5647 
5648 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
5649 	zend_ffi_finalize_type(field_dcl);
5650 	field_type = ZEND_FFI_TYPE(field_dcl->type);
5651 	if (field_type->kind != ZEND_FFI_TYPE_STRUCT) {
5652 		zend_ffi_cleanup_dcl(field_dcl);
5653 		zend_ffi_parser_error("Declaration does not declare anything at line %d", FFI_G(line));
5654 		return;
5655 	}
5656 
5657 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
5658 		struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
5659 	}
5660 	if (!(struct_type->attr & ZEND_FFI_ATTR_UNION)) {
5661 		if (zend_ffi_validate_prev_field_type(struct_type) != SUCCESS) {
5662 			zend_ffi_cleanup_dcl(field_dcl);
5663 			LONGJMP(FFI_G(bailout), FAILURE);
5664 		}
5665 		if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
5666 			uint32_t field_align = MAX(field_type->align, field_dcl->align);
5667 			struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
5668 		}
5669 	}
5670 
5671 	ZEND_HASH_FOREACH_STR_KEY_PTR(&field_type->record.fields, key, field) {
5672 		zend_ffi_field *new_field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
5673 
5674 		if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
5675 			new_field->offset = field->offset;
5676 		} else {
5677 			new_field->offset = struct_type->size + field->offset;
5678 		}
5679 		new_field->type = field->type;
5680 		new_field->is_const = field->is_const;
5681 		new_field->is_nested = 1;
5682 		new_field->first_bit = field->first_bit;
5683 		new_field->bits = field->bits;
5684 		field->type = ZEND_FFI_TYPE(field->type); /* reset "owned" flag */
5685 
5686 		if (key) {
5687 			if (!zend_hash_add_ptr(&struct_type->record.fields, key, new_field)) {
5688 				zend_ffi_type_dtor(new_field->type);
5689 				pefree(new_field, FFI_G(persistent));
5690 				zend_ffi_parser_error("Duplicate field name \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
5691 				return;
5692 			}
5693 		} else {
5694 			zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
5695 		}
5696 	} ZEND_HASH_FOREACH_END();
5697 
5698 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
5699 		struct_type->size = MAX(struct_type->size, field_type->size);
5700 	} else {
5701 		struct_type->size += field_type->size;
5702 	}
5703 
5704 	zend_ffi_type_dtor(field_dcl->type);
5705 	field_dcl->type = NULL;
5706 }
5707 /* }}} */
5708 
5709 void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits) /* {{{ */
5710 {
5711 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
5712 	zend_ffi_type *field_type;
5713 	zend_ffi_field *field;
5714 
5715 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
5716 	zend_ffi_finalize_type(field_dcl);
5717 	field_type = ZEND_FFI_TYPE(field_dcl->type);
5718 	if (zend_ffi_validate_field_type(field_type, struct_type) != SUCCESS) {
5719 		zend_ffi_cleanup_dcl(field_dcl);
5720 		LONGJMP(FFI_G(bailout), FAILURE);
5721 	}
5722 
5723 	if (field_type->kind < ZEND_FFI_TYPE_UINT8 || field_type->kind > ZEND_FFI_TYPE_BOOL) {
5724 		zend_ffi_cleanup_dcl(field_dcl);
5725 		zend_ffi_parser_error("Wrong type of bit field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5726 	}
5727 
5728 	if (bits->kind == ZEND_FFI_VAL_INT32 || bits->kind == ZEND_FFI_VAL_INT64) {
5729 		if (bits->i64 < 0) {
5730 			zend_ffi_cleanup_dcl(field_dcl);
5731 			zend_ffi_parser_error("Negative width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5732 		} else if (bits->i64 == 0) {
5733 			zend_ffi_cleanup_dcl(field_dcl);
5734 			if (name) {
5735 				zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5736 			}
5737 			return;
5738 		} else if (bits->i64 > field_type->size * 8) {
5739 			zend_ffi_cleanup_dcl(field_dcl);
5740 			zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5741 		}
5742 	} else if (bits->kind == ZEND_FFI_VAL_UINT32 || bits->kind == ZEND_FFI_VAL_UINT64) {
5743 		if (bits->u64 == 0) {
5744 			zend_ffi_cleanup_dcl(field_dcl);
5745 			if (name) {
5746 				zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5747 			}
5748 			return;
5749 		} else if (bits->u64 > field_type->size * 8) {
5750 			zend_ffi_cleanup_dcl(field_dcl);
5751 			zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5752 		}
5753 	} else {
5754 		zend_ffi_cleanup_dcl(field_dcl);
5755 		zend_ffi_parser_error("Bit field \"%.*s\" width not an integer constant at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
5756 	}
5757 
5758 	field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
5759 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
5760 		struct_type->align = MAX(struct_type->align, sizeof(uint32_t));
5761 	}
5762 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
5763 		field->offset = 0;
5764 		field->first_bit = 0;
5765 		field->bits = bits->u64;
5766 		if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
5767 			struct_type->size = MAX(struct_type->size, (bits->u64 + 7) / 8);
5768 		} else {
5769 			struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4);
5770 		}
5771 	} else {
5772 		zend_ffi_field *prev_field = NULL;
5773 
5774 		if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
5775 			ZEND_HASH_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) {
5776 				break;
5777 			} ZEND_HASH_FOREACH_END();
5778 		}
5779 		if (prev_field && prev_field->bits) {
5780 			field->offset = prev_field->offset;
5781 			field->first_bit = prev_field->first_bit + prev_field->bits;
5782 			field->bits = bits->u64;
5783 		} else {
5784 			field->offset = struct_type->size;
5785 			field->first_bit = 0;
5786 			field->bits = bits->u64;
5787 		}
5788 		if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
5789 			struct_type->size = field->offset + ((field->first_bit + field->bits) + 7) / 8;
5790 		} else {
5791 			struct_type->size = field->offset + (((field->first_bit + field->bits) + 31) / 32) * 4;
5792 		}
5793 	}
5794 	field->type = field_dcl->type;
5795 	field->is_const = (zend_bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
5796 	field->is_nested = 0;
5797 	field_dcl->type = field_type; /* reset "owned" flag */
5798 
5799 	if (name) {
5800 		if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
5801 			zend_ffi_type_dtor(field->type);
5802 			pefree(field, FFI_G(persistent));
5803 			zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
5804 		}
5805 	} else {
5806 		zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
5807 	}
5808 }
5809 /* }}} */
5810 
5811 void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl) /* {{{ */
5812 {
5813 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(dcl->type);
5814 
5815 	ZEND_ASSERT(struct_type->kind == ZEND_FFI_TYPE_STRUCT);
5816 	if (dcl->align > struct_type->align) {
5817 		struct_type->align = dcl->align;
5818 	}
5819 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
5820 		struct_type->size = ((struct_type->size + (struct_type->align - 1)) / struct_type->align) * struct_type->align;
5821 	}
5822 	dcl->align = 0;
5823 }
5824 /* }}} */
5825 
5826 void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl) /* {{{ */
5827 {
5828 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5829 	type->kind = ZEND_FFI_TYPE_POINTER;
5830 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_POINTER_ATTRS);
5831 	type->size = sizeof(void*);
5832 	type->align = _Alignof(void*);
5833 	zend_ffi_finalize_type(dcl);
5834 	if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) != SUCCESS) {
5835 		zend_ffi_cleanup_dcl(dcl);
5836 		LONGJMP(FFI_G(bailout), FAILURE);
5837 	}
5838 	type->pointer.type = dcl->type;
5839 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5840 	dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
5841 	dcl->attr &= ~ZEND_FFI_POINTER_ATTRS;
5842 	dcl->align = 0;
5843 }
5844 /* }}} */
5845 
5846 static int zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */
5847 {
5848 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
5849 		zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line));
5850 		return FAILURE;
5851 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
5852 		zend_ffi_throw_parser_error("Only the leftmost array can be undimensioned at line %d", FFI_G(line));
5853 		return FAILURE;
5854 	}
5855 	return zend_ffi_validate_type(type, 0, 1);
5856 }
5857 /* }}} */
5858 
5859 void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */
5860 {
5861 	int length = 0;
5862 	zend_ffi_type *element_type;
5863 	zend_ffi_type *type;
5864 
5865 	zend_ffi_finalize_type(dcl);
5866 	element_type = ZEND_FFI_TYPE(dcl->type);
5867 
5868 	if (len->kind == ZEND_FFI_VAL_EMPTY) {
5869 		length = 0;
5870 	} else if (len->kind == ZEND_FFI_VAL_UINT32 || len->kind == ZEND_FFI_VAL_UINT64) {
5871 		length = len->u64;
5872 	} else if (len->kind == ZEND_FFI_VAL_INT32 || len->kind == ZEND_FFI_VAL_INT64) {
5873 		length = len->i64;
5874 	} else if (len->kind == ZEND_FFI_VAL_CHAR) {
5875 		length = len->ch;
5876 	} else {
5877 		zend_ffi_cleanup_dcl(dcl);
5878 		zend_ffi_parser_error("Unsupported array index type at line %d", FFI_G(line));
5879 		return;
5880 	}
5881 	if (length < 0) {
5882 		zend_ffi_cleanup_dcl(dcl);
5883 		zend_ffi_parser_error("Negative array index at line %d", FFI_G(line));
5884 		return;
5885 	}
5886 
5887 	if (zend_ffi_validate_array_element_type(element_type) != SUCCESS) {
5888 		zend_ffi_cleanup_dcl(dcl);
5889 		LONGJMP(FFI_G(bailout), FAILURE);
5890 	}
5891 
5892 	type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5893 	type->kind = ZEND_FFI_TYPE_ARRAY;
5894 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ARRAY_ATTRS);
5895 	type->size = length * element_type->size;
5896 	type->align = element_type->align;
5897 	type->array.type = dcl->type;
5898 	type->array.length = length;
5899 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5900 	dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
5901 	dcl->attr &= ~ZEND_FFI_ARRAY_ATTRS;
5902 	dcl->align = 0;
5903 }
5904 /* }}} */
5905 
5906 static int zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */
5907 {
5908 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
5909 		zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line));
5910 		return FAILURE;
5911 	 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
5912 		zend_ffi_throw_parser_error("Function returning array is not allowed at line %d", FFI_G(line));
5913 		return FAILURE;
5914 	}
5915 	return zend_ffi_validate_incomplete_type(type, 1, 0);
5916 }
5917 /* }}} */
5918 
5919 void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl) /* {{{ */
5920 {
5921 	zend_ffi_type *type;
5922 	zend_ffi_type *ret_type;
5923 
5924 	zend_ffi_finalize_type(dcl);
5925 	ret_type = ZEND_FFI_TYPE(dcl->type);
5926 
5927 	if (args) {
5928 		int no_args = 0;
5929 		zend_ffi_type *arg_type;
5930 
5931 		ZEND_HASH_FOREACH_PTR(args, arg_type) {
5932 			arg_type = ZEND_FFI_TYPE(arg_type);
5933 			if (arg_type->kind == ZEND_FFI_TYPE_VOID) {
5934 				if (zend_hash_num_elements(args) != 1) {
5935 					zend_ffi_cleanup_dcl(nested_dcl);
5936 					zend_ffi_cleanup_dcl(dcl);
5937 					zend_hash_destroy(args);
5938 					pefree(args, FFI_G(persistent));
5939 					zend_ffi_parser_error("void type is not allowed at line %d", FFI_G(line));
5940 					return;
5941 				} else {
5942 					no_args = 1;
5943 				}
5944 			}
5945 		} ZEND_HASH_FOREACH_END();
5946 		if (no_args) {
5947 			zend_hash_destroy(args);
5948 			pefree(args, FFI_G(persistent));
5949 			args = NULL;
5950 		}
5951 	}
5952 
5953 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
5954 	if (dcl->abi == ZEND_FFI_ABI_VECTORCALL && args) {
5955 		zend_ulong i;
5956 		zend_ffi_type *arg_type;
5957 
5958 		ZEND_HASH_FOREACH_NUM_KEY_PTR(args, i, arg_type) {
5959 			arg_type = ZEND_FFI_TYPE(arg_type);
5960 # ifdef _WIN64
5961 			if (i >= 4 && i <= 5 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
5962 # else
5963 			if (i < 6 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
5964 # endif
5965 				zend_ffi_cleanup_dcl(nested_dcl);
5966 				zend_ffi_cleanup_dcl(dcl);
5967 				zend_hash_destroy(args);
5968 				pefree(args, FFI_G(persistent));
5969 				zend_ffi_parser_error("Type float/double is not allowed at position " ZEND_ULONG_FMT " with __vectorcall at line %d", i+1, FFI_G(line));
5970 				return;
5971 			}
5972 		} ZEND_HASH_FOREACH_END();
5973 	}
5974 #endif
5975 
5976 	if (zend_ffi_validate_func_ret_type(ret_type) != SUCCESS) {
5977 		zend_ffi_cleanup_dcl(nested_dcl);
5978 		zend_ffi_cleanup_dcl(dcl);
5979 		if (args) {
5980 			zend_hash_destroy(args);
5981 			pefree(args, FFI_G(persistent));
5982 		}
5983 		LONGJMP(FFI_G(bailout), FAILURE);
5984 	}
5985 
5986 	type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5987 	type->kind = ZEND_FFI_TYPE_FUNC;
5988 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_FUNC_ATTRS);
5989 	type->size = sizeof(void*);
5990 	type->align = 1;
5991 	type->func.ret_type = dcl->type;
5992 	switch (dcl->abi) {
5993 		case ZEND_FFI_ABI_DEFAULT:
5994 		case ZEND_FFI_ABI_CDECL:
5995 			type->func.abi = FFI_DEFAULT_ABI;
5996 			break;
5997 #ifdef HAVE_FFI_FASTCALL
5998 		case ZEND_FFI_ABI_FASTCALL:
5999 			type->func.abi = FFI_FASTCALL;
6000 			break;
6001 #endif
6002 #ifdef HAVE_FFI_THISCALL
6003 		case ZEND_FFI_ABI_THISCALL:
6004 			type->func.abi = FFI_THISCALL;
6005 			break;
6006 #endif
6007 #ifdef HAVE_FFI_STDCALL
6008 		case ZEND_FFI_ABI_STDCALL:
6009 			type->func.abi = FFI_STDCALL;
6010 			break;
6011 #endif
6012 #ifdef HAVE_FFI_PASCAL
6013 		case ZEND_FFI_ABI_PASCAL:
6014 			type->func.abi = FFI_PASCAL;
6015 			break;
6016 #endif
6017 #ifdef HAVE_FFI_REGISTER
6018 		case ZEND_FFI_ABI_REGISTER:
6019 			type->func.abi = FFI_REGISTER;
6020 			break;
6021 #endif
6022 #ifdef HAVE_FFI_MS_CDECL
6023 		case ZEND_FFI_ABI_MS:
6024 			type->func.abi = FFI_MS_CDECL;
6025 			break;
6026 #endif
6027 #ifdef HAVE_FFI_SYSV
6028 		case ZEND_FFI_ABI_SYSV:
6029 			type->func.abi = FFI_SYSV;
6030 			break;
6031 #endif
6032 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
6033 		case ZEND_FFI_ABI_VECTORCALL:
6034 			type->func.abi = FFI_VECTORCALL_PARTIAL;
6035 			break;
6036 #endif
6037 		default:
6038 			type->func.abi = FFI_DEFAULT_ABI;
6039 			zend_ffi_cleanup_dcl(nested_dcl);
6040 			if (args) {
6041 				zend_hash_destroy(args);
6042 				pefree(args, FFI_G(persistent));
6043 			}
6044 			type->func.args = NULL;
6045 			_zend_ffi_type_dtor(type);
6046 			zend_ffi_parser_error("Unsupported calling convention line %d", FFI_G(line));
6047 			break;
6048 	}
6049 	type->func.args = args;
6050 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6051 	dcl->attr &= ~ZEND_FFI_FUNC_ATTRS;
6052 	dcl->align = 0;
6053 	dcl->abi = 0;
6054 }
6055 /* }}} */
6056 
6057 void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl) /* {{{ */
6058 {
6059 	zend_ffi_type *type;
6060 
6061 	if (!*args) {
6062 		*args = pemalloc(sizeof(HashTable), FFI_G(persistent));
6063 		zend_hash_init(*args, 0, NULL, zend_ffi_type_hash_dtor, FFI_G(persistent));
6064 	}
6065 	zend_ffi_finalize_type(arg_dcl);
6066 	type = ZEND_FFI_TYPE(arg_dcl->type);
6067 	if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6068 		if (ZEND_FFI_TYPE_IS_OWNED(arg_dcl->type)) {
6069 			type->kind = ZEND_FFI_TYPE_POINTER;
6070 			type->size = sizeof(void*);
6071 		} else {
6072 			zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6073 			new_type->kind = ZEND_FFI_TYPE_POINTER;
6074 			new_type->attr = FFI_G(default_type_attr) | (type->attr & ZEND_FFI_POINTER_ATTRS);
6075 			new_type->size = sizeof(void*);
6076 			new_type->align = _Alignof(void*);
6077 			new_type->pointer.type = ZEND_FFI_TYPE(type->array.type);
6078 			arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6079 		}
6080 	} else if (type->kind == ZEND_FFI_TYPE_FUNC) {
6081 		zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6082 		new_type->kind = ZEND_FFI_TYPE_POINTER;
6083 		new_type->attr = FFI_G(default_type_attr);
6084 		new_type->size = sizeof(void*);
6085 		new_type->align = _Alignof(void*);
6086 		new_type->pointer.type = arg_dcl->type;
6087 		arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6088 	}
6089 	if (zend_ffi_validate_incomplete_type(type, 1, 1) != SUCCESS) {
6090 		zend_ffi_cleanup_dcl(arg_dcl);
6091 		zend_hash_destroy(*args);
6092 		pefree(*args, FFI_G(persistent));
6093 		*args = NULL;
6094 		LONGJMP(FFI_G(bailout), FAILURE);
6095 	}
6096 	zend_hash_next_index_insert_ptr(*args, (void*)arg_dcl->type);
6097 }
6098 /* }}} */
6099 
6100 void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
6101 {
6102 	zend_ffi_symbol *sym;
6103 
6104 	if (!FFI_G(symbols)) {
6105 		FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6106 		zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
6107 	}
6108 	zend_ffi_finalize_type(dcl);
6109 	sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6110 	if (sym) {
6111 		if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF
6112 		 && sym->kind == ZEND_FFI_SYM_TYPE
6113 		 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(dcl->type))
6114 		 && sym->is_const == (zend_bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6115 			/* allowed redeclaration */
6116 			zend_ffi_type_dtor(dcl->type);
6117 			return;
6118 		} else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0
6119 		 || (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6120 			zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type);
6121 
6122 			if (type->kind == ZEND_FFI_TYPE_FUNC) {
6123 				if (sym->kind == ZEND_FFI_SYM_FUNC
6124 				 && zend_ffi_same_types(ZEND_FFI_TYPE(sym->type), type)) {
6125 					/* allowed redeclaration */
6126 					zend_ffi_type_dtor(dcl->type);
6127 					return;
6128 				}
6129 			} else {
6130 				if (sym->kind == ZEND_FFI_SYM_VAR
6131 				 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), type)
6132 				 && sym->is_const == (zend_bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6133 					/* allowed redeclaration */
6134 					zend_ffi_type_dtor(dcl->type);
6135 					return;
6136 				}
6137 			}
6138 		}
6139 		zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6140 	} else {
6141 		if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF) {
6142 			if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) != SUCCESS) {
6143 				zend_ffi_cleanup_dcl(dcl);
6144 				LONGJMP(FFI_G(bailout), FAILURE);
6145 			}
6146 			if (dcl->align && dcl->align > ZEND_FFI_TYPE(dcl->type)->align) {
6147 				if (ZEND_FFI_TYPE_IS_OWNED(dcl->type)) {
6148 					ZEND_FFI_TYPE(dcl->type)->align = dcl->align;
6149 				} else {
6150 					zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6151 
6152 					memcpy(type, ZEND_FFI_TYPE(dcl->type), sizeof(zend_ffi_type));
6153 					type->attr |= FFI_G(default_type_attr);
6154 					type->align = dcl->align;
6155 					dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6156 				}
6157 			}
6158 			sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6159 			sym->kind = ZEND_FFI_SYM_TYPE;
6160 			sym->type = dcl->type;
6161 			sym->is_const = (zend_bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6162 			dcl->type = ZEND_FFI_TYPE(dcl->type); /* reset "owned" flag */
6163 			zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6164 		} else {
6165 			zend_ffi_type *type;
6166 
6167 			type = ZEND_FFI_TYPE(dcl->type);
6168 			if (zend_ffi_validate_type(type, (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN, 1) != SUCCESS) {
6169 				zend_ffi_cleanup_dcl(dcl);
6170 				LONGJMP(FFI_G(bailout), FAILURE);
6171 			}
6172 			if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 ||
6173 			    (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6174 				sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6175 				sym->kind = (type->kind == ZEND_FFI_TYPE_FUNC) ? ZEND_FFI_SYM_FUNC : ZEND_FFI_SYM_VAR;
6176 				sym->type = dcl->type;
6177 				sym->is_const = (zend_bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6178 				dcl->type = type; /* reset "owned" flag */
6179 				zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6180 			} else {
6181 				/* useless declarartion */
6182 				zend_ffi_type_dtor(dcl->type);
6183 			}
6184 		}
6185 	}
6186 }
6187 /* }}} */
6188 
6189 void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, zend_bool incomplete) /* {{{ */
6190 {
6191 	zend_ffi_tag *tag;
6192 	zend_ffi_type *type;
6193 
6194 	if (!FFI_G(tags)) {
6195 		FFI_G(tags) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6196 		zend_hash_init(FFI_G(tags), 0, NULL, FFI_G(persistent) ? zend_ffi_tag_hash_persistent_dtor : zend_ffi_tag_hash_dtor, FFI_G(persistent));
6197 	}
6198 	tag = zend_hash_str_find_ptr(FFI_G(tags), name, name_len);
6199 	if (tag) {
6200 		zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
6201 
6202 		if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6203 			if (tag->kind != ZEND_FFI_TAG_STRUCT) {
6204 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6205 				return;
6206 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6207 				zend_ffi_parser_error("Redefinition of \"struct %.*s\" at line %d", name_len, name, FFI_G(line));
6208 				return;
6209 			}
6210 		} else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6211 			if (tag->kind != ZEND_FFI_TAG_UNION) {
6212 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6213 				return;
6214 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6215 				zend_ffi_parser_error("Redefinition of \"union %.*s\" at line %d", name_len, name, FFI_G(line));
6216 				return;
6217 			}
6218 		} else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6219 			if (tag->kind != ZEND_FFI_TAG_ENUM) {
6220 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6221 				return;
6222 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6223 				zend_ffi_parser_error("Redefinition of \"enum %.*s\" at line %d", name_len, name, FFI_G(line));
6224 				return;
6225 			}
6226 		} else {
6227 			ZEND_UNREACHABLE();
6228 			return;
6229 		}
6230 		dcl->type = type;
6231 		if (!incomplete) {
6232 			type->attr &= ~ZEND_FFI_ATTR_INCOMPLETE_TAG;
6233 		}
6234 	} else {
6235 		zend_ffi_tag *tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent));
6236 		zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent));
6237 
6238 		if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6239 			tag->kind = ZEND_FFI_TAG_STRUCT;
6240 			zend_ffi_make_struct_type(dcl);
6241 			type = ZEND_FFI_TYPE(dcl->type);
6242 			type->record.tag_name = zend_string_copy(tag_name);
6243 		} else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6244 			tag->kind = ZEND_FFI_TAG_UNION;
6245 			zend_ffi_make_struct_type(dcl);
6246 			type = ZEND_FFI_TYPE(dcl->type);
6247 			type->record.tag_name = zend_string_copy(tag_name);
6248 		} else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6249 			tag->kind = ZEND_FFI_TAG_ENUM;
6250 			zend_ffi_make_enum_type(dcl);
6251 			type = ZEND_FFI_TYPE(dcl->type);
6252 			type->enumeration.tag_name = zend_string_copy(tag_name);
6253 		} else {
6254 			ZEND_UNREACHABLE();
6255 		}
6256 		tag->type = ZEND_FFI_TYPE_MAKE_OWNED(dcl->type);
6257 		dcl->type = ZEND_FFI_TYPE(dcl->type);
6258 		if (incomplete) {
6259 			dcl->type->attr |= ZEND_FFI_ATTR_INCOMPLETE_TAG;
6260 		}
6261 		zend_hash_add_new_ptr(FFI_G(tags), tag_name, tag);
6262 		zend_string_release(tag_name);
6263 	}
6264 }
6265 /* }}} */
6266 
6267 void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi) /* {{{ */
6268 {
6269 	if (dcl->abi != ZEND_FFI_ABI_DEFAULT) {
6270 		zend_ffi_parser_error("Multiple calling convention specifiers at line %d", FFI_G(line));
6271 	} else {
6272 		dcl->abi = abi;
6273 	}
6274 }
6275 /* }}} */
6276 
6277 #define SIMPLE_ATTRIBUTES(_) \
6278 	_(cdecl) \
6279 	_(fastcall) \
6280 	_(thiscall) \
6281 	_(stdcall) \
6282 	_(ms_abi) \
6283 	_(sysv_abi) \
6284 	_(vectorcall) \
6285 	_(aligned) \
6286 	_(packed) \
6287 	_(ms_struct) \
6288 	_(gcc_struct) \
6289 	_(const) \
6290 	_(malloc) \
6291 	_(deprecated) \
6292 	_(nothrow) \
6293 	_(leaf) \
6294 	_(pure) \
6295 	_(noreturn) \
6296 	_(warn_unused_result)
6297 
6298 #define ATTR_ID(name)   attr_ ## name,
6299 #define ATTR_NAME(name) {sizeof(#name)-1, #name},
6300 
6301 void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len) /* {{{ */
6302 {
6303 	enum {
6304 		SIMPLE_ATTRIBUTES(ATTR_ID)
6305 		attr_unsupported
6306 	};
6307 	static const struct {
6308 		size_t len;
6309 		const char * const name;
6310 	} names[] = {
6311 		SIMPLE_ATTRIBUTES(ATTR_NAME)
6312 		{0, NULL}
6313 	};
6314 	int id;
6315 
6316 	if (name_len > 4
6317 	 && name[0] == '_'
6318 	 && name[1] == '_'
6319 	 && name[name_len-2] == '_'
6320 	 && name[name_len-1] == '_') {
6321 		name += 2;
6322 		name_len -= 4;
6323 	}
6324 	for (id = 0; names[id].len != 0; id++) {
6325 		if (name_len == names[id].len) {
6326 			if (memcmp(name, names[id].name, name_len) == 0) {
6327 				break;
6328 			}
6329 		}
6330 	}
6331 	switch (id) {
6332 		case attr_cdecl:
6333 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_CDECL);
6334 			break;
6335 		case attr_fastcall:
6336 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_FASTCALL);
6337 			break;
6338 		case attr_thiscall:
6339 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_THISCALL);
6340 			break;
6341 		case attr_stdcall:
6342 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_STDCALL);
6343 			break;
6344 		case attr_ms_abi:
6345 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_MS);
6346 			break;
6347 		case attr_sysv_abi:
6348 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_SYSV);
6349 			break;
6350 		case attr_vectorcall:
6351 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_VECTORCALL);
6352 			break;
6353 		case attr_aligned:
6354 			dcl->align = __BIGGEST_ALIGNMENT__;
6355 			break;
6356 		case attr_packed:
6357 			dcl->attr |= ZEND_FFI_ATTR_PACKED;
6358 			break;
6359 		case attr_ms_struct:
6360 			dcl->attr |= ZEND_FFI_ATTR_MS_STRUCT;
6361 			break;
6362 		case attr_gcc_struct:
6363 			dcl->attr |= ZEND_FFI_ATTR_GCC_STRUCT;
6364 			break;
6365 		case attr_unsupported:
6366 			zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6367 			break;
6368 		default:
6369 			/* ignore */
6370 			break;
6371 	}
6372 }
6373 /* }}} */
6374 
6375 #define VALUE_ATTRIBUTES(_) \
6376 	_(regparam) \
6377 	_(aligned) \
6378 	_(mode) \
6379 	_(nonnull) \
6380 	_(alloc_size) \
6381 	_(format) \
6382 	_(deprecated)
6383 
6384 void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */
6385 {
6386 	enum {
6387 		VALUE_ATTRIBUTES(ATTR_ID)
6388 		attr_unsupported
6389 	};
6390 	static const struct {
6391 		size_t len;
6392 		const char * const name;
6393 	} names[] = {
6394 		VALUE_ATTRIBUTES(ATTR_NAME)
6395 		{0, NULL}
6396 	};
6397 	int id;
6398 
6399 	if (name_len > 4
6400 	 && name[0] == '_'
6401 	 && name[1] == '_'
6402 	 && name[name_len-2] == '_'
6403 	 && name[name_len-1] == '_') {
6404 		name += 2;
6405 		name_len -= 4;
6406 	}
6407 	for (id = 0; names[id].len != 0; id++) {
6408 		if (name_len == names[id].len) {
6409 			if (memcmp(name, names[id].name, name_len) == 0) {
6410 				break;
6411 			}
6412 		}
6413 	}
6414 	switch (id) {
6415 		case attr_regparam:
6416 			if (n == 0
6417 			 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6418 			 && val->i64 == 3) {
6419 				zend_ffi_set_abi(dcl, ZEND_FFI_ABI_REGISTER);
6420 			} else {
6421 				zend_ffi_parser_error("Incorrect \"regparam\" value at line %d", FFI_G(line));
6422 			}
6423 			break;
6424 		case attr_aligned:
6425 			if (n == 0
6426 			 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6427 			 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6428 				dcl->align = val->i64;
6429 			} else {
6430 				zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6431 			}
6432 			break;
6433 		case attr_mode:
6434 			if (n == 0
6435 			 && (val->kind == ZEND_FFI_VAL_NAME)) {
6436 				const char *str = val->str;
6437 				size_t len = val->len;
6438 				if (len > 4
6439 				 && str[0] == '_'
6440 				 && str[1] == '_'
6441 				 && str[len-2] == '_'
6442 				 && str[len-1] == '_') {
6443 					str += 2;
6444 					len -= 4;
6445 				}
6446 				// TODO: Add support for vector type 'VnXX' ???
6447 				if (len == 2) {
6448 					if (str[1] == 'I') {
6449 						if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED))) {
6450 							/* inappropriate type */
6451 						} else if (str[0] == 'Q') {
6452 							dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6453 							dcl->flags |= ZEND_FFI_DCL_CHAR;
6454 							break;
6455 						} else if (str[0] == 'H') {
6456 							dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6457 							dcl->flags |= ZEND_FFI_DCL_SHORT;
6458 							break;
6459 						} else if (str[0] == 'S') {
6460 							dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6461 							dcl->flags |= ZEND_FFI_DCL_INT;
6462 							break;
6463 						} else if (str[0] == 'D') {
6464 							dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6465 							if (sizeof(long) == 8) {
6466 								dcl->flags |= ZEND_FFI_DCL_LONG;
6467 							} else {
6468 								dcl->flags |= ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG;
6469 							}
6470 							break;
6471 						}
6472 					} else if (str[1] == 'F') {
6473 						if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
6474 							/* inappropriate type */
6475 						} else if (str[0] == 'S') {
6476 							dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6477 							dcl->flags |= ZEND_FFI_DCL_FLOAT;
6478 							break;
6479 						} else if (str[0] == 'D') {
6480 							dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6481 							dcl->flags |= ZEND_FFI_DCL_DOUBLE;
6482 							break;
6483 						}
6484 					}
6485 				}
6486 			}
6487 			zend_ffi_parser_error("Unsupported \"mode\" value at line %d", FFI_G(line));
6488 			// TODO: ???
6489 		case attr_unsupported:
6490 			zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6491 			break;
6492 		default:
6493 			/* ignore */
6494 			break;
6495 	}
6496 }
6497 /* }}} */
6498 
6499 void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
6500 {
6501 	if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) {
6502 		if ((val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6503 		 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6504 			dcl->align = val->i64;
6505 		} else {
6506 			zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6507 		}
6508 	} else {
6509 		/* ignore */
6510 	}
6511 }
6512 /* }}} */
6513 
6514 static int zend_ffi_nested_type(zend_ffi_type *type, zend_ffi_type *nested_type) /* {{{ */
6515 {
6516 	nested_type = ZEND_FFI_TYPE(nested_type);
6517 	switch (nested_type->kind) {
6518 		case ZEND_FFI_TYPE_POINTER:
6519 			/* "char" is used as a terminator of nested declaration */
6520 			if (nested_type->pointer.type == &zend_ffi_type_char) {
6521 				nested_type->pointer.type = type;
6522 				return zend_ffi_validate_vla(ZEND_FFI_TYPE(type));
6523 			} else {
6524 				return zend_ffi_nested_type(type, nested_type->pointer.type);
6525 			}
6526 			break;
6527 		case ZEND_FFI_TYPE_ARRAY:
6528 			/* "char" is used as a terminator of nested declaration */
6529 			if (nested_type->array.type == &zend_ffi_type_char) {
6530 				nested_type->array.type = type;
6531 				if (zend_ffi_validate_array_element_type(ZEND_FFI_TYPE(type)) != SUCCESS) {
6532 					return FAILURE;
6533 				}
6534 			} else {
6535 				if (zend_ffi_nested_type(type, nested_type->array.type) != SUCCESS) {
6536 					return FAILURE;
6537 				}
6538 			}
6539 			nested_type->size = nested_type->array.length * ZEND_FFI_TYPE(nested_type->array.type)->size;
6540 			nested_type->align = ZEND_FFI_TYPE(nested_type->array.type)->align;
6541 			return SUCCESS;
6542 			break;
6543 		case ZEND_FFI_TYPE_FUNC:
6544 			/* "char" is used as a terminator of nested declaration */
6545 			if (nested_type->func.ret_type == &zend_ffi_type_char) {
6546 				nested_type->func.ret_type = type;
6547 				return zend_ffi_validate_func_ret_type(ZEND_FFI_TYPE(type));
6548 			} else {
6549 				return zend_ffi_nested_type(type, nested_type->func.ret_type);
6550 			}
6551 			break;
6552 		default:
6553 			ZEND_UNREACHABLE();
6554 	}
6555 }
6556 /* }}} */
6557 
6558 void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl) /* {{{ */
6559 {
6560 	/* "char" is used as a terminator of nested declaration */
6561 	zend_ffi_finalize_type(dcl);
6562 	if (!nested_dcl->type || nested_dcl->type == &zend_ffi_type_char) {
6563 		nested_dcl->type = dcl->type;
6564 	} else {
6565 		if (zend_ffi_nested_type(dcl->type, nested_dcl->type) != SUCCESS) {
6566 			zend_ffi_cleanup_dcl(nested_dcl);
6567 			LONGJMP(FFI_G(bailout), FAILURE);
6568 		}
6569 	}
6570 	dcl->type = nested_dcl->type;
6571 }
6572 /* }}} */
6573 
6574 void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl) /* {{{ */
6575 {
6576 	zend_ffi_finalize_type(align_dcl);
6577 	dcl->align = MAX(align_dcl->align, ZEND_FFI_TYPE(align_dcl->type)->align);
6578 }
6579 /* }}} */
6580 
6581 void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */
6582 {
6583 	switch (align_val->kind) {
6584 		case ZEND_FFI_VAL_INT32:
6585 		case ZEND_FFI_VAL_UINT32:
6586 			dcl->align = zend_ffi_type_uint32.align;
6587 			break;
6588 		case ZEND_FFI_VAL_INT64:
6589 		case ZEND_FFI_VAL_UINT64:
6590 			dcl->align = zend_ffi_type_uint64.align;
6591 			break;
6592 		case ZEND_FFI_VAL_FLOAT:
6593 			dcl->align = zend_ffi_type_float.align;
6594 			break;
6595 		case ZEND_FFI_VAL_DOUBLE:
6596 			dcl->align = zend_ffi_type_double.align;
6597 			break;
6598 #ifdef HAVE_LONG_DOUBLE
6599 		case ZEND_FFI_VAL_LONG_DOUBLE:
6600 			dcl->align = zend_ffi_type_long_double.align;
6601 			break;
6602 #endif
6603 		case ZEND_FFI_VAL_CHAR:
6604 		case ZEND_FFI_VAL_STRING:
6605 			dcl->align = zend_ffi_type_char.align;
6606 			break;
6607 		default:
6608 			break;
6609 	}
6610 }
6611 /* }}} */
6612 
6613 #define zend_ffi_expr_bool(val) do { \
6614 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
6615 		val->kind = ZEND_FFI_VAL_INT32; \
6616 		val->i64 = !!val->u64; \
6617 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
6618 		val->kind = ZEND_FFI_VAL_INT32; \
6619 		val->i64 = !!val->i64; \
6620 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6621 		val->kind = ZEND_FFI_VAL_INT32; \
6622 		val->i64 = !!val->d; \
6623 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
6624 		val->kind = ZEND_FFI_VAL_INT32; \
6625 		val->i64 = !!val->ch; \
6626 	} else { \
6627 		val->kind = ZEND_FFI_VAL_ERROR; \
6628 	} \
6629 } while (0)
6630 
6631 #define zend_ffi_expr_math(val, op2, OP) do { \
6632 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
6633 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6634 			val->kind = MAX(val->kind, op2->kind); \
6635 			val->u64 = val->u64 OP op2->u64; \
6636 		} else if (op2->kind == ZEND_FFI_VAL_INT32) { \
6637 			val->u64 = val->u64 OP op2->i64; \
6638 		} else if (op2->kind == ZEND_FFI_VAL_INT64) { \
6639 			val->u64 = val->u64 OP op2->i64; \
6640 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6641 			val->kind = op2->kind; \
6642 			val->d = (zend_ffi_double)val->u64 OP op2->d; \
6643 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6644 			val->u64 = val->u64 OP op2->ch; \
6645 		} else { \
6646 			val->kind = ZEND_FFI_VAL_ERROR; \
6647 		} \
6648 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
6649 		if (op2->kind == ZEND_FFI_VAL_UINT32) { \
6650 			val->i64 = val->i64 OP op2->u64; \
6651 		} else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
6652 			val->i64 = val->i64 OP op2->u64; \
6653 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6654 			val->kind = MAX(val->kind, op2->kind); \
6655 			val->i64 = val->i64 OP op2->i64; \
6656 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6657 			val->kind = op2->kind; \
6658 			val->d = (zend_ffi_double)val->i64 OP op2->d; \
6659 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6660 			val->i64 = val->i64 OP op2->ch; \
6661 		} else { \
6662 			val->kind = ZEND_FFI_VAL_ERROR; \
6663 		} \
6664 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6665 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6666 			val->d = val->d OP (zend_ffi_double)op2->u64; \
6667 		} else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
6668 			val->d = val->d OP (zend_ffi_double)op2->i64; \
6669 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6670 			val->kind = MAX(val->kind, op2->kind); \
6671 			val->d = val->d OP op2->d; \
6672 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6673 			val->d = val->d OP (zend_ffi_double)op2->ch; \
6674 		} else { \
6675 			val->kind = ZEND_FFI_VAL_ERROR; \
6676 		} \
6677 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
6678 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6679 			val->kind = op2->kind; \
6680 			val->u64 = val->ch OP op2->u64; \
6681 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6682 			val->kind = ZEND_FFI_VAL_INT64; \
6683 			val->i64 = val->ch OP op2->i64; \
6684 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6685 			val->kind = op2->kind; \
6686 			val->d = (zend_ffi_double)val->ch OP op2->d; \
6687 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6688 			val->ch = val->ch OP op2->ch; \
6689 		} else { \
6690 			val->kind = ZEND_FFI_VAL_ERROR; \
6691 		} \
6692 	} else { \
6693 		val->kind = ZEND_FFI_VAL_ERROR; \
6694 	} \
6695 } while (0)
6696 
6697 #define zend_ffi_expr_int_math(val, op2, OP) do { \
6698 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
6699 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6700 			val->kind = MAX(val->kind, op2->kind); \
6701 			val->u64 = val->u64 OP op2->u64; \
6702 		} else if (op2->kind == ZEND_FFI_VAL_INT32) { \
6703 			val->u64 = val->u64 OP op2->i64; \
6704 		} else if (op2->kind == ZEND_FFI_VAL_INT64) { \
6705 			val->u64 = val->u64 OP op2->i64; \
6706 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6707 			val->u64 = val->u64 OP (uint64_t)op2->d; \
6708 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6709 			val->u64 = val->u64 OP op2->ch; \
6710 		} else { \
6711 			val->kind = ZEND_FFI_VAL_ERROR; \
6712 		} \
6713 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
6714 		if (op2->kind == ZEND_FFI_VAL_UINT32) { \
6715 			val->i64 = val->i64 OP op2->u64; \
6716 		} else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
6717 			val->i64 = val->i64 OP op2->u64; \
6718 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6719 			val->kind = MAX(val->kind, op2->kind); \
6720 			val->i64 = val->i64 OP op2->i64; \
6721 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6722 			val->u64 = val->u64 OP (int64_t)op2->d; \
6723 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6724 			val->i64 = val->i64 OP op2->ch; \
6725 		} else { \
6726 			val->kind = ZEND_FFI_VAL_ERROR; \
6727 		} \
6728 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6729 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6730 			val->kind = op2->kind; \
6731 			val->u64 = (uint64_t)val->d OP op2->u64; \
6732 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6733 			val->kind = op2->kind; \
6734 			val->i64 = (int64_t)val->d OP op2->i64; \
6735 		} else { \
6736 			val->kind = ZEND_FFI_VAL_ERROR; \
6737 		} \
6738 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
6739 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6740 			val->kind = op2->kind; \
6741 			val->u64 = (uint64_t)val->ch OP op2->u64; \
6742 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6743 			val->kind = op2->kind; \
6744 			val->i64 = (int64_t)val->ch OP op2->u64; \
6745 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6746 			val->ch = val->ch OP op2->ch; \
6747 		} else { \
6748 			val->kind = ZEND_FFI_VAL_ERROR; \
6749 		} \
6750 	} else { \
6751 		val->kind = ZEND_FFI_VAL_ERROR; \
6752 	} \
6753 } while (0)
6754 
6755 #define zend_ffi_expr_cmp(val, op2, OP) do { \
6756 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
6757 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6758 			val->kind = ZEND_FFI_VAL_INT32; \
6759 			val->i64 = val->u64 OP op2->u64; \
6760 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6761 			val->kind = ZEND_FFI_VAL_INT32; \
6762 			val->i64 = val->u64 OP op2->u64; /*signed/unsigned */ \
6763 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6764 			val->kind = ZEND_FFI_VAL_INT32; \
6765 			val->i64 = (zend_ffi_double)val->u64 OP op2->d; \
6766 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6767 			val->kind = ZEND_FFI_VAL_INT32; \
6768 			val->i64 = val->u64 OP op2->d; \
6769 		} else { \
6770 			val->kind = ZEND_FFI_VAL_ERROR; \
6771 		} \
6772 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
6773 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6774 			val->kind = ZEND_FFI_VAL_INT32; \
6775 			val->i64 = val->i64 OP op2->i64; /* signed/unsigned */ \
6776 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6777 			val->kind = ZEND_FFI_VAL_INT32; \
6778 			val->i64 = val->i64 OP op2->i64; \
6779 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6780 			val->kind = ZEND_FFI_VAL_INT32; \
6781 			val->i64 = (zend_ffi_double)val->i64 OP op2->d; \
6782 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6783 			val->kind = ZEND_FFI_VAL_INT32; \
6784 			val->i64 = val->i64 OP op2->ch; \
6785 		} else { \
6786 			val->kind = ZEND_FFI_VAL_ERROR; \
6787 		} \
6788 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6789 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6790 			val->kind = ZEND_FFI_VAL_INT32; \
6791 			val->i64 = val->d OP (zend_ffi_double)op2->u64; \
6792 		} else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
6793 			val->kind = ZEND_FFI_VAL_INT32; \
6794 			val->i64 = val->d OP (zend_ffi_double)op2->i64; \
6795 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6796 			val->kind = ZEND_FFI_VAL_INT32; \
6797 			val->i64 = val->d OP op2->d; \
6798 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6799 			val->kind = ZEND_FFI_VAL_INT32; \
6800 			val->i64 = val->d OP (zend_ffi_double)op2->ch; \
6801 		} else { \
6802 			val->kind = ZEND_FFI_VAL_ERROR; \
6803 		} \
6804 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
6805 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
6806 			val->kind = ZEND_FFI_VAL_INT32; \
6807 			val->i64 = val->ch OP op2->i64; /* signed/unsigned */ \
6808 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
6809 			val->kind = ZEND_FFI_VAL_INT32; \
6810 			val->i64 = val->ch OP op2->i64; \
6811 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
6812 			val->kind = ZEND_FFI_VAL_INT32; \
6813 			val->i64 = (zend_ffi_double)val->ch OP op2->d; \
6814 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
6815 			val->kind = ZEND_FFI_VAL_INT32; \
6816 			val->i64 = val->ch OP op2->ch; \
6817 		} else { \
6818 			val->kind = ZEND_FFI_VAL_ERROR; \
6819 		} \
6820 	} else { \
6821 		val->kind = ZEND_FFI_VAL_ERROR; \
6822 	} \
6823 } while (0)
6824 
6825 void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3) /* {{{ */
6826 {
6827 	zend_ffi_expr_bool(val);
6828 	if (val->kind == ZEND_FFI_VAL_INT32) {
6829 		if (val->i64) {
6830 			*val = *op2;
6831 		} else {
6832 			*val = *op3;
6833 		}
6834 	}
6835 }
6836 /* }}} */
6837 
6838 void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6839 {
6840 	zend_ffi_expr_bool(val);
6841 	zend_ffi_expr_bool(op2);
6842 	if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
6843 		val->i64 = val->i64 || op2->i64;
6844 	} else {
6845 		val->kind = ZEND_FFI_VAL_ERROR;
6846 	}
6847 }
6848 /* }}} */
6849 
6850 void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6851 {
6852 	zend_ffi_expr_bool(val);
6853 	zend_ffi_expr_bool(op2);
6854 	if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
6855 		val->i64 = val->i64 && op2->i64;
6856 	} else {
6857 		val->kind = ZEND_FFI_VAL_ERROR;
6858 	}
6859 }
6860 /* }}} */
6861 
6862 void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6863 {
6864 	zend_ffi_expr_int_math(val, op2, |);
6865 }
6866 /* }}} */
6867 
6868 void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6869 {
6870 	zend_ffi_expr_int_math(val, op2, ^);
6871 }
6872 /* }}} */
6873 
6874 void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6875 {
6876 	zend_ffi_expr_int_math(val, op2, &);
6877 }
6878 /* }}} */
6879 
6880 void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6881 {
6882 	zend_ffi_expr_cmp(val, op2, ==);
6883 }
6884 /* }}} */
6885 
6886 void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6887 {
6888 	zend_ffi_expr_cmp(val, op2, !=);
6889 }
6890 /* }}} */
6891 
6892 void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6893 {
6894 	zend_ffi_expr_cmp(val, op2, <);
6895 }
6896 /* }}} */
6897 
6898 void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6899 {
6900 	zend_ffi_expr_cmp(val, op2, >);
6901 }
6902 /* }}} */
6903 
6904 void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6905 {
6906 	zend_ffi_expr_cmp(val, op2, <=);
6907 }
6908 /* }}} */
6909 
6910 void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6911 {
6912 	zend_ffi_expr_cmp(val, op2, >=);
6913 }
6914 /* }}} */
6915 
6916 void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6917 {
6918 	zend_ffi_expr_int_math(val, op2, <<);
6919 }
6920 /* }}} */
6921 
6922 void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6923 {
6924 	zend_ffi_expr_int_math(val, op2, >>);
6925 }
6926 /* }}} */
6927 
6928 void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6929 {
6930 	zend_ffi_expr_math(val, op2, +);
6931 }
6932 /* }}} */
6933 
6934 void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6935 {
6936 	zend_ffi_expr_math(val, op2, -);
6937 }
6938 /* }}} */
6939 
6940 void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6941 {
6942 	zend_ffi_expr_math(val, op2, *);
6943 }
6944 /* }}} */
6945 
6946 void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6947 {
6948 	zend_ffi_expr_math(val, op2, /);
6949 }
6950 /* }}} */
6951 
6952 void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
6953 {
6954 	zend_ffi_expr_int_math(val, op2, %); // ???
6955 }
6956 /* }}} */
6957 
6958 void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
6959 {
6960 	zend_ffi_finalize_type(dcl);
6961 	switch (ZEND_FFI_TYPE(dcl->type)->kind) {
6962 		case ZEND_FFI_TYPE_FLOAT:
6963 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
6964 				val->kind = ZEND_FFI_VAL_FLOAT;
6965 				val->d = val->u64;
6966 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
6967 				val->kind = ZEND_FFI_VAL_FLOAT;
6968 				val->d = val->i64;
6969 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
6970 				val->kind = ZEND_FFI_VAL_FLOAT;
6971 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
6972 				val->kind = ZEND_FFI_VAL_FLOAT;
6973 				val->d = val->ch;
6974 			} else {
6975 				val->kind = ZEND_FFI_VAL_ERROR;
6976 			}
6977 			break;
6978 		case ZEND_FFI_TYPE_DOUBLE:
6979 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
6980 				val->kind = ZEND_FFI_VAL_DOUBLE;
6981 				val->d = val->u64;
6982 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
6983 				val->kind = ZEND_FFI_VAL_DOUBLE;
6984 				val->d = val->i64;
6985 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
6986 				val->kind = ZEND_FFI_VAL_DOUBLE;
6987 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
6988 				val->kind = ZEND_FFI_VAL_DOUBLE;
6989 				val->d = val->ch;
6990 			} else {
6991 				val->kind = ZEND_FFI_VAL_ERROR;
6992 			}
6993 			break;
6994 #ifdef HAVE_LONG_DOUBLE
6995 		case ZEND_FFI_TYPE_LONGDOUBLE:
6996 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
6997 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
6998 				val->d = val->u64;
6999 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7000 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7001 				val->d = val->i64;
7002 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7003 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7004 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7005 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7006 				val->d = val->ch;
7007 			} else {
7008 				val->kind = ZEND_FFI_VAL_ERROR;
7009 			}
7010 			break;
7011 #endif
7012 		case ZEND_FFI_TYPE_UINT8:
7013 		case ZEND_FFI_TYPE_UINT16:
7014 		case ZEND_FFI_TYPE_UINT32:
7015 		case ZEND_FFI_TYPE_BOOL:
7016 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7017 				val->kind = ZEND_FFI_VAL_UINT32;
7018 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7019 				val->kind = ZEND_FFI_VAL_UINT32;
7020 				val->u64 = val->d;
7021 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7022 				val->kind = ZEND_FFI_VAL_UINT32;
7023 				val->u64 = val->ch;
7024 			} else {
7025 				val->kind = ZEND_FFI_VAL_ERROR;
7026 			}
7027 			break;
7028 		case ZEND_FFI_TYPE_SINT8:
7029 		case ZEND_FFI_TYPE_SINT16:
7030 		case ZEND_FFI_TYPE_SINT32:
7031 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7032 				val->kind = ZEND_FFI_VAL_INT32;
7033 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7034 				val->kind = ZEND_FFI_VAL_INT32;
7035 				val->i64 = val->d;
7036 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7037 				val->kind = ZEND_FFI_VAL_INT32;
7038 				val->i64 = val->ch;
7039 			} else {
7040 				val->kind = ZEND_FFI_VAL_ERROR;
7041 			}
7042 			break;
7043 		case ZEND_FFI_TYPE_UINT64:
7044 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7045 				val->kind = ZEND_FFI_VAL_UINT64;
7046 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7047 				val->kind = ZEND_FFI_VAL_UINT64;
7048 				val->u64 = val->d;
7049 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7050 				val->kind = ZEND_FFI_VAL_UINT64;
7051 				val->u64 = val->ch;
7052 			} else {
7053 				val->kind = ZEND_FFI_VAL_ERROR;
7054 			}
7055 			break;
7056 		case ZEND_FFI_TYPE_SINT64:
7057 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7058 				val->kind = ZEND_FFI_VAL_CHAR;
7059 				val->ch = val->u64;
7060 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7061 				val->kind = ZEND_FFI_VAL_CHAR;
7062 				val->ch = val->i64;
7063 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7064 				val->kind = ZEND_FFI_VAL_CHAR;
7065 				val->ch = val->d;
7066 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7067 			} else {
7068 				val->kind = ZEND_FFI_VAL_ERROR;
7069 			}
7070 			break;
7071 		case ZEND_FFI_TYPE_CHAR:
7072 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7073 				val->kind = ZEND_FFI_VAL_UINT32;
7074 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7075 				val->kind = ZEND_FFI_VAL_UINT32;
7076 				val->u64 = val->d;
7077 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7078 				val->kind = ZEND_FFI_VAL_UINT32;
7079 				val->u64 = val->ch;
7080 			} else {
7081 				val->kind = ZEND_FFI_VAL_ERROR;
7082 			}
7083 			break;
7084 		default:
7085 			val->kind = ZEND_FFI_VAL_ERROR;
7086 			break;
7087 	}
7088 	zend_ffi_type_dtor(dcl->type);
7089 }
7090 /* }}} */
7091 
7092 void zend_ffi_expr_plus(zend_ffi_val *val) /* {{{ */
7093 {
7094 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7095 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7096 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7097 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7098 	} else {
7099 		val->kind = ZEND_FFI_VAL_ERROR;
7100 	}
7101 }
7102 /* }}} */
7103 
7104 void zend_ffi_expr_neg(zend_ffi_val *val) /* {{{ */
7105 {
7106 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7107 		val->u64 = -val->u64;
7108 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7109 		val->i64 = -val->i64;
7110 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7111 		val->d = -val->d;
7112 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7113 		val->ch = -val->ch;
7114 	} else {
7115 		val->kind = ZEND_FFI_VAL_ERROR;
7116 	}
7117 }
7118 /* }}} */
7119 
7120 void zend_ffi_expr_bw_not(zend_ffi_val *val) /* {{{ */
7121 {
7122 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7123 		val->u64 = ~val->u64;
7124 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7125 		val->i64 = ~val->i64;
7126 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7127 		val->ch = ~val->ch;
7128 	} else {
7129 		val->kind = ZEND_FFI_VAL_ERROR;
7130 	}
7131 }
7132 /* }}} */
7133 
7134 void zend_ffi_expr_bool_not(zend_ffi_val *val) /* {{{ */
7135 {
7136 	zend_ffi_expr_bool(val);
7137 	if (val->kind == ZEND_FFI_VAL_INT32) {
7138 		val->i64 = !val->i64;
7139 	}
7140 }
7141 /* }}} */
7142 
7143 void zend_ffi_expr_sizeof_val(zend_ffi_val *val) /* {{{ */
7144 {
7145 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7146 		val->kind = ZEND_FFI_VAL_UINT32;
7147 		val->u64 = zend_ffi_type_uint32.size;
7148 	} else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7149 		val->kind = ZEND_FFI_VAL_UINT32;
7150 		val->u64 = zend_ffi_type_uint64.size;
7151 	} else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7152 		val->kind = ZEND_FFI_VAL_UINT32;
7153 		val->u64 = zend_ffi_type_float.size;
7154 	} else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7155 		val->kind = ZEND_FFI_VAL_UINT32;
7156 		val->u64 = zend_ffi_type_double.size;
7157 	} else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7158 		val->kind = ZEND_FFI_VAL_UINT32;
7159 #ifdef _WIN32
7160 		val->u64 = zend_ffi_type_double.size;
7161 #else
7162 		val->u64 = zend_ffi_type_long_double.size;
7163 #endif
7164 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7165 		val->kind = ZEND_FFI_VAL_UINT32;
7166 		val->u64 = zend_ffi_type_char.size;
7167 	} else if (val->kind == ZEND_FFI_VAL_STRING) {
7168 		if (memchr(val->str, '\\', val->len)) {
7169 			// TODO: support for escape sequences ???
7170 			val->kind = ZEND_FFI_VAL_ERROR;
7171 		} else {
7172 			val->kind = ZEND_FFI_VAL_UINT32;
7173 			val->u64 = val->len + 1;
7174 		}
7175 	} else {
7176 		val->kind = ZEND_FFI_VAL_ERROR;
7177 	}
7178 }
7179 /* }}} */
7180 
7181 void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7182 {
7183 	zend_ffi_type *type;
7184 
7185 	zend_ffi_finalize_type(dcl);
7186 	type = ZEND_FFI_TYPE(dcl->type);
7187 	val->kind = (type->size > 0xffffffff) ? ZEND_FFI_VAL_UINT64 : ZEND_FFI_VAL_UINT32;
7188 	val->u64 = type->size;
7189 	zend_ffi_type_dtor(dcl->type);
7190 }
7191 /* }}} */
7192 
7193 void zend_ffi_expr_alignof_val(zend_ffi_val *val) /* {{{ */
7194 {
7195 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7196 		val->kind = ZEND_FFI_VAL_UINT32;
7197 		val->u64 = zend_ffi_type_uint32.align;
7198 	} else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7199 		val->kind = ZEND_FFI_VAL_UINT32;
7200 		val->u64 = zend_ffi_type_uint64.align;
7201 	} else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7202 		val->kind = ZEND_FFI_VAL_UINT32;
7203 		val->u64 = zend_ffi_type_float.align;
7204 	} else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7205 		val->kind = ZEND_FFI_VAL_UINT32;
7206 		val->u64 = zend_ffi_type_double.align;
7207 #ifdef HAVE_LONG_DOUBLE
7208 	} else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7209 		val->kind = ZEND_FFI_VAL_UINT32;
7210 		val->u64 = zend_ffi_type_long_double.align;
7211 #endif
7212 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7213 		val->kind = ZEND_FFI_VAL_UINT32;
7214 		val->u64 = zend_ffi_type_char.size;
7215 	} else if (val->kind == ZEND_FFI_VAL_STRING) {
7216 		val->kind = ZEND_FFI_VAL_UINT32;
7217 		val->u64 = _Alignof(char*);
7218 	} else {
7219 		val->kind = ZEND_FFI_VAL_ERROR;
7220 	}
7221 }
7222 /* }}} */
7223 
7224 void zend_ffi_expr_alignof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7225 {
7226 	zend_ffi_finalize_type(dcl);
7227 	val->kind = ZEND_FFI_VAL_UINT32;
7228 	val->u64 = ZEND_FFI_TYPE(dcl->type)->align;
7229 	zend_ffi_type_dtor(dcl->type);
7230 }
7231 /* }}} */
7232 
7233 void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len) /* {{{ */
7234 {
7235 	int u = 0;
7236 	int l = 0;
7237 
7238 	if (str[str_len-1] == 'u' || str[str_len-1] == 'U') {
7239 		u = 1;
7240 		if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7241 			l = 1;
7242 			if (str[str_len-3] == 'l' || str[str_len-3] == 'L') {
7243 				l = 2;
7244 			}
7245 		}
7246 	} else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7247 		l = 1;
7248 		if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7249 			l = 2;
7250 			if (str[str_len-3] == 'u' || str[str_len-3] == 'U') {
7251 				u = 1;
7252 			}
7253 		} else if (str[str_len-2] == 'u' || str[str_len-2] == 'U') {
7254 			u = 1;
7255 		}
7256 	}
7257 	if (u) {
7258 		val->u64 = strtoull(str, NULL, base);
7259 		if (l == 0) {
7260 			val->kind = ZEND_FFI_VAL_UINT32;
7261 		} else if (l == 1) {
7262 			val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_UINT32 : ZEND_FFI_VAL_UINT64;
7263 		} else if (l == 2) {
7264 			val->kind = ZEND_FFI_VAL_UINT64;
7265 		}
7266 	} else {
7267 		val->i64 = strtoll(str, NULL, base);
7268 		if (l == 0) {
7269 			val->kind = ZEND_FFI_VAL_INT32;
7270 		} else if (l == 1) {
7271 			val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_INT32 : ZEND_FFI_VAL_INT64;
7272 		} else if (l == 2) {
7273 			val->kind = ZEND_FFI_VAL_INT64;
7274 		}
7275 	}
7276 }
7277 /* }}} */
7278 
7279 void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7280 {
7281 	val->d = strtold(str, NULL);
7282 	if (str[str_len-1] == 'f' || str[str_len-1] == 'F') {
7283 		val->kind = ZEND_FFI_VAL_FLOAT;
7284 	} else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7285 		val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7286 	} else {
7287 		val->kind = ZEND_FFI_VAL_DOUBLE;
7288 	}
7289 }
7290 /* }}} */
7291 
7292 void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7293 {
7294 	if (str[0] != '\"') {
7295 		val->kind = ZEND_FFI_VAL_ERROR;
7296 	} else {
7297 		val->kind = ZEND_FFI_VAL_STRING;
7298 		val->str = str + 1;
7299 		val->len = str_len - 2;
7300 	}
7301 }
7302 /* }}} */
7303 
7304 void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7305 {
7306 	int n;
7307 
7308 	if (str[0] != '\'') {
7309 		val->kind = ZEND_FFI_VAL_ERROR;
7310 	} else {
7311 		val->kind = ZEND_FFI_VAL_CHAR;
7312 		if (str_len == 3) {
7313 			val->ch = str[1];
7314 		} else if (str[1] == '\\') {
7315 			if (str[2] == 'a') {
7316 			} else if (str[2] == 'b' && str_len == 4) {
7317 				val->ch = '\b';
7318 			} else if (str[2] == 'f' && str_len == 4) {
7319 				val->ch = '\f';
7320 			} else if (str[2] == 'n' && str_len == 4) {
7321 				val->ch = '\n';
7322 			} else if (str[2] == 'r' && str_len == 4) {
7323 				val->ch = '\r';
7324 			} else if (str[2] == 't' && str_len == 4) {
7325 				val->ch = '\t';
7326 			} else if (str[2] == 'v' && str_len == 4) {
7327 				val->ch = '\v';
7328 			} else if (str[2] >= '0' && str[2] <= '7') {
7329 				n = str[2] - '0';
7330 				if (str[3] >= '0' && str[3] <= '7') {
7331 					n = n * 8 + (str[3] - '0');
7332 					if ((str[4] >= '0' && str[4] <= '7') && str_len == 6) {
7333 						n = n * 8 + (str[4] - '0');
7334 					} else if (str_len != 5) {
7335 						val->kind = ZEND_FFI_VAL_ERROR;
7336 					}
7337 				} else if (str_len != 4) {
7338 					val->kind = ZEND_FFI_VAL_ERROR;
7339 				}
7340 				if (n <= 0xff) {
7341 					val->ch = n;
7342 				} else {
7343 					val->kind = ZEND_FFI_VAL_ERROR;
7344 				}
7345 			} else if (str[2] == 'x') {
7346 				if (str[3] >= '0' && str[3] <= '9') {
7347 					n = str[3] - '0';
7348 				} else if (str[3] >= 'A' && str[3] <= 'F') {
7349 					n = str[3] - 'A';
7350 				} else if (str[3] >= 'a' && str[3] <= 'f') {
7351 					n = str[3] - 'a';
7352 				} else {
7353 					val->kind = ZEND_FFI_VAL_ERROR;
7354 					return;
7355 				}
7356 				if ((str[4] >= '0' && str[4] <= '9') && str_len == 6) {
7357 					n = n * 16 + (str[4] - '0');
7358 				} else if ((str[4] >= 'A' && str[4] <= 'F') && str_len == 6) {
7359 					n = n * 16 + (str[4] - 'A');
7360 				} else if ((str[4] >= 'a' && str[4] <= 'f') && str_len == 6) {
7361 					n = n * 16 + (str[4] - 'a');
7362 				} else if (str_len != 5) {
7363 					val->kind = ZEND_FFI_VAL_ERROR;
7364 					return;
7365 				}
7366 				val->ch = n;
7367 			} else if (str_len == 4) {
7368 				val->ch = str[2];
7369 			} else {
7370 				val->kind = ZEND_FFI_VAL_ERROR;
7371 			}
7372 		} else {
7373 			val->kind = ZEND_FFI_VAL_ERROR;
7374 		}
7375 	}
7376 }
7377 /* }}} */
7378