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