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