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