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