xref: /php-src/ext/ffi/ffi.c (revision ebd1a366)
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[] 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 	int open_flags = O_RDONLY;
3287 #ifdef PHP_WIN32
3288 	open_flags |= _O_BINARY;
3289 #endif
3290 	fd = open(filename, open_flags, 0);
3291 	if (fd < 0 || read(fd, code, code_size) != code_size) {
3292 		if (preload) {
3293 			zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);
3294 		} else {
3295 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', cannot read_file", filename);
3296 		}
3297 		efree(code);
3298 		close(fd);
3299 		return NULL;
3300 	}
3301 	close(fd);
3302 	code[code_size] = 0;
3303 
3304 	FFI_G(symbols) = NULL;
3305 	FFI_G(tags) = NULL;
3306 	FFI_G(persistent) = preload;
3307 	FFI_G(default_type_attr) = preload ?
3308 		ZEND_FFI_ATTR_STORED | ZEND_FFI_ATTR_PERSISTENT :
3309 		ZEND_FFI_ATTR_STORED;
3310 
3311 	scope_name = NULL;
3312 	scope_name_len = 0;
3313 	lib = NULL;
3314 	code_pos = zend_ffi_parse_directives(filename, code, &scope_name, &lib, preload);
3315 	if (!code_pos) {
3316 		efree(code);
3317 		FFI_G(persistent) = 0;
3318 		return NULL;
3319 	}
3320 	code_size -= code_pos - code;
3321 
3322 	if (zend_ffi_parse_decl(code_pos, code_size) == FAILURE) {
3323 		if (preload) {
3324 			zend_error(E_WARNING, "FFI: failed pre-loading '%s'", filename);
3325 		} else {
3326 			zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", filename);
3327 		}
3328 		goto cleanup;
3329 	}
3330 
3331 	if (lib) {
3332 		handle = DL_LOAD(lib);
3333 		if (!handle) {
3334 			if (preload) {
3335 				zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
3336 			} else {
3337 				err = GET_DL_ERROR();
3338 #ifdef PHP_WIN32
3339 				if (err && err[0]) {
3340 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3341 					php_win32_error_msg_free(err);
3342 				} else {
3343 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (Unknown reason)", lib);
3344 				}
3345 #else
3346 				zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s' (%s)", lib, err);
3347 				GET_DL_ERROR(); /* free the buffer storing the error */
3348 #endif
3349 			}
3350 			goto cleanup;
3351 		}
3352 #ifdef RTLD_DEFAULT
3353 	} else if (1) {
3354 		// TODO: this might need to be disabled or protected ???
3355 		handle = RTLD_DEFAULT;
3356 #endif
3357 	}
3358 
3359 	if (preload) {
3360 		if (!scope_name) {
3361 			scope_name = "C";
3362 		}
3363 		scope_name_len = strlen(scope_name);
3364 		if (FFI_G(scopes)) {
3365 			scope = zend_hash_str_find_ptr(FFI_G(scopes), scope_name, scope_name_len);
3366 		}
3367 	}
3368 
3369 	if (FFI_G(symbols)) {
3370 		ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3371 			if (sym->kind == ZEND_FFI_SYM_VAR) {
3372 				addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
3373 				if (!addr) {
3374 					if (preload) {
3375 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', cannot resolve C variable '%s'", filename, ZSTR_VAL(name));
3376 					} else {
3377 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
3378 					}
3379 					if (lib) {
3380 						DL_UNLOAD(handle);
3381 					}
3382 					goto cleanup;
3383 				}
3384 				sym->addr = addr;
3385 			} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
3386 				zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
3387 
3388 				addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
3389 				zend_string_release(mangled_name);
3390 				if (!addr) {
3391 					if (preload) {
3392 						zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
3393 					} else {
3394 						zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
3395 					}
3396 					if (lib) {
3397 						DL_UNLOAD(handle);
3398 					}
3399 					goto cleanup;
3400 				}
3401 				sym->addr = addr;
3402 			}
3403 			if (scope && scope->symbols) {
3404 				zend_ffi_symbol *old_sym = zend_hash_find_ptr(scope->symbols, name);
3405 
3406 				if (old_sym) {
3407 					if (zend_ffi_same_symbols(old_sym, sym)) {
3408 						if (ZEND_FFI_TYPE_IS_OWNED(sym->type)
3409 						 && ZEND_FFI_TYPE(old_sym->type) != ZEND_FFI_TYPE(sym->type)) {
3410 							zend_ffi_type *type = ZEND_FFI_TYPE(sym->type);
3411 							zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_sym->type), ZEND_FFI_TYPE(type));
3412 							zend_ffi_type_dtor(type);
3413 						}
3414 					} else {
3415 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s'", filename, ZSTR_VAL(name));
3416 						if (lib) {
3417 							DL_UNLOAD(handle);
3418 						}
3419 						goto cleanup;
3420 					}
3421 				}
3422 			}
3423 		} ZEND_HASH_FOREACH_END();
3424 	}
3425 
3426 	if (preload) {
3427 		if (scope && scope->tags && FFI_G(tags)) {
3428 			ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3429 				zend_ffi_tag *old_tag = zend_hash_find_ptr(scope->tags, name);
3430 
3431 				if (old_tag) {
3432 					if (zend_ffi_same_tags(old_tag, tag)) {
3433 						if (ZEND_FFI_TYPE_IS_OWNED(tag->type)
3434 						 && ZEND_FFI_TYPE(old_tag->type) != ZEND_FFI_TYPE(tag->type)) {
3435 							zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3436 							zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_tag->type), ZEND_FFI_TYPE(type));
3437 							zend_ffi_type_dtor(type);
3438 						}
3439 					} else {
3440 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s %s'", filename, zend_ffi_tag_kind_name[tag->kind], ZSTR_VAL(name));
3441 						if (lib) {
3442 							DL_UNLOAD(handle);
3443 						}
3444 						goto cleanup;
3445 					}
3446 				}
3447 			} ZEND_HASH_FOREACH_END();
3448 		}
3449 
3450 		if (!scope) {
3451 			scope = malloc(sizeof(zend_ffi_scope));
3452 			scope->symbols = FFI_G(symbols);
3453 			scope->tags = FFI_G(tags);
3454 
3455 			if (!FFI_G(scopes)) {
3456 				FFI_G(scopes) = malloc(sizeof(HashTable));
3457 				zend_hash_init(FFI_G(scopes), 0, NULL, zend_ffi_scope_hash_dtor, 1);
3458 			}
3459 
3460 			zend_hash_str_add_ptr(FFI_G(scopes), scope_name, scope_name_len, scope);
3461 		} else {
3462 			if (FFI_G(symbols)) {
3463 				if (!scope->symbols) {
3464 					scope->symbols = FFI_G(symbols);
3465 					FFI_G(symbols) = NULL;
3466 				} else {
3467 					ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
3468 						if (!zend_hash_add_ptr(scope->symbols, name, sym)) {
3469 							zend_ffi_type_dtor(sym->type);
3470 							free(sym);
3471 						}
3472 					} ZEND_HASH_FOREACH_END();
3473 					FFI_G(symbols)->pDestructor = NULL;
3474 					zend_hash_destroy(FFI_G(symbols));
3475 				}
3476 			}
3477 			if (FFI_G(tags)) {
3478 				if (!scope->tags) {
3479 					scope->tags = FFI_G(tags);
3480 					FFI_G(tags) = NULL;
3481 				} else {
3482 					ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
3483 						if (!zend_hash_add_ptr(scope->tags, name, tag)) {
3484 							zend_ffi_type_dtor(tag->type);
3485 							free(tag);
3486 						}
3487 					} ZEND_HASH_FOREACH_END();
3488 					FFI_G(tags)->pDestructor = NULL;
3489 					zend_hash_destroy(FFI_G(tags));
3490 				}
3491 			}
3492 		}
3493 
3494 		if (EG(objects_store).object_buckets) {
3495 			ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3496 		} else {
3497 			ffi = ecalloc(1, sizeof(zend_ffi));
3498 		}
3499 		ffi->symbols = scope->symbols;
3500 		ffi->tags = scope->tags;
3501 		ffi->persistent = 1;
3502 	} else {
3503 		ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3504 		ffi->lib = handle;
3505 		ffi->symbols = FFI_G(symbols);
3506 		ffi->tags = FFI_G(tags);
3507 	}
3508 
3509 	efree(code);
3510 	FFI_G(symbols) = NULL;
3511 	FFI_G(tags) = NULL;
3512 	FFI_G(persistent) = 0;
3513 
3514 	return ffi;
3515 
3516 cleanup:
3517 	efree(code);
3518 	if (FFI_G(symbols)) {
3519 		zend_hash_destroy(FFI_G(symbols));
3520 		pefree(FFI_G(symbols), preload);
3521 		FFI_G(symbols) = NULL;
3522 	}
3523 	if (FFI_G(tags)) {
3524 		zend_hash_destroy(FFI_G(tags));
3525 		pefree(FFI_G(tags), preload);
3526 		FFI_G(tags) = NULL;
3527 	}
3528 	FFI_G(persistent) = 0;
3529 	return NULL;
3530 }
3531 /* }}} */
3532 
ZEND_METHOD(FFI,load)3533 ZEND_METHOD(FFI, load) /* {{{ */
3534 {
3535 	zend_string *fn;
3536 	zend_ffi *ffi;
3537 
3538 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3539 	ZEND_PARSE_PARAMETERS_START(1, 1)
3540 		Z_PARAM_STR(fn)
3541 	ZEND_PARSE_PARAMETERS_END();
3542 
3543 	if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
3544 		zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.preload_user\". Use \"ffi.preload\" instead.");
3545 		RETURN_THROWS();
3546 	}
3547 
3548 	ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
3549 
3550 	if (ffi) {
3551 		RETURN_OBJ(&ffi->std);
3552 	}
3553 }
3554 /* }}} */
3555 
ZEND_METHOD(FFI,scope)3556 ZEND_METHOD(FFI, scope) /* {{{ */
3557 {
3558 	zend_string *scope_name;
3559 	zend_ffi_scope *scope = NULL;
3560 	zend_ffi *ffi;
3561 
3562 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3563 	ZEND_PARSE_PARAMETERS_START(1, 1)
3564 		Z_PARAM_STR(scope_name)
3565 	ZEND_PARSE_PARAMETERS_END();
3566 
3567 	if (FFI_G(scopes)) {
3568 		scope = zend_hash_find_ptr(FFI_G(scopes), scope_name);
3569 	}
3570 
3571 	if (!scope) {
3572 		zend_throw_error(zend_ffi_exception_ce, "Failed loading scope '%s'", ZSTR_VAL(scope_name));
3573 		RETURN_THROWS();
3574 	}
3575 
3576 	ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
3577 
3578 	ffi->symbols = scope->symbols;
3579 	ffi->tags = scope->tags;
3580 	ffi->persistent = 1;
3581 
3582 	RETURN_OBJ(&ffi->std);
3583 }
3584 /* }}} */
3585 
zend_ffi_cleanup_dcl(zend_ffi_dcl * dcl)3586 static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
3587 {
3588 	if (dcl) {
3589 		zend_ffi_type_dtor(dcl->type);
3590 		dcl->type = NULL;
3591 	}
3592 }
3593 /* }}} */
3594 
zend_ffi_throw_parser_error(const char * format,...)3595 static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */
3596 {
3597 	va_list va;
3598 	char *message = NULL;
3599 
3600 	va_start(va, format);
3601 	zend_vspprintf(&message, 0, format, va);
3602 
3603 	if (EG(current_execute_data)) {
3604 		zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
3605 	} else {
3606 		zend_error(E_WARNING, "FFI Parser: %s", message);
3607 	}
3608 
3609 	efree(message);
3610 	va_end(va);
3611 }
3612 /* }}} */
3613 
zend_ffi_validate_vla(zend_ffi_type * type)3614 static zend_result zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */
3615 {
3616 	if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3617 		zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3618 		return FAILURE;
3619 	}
3620 	return SUCCESS;
3621 }
3622 /* }}} */
3623 
zend_ffi_validate_incomplete_type(zend_ffi_type * type,bool allow_incomplete_tag,bool allow_incomplete_array)3624 static zend_result zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3625 {
3626 	if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
3627 		if (FFI_G(tags)) {
3628 			zend_string *key;
3629 			zend_ffi_tag *tag;
3630 
3631 			ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(tags), key, tag) {
3632 				if (ZEND_FFI_TYPE(tag->type) == type) {
3633 					if (type->kind == ZEND_FFI_TYPE_ENUM) {
3634 						zend_ffi_throw_parser_error("Incomplete enum \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3635 					} else if (type->attr & ZEND_FFI_ATTR_UNION) {
3636 						zend_ffi_throw_parser_error("Incomplete union \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3637 					} else {
3638 						zend_ffi_throw_parser_error("Incomplete struct \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
3639 					}
3640 					return FAILURE;
3641 				}
3642 			} ZEND_HASH_FOREACH_END();
3643 		}
3644 		if (FFI_G(symbols)) {
3645 			zend_string *key;
3646 			zend_ffi_symbol *sym;
3647 
3648 			ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(FFI_G(symbols), key, sym) {
3649 				if (type == ZEND_FFI_TYPE(sym->type)) {
3650 					zend_ffi_throw_parser_error("Incomplete C type %s at line %d", ZSTR_VAL(key), FFI_G(line));
3651 					return FAILURE;
3652 				}
3653 			} ZEND_HASH_FOREACH_END();
3654 		}
3655 		zend_ffi_throw_parser_error("Incomplete type at line %d", FFI_G(line));
3656 		return FAILURE;
3657 	} else if (!allow_incomplete_array && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
3658 		zend_ffi_throw_parser_error("\"[]\" is not allowed at line %d", FFI_G(line));
3659 		return FAILURE;
3660 	} else if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
3661 		zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
3662 		return FAILURE;
3663 	}
3664 	return SUCCESS;
3665 }
3666 /* }}} */
3667 
zend_ffi_validate_type(zend_ffi_type * type,bool allow_incomplete_tag,bool allow_incomplete_array)3668 static zend_result zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
3669 {
3670 	if (type->kind == ZEND_FFI_TYPE_VOID) {
3671 		zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line));
3672 		return FAILURE;
3673 	}
3674 	return zend_ffi_validate_incomplete_type(type, allow_incomplete_tag, allow_incomplete_array);
3675 }
3676 /* }}} */
3677 
zend_ffi_validate_var_type(zend_ffi_type * type,bool allow_incomplete_array)3678 static zend_result zend_ffi_validate_var_type(zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */
3679 {
3680 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
3681 		zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line));
3682 		return FAILURE;
3683 	}
3684 	return zend_ffi_validate_type(type, 0, allow_incomplete_array);
3685 }
3686 /* }}} */
3687 
zend_ffi_validate_type_name(zend_ffi_dcl * dcl)3688 void zend_ffi_validate_type_name(zend_ffi_dcl *dcl) /* {{{ */
3689 {
3690 	zend_ffi_finalize_type(dcl);
3691 	if (zend_ffi_validate_var_type(ZEND_FFI_TYPE(dcl->type), 0) == FAILURE) {
3692 		zend_ffi_cleanup_dcl(dcl);
3693 		LONGJMP(FFI_G(bailout), FAILURE);
3694 	}
3695 }
3696 /* }}} */
3697 
zend_ffi_subst_type(zend_ffi_type ** dcl,zend_ffi_type * type)3698 static bool zend_ffi_subst_type(zend_ffi_type **dcl, zend_ffi_type *type) /* {{{ */
3699 {
3700 	zend_ffi_type *dcl_type;
3701 	zend_ffi_field *field;
3702 
3703 	if (*dcl == type) {
3704 		*dcl = ZEND_FFI_TYPE_MAKE_OWNED(type);
3705 		return 1;
3706 	}
3707 	dcl_type = *dcl;
3708 	switch (dcl_type->kind) {
3709 		case ZEND_FFI_TYPE_POINTER:
3710 			return zend_ffi_subst_type(&dcl_type->pointer.type, type);
3711 		case ZEND_FFI_TYPE_ARRAY:
3712 			return zend_ffi_subst_type(&dcl_type->array.type, type);
3713 		case ZEND_FFI_TYPE_FUNC:
3714 			if (zend_ffi_subst_type(&dcl_type->func.ret_type, type)) {
3715 				return 1;
3716 			}
3717 			if (dcl_type->func.args) {
3718 				zval *zv;
3719 
3720 				ZEND_HASH_PACKED_FOREACH_VAL(dcl_type->func.args, zv) {
3721 					if (zend_ffi_subst_type((zend_ffi_type**)&Z_PTR_P(zv), type)) {
3722 						return 1;
3723 					}
3724 				} ZEND_HASH_FOREACH_END();
3725 			}
3726 			break;
3727 		case ZEND_FFI_TYPE_STRUCT:
3728 			ZEND_HASH_MAP_FOREACH_PTR(&dcl_type->record.fields, field) {
3729 				if (zend_ffi_subst_type(&field->type, type)) {
3730 					return 1;
3731 				}
3732 			} ZEND_HASH_FOREACH_END();
3733 			break;
3734 		default:
3735 			break;
3736 	}
3737 	return 0;
3738 } /* }}} */
3739 
zend_ffi_tags_cleanup(zend_ffi_dcl * dcl)3740 static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
3741 {
3742 	zend_ffi_tag *tag;
3743 	ZEND_HASH_MAP_FOREACH_PTR(FFI_G(tags), tag) {
3744 		if (ZEND_FFI_TYPE_IS_OWNED(tag->type)) {
3745 			zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
3746 			zend_ffi_subst_type(&dcl->type, type);
3747 			tag->type = type;
3748 		}
3749 	} ZEND_HASH_FOREACH_END();
3750 	zend_hash_destroy(FFI_G(tags));
3751 	efree(FFI_G(tags));
3752 }
3753 /* }}} */
3754 
ZEND_METHOD(FFI,new)3755 ZEND_METHOD(FFI, new) /* {{{ */
3756 {
3757 	zend_string *type_def = NULL;
3758 	zend_object *type_obj = NULL;
3759 	zend_ffi_type *type, *type_ptr;
3760 	zend_ffi_cdata *cdata;
3761 	void *ptr;
3762 	bool owned = 1;
3763 	bool persistent = 0;
3764 	bool is_const = 0;
3765 	bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
3766 	zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
3767 
3768 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3769 	ZEND_PARSE_PARAMETERS_START(1, 3)
3770 		Z_PARAM_OBJ_OF_CLASS_OR_STR(type_obj, zend_ffi_ctype_ce, type_def)
3771 		Z_PARAM_OPTIONAL
3772 		Z_PARAM_BOOL(owned)
3773 		Z_PARAM_BOOL(persistent)
3774 	ZEND_PARSE_PARAMETERS_END();
3775 
3776 	if (is_static_call) {
3777 		zend_error(E_DEPRECATED, "Calling FFI::new() statically is deprecated");
3778 		if (EG(exception)) {
3779 			RETURN_THROWS();
3780 		}
3781 	}
3782 
3783 	if (!owned) {
3784 		flags &= ~ZEND_FFI_FLAG_OWNED;
3785 	}
3786 
3787 	if (persistent) {
3788 		flags |= ZEND_FFI_FLAG_PERSISTENT;
3789 	}
3790 
3791 	if (type_def) {
3792 		zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3793 
3794 		if (!is_static_call) {
3795 			zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3796 			FFI_G(symbols) = ffi->symbols;
3797 			FFI_G(tags) = ffi->tags;
3798 		} else {
3799 			FFI_G(symbols) = NULL;
3800 			FFI_G(tags) = NULL;
3801 		}
3802 		bool clean_symbols = FFI_G(symbols) == NULL;
3803 		bool clean_tags = FFI_G(tags) == NULL;
3804 
3805 		FFI_G(default_type_attr) = 0;
3806 
3807 		if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
3808 			zend_ffi_type_dtor(dcl.type);
3809 			if (clean_tags && FFI_G(tags)) {
3810 				zend_hash_destroy(FFI_G(tags));
3811 				efree(FFI_G(tags));
3812 				FFI_G(tags) = NULL;
3813 			}
3814 			if (clean_symbols && FFI_G(symbols)) {
3815 				zend_hash_destroy(FFI_G(symbols));
3816 				efree(FFI_G(symbols));
3817 				FFI_G(symbols) = NULL;
3818 			}
3819 			return;
3820 		}
3821 
3822 		type = ZEND_FFI_TYPE(dcl.type);
3823 		if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3824 			is_const = 1;
3825 		}
3826 
3827 		if (clean_tags && FFI_G(tags)) {
3828 			zend_ffi_tags_cleanup(&dcl);
3829 		}
3830 		if (clean_symbols && FFI_G(symbols)) {
3831 			zend_hash_destroy(FFI_G(symbols));
3832 			efree(FFI_G(symbols));
3833 			FFI_G(symbols) = NULL;
3834 		}
3835 		FFI_G(symbols) = NULL;
3836 		FFI_G(tags) = NULL;
3837 
3838 		type_ptr = dcl.type;
3839 	} else {
3840 		zend_ffi_ctype *ctype = (zend_ffi_ctype*) type_obj;
3841 
3842 		type_ptr = type = ctype->type;
3843 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3844 			type = ZEND_FFI_TYPE(type);
3845 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3846 				if (GC_REFCOUNT(&ctype->std) == 1) {
3847 					/* transfer type ownership */
3848 					ctype->type = type;
3849 				} else {
3850 					ctype->type = type_ptr = type = zend_ffi_remember_type(type);
3851 				}
3852 			}
3853 		}
3854 	}
3855 
3856 	if (type->size == 0) {
3857 		zend_throw_error(zend_ffi_exception_ce, "Cannot instantiate FFI\\CData of zero size");
3858 		zend_ffi_type_dtor(type_ptr);
3859 		return;
3860 	}
3861 
3862 	ptr = pemalloc(type->size, flags & ZEND_FFI_FLAG_PERSISTENT);
3863 	memset(ptr, 0, type->size);
3864 
3865 	cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
3866 	if (type->kind < ZEND_FFI_TYPE_POINTER) {
3867 		cdata->std.handlers = &zend_ffi_cdata_value_handlers;
3868 	}
3869 	cdata->type = type_ptr;
3870 	cdata->ptr = ptr;
3871 	cdata->flags = flags;
3872 	if (is_const) {
3873 		cdata->flags |= ZEND_FFI_FLAG_CONST;
3874 	}
3875 
3876 	RETURN_OBJ(&cdata->std);
3877 }
3878 /* }}} */
3879 
ZEND_METHOD(FFI,free)3880 ZEND_METHOD(FFI, free) /* {{{ */
3881 {
3882 	zval *zv;
3883 	zend_ffi_cdata *cdata;
3884 
3885 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3886 	ZEND_PARSE_PARAMETERS_START(1, 1)
3887 		Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
3888 	ZEND_PARSE_PARAMETERS_END();
3889 
3890 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
3891 
3892 	if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
3893 		if (!cdata->ptr) {
3894 			zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
3895 			RETURN_THROWS();
3896 		}
3897 		if (cdata->ptr != (void*)&cdata->ptr_holder) {
3898 			pefree(*(void**)cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3899 		} else {
3900 			pefree(cdata->ptr_holder, (cdata->flags & ZEND_FFI_FLAG_PERSISTENT) || !is_zend_ptr(cdata->ptr_holder));
3901 		}
3902 		*(void**)cdata->ptr = NULL;
3903 	} else if (!(cdata->flags & ZEND_FFI_FLAG_OWNED)) {
3904 		pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
3905 		cdata->ptr = NULL;
3906 		cdata->flags &= ~(ZEND_FFI_FLAG_OWNED|ZEND_FFI_FLAG_PERSISTENT);
3907 		cdata->std.handlers = &zend_ffi_cdata_free_handlers;
3908 	} else {
3909 		zend_throw_error(zend_ffi_exception_ce, "free() non a C pointer");
3910 	}
3911 }
3912 /* }}} */
3913 
ZEND_METHOD(FFI,cast)3914 ZEND_METHOD(FFI, cast) /* {{{ */
3915 {
3916 	zend_string *type_def = NULL;
3917 	zend_object *ztype = NULL;
3918 	zend_ffi_type *old_type, *type, *type_ptr;
3919 	zend_ffi_cdata *old_cdata, *cdata;
3920 	bool is_const = 0;
3921 	bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
3922 	zval *zv, *arg;
3923 	void *ptr;
3924 
3925 	ZEND_FFI_VALIDATE_API_RESTRICTION();
3926 	ZEND_PARSE_PARAMETERS_START(2, 2)
3927 		Z_PARAM_OBJ_OF_CLASS_OR_STR(ztype, zend_ffi_ctype_ce, type_def)
3928 		Z_PARAM_ZVAL(zv)
3929 	ZEND_PARSE_PARAMETERS_END();
3930 
3931 	if (is_static_call) {
3932 		zend_error(E_DEPRECATED, "Calling FFI::cast() statically is deprecated");
3933 		if (EG(exception)) {
3934 			RETURN_THROWS();
3935 		}
3936 	}
3937 
3938 	arg = zv;
3939 	ZVAL_DEREF(zv);
3940 
3941 	if (type_def) {
3942 		zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
3943 
3944 		if (!is_static_call) {
3945 			zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
3946 			FFI_G(symbols) = ffi->symbols;
3947 			FFI_G(tags) = ffi->tags;
3948 		} else {
3949 			FFI_G(symbols) = NULL;
3950 			FFI_G(tags) = NULL;
3951 		}
3952 		bool clean_symbols = FFI_G(symbols) == NULL;
3953 		bool clean_tags = FFI_G(tags) == NULL;
3954 
3955 		FFI_G(default_type_attr) = 0;
3956 
3957 		if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
3958 			zend_ffi_type_dtor(dcl.type);
3959 			if (clean_tags && FFI_G(tags)) {
3960 				zend_hash_destroy(FFI_G(tags));
3961 				efree(FFI_G(tags));
3962 				FFI_G(tags) = NULL;
3963 			}
3964 			if (clean_symbols && FFI_G(symbols)) {
3965 				zend_hash_destroy(FFI_G(symbols));
3966 				efree(FFI_G(symbols));
3967 				FFI_G(symbols) = NULL;
3968 			}
3969 			return;
3970 		}
3971 
3972 		type = ZEND_FFI_TYPE(dcl.type);
3973 		if (dcl.attr & ZEND_FFI_ATTR_CONST) {
3974 			is_const = 1;
3975 		}
3976 
3977 		if (clean_tags && FFI_G(tags)) {
3978 			zend_ffi_tags_cleanup(&dcl);
3979 		}
3980 		if (clean_symbols && FFI_G(symbols)) {
3981 			zend_hash_destroy(FFI_G(symbols));
3982 			efree(FFI_G(symbols));
3983 			FFI_G(symbols) = NULL;
3984 		}
3985 		FFI_G(symbols) = NULL;
3986 		FFI_G(tags) = NULL;
3987 
3988 		type_ptr = dcl.type;
3989 	} else {
3990 		zend_ffi_ctype *ctype = (zend_ffi_ctype*) ztype;
3991 
3992 		type_ptr = type = ctype->type;
3993 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
3994 			type = ZEND_FFI_TYPE(type);
3995 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
3996 				if (GC_REFCOUNT(&ctype->std) == 1) {
3997 					/* transfer type ownership */
3998 					ctype->type = type;
3999 				} else {
4000 					ctype->type = type_ptr = type = zend_ffi_remember_type(type);
4001 				}
4002 			}
4003 		}
4004 	}
4005 
4006 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4007 		if (type->kind < ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) < IS_STRING) {
4008 			/* numeric conversion */
4009 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4010 			cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4011 			cdata->type = type_ptr;
4012 			cdata->ptr = emalloc(type->size);
4013 			zend_ffi_zval_to_cdata(cdata->ptr, type, zv);
4014 			cdata->flags = ZEND_FFI_FLAG_OWNED;
4015 			if (is_const) {
4016 				cdata->flags |= ZEND_FFI_FLAG_CONST;
4017 			}
4018 			RETURN_OBJ(&cdata->std);
4019 		} else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_LONG) {
4020 			/* number to pointer conversion */
4021 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4022 			cdata->type = type_ptr;
4023 			cdata->ptr = &cdata->ptr_holder;
4024 			cdata->ptr_holder = (void*)(intptr_t)Z_LVAL_P(zv);
4025 			if (is_const) {
4026 				cdata->flags |= ZEND_FFI_FLAG_CONST;
4027 			}
4028 			RETURN_OBJ(&cdata->std);
4029 		} else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_NULL) {
4030 			/* null -> pointer */
4031 			cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4032 			cdata->type = type_ptr;
4033 			cdata->ptr = &cdata->ptr_holder;
4034 			cdata->ptr_holder = NULL;
4035 			if (is_const) {
4036 				cdata->flags |= ZEND_FFI_FLAG_CONST;
4037 			}
4038 			RETURN_OBJ(&cdata->std);
4039 		} else {
4040 			zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
4041 			RETURN_THROWS();
4042 		}
4043 	}
4044 
4045 	old_cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4046 	old_type = ZEND_FFI_TYPE(old_cdata->type);
4047 	ptr = old_cdata->ptr;
4048 
4049 	cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4050 	if (type->kind < ZEND_FFI_TYPE_POINTER) {
4051 		cdata->std.handlers = &zend_ffi_cdata_value_handlers;
4052 	}
4053 	cdata->type = type_ptr;
4054 
4055 	if (old_type->kind == ZEND_FFI_TYPE_POINTER
4056 	 && type->kind != ZEND_FFI_TYPE_POINTER
4057 	 && ZEND_FFI_TYPE(old_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
4058 		/* automatically dereference void* pointers ??? */
4059 		cdata->ptr = *(void**)ptr;
4060 	} else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
4061 	 && type->kind == ZEND_FFI_TYPE_POINTER
4062 	 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) {		cdata->ptr = &cdata->ptr_holder;
4063  		cdata->ptr = &cdata->ptr_holder;
4064  		cdata->ptr_holder = old_cdata->ptr;
4065 	} else if (old_type->kind == ZEND_FFI_TYPE_POINTER
4066 	 && type->kind == ZEND_FFI_TYPE_ARRAY
4067 	 && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->pointer.type), ZEND_FFI_TYPE(type->array.type))) {
4068 		cdata->ptr = old_cdata->ptr_holder;
4069 	} else if (type->size > old_type->size) {
4070 		zend_object_release(&cdata->std);
4071 		zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");
4072 		RETURN_THROWS();
4073 	} else if (ptr != &old_cdata->ptr_holder) {
4074 		cdata->ptr = ptr;
4075 	} else {
4076 		cdata->ptr = &cdata->ptr_holder;
4077 		cdata->ptr_holder = old_cdata->ptr_holder;
4078 	}
4079 	if (is_const) {
4080 		cdata->flags |= ZEND_FFI_FLAG_CONST;
4081 	}
4082 
4083 	if (old_cdata->flags & ZEND_FFI_FLAG_OWNED) {
4084 		if (GC_REFCOUNT(&old_cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4085 			/* transfer ownership */
4086 			old_cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4087 			cdata->flags |= ZEND_FFI_FLAG_OWNED;
4088 		} else {
4089 			//???zend_throw_error(zend_ffi_exception_ce, "Attempt to cast owned C pointer");
4090 		}
4091 	}
4092 
4093 	RETURN_OBJ(&cdata->std);
4094 }
4095 /* }}} */
4096 
ZEND_METHOD(FFI,type)4097 ZEND_METHOD(FFI, type) /* {{{ */
4098 {
4099 	zend_ffi_ctype *ctype;
4100 	zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
4101 	zend_string *type_def;
4102 	bool is_static_call = Z_TYPE(EX(This)) != IS_OBJECT;
4103 
4104 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4105 	ZEND_PARSE_PARAMETERS_START(1, 1)
4106 		Z_PARAM_STR(type_def);
4107 	ZEND_PARSE_PARAMETERS_END();
4108 
4109 	if (is_static_call) {
4110 		zend_error(E_DEPRECATED, "Calling FFI::type() statically is deprecated");
4111 		if (EG(exception)) {
4112 			RETURN_THROWS();
4113 		}
4114 	}
4115 
4116 	if (!is_static_call) {
4117 		zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
4118 		FFI_G(symbols) = ffi->symbols;
4119 		FFI_G(tags) = ffi->tags;
4120 	} else {
4121 		FFI_G(symbols) = NULL;
4122 		FFI_G(tags) = NULL;
4123 	}
4124 	bool clean_symbols = FFI_G(symbols) == NULL;
4125 	bool clean_tags = FFI_G(tags) == NULL;
4126 
4127 	FFI_G(default_type_attr) = 0;
4128 
4129 	if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) == FAILURE) {
4130 		zend_ffi_type_dtor(dcl.type);
4131 		if (clean_tags && FFI_G(tags)) {
4132 			zend_hash_destroy(FFI_G(tags));
4133 			efree(FFI_G(tags));
4134 			FFI_G(tags) = NULL;
4135 		}
4136 		if (clean_symbols && FFI_G(symbols)) {
4137 			zend_hash_destroy(FFI_G(symbols));
4138 			efree(FFI_G(symbols));
4139 			FFI_G(symbols) = NULL;
4140 		}
4141 		return;
4142 	}
4143 
4144 	if (clean_tags && FFI_G(tags)) {
4145 		zend_ffi_tags_cleanup(&dcl);
4146 	}
4147 	if (clean_symbols && FFI_G(symbols)) {
4148 		zend_hash_destroy(FFI_G(symbols));
4149 		efree(FFI_G(symbols));
4150 		FFI_G(symbols) = NULL;
4151 	}
4152 	FFI_G(symbols) = NULL;
4153 	FFI_G(tags) = NULL;
4154 
4155 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4156 	ctype->type = dcl.type;
4157 
4158 	RETURN_OBJ(&ctype->std);
4159 }
4160 /* }}} */
4161 
ZEND_METHOD(FFI,typeof)4162 ZEND_METHOD(FFI, typeof) /* {{{ */
4163 {
4164 	zval *zv, *arg;
4165 	zend_ffi_ctype *ctype;
4166 	zend_ffi_type *type;
4167 
4168 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4169 	ZEND_PARSE_PARAMETERS_START(1, 1)
4170 		Z_PARAM_ZVAL(zv);
4171 	ZEND_PARSE_PARAMETERS_END();
4172 
4173 	arg = zv;
4174 	ZVAL_DEREF(zv);
4175 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4176 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4177 
4178 		type = cdata->type;
4179 		if (ZEND_FFI_TYPE_IS_OWNED(type)) {
4180 			type = ZEND_FFI_TYPE(type);
4181 			if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4182 				if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4183 					/* transfer type ownership */
4184 					cdata->type = type;
4185 					type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4186 				} else {
4187 					cdata->type = type = zend_ffi_remember_type(type);
4188 				}
4189 			}
4190 		}
4191 	} else {
4192 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4193 		RETURN_THROWS();
4194 	}
4195 
4196 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4197 	ctype->type = type;
4198 
4199 	RETURN_OBJ(&ctype->std);
4200 }
4201 /* }}} */
4202 
ZEND_METHOD(FFI,arrayType)4203 ZEND_METHOD(FFI, arrayType) /* {{{ */
4204 {
4205 	zval *ztype;
4206 	zend_ffi_ctype *ctype;
4207 	zend_ffi_type *type;
4208 	HashTable *dims;
4209 	zval *val;
4210 
4211 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4212 	ZEND_PARSE_PARAMETERS_START(2, 2)
4213 		Z_PARAM_OBJECT_OF_CLASS(ztype, zend_ffi_ctype_ce)
4214 		Z_PARAM_ARRAY_HT(dims)
4215 	ZEND_PARSE_PARAMETERS_END();
4216 
4217 	ctype = (zend_ffi_ctype*)Z_OBJ_P(ztype);
4218 	type = ZEND_FFI_TYPE(ctype->type);
4219 
4220 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
4221 		zend_throw_error(zend_ffi_exception_ce, "Array of functions is not allowed");
4222 		RETURN_THROWS();
4223 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4224 		zend_throw_error(zend_ffi_exception_ce, "Only the leftmost array can be undimensioned");
4225 		RETURN_THROWS();
4226 	} else if (type->kind == ZEND_FFI_TYPE_VOID) {
4227 		zend_throw_error(zend_ffi_exception_ce, "Array of void type is not allowed");
4228 		RETURN_THROWS();
4229 	} else if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG) {
4230 		zend_throw_error(zend_ffi_exception_ce, "Array of incomplete type is not allowed");
4231 		RETURN_THROWS();
4232 	}
4233 
4234 	if (ZEND_FFI_TYPE_IS_OWNED(ctype->type)) {
4235 		if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
4236 			if (GC_REFCOUNT(&ctype->std) == 1) {
4237 				/* transfer type ownership */
4238 				ctype->type = type;
4239 				type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4240 			} else {
4241 				ctype->type = type = zend_ffi_remember_type(type);
4242 			}
4243 		}
4244 	}
4245 
4246 	ZEND_HASH_REVERSE_FOREACH_VAL(dims, val) {
4247 		zend_long n = zval_get_long(val);
4248 		zend_ffi_type *new_type;
4249 
4250 		if (n < 0) {
4251 			zend_throw_error(zend_ffi_exception_ce, "negative array index");
4252 			zend_ffi_type_dtor(type);
4253 			RETURN_THROWS();
4254 		} else if (ZEND_FFI_TYPE(type)->kind == ZEND_FFI_TYPE_ARRAY && (ZEND_FFI_TYPE(type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
4255 			zend_throw_error(zend_ffi_exception_ce, "only the leftmost array can be undimensioned");
4256 			zend_ffi_type_dtor(type);
4257 			RETURN_THROWS();
4258 		}
4259 
4260 		new_type = emalloc(sizeof(zend_ffi_type));
4261 		new_type->kind = ZEND_FFI_TYPE_ARRAY;
4262 		new_type->attr = 0;
4263 		new_type->size = n * ZEND_FFI_TYPE(type)->size;
4264 		new_type->align = ZEND_FFI_TYPE(type)->align;
4265 		new_type->array.type = type;
4266 		new_type->array.length = n;
4267 
4268 		if (n == 0) {
4269 			new_type->attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;
4270 		}
4271 
4272 		type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4273 	} ZEND_HASH_FOREACH_END();
4274 
4275 	ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4276 	ctype->type = type;
4277 
4278 	RETURN_OBJ(&ctype->std);
4279 }
4280 /* }}} */
4281 
ZEND_METHOD(FFI,addr)4282 ZEND_METHOD(FFI, addr) /* {{{ */
4283 {
4284 	zend_ffi_type *type, *new_type;
4285 	zend_ffi_cdata *cdata, *new_cdata;
4286 	zval *zv, *arg;
4287 
4288 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4289 	ZEND_PARSE_PARAMETERS_START(1, 1)
4290 		Z_PARAM_ZVAL(zv)
4291 	ZEND_PARSE_PARAMETERS_END();
4292 
4293 	arg = zv;
4294 	ZVAL_DEREF(zv);
4295 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4296 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4297 		RETURN_THROWS();
4298 	}
4299 
4300 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4301 	type = ZEND_FFI_TYPE(cdata->type);
4302 
4303 	if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1 && type->kind == ZEND_FFI_TYPE_POINTER
4304 	 && cdata->ptr == &cdata->ptr_holder) {
4305 		zend_throw_error(zend_ffi_exception_ce, "FFI::addr() cannot create a reference to a temporary pointer");
4306 		RETURN_THROWS();
4307 	}
4308 
4309 	new_type = emalloc(sizeof(zend_ffi_type));
4310 	new_type->kind = ZEND_FFI_TYPE_POINTER;
4311 	new_type->attr = 0;
4312 	new_type->size = sizeof(void*);
4313 	new_type->align = _Alignof(void*);
4314 	/* life-time (source must relive the resulting pointer) ??? */
4315 	new_type->pointer.type = type;
4316 
4317 	new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
4318 	new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
4319 	new_cdata->ptr_holder = cdata->ptr;
4320 	new_cdata->ptr = &new_cdata->ptr_holder;
4321 
4322 	if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
4323 		if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
4324 			/* transfer type ownership */
4325 			cdata->type = type;
4326 			new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
4327 		}
4328 		if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
4329 			/* transfer ownership */
4330 			cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
4331 			new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
4332 		}
4333 	}
4334 
4335 	RETURN_OBJ(&new_cdata->std);
4336 }
4337 /* }}} */
4338 
ZEND_METHOD(FFI,sizeof)4339 ZEND_METHOD(FFI, sizeof) /* {{{ */
4340 {
4341 	zval *zv;
4342 	zend_ffi_type *type;
4343 
4344 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4345 	ZEND_PARSE_PARAMETERS_START(1, 1)
4346 		Z_PARAM_ZVAL(zv);
4347 	ZEND_PARSE_PARAMETERS_END();
4348 
4349 	ZVAL_DEREF(zv);
4350 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4351 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4352 		type = ZEND_FFI_TYPE(cdata->type);
4353 	} else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4354 		zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4355 		type = ZEND_FFI_TYPE(ctype->type);
4356 	} else {
4357 		zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4358 		RETURN_THROWS();
4359 	}
4360 
4361 	RETURN_LONG(type->size);
4362 }
4363 /* }}} */
4364 
ZEND_METHOD(FFI,alignof)4365 ZEND_METHOD(FFI, alignof) /* {{{ */
4366 {
4367 	zval *zv;
4368 	zend_ffi_type *type;
4369 
4370 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4371 	ZEND_PARSE_PARAMETERS_START(1, 1)
4372 		Z_PARAM_ZVAL(zv);
4373 	ZEND_PARSE_PARAMETERS_END();
4374 
4375 	ZVAL_DEREF(zv);
4376 	if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
4377 		zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4378 		type = ZEND_FFI_TYPE(cdata->type);
4379 	} else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
4380 		zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
4381 		type = ZEND_FFI_TYPE(ctype->type);
4382 	} else {
4383 		zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
4384 		RETURN_THROWS();
4385 	}
4386 
4387 	RETURN_LONG(type->align);
4388 }
4389 /* }}} */
4390 
ZEND_METHOD(FFI,memcpy)4391 ZEND_METHOD(FFI, memcpy) /* {{{ */
4392 {
4393 	zval *zv1, *zv2;
4394 	zend_ffi_cdata *cdata1, *cdata2;
4395 	zend_ffi_type *type1, *type2;
4396 	void *ptr1, *ptr2;
4397 	zend_long size;
4398 
4399 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4400 	ZEND_PARSE_PARAMETERS_START(3, 3)
4401 		Z_PARAM_OBJECT_OF_CLASS_EX(zv1, zend_ffi_cdata_ce, 0, 1);
4402 		Z_PARAM_ZVAL(zv2)
4403 		Z_PARAM_LONG(size)
4404 	ZEND_PARSE_PARAMETERS_END();
4405 
4406 	cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4407 	type1 = ZEND_FFI_TYPE(cdata1->type);
4408 	if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4409 		ptr1 = *(void**)cdata1->ptr;
4410 	} else {
4411 		ptr1 = cdata1->ptr;
4412 		if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4413 			zend_throw_error(zend_ffi_exception_ce, "Attempt to write over data boundary");
4414 			RETURN_THROWS();
4415 		}
4416 	}
4417 
4418 	ZVAL_DEREF(zv2);
4419 	if (Z_TYPE_P(zv2) == IS_STRING) {
4420 		ptr2 = Z_STRVAL_P(zv2);
4421 		if (size > Z_STRLEN_P(zv2)) {
4422 			zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4423 			RETURN_THROWS();
4424 		}
4425 	} else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4426 		cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4427 		type2 = ZEND_FFI_TYPE(cdata2->type);
4428 		if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4429 			ptr2 = *(void**)cdata2->ptr;
4430 		} else {
4431 			ptr2 = cdata2->ptr;
4432 			if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4433 				zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4434 				RETURN_THROWS();
4435 			}
4436 		}
4437 	} else {
4438 		zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4439 		RETURN_THROWS();
4440 	}
4441 
4442 	memcpy(ptr1, ptr2, size);
4443 }
4444 /* }}} */
4445 
ZEND_METHOD(FFI,memcmp)4446 ZEND_METHOD(FFI, memcmp) /* {{{ */
4447 {
4448 	zval *zv1, *zv2;
4449 	zend_ffi_cdata *cdata1, *cdata2;
4450 	zend_ffi_type *type1, *type2;
4451 	void *ptr1, *ptr2;
4452 	zend_long size;
4453 	int ret;
4454 
4455 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4456 	ZEND_PARSE_PARAMETERS_START(3, 3)
4457 		Z_PARAM_ZVAL(zv1);
4458 		Z_PARAM_ZVAL(zv2);
4459 		Z_PARAM_LONG(size)
4460 	ZEND_PARSE_PARAMETERS_END();
4461 
4462 	ZVAL_DEREF(zv1);
4463 	if (Z_TYPE_P(zv1) == IS_STRING) {
4464 		ptr1 = Z_STRVAL_P(zv1);
4465 		if (size > Z_STRLEN_P(zv1)) {
4466 			zend_throw_error(zend_ffi_exception_ce, "attempt to read over string boundary");
4467 			RETURN_THROWS();
4468 		}
4469 	} else if (Z_TYPE_P(zv1) == IS_OBJECT && Z_OBJCE_P(zv1) == zend_ffi_cdata_ce) {
4470 		cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
4471 		type1 = ZEND_FFI_TYPE(cdata1->type);
4472 		if (type1->kind == ZEND_FFI_TYPE_POINTER) {
4473 			ptr1 = *(void**)cdata1->ptr;
4474 		} else {
4475 			ptr1 = cdata1->ptr;
4476 			if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
4477 				zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4478 				RETURN_THROWS();
4479 			}
4480 		}
4481 	} else {
4482 		zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
4483 		RETURN_THROWS();
4484 	}
4485 
4486 	ZVAL_DEREF(zv2);
4487 	if (Z_TYPE_P(zv2) == IS_STRING) {
4488 		ptr2 = Z_STRVAL_P(zv2);
4489 		if (size > Z_STRLEN_P(zv2)) {
4490 			zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
4491 			RETURN_THROWS();
4492 		}
4493 	} else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
4494 		cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
4495 		type2 = ZEND_FFI_TYPE(cdata2->type);
4496 		if (type2->kind == ZEND_FFI_TYPE_POINTER) {
4497 			ptr2 = *(void**)cdata2->ptr;
4498 		} else {
4499 			ptr2 = cdata2->ptr;
4500 			if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
4501 				zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
4502 				RETURN_THROWS();
4503 			}
4504 		}
4505 	} else {
4506 		zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
4507 		RETURN_THROWS();
4508 	}
4509 
4510 	ret = memcmp(ptr1, ptr2, size);
4511 	if (ret == 0) {
4512 		RETVAL_LONG(0);
4513 	} else if (ret < 0) {
4514 		RETVAL_LONG(-1);
4515 	} else {
4516 		RETVAL_LONG(1);
4517 	}
4518 }
4519 /* }}} */
4520 
ZEND_METHOD(FFI,memset)4521 ZEND_METHOD(FFI, memset) /* {{{ */
4522 {
4523 	zval *zv;
4524 	zend_ffi_cdata *cdata;
4525 	zend_ffi_type *type;
4526 	void *ptr;
4527 	zend_long ch, size;
4528 
4529 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4530 	ZEND_PARSE_PARAMETERS_START(3, 3)
4531 		Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4532 		Z_PARAM_LONG(ch)
4533 		Z_PARAM_LONG(size)
4534 	ZEND_PARSE_PARAMETERS_END();
4535 
4536 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4537 	type = ZEND_FFI_TYPE(cdata->type);
4538 	if (type->kind == ZEND_FFI_TYPE_POINTER) {
4539 		ptr = *(void**)cdata->ptr;
4540 	} else {
4541 		ptr = cdata->ptr;
4542 		if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4543 			zend_throw_error(zend_ffi_exception_ce, "attempt to write over data boundary");
4544 			RETURN_THROWS();
4545 		}
4546 	}
4547 
4548 	memset(ptr, ch, size);
4549 }
4550 /* }}} */
4551 
ZEND_METHOD(FFI,string)4552 ZEND_METHOD(FFI, string) /* {{{ */
4553 {
4554 	zval *zv;
4555 	zend_ffi_cdata *cdata;
4556 	zend_ffi_type *type;
4557 	void *ptr;
4558 	zend_long size;
4559 	bool size_is_null = 1;
4560 
4561 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4562 	ZEND_PARSE_PARAMETERS_START(1, 2)
4563 		Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
4564 		Z_PARAM_OPTIONAL
4565 		Z_PARAM_LONG_OR_NULL(size, size_is_null)
4566 	ZEND_PARSE_PARAMETERS_END();
4567 
4568 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4569 	type = ZEND_FFI_TYPE(cdata->type);
4570 	if (!size_is_null) {
4571 		if (type->kind == ZEND_FFI_TYPE_POINTER) {
4572 			ptr = *(void**)cdata->ptr;
4573 		} else {
4574 			ptr = cdata->ptr;
4575 			if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
4576 				zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
4577 				RETURN_THROWS();
4578 			}
4579 		}
4580 		RETURN_STRINGL((char*)ptr, size);
4581 	} else {
4582 		if (type->kind == ZEND_FFI_TYPE_POINTER && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
4583 			ptr = *(void**)cdata->ptr;
4584 		} else if (type->kind == ZEND_FFI_TYPE_ARRAY && ZEND_FFI_TYPE(type->array.type)->kind == ZEND_FFI_TYPE_CHAR) {
4585 			ptr = cdata->ptr;
4586 		} else {
4587 			zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a C string");
4588 			RETURN_THROWS();
4589 		}
4590 		RETURN_STRING((char*)ptr);
4591 	}
4592 }
4593 /* }}} */
4594 
ZEND_METHOD(FFI,isNull)4595 ZEND_METHOD(FFI, isNull) /* {{{ */
4596 {
4597 	zval *zv;
4598 	zend_ffi_cdata *cdata;
4599 	zend_ffi_type *type;
4600 
4601 	ZEND_FFI_VALIDATE_API_RESTRICTION();
4602 	ZEND_PARSE_PARAMETERS_START(1, 1)
4603 		Z_PARAM_ZVAL(zv);
4604 	ZEND_PARSE_PARAMETERS_END();
4605 
4606 	ZVAL_DEREF(zv);
4607 	if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
4608 		zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
4609 		RETURN_THROWS();
4610 	}
4611 
4612 	cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
4613 	type = ZEND_FFI_TYPE(cdata->type);
4614 
4615 	if (type->kind != ZEND_FFI_TYPE_POINTER){
4616 		zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a pointer");
4617 		RETURN_THROWS();
4618 	}
4619 
4620 	RETURN_BOOL(*(void**)cdata->ptr == NULL);
4621 }
4622 /* }}} */
4623 
4624 
ZEND_METHOD(FFI_CType,getName)4625 ZEND_METHOD(FFI_CType, getName) /* {{{ */
4626 {
4627 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4628 	if (zend_parse_parameters_none() == FAILURE) {
4629 		RETURN_THROWS();
4630 	}
4631 
4632 	zend_ffi_ctype_name_buf buf;
4633 
4634 	buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
4635 	if (!zend_ffi_ctype_name(&buf, ZEND_FFI_TYPE(ctype->type))) {
4636 		RETURN_STR_COPY(Z_OBJ_P(ZEND_THIS)->ce->name);
4637 	} else {
4638 		size_t len = buf.end - buf.start;
4639 		zend_string *res = zend_string_init(buf.start, len, 0);
4640 		RETURN_STR(res);
4641 	}
4642 }
4643 /* }}} */
4644 
ZEND_METHOD(FFI_CType,getKind)4645 ZEND_METHOD(FFI_CType, getKind) /* {{{ */
4646 {
4647 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4648 	zend_ffi_type *type;
4649 
4650 	if (zend_parse_parameters_none() == FAILURE) {
4651 		RETURN_THROWS();
4652 	}
4653 
4654 	type = ZEND_FFI_TYPE(ctype->type);
4655 	RETURN_LONG(type->kind);
4656 }
4657 /* }}} */
4658 
ZEND_METHOD(FFI_CType,getSize)4659 ZEND_METHOD(FFI_CType, getSize) /* {{{ */
4660 {
4661 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4662 	zend_ffi_type *type;
4663 
4664 	if (zend_parse_parameters_none() == FAILURE) {
4665 		RETURN_THROWS();
4666 	}
4667 
4668 	type = ZEND_FFI_TYPE(ctype->type);
4669 	RETURN_LONG(type->size);
4670 }
4671 /* }}} */
4672 
ZEND_METHOD(FFI_CType,getAlignment)4673 ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */
4674 {
4675 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4676 	zend_ffi_type *type;
4677 
4678 	if (zend_parse_parameters_none() == FAILURE) {
4679 		RETURN_THROWS();
4680 	}
4681 
4682 	type = ZEND_FFI_TYPE(ctype->type);
4683 	RETURN_LONG(type->align);
4684 }
4685 /* }}} */
4686 
ZEND_METHOD(FFI_CType,getAttributes)4687 ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */
4688 {
4689 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4690 	zend_ffi_type *type;
4691 
4692 	if (zend_parse_parameters_none() == FAILURE) {
4693 		RETURN_THROWS();
4694 	}
4695 
4696 	type = ZEND_FFI_TYPE(ctype->type);
4697 	RETURN_LONG(type->attr);
4698 }
4699 /* }}} */
4700 
ZEND_METHOD(FFI_CType,getEnumKind)4701 ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */
4702 {
4703 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4704 	zend_ffi_type *type;
4705 
4706 	if (zend_parse_parameters_none() == FAILURE) {
4707 		RETURN_THROWS();
4708 	}
4709 
4710 	type = ZEND_FFI_TYPE(ctype->type);
4711 	if (type->kind != ZEND_FFI_TYPE_ENUM) {
4712 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an enumeration");
4713 		RETURN_THROWS();
4714 	}
4715 	RETURN_LONG(type->enumeration.kind);
4716 }
4717 /* }}} */
4718 
ZEND_METHOD(FFI_CType,getArrayElementType)4719 ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */
4720 {
4721 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4722 	zend_ffi_type *type;
4723 	zend_ffi_ctype *ret;
4724 
4725 	if (zend_parse_parameters_none() == FAILURE) {
4726 		RETURN_THROWS();
4727 	}
4728 
4729 	type = ZEND_FFI_TYPE(ctype->type);
4730 	if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4731 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4732 		RETURN_THROWS();
4733 	}
4734 
4735 	ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4736 	ret->type = ZEND_FFI_TYPE(type->array.type);
4737 	RETURN_OBJ(&ret->std);
4738 }
4739 /* }}} */
4740 
ZEND_METHOD(FFI_CType,getArrayLength)4741 ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */
4742 {
4743 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4744 	zend_ffi_type *type;
4745 
4746 	if (zend_parse_parameters_none() == FAILURE) {
4747 		RETURN_THROWS();
4748 	}
4749 
4750 	type = ZEND_FFI_TYPE(ctype->type);
4751 	if (type->kind != ZEND_FFI_TYPE_ARRAY) {
4752 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
4753 		RETURN_THROWS();
4754 	}
4755 	RETURN_LONG(type->array.length);
4756 }
4757 /* }}} */
4758 
ZEND_METHOD(FFI_CType,getPointerType)4759 ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */
4760 {
4761 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4762 	zend_ffi_ctype *ret;
4763 	zend_ffi_type *type;
4764 
4765 	if (zend_parse_parameters_none() == FAILURE) {
4766 		RETURN_THROWS();
4767 	}
4768 
4769 	type = ZEND_FFI_TYPE(ctype->type);
4770 	if (type->kind != ZEND_FFI_TYPE_POINTER) {
4771 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a pointer");
4772 		RETURN_THROWS();
4773 	}
4774 
4775 	ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4776 	ret->type = ZEND_FFI_TYPE(type->pointer.type);
4777 	RETURN_OBJ(&ret->std);
4778 }
4779 /* }}} */
4780 
ZEND_METHOD(FFI_CType,getStructFieldNames)4781 ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */
4782 {
4783 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4784 	zend_ffi_type *type;
4785 	HashTable *ht;
4786 	zend_string* name;
4787 	zval zv;
4788 
4789 	if (zend_parse_parameters_none() == FAILURE) {
4790 		RETURN_THROWS();
4791 	}
4792 
4793 	type = ZEND_FFI_TYPE(ctype->type);
4794 	if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4795 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4796 		RETURN_THROWS();
4797 	}
4798 
4799 	ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
4800 	RETVAL_ARR(ht);
4801 	ZEND_HASH_MAP_FOREACH_STR_KEY(&type->record.fields, name) {
4802 		ZVAL_STR_COPY(&zv, name);
4803 		zend_hash_next_index_insert_new(ht, &zv);
4804 	} ZEND_HASH_FOREACH_END();
4805 }
4806 /* }}} */
4807 
ZEND_METHOD(FFI_CType,getStructFieldOffset)4808 ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */
4809 {
4810 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4811 	zend_ffi_type *type;
4812 	zend_string *name;
4813 	zend_ffi_field *ptr;
4814 
4815 	ZEND_PARSE_PARAMETERS_START(1, 1)
4816 		Z_PARAM_STR(name)
4817 	ZEND_PARSE_PARAMETERS_END();
4818 
4819 	type = ZEND_FFI_TYPE(ctype->type);
4820 	if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4821 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4822 		RETURN_THROWS();
4823 	}
4824 
4825 	ptr = zend_hash_find_ptr(&type->record.fields, name);
4826 	if (!ptr) {
4827 		zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4828 		RETURN_THROWS();
4829 	}
4830 	RETURN_LONG(ptr->offset);
4831 }
4832 /* }}} */
4833 
ZEND_METHOD(FFI_CType,getStructFieldType)4834 ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */
4835 {
4836 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4837 	zend_ffi_type *type;
4838 	zend_string *name;
4839 	zend_ffi_field *ptr;
4840 	zend_ffi_ctype *ret;
4841 
4842 	ZEND_PARSE_PARAMETERS_START(1, 1)
4843 		Z_PARAM_STR(name)
4844 	ZEND_PARSE_PARAMETERS_END();
4845 
4846 	type = ZEND_FFI_TYPE(ctype->type);
4847 	if (type->kind != ZEND_FFI_TYPE_STRUCT) {
4848 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
4849 		RETURN_THROWS();
4850 	}
4851 
4852 	ptr = zend_hash_find_ptr(&type->record.fields, name);
4853 	if (!ptr) {
4854 		zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
4855 		RETURN_THROWS();
4856 	}
4857 
4858 	ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4859 	ret->type = ZEND_FFI_TYPE(ptr->type);
4860 	RETURN_OBJ(&ret->std);
4861 }
4862 /* }}} */
4863 
ZEND_METHOD(FFI_CType,getFuncABI)4864 ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */
4865 {
4866 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4867 	zend_ffi_type *type;
4868 
4869 	if (zend_parse_parameters_none() == FAILURE) {
4870 		RETURN_THROWS();
4871 	}
4872 
4873 	type = ZEND_FFI_TYPE(ctype->type);
4874 	if (type->kind != ZEND_FFI_TYPE_FUNC) {
4875 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4876 		RETURN_THROWS();
4877 	}
4878 	RETURN_LONG(type->func.abi);
4879 }
4880 /* }}} */
4881 
ZEND_METHOD(FFI_CType,getFuncReturnType)4882 ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */
4883 {
4884 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4885 	zend_ffi_ctype *ret;
4886 	zend_ffi_type *type;
4887 
4888 	if (zend_parse_parameters_none() == FAILURE) {
4889 		RETURN_THROWS();
4890 	}
4891 
4892 	type = ZEND_FFI_TYPE(ctype->type);
4893 	if (type->kind != ZEND_FFI_TYPE_FUNC) {
4894 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4895 		RETURN_THROWS();
4896 	}
4897 
4898 	ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4899 	ret->type = ZEND_FFI_TYPE(type->func.ret_type);
4900 	RETURN_OBJ(&ret->std);
4901 }
4902 /* }}} */
4903 
ZEND_METHOD(FFI_CType,getFuncParameterCount)4904 ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */
4905 {
4906 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4907 	zend_ffi_type *type;
4908 
4909 	if (zend_parse_parameters_none() == FAILURE) {
4910 		RETURN_THROWS();
4911 	}
4912 
4913 	type = ZEND_FFI_TYPE(ctype->type);
4914 	if (type->kind != ZEND_FFI_TYPE_FUNC) {
4915 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4916 		RETURN_THROWS();
4917 	}
4918 	RETURN_LONG(type->func.args ? zend_hash_num_elements(type->func.args) : 0);
4919 }
4920 /* }}} */
4921 
ZEND_METHOD(FFI_CType,getFuncParameterType)4922 ZEND_METHOD(FFI_CType, getFuncParameterType) /* {{{ */
4923 {
4924 	zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
4925 	zend_ffi_type *type, *ptr;
4926 	zend_long n;
4927 	zend_ffi_ctype *ret;
4928 
4929 	ZEND_PARSE_PARAMETERS_START(1, 1)
4930 		Z_PARAM_LONG(n)
4931 	ZEND_PARSE_PARAMETERS_END();
4932 
4933 	type = ZEND_FFI_TYPE(ctype->type);
4934 	if (type->kind != ZEND_FFI_TYPE_FUNC) {
4935 		zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
4936 		RETURN_THROWS();
4937 	}
4938 
4939 	if (!type->func.args) {
4940 		zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4941 		RETURN_THROWS();
4942 	}
4943 
4944 	ptr = zend_hash_index_find_ptr(type->func.args, n);
4945 	if (!ptr) {
4946 		zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
4947 		RETURN_THROWS();
4948 	}
4949 
4950 	ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
4951 	ret->type = ZEND_FFI_TYPE(ptr);
4952 	RETURN_OBJ(&ret->std);
4953 }
4954 /* }}} */
4955 
zend_ffi_parse_directives(const char * filename,char * code_pos,char ** scope_name,char ** lib,bool preload)4956 static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */
4957 {
4958 	char *p;
4959 
4960 	*scope_name = NULL;
4961 	*lib = NULL;
4962 	while (*code_pos == '#') {
4963 		if (strncmp(code_pos, "#define FFI_SCOPE", sizeof("#define FFI_SCOPE") - 1) == 0
4964 		 && (code_pos[sizeof("#define FFI_SCOPE") - 1] == ' '
4965 		  || code_pos[sizeof("#define FFI_SCOPE") - 1] == '\t')) {
4966 			p = code_pos + sizeof("#define FFI_SCOPE");
4967 			while (*p == ' ' || *p == '\t') {
4968 				p++;
4969 			}
4970 			if (*p != '"') {
4971 				if (preload) {
4972 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4973 				} else {
4974 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4975 				}
4976 				return NULL;
4977 			}
4978 			p++;
4979 			if (*scope_name) {
4980 				if (preload) {
4981 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_SCOPE defined twice", filename);
4982 				} else {
4983 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_SCOPE defined twice", filename);
4984 				}
4985 				return NULL;
4986 			}
4987 			*scope_name = p;
4988 			while (1) {
4989 				if (*p == '\"') {
4990 					*p = 0;
4991 					p++;
4992 					break;
4993 				} else if (*p <= ' ') {
4994 					if (preload) {
4995 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
4996 					} else {
4997 						zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
4998 					}
4999 					return NULL;
5000 				}
5001 				p++;
5002 			}
5003 			while (*p == ' ' || *p == '\t') {
5004 				p++;
5005 			}
5006 			while (*p == '\r' || *p == '\n') {
5007 				p++;
5008 			}
5009 			code_pos = p;
5010 		} else if (strncmp(code_pos, "#define FFI_LIB", sizeof("#define FFI_LIB") - 1) == 0
5011 		 && (code_pos[sizeof("#define FFI_LIB") - 1] == ' '
5012 		  || code_pos[sizeof("#define FFI_LIB") - 1] == '\t')) {
5013 			p = code_pos + sizeof("#define FFI_LIB");
5014 			while (*p == ' ' || *p == '\t') {
5015 				p++;
5016 			}
5017 			if (*p != '"') {
5018 				if (preload) {
5019 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
5020 				} else {
5021 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
5022 				}
5023 				return NULL;
5024 			}
5025 			p++;
5026 			if (*lib) {
5027 				if (preload) {
5028 					zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_LIB defined twice", filename);
5029 				} else {
5030 					zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_LIB defined twice", filename);
5031 				}
5032 				return NULL;
5033 			}
5034 			*lib = p;
5035 			while (1) {
5036 				if (*p == '\"') {
5037 					*p = 0;
5038 					p++;
5039 					break;
5040 				} else if (*p <= ' ') {
5041 					if (preload) {
5042 						zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
5043 					} else {
5044 						zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
5045 					}
5046 					return NULL;
5047 				}
5048 				p++;
5049 			}
5050 			while (*p == ' ' || *p == '\t') {
5051 				p++;
5052 			}
5053 			while (*p == '\r' || *p == '\n') {
5054 				p++;
5055 			}
5056 			code_pos = p;
5057 		} else {
5058 			break;
5059 		}
5060 	}
5061 	return code_pos;
5062 }
5063 /* }}} */
5064 
zend_fake_get_constructor(zend_object * object)5065 static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */
5066 {
5067 	zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name));
5068 	return NULL;
5069 }
5070 /* }}} */
5071 
zend_bad_array_access(zend_class_entry * ce)5072 static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
5073 {
5074 	zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
5075 }
5076 /* }}} */
5077 
zend_fake_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)5078 static ZEND_COLD zval *zend_fake_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5079 {
5080 	zend_bad_array_access(obj->ce);
5081 	return NULL;
5082 }
5083 /* }}} */
5084 
zend_fake_write_dimension(zend_object * obj,zval * offset,zval * value)5085 static ZEND_COLD void zend_fake_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5086 {
5087 	zend_bad_array_access(obj->ce);
5088 }
5089 /* }}} */
5090 
zend_fake_has_dimension(zend_object * obj,zval * offset,int check_empty)5091 static ZEND_COLD int zend_fake_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5092 {
5093 	zend_bad_array_access(obj->ce);
5094 	return 0;
5095 }
5096 /* }}} */
5097 
zend_fake_unset_dimension(zend_object * obj,zval * offset)5098 static ZEND_COLD void zend_fake_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5099 {
5100 	zend_bad_array_access(obj->ce);
5101 }
5102 /* }}} */
5103 
zend_bad_property_access(zend_class_entry * ce)5104 static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_class_entry *ce) /* {{{ */
5105 {
5106 	zend_throw_error(NULL, "Cannot access property of object of type %s", ZSTR_VAL(ce->name));
5107 }
5108 /* }}} */
5109 
zend_fake_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)5110 static ZEND_COLD zval *zend_fake_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5111 {
5112 	zend_bad_property_access(obj->ce);
5113 	return &EG(uninitialized_zval);
5114 }
5115 /* }}} */
5116 
zend_fake_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)5117 static ZEND_COLD zval *zend_fake_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5118 {
5119 	zend_bad_array_access(obj->ce);
5120 	return value;
5121 }
5122 /* }}} */
5123 
zend_fake_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)5124 static ZEND_COLD int zend_fake_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5125 {
5126 	zend_bad_array_access(obj->ce);
5127 	return 0;
5128 }
5129 /* }}} */
5130 
zend_fake_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)5131 static ZEND_COLD void zend_fake_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5132 {
5133 	zend_bad_array_access(obj->ce);
5134 }
5135 /* }}} */
5136 
zend_fake_get_property_ptr_ptr(zend_object * obj,zend_string * member,int type,void ** cache_slot)5137 static zval *zend_fake_get_property_ptr_ptr(zend_object *obj, zend_string *member, int type, void **cache_slot) /* {{{ */
5138 {
5139 	return NULL;
5140 }
5141 /* }}} */
5142 
zend_fake_get_method(zend_object ** obj_ptr,zend_string * method_name,const zval * key)5143 static ZEND_COLD zend_function *zend_fake_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
5144 {
5145 	zend_class_entry *ce = (*obj_ptr)->ce;
5146 	zend_throw_error(NULL, "Object of type %s does not support method calls", ZSTR_VAL(ce->name));
5147 	return NULL;
5148 }
5149 /* }}} */
5150 
zend_fake_get_properties(zend_object * obj)5151 static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
5152 {
5153 	return (HashTable*)&zend_empty_array;
5154 }
5155 /* }}} */
5156 
zend_fake_get_gc(zend_object * ob,zval ** table,int * n)5157 static HashTable *zend_fake_get_gc(zend_object *ob, zval **table, int *n) /* {{{ */
5158 {
5159 	*table = NULL;
5160 	*n = 0;
5161 	return NULL;
5162 }
5163 /* }}} */
5164 
zend_fake_cast_object(zend_object * obj,zval * result,int type)5165 static zend_result zend_fake_cast_object(zend_object *obj, zval *result, int type)
5166 {
5167 	switch (type) {
5168 		case _IS_BOOL:
5169 			ZVAL_TRUE(result);
5170 			return SUCCESS;
5171 		default:
5172 			return FAILURE;
5173 	}
5174 }
5175 
zend_ffi_use_after_free(void)5176 static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
5177 {
5178 	zend_throw_error(zend_ffi_exception_ce, "Use after free()");
5179 }
5180 /* }}} */
5181 
zend_ffi_free_clone_obj(zend_object * obj)5182 static zend_object *zend_ffi_free_clone_obj(zend_object *obj) /* {{{ */
5183 {
5184 	zend_ffi_use_after_free();
5185 	return NULL;
5186 }
5187 /* }}} */
5188 
zend_ffi_free_read_dimension(zend_object * obj,zval * offset,int type,zval * rv)5189 static ZEND_COLD zval *zend_ffi_free_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
5190 {
5191 	zend_ffi_use_after_free();
5192 	return NULL;
5193 }
5194 /* }}} */
5195 
zend_ffi_free_write_dimension(zend_object * obj,zval * offset,zval * value)5196 static ZEND_COLD void zend_ffi_free_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
5197 {
5198 	zend_ffi_use_after_free();
5199 }
5200 /* }}} */
5201 
zend_ffi_free_has_dimension(zend_object * obj,zval * offset,int check_empty)5202 static ZEND_COLD int zend_ffi_free_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
5203 {
5204 	zend_ffi_use_after_free();
5205 	return 0;
5206 }
5207 /* }}} */
5208 
zend_ffi_free_unset_dimension(zend_object * obj,zval * offset)5209 static ZEND_COLD void zend_ffi_free_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
5210 {
5211 	zend_ffi_use_after_free();
5212 }
5213 /* }}} */
5214 
zend_ffi_free_read_property(zend_object * obj,zend_string * member,int type,void ** cache_slot,zval * rv)5215 static ZEND_COLD zval *zend_ffi_free_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
5216 {
5217 	zend_ffi_use_after_free();
5218 	return &EG(uninitialized_zval);
5219 }
5220 /* }}} */
5221 
zend_ffi_free_write_property(zend_object * obj,zend_string * member,zval * value,void ** cache_slot)5222 static ZEND_COLD zval *zend_ffi_free_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
5223 {
5224 	zend_ffi_use_after_free();
5225 	return value;
5226 }
5227 /* }}} */
5228 
zend_ffi_free_has_property(zend_object * obj,zend_string * member,int has_set_exists,void ** cache_slot)5229 static ZEND_COLD int zend_ffi_free_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
5230 {
5231 	zend_ffi_use_after_free();
5232 	return 0;
5233 }
5234 /* }}} */
5235 
zend_ffi_free_unset_property(zend_object * obj,zend_string * member,void ** cache_slot)5236 static ZEND_COLD void zend_ffi_free_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
5237 {
5238 	zend_ffi_use_after_free();
5239 }
5240 /* }}} */
5241 
zend_ffi_free_get_debug_info(zend_object * obj,int * is_temp)5242 static HashTable *zend_ffi_free_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
5243 {
5244 	zend_ffi_use_after_free();
5245 	return NULL;
5246 }
5247 /* }}} */
5248 
ZEND_INI_MH(OnUpdateFFIEnable)5249 static ZEND_INI_MH(OnUpdateFFIEnable) /* {{{ */
5250 {
5251 	if (zend_string_equals_literal_ci(new_value, "preload")) {
5252 		FFI_G(restriction) = ZEND_FFI_PRELOAD;
5253 	} else {
5254 		FFI_G(restriction) = (zend_ffi_api_restriction)zend_ini_parse_bool(new_value);
5255 	}
5256 	return SUCCESS;
5257 }
5258 /* }}} */
5259 
ZEND_INI_DISP(zend_ffi_enable_displayer_cb)5260 static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
5261 {
5262 	if (FFI_G(restriction) == ZEND_FFI_PRELOAD) {
5263 		ZEND_PUTS("preload");
5264 	} else if (FFI_G(restriction) == ZEND_FFI_ENABLED) {
5265 		ZEND_PUTS("On");
5266 	} else {
5267 		ZEND_PUTS("Off");
5268 	}
5269 }
5270 /* }}} */
5271 
5272 ZEND_INI_BEGIN()
5273 	ZEND_INI_ENTRY_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, zend_ffi_enable_displayer_cb)
5274 	STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
ZEND_INI_END()5275 ZEND_INI_END()
5276 
5277 static zend_result zend_ffi_preload_glob(const char *filename) /* {{{ */
5278 {
5279 #ifdef HAVE_GLOB
5280 	glob_t globbuf;
5281 	int    ret;
5282 	unsigned int i;
5283 
5284 	memset(&globbuf, 0, sizeof(glob_t));
5285 
5286 	ret = glob(filename, 0, NULL, &globbuf);
5287 #ifdef GLOB_NOMATCH
5288 	if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
5289 #else
5290 	if (!globbuf.gl_pathc) {
5291 #endif
5292 		/* pass */
5293 	} else {
5294 		for(i=0 ; i<globbuf.gl_pathc; i++) {
5295 			zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
5296 			if (!ffi) {
5297 				globfree(&globbuf);
5298 				return FAILURE;
5299 			}
5300 			efree(ffi);
5301 		}
5302 		globfree(&globbuf);
5303 	}
5304 #else
5305 	zend_ffi *ffi = zend_ffi_load(filename, 1);
5306 	if (!ffi) {
5307 		return FAILURE;
5308 	}
5309 	efree(ffi);
5310 #endif
5311 
5312 	return SUCCESS;
5313 }
5314 /* }}} */
5315 
5316 static zend_result zend_ffi_preload(char *preload) /* {{{ */
5317 {
5318 	zend_ffi *ffi;
5319 	char *s = NULL, *e, *filename;
5320 	bool is_glob = 0;
5321 
5322 	e = preload;
5323 	while (*e) {
5324 		switch (*e) {
5325 			case ZEND_PATHS_SEPARATOR:
5326 				if (s) {
5327 					filename = estrndup(s, e-s);
5328 					s = NULL;
5329 					if (!is_glob) {
5330 						ffi = zend_ffi_load(filename, 1);
5331 						efree(filename);
5332 						if (!ffi) {
5333 							return FAILURE;
5334 						}
5335 						efree(ffi);
5336 					} else {
5337 						zend_result ret = zend_ffi_preload_glob(filename);
5338 
5339 						efree(filename);
5340 						if (ret == FAILURE) {
5341 							return FAILURE;
5342 						}
5343 						is_glob = 0;
5344 					}
5345 				}
5346 				break;
5347 			case '*':
5348 			case '?':
5349 			case '[':
5350 				is_glob = 1;
5351 				break;
5352 			default:
5353 				if (!s) {
5354 					s = e;
5355 				}
5356 				break;
5357 		}
5358 		e++;
5359 	}
5360 	if (s) {
5361 		filename = estrndup(s, e-s);
5362 		if (!is_glob) {
5363 			ffi = zend_ffi_load(filename, 1);
5364 			efree(filename);
5365 			if (!ffi) {
5366 				return FAILURE;
5367 			}
5368 			efree(ffi);
5369 		} else {
5370 			zend_result ret = zend_ffi_preload_glob(filename);
5371 			efree(filename);
5372 			if (ret == FAILURE) {
5373 				return FAILURE;
5374 			}
5375 		}
5376 	}
5377 
5378 	return SUCCESS;
5379 }
5380 /* }}} */
5381 
5382 /* The startup code for observers adds a temporary to each function for internal use.
5383  * The "new", "cast", and "type" functions in FFI are both static and non-static.
5384  * Only the static versions are in the function table and the non-static versions are not.
5385  * This means the non-static versions will be skipped by the observers startup code.
5386  * This function fixes that by incrementing the temporary count for the non-static versions.
5387  */
5388 static zend_result (*prev_zend_post_startup_cb)(void);
5389 static zend_result ffi_fixup_temporaries(void) {
5390 	if (ZEND_OBSERVER_ENABLED) {
5391 		++zend_ffi_new_fn.T;
5392 		++zend_ffi_cast_fn.T;
5393 		++zend_ffi_type_fn.T;
5394 	}
5395 	if (prev_zend_post_startup_cb) {
5396 		return prev_zend_post_startup_cb();
5397 	}
5398 	return SUCCESS;
5399 }
5400 
5401 /* {{{ ZEND_MINIT_FUNCTION */
5402 ZEND_MINIT_FUNCTION(ffi)
5403 {
5404 	REGISTER_INI_ENTRIES();
5405 
5406 	FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0;
5407 
5408 	zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error);
5409 
5410 	zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
5411 
5412 	zend_ffi_ce = register_class_FFI();
5413 	zend_ffi_ce->create_object = zend_ffi_new;
5414 	zend_ffi_ce->default_object_handlers = &zend_ffi_handlers;
5415 
5416 	memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
5417 	zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
5418 	memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
5419 	zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
5420 	memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
5421 	zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
5422 
5423 	prev_zend_post_startup_cb = zend_post_startup_cb;
5424 	zend_post_startup_cb = ffi_fixup_temporaries;
5425 
5426 	memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5427 	zend_ffi_handlers.get_constructor      = zend_fake_get_constructor;
5428 	zend_ffi_handlers.free_obj             = zend_ffi_free_obj;
5429 	zend_ffi_handlers.clone_obj            = NULL;
5430 	zend_ffi_handlers.read_property        = zend_ffi_read_var;
5431 	zend_ffi_handlers.write_property       = zend_ffi_write_var;
5432 	zend_ffi_handlers.read_dimension       = zend_fake_read_dimension;
5433 	zend_ffi_handlers.write_dimension      = zend_fake_write_dimension;
5434 	zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5435 	zend_ffi_handlers.has_property         = zend_fake_has_property;
5436 	zend_ffi_handlers.unset_property       = zend_fake_unset_property;
5437 	zend_ffi_handlers.has_dimension        = zend_fake_has_dimension;
5438 	zend_ffi_handlers.unset_dimension      = zend_fake_unset_dimension;
5439 	zend_ffi_handlers.get_method           = zend_ffi_get_func;
5440 	zend_ffi_handlers.compare              = NULL;
5441 	zend_ffi_handlers.cast_object          = zend_fake_cast_object;
5442 	zend_ffi_handlers.get_debug_info       = NULL;
5443 	zend_ffi_handlers.get_closure          = NULL;
5444 	zend_ffi_handlers.get_properties       = zend_fake_get_properties;
5445 	zend_ffi_handlers.get_gc               = zend_fake_get_gc;
5446 
5447 	zend_ffi_cdata_ce = register_class_FFI_CData();
5448 	zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;
5449 	zend_ffi_cdata_ce->default_object_handlers = &zend_ffi_cdata_handlers;
5450 	zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator;
5451 
5452 	memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5453 	zend_ffi_cdata_handlers.get_constructor      = zend_fake_get_constructor;
5454 	zend_ffi_cdata_handlers.free_obj             = zend_ffi_cdata_free_obj;
5455 	zend_ffi_cdata_handlers.clone_obj            = zend_ffi_cdata_clone_obj;
5456 	zend_ffi_cdata_handlers.read_property        = zend_ffi_cdata_read_field;
5457 	zend_ffi_cdata_handlers.write_property       = zend_ffi_cdata_write_field;
5458 	zend_ffi_cdata_handlers.read_dimension       = zend_ffi_cdata_read_dim;
5459 	zend_ffi_cdata_handlers.write_dimension      = zend_ffi_cdata_write_dim;
5460 	zend_ffi_cdata_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5461 	zend_ffi_cdata_handlers.has_property         = zend_fake_has_property;
5462 	zend_ffi_cdata_handlers.unset_property       = zend_fake_unset_property;
5463 	zend_ffi_cdata_handlers.has_dimension        = zend_fake_has_dimension;
5464 	zend_ffi_cdata_handlers.unset_dimension      = zend_fake_unset_dimension;
5465 	zend_ffi_cdata_handlers.get_method           = zend_fake_get_method;
5466 	zend_ffi_cdata_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
5467 	zend_ffi_cdata_handlers.do_operation         = zend_ffi_cdata_do_operation;
5468 	zend_ffi_cdata_handlers.compare              = zend_ffi_cdata_compare_objects;
5469 	zend_ffi_cdata_handlers.cast_object          = zend_ffi_cdata_cast_object;
5470 	zend_ffi_cdata_handlers.count_elements       = zend_ffi_cdata_count_elements;
5471 	zend_ffi_cdata_handlers.get_debug_info       = zend_ffi_cdata_get_debug_info;
5472 	zend_ffi_cdata_handlers.get_closure          = zend_ffi_cdata_get_closure;
5473 	zend_ffi_cdata_handlers.get_properties       = zend_fake_get_properties;
5474 	zend_ffi_cdata_handlers.get_gc               = zend_fake_get_gc;
5475 
5476 	memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5477 	zend_ffi_cdata_value_handlers.get_constructor      = zend_fake_get_constructor;
5478 	zend_ffi_cdata_value_handlers.free_obj             = zend_ffi_cdata_free_obj;
5479 	zend_ffi_cdata_value_handlers.clone_obj            = zend_ffi_cdata_clone_obj;
5480 	zend_ffi_cdata_value_handlers.read_property        = zend_ffi_cdata_get;
5481 	zend_ffi_cdata_value_handlers.write_property       = zend_ffi_cdata_set;
5482 	zend_ffi_cdata_value_handlers.read_dimension       = zend_fake_read_dimension;
5483 	zend_ffi_cdata_value_handlers.write_dimension      = zend_fake_write_dimension;
5484 	zend_ffi_cdata_value_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5485 	zend_ffi_cdata_value_handlers.has_property         = zend_fake_has_property;
5486 	zend_ffi_cdata_value_handlers.unset_property       = zend_fake_unset_property;
5487 	zend_ffi_cdata_value_handlers.has_dimension        = zend_fake_has_dimension;
5488 	zend_ffi_cdata_value_handlers.unset_dimension      = zend_fake_unset_dimension;
5489 	zend_ffi_cdata_value_handlers.get_method           = zend_fake_get_method;
5490 	zend_ffi_cdata_value_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
5491 	zend_ffi_cdata_value_handlers.compare              = zend_ffi_cdata_compare_objects;
5492 	zend_ffi_cdata_value_handlers.cast_object          = zend_ffi_cdata_cast_object;
5493 	zend_ffi_cdata_value_handlers.count_elements       = NULL;
5494 	zend_ffi_cdata_value_handlers.get_debug_info       = zend_ffi_cdata_get_debug_info;
5495 	zend_ffi_cdata_value_handlers.get_closure          = NULL;
5496 	zend_ffi_cdata_value_handlers.get_properties       = zend_fake_get_properties;
5497 	zend_ffi_cdata_value_handlers.get_gc               = zend_fake_get_gc;
5498 
5499 	memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5500 	zend_ffi_cdata_free_handlers.get_constructor      = zend_fake_get_constructor;
5501 	zend_ffi_cdata_free_handlers.free_obj             = zend_ffi_cdata_free_obj;
5502 	zend_ffi_cdata_free_handlers.clone_obj            = zend_ffi_free_clone_obj;
5503 	zend_ffi_cdata_free_handlers.read_property        = zend_ffi_free_read_property;
5504 	zend_ffi_cdata_free_handlers.write_property       = zend_ffi_free_write_property;
5505 	zend_ffi_cdata_free_handlers.read_dimension       = zend_ffi_free_read_dimension;
5506 	zend_ffi_cdata_free_handlers.write_dimension      = zend_ffi_free_write_dimension;
5507 	zend_ffi_cdata_free_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5508 	zend_ffi_cdata_free_handlers.has_property         = zend_ffi_free_has_property;
5509 	zend_ffi_cdata_free_handlers.unset_property       = zend_ffi_free_unset_property;
5510 	zend_ffi_cdata_free_handlers.has_dimension        = zend_ffi_free_has_dimension;
5511 	zend_ffi_cdata_free_handlers.unset_dimension      = zend_ffi_free_unset_dimension;
5512 	zend_ffi_cdata_free_handlers.get_method           = zend_fake_get_method;
5513 	zend_ffi_cdata_free_handlers.get_class_name       = zend_ffi_cdata_get_class_name;
5514 	zend_ffi_cdata_free_handlers.compare              = zend_ffi_cdata_compare_objects;
5515 	zend_ffi_cdata_free_handlers.cast_object          = zend_fake_cast_object;
5516 	zend_ffi_cdata_free_handlers.count_elements       = NULL;
5517 	zend_ffi_cdata_free_handlers.get_debug_info       = zend_ffi_free_get_debug_info;
5518 	zend_ffi_cdata_free_handlers.get_closure          = NULL;
5519 	zend_ffi_cdata_free_handlers.get_properties       = zend_fake_get_properties;
5520 	zend_ffi_cdata_free_handlers.get_gc               = zend_fake_get_gc;
5521 
5522 	zend_ffi_ctype_ce = register_class_FFI_CType();
5523 	zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;
5524 	zend_ffi_ctype_ce->default_object_handlers = &zend_ffi_ctype_handlers;
5525 
5526 	memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
5527 	zend_ffi_ctype_handlers.get_constructor      = zend_fake_get_constructor;
5528 	zend_ffi_ctype_handlers.free_obj             = zend_ffi_ctype_free_obj;
5529 	zend_ffi_ctype_handlers.clone_obj            = NULL;
5530 	zend_ffi_ctype_handlers.read_property        = zend_fake_read_property;
5531 	zend_ffi_ctype_handlers.write_property       = zend_fake_write_property;
5532 	zend_ffi_ctype_handlers.read_dimension       = zend_fake_read_dimension;
5533 	zend_ffi_ctype_handlers.write_dimension      = zend_fake_write_dimension;
5534 	zend_ffi_ctype_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
5535 	zend_ffi_ctype_handlers.has_property         = zend_fake_has_property;
5536 	zend_ffi_ctype_handlers.unset_property       = zend_fake_unset_property;
5537 	zend_ffi_ctype_handlers.has_dimension        = zend_fake_has_dimension;
5538 	zend_ffi_ctype_handlers.unset_dimension      = zend_fake_unset_dimension;
5539 	//zend_ffi_ctype_handlers.get_method           = zend_fake_get_method;
5540 	zend_ffi_ctype_handlers.get_class_name       = zend_ffi_ctype_get_class_name;
5541 	zend_ffi_ctype_handlers.compare              = zend_ffi_ctype_compare_objects;
5542 	zend_ffi_ctype_handlers.cast_object          = zend_fake_cast_object;
5543 	zend_ffi_ctype_handlers.count_elements       = NULL;
5544 	zend_ffi_ctype_handlers.get_debug_info       = zend_ffi_ctype_get_debug_info;
5545 	zend_ffi_ctype_handlers.get_closure          = NULL;
5546 	zend_ffi_ctype_handlers.get_properties       = zend_fake_get_properties;
5547 	zend_ffi_ctype_handlers.get_gc               = zend_fake_get_gc;
5548 
5549 	if (FFI_G(preload)) {
5550 		return zend_ffi_preload(FFI_G(preload));
5551 	}
5552 
5553 	return SUCCESS;
5554 }
5555 /* }}} */
5556 
5557 /* {{{ ZEND_RSHUTDOWN_FUNCTION */
5558 ZEND_RSHUTDOWN_FUNCTION(ffi)
5559 {
5560 	if (FFI_G(callbacks)) {
5561 		zend_hash_destroy(FFI_G(callbacks));
5562 		efree(FFI_G(callbacks));
5563 		FFI_G(callbacks) = NULL;
5564 	}
5565 	if (FFI_G(weak_types)) {
5566 #if 0
5567 		fprintf(stderr, "WeakTypes: %d\n", zend_hash_num_elements(FFI_G(weak_types)));
5568 #endif
5569 		zend_hash_destroy(FFI_G(weak_types));
5570 		efree(FFI_G(weak_types));
5571 		FFI_G(weak_types) = NULL;
5572 	}
5573 	return SUCCESS;
5574 }
5575 /* }}} */
5576 
5577 /* {{{ ZEND_MINFO_FUNCTION */
5578 ZEND_MINFO_FUNCTION(ffi)
5579 {
5580 	php_info_print_table_start();
5581 	php_info_print_table_row(2, "FFI support", "enabled");
5582 	php_info_print_table_end();
5583 
5584 	DISPLAY_INI_ENTRIES();
5585 }
5586 /* }}} */
5587 
5588 static const zend_ffi_type zend_ffi_type_void = {.kind=ZEND_FFI_TYPE_VOID, .size=1, .align=1};
5589 static const zend_ffi_type zend_ffi_type_char = {.kind=ZEND_FFI_TYPE_CHAR, .size=1, .align=_Alignof(char)};
5590 static const zend_ffi_type zend_ffi_type_bool = {.kind=ZEND_FFI_TYPE_BOOL, .size=1, .align=_Alignof(uint8_t)};
5591 static const zend_ffi_type zend_ffi_type_sint8 = {.kind=ZEND_FFI_TYPE_SINT8, .size=1, .align=_Alignof(int8_t)};
5592 static const zend_ffi_type zend_ffi_type_uint8 = {.kind=ZEND_FFI_TYPE_UINT8, .size=1, .align=_Alignof(uint8_t)};
5593 static const zend_ffi_type zend_ffi_type_sint16 = {.kind=ZEND_FFI_TYPE_SINT16, .size=2, .align=_Alignof(int16_t)};
5594 static const zend_ffi_type zend_ffi_type_uint16 = {.kind=ZEND_FFI_TYPE_UINT16, .size=2, .align=_Alignof(uint16_t)};
5595 static const zend_ffi_type zend_ffi_type_sint32 = {.kind=ZEND_FFI_TYPE_SINT32, .size=4, .align=_Alignof(int32_t)};
5596 static const zend_ffi_type zend_ffi_type_uint32 = {.kind=ZEND_FFI_TYPE_UINT32, .size=4, .align=_Alignof(uint32_t)};
5597 static const zend_ffi_type zend_ffi_type_sint64 = {.kind=ZEND_FFI_TYPE_SINT64, .size=8, .align=_Alignof(int64_t)};
5598 static const zend_ffi_type zend_ffi_type_uint64 = {.kind=ZEND_FFI_TYPE_UINT64, .size=8, .align=_Alignof(uint64_t)};
5599 static const zend_ffi_type zend_ffi_type_float = {.kind=ZEND_FFI_TYPE_FLOAT, .size=sizeof(float), .align=_Alignof(float)};
5600 static const zend_ffi_type zend_ffi_type_double = {.kind=ZEND_FFI_TYPE_DOUBLE, .size=sizeof(double), .align=_Alignof(double)};
5601 
5602 #ifdef HAVE_LONG_DOUBLE
5603 static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONGDOUBLE, .size=sizeof(long double), .align=_Alignof(long double)};
5604 #endif
5605 
5606 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};
5607 
5608 static const struct {
5609 	const char *name;
5610 	const zend_ffi_type *type;
5611 } zend_ffi_types[] = {
5612 	{"void",        &zend_ffi_type_void},
5613 	{"char",        &zend_ffi_type_char},
5614 	{"bool",        &zend_ffi_type_bool},
5615 	{"int8_t",      &zend_ffi_type_sint8},
5616 	{"uint8_t",     &zend_ffi_type_uint8},
5617 	{"int16_t",     &zend_ffi_type_sint16},
5618 	{"uint16_t",    &zend_ffi_type_uint16},
5619 	{"int32_t",     &zend_ffi_type_sint32},
5620 	{"uint32_t",    &zend_ffi_type_uint32},
5621 	{"int64_t",     &zend_ffi_type_sint64},
5622 	{"uint64_t",    &zend_ffi_type_uint64},
5623 	{"float",       &zend_ffi_type_float},
5624 	{"double",      &zend_ffi_type_double},
5625 #ifdef HAVE_LONG_DOUBLE
5626 	{"long double", &zend_ffi_type_long_double},
5627 #endif
5628 #if SIZEOF_SIZE_T == 4
5629 	{"uintptr_t",  &zend_ffi_type_uint32},
5630 	{"intptr_t",   &zend_ffi_type_sint32},
5631 	{"size_t",     &zend_ffi_type_uint32},
5632 	{"ssize_t",    &zend_ffi_type_sint32},
5633 	{"ptrdiff_t",  &zend_ffi_type_sint32},
5634 #else
5635 	{"uintptr_t",  &zend_ffi_type_uint64},
5636 	{"intptr_t",   &zend_ffi_type_sint64},
5637 	{"size_t",     &zend_ffi_type_uint64},
5638 	{"ssize_t",    &zend_ffi_type_sint64},
5639 	{"ptrdiff_t",  &zend_ffi_type_sint64},
5640 #endif
5641 #if SIZEOF_OFF_T == 4
5642 	{"off_t",      &zend_ffi_type_sint32},
5643 #else
5644 	{"off_t",      &zend_ffi_type_sint64},
5645 #endif
5646 
5647 	{"va_list",           &zend_ffi_type_ptr},
5648 	{"__builtin_va_list", &zend_ffi_type_ptr},
5649 	{"__gnuc_va_list",    &zend_ffi_type_ptr},
5650 };
5651 
5652 /* {{{ ZEND_GINIT_FUNCTION */
5653 static ZEND_GINIT_FUNCTION(ffi)
5654 {
5655 	size_t i;
5656 
5657 #if defined(COMPILE_DL_FFI) && defined(ZTS)
5658 	ZEND_TSRMLS_CACHE_UPDATE();
5659 #endif
5660 	memset(ffi_globals, 0, sizeof(*ffi_globals));
5661 	zend_hash_init(&ffi_globals->types, 0, NULL, NULL, 1);
5662 	for (i = 0; i < sizeof(zend_ffi_types)/sizeof(zend_ffi_types[0]); i++) {
5663 		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);
5664 	}
5665 }
5666 /* }}} */
5667 
5668 /* {{{ ZEND_GINIT_FUNCTION */
5669 static ZEND_GSHUTDOWN_FUNCTION(ffi)
5670 {
5671 	if (ffi_globals->scopes) {
5672 		zend_hash_destroy(ffi_globals->scopes);
5673 		free(ffi_globals->scopes);
5674 	}
5675 	zend_hash_destroy(&ffi_globals->types);
5676 }
5677 /* }}} */
5678 
5679 /* {{{ ffi_module_entry */
5680 zend_module_entry ffi_module_entry = {
5681 	STANDARD_MODULE_HEADER,
5682 	"FFI",					/* Extension name */
5683 	NULL,					/* zend_function_entry */
5684 	ZEND_MINIT(ffi),		/* ZEND_MINIT - Module initialization */
5685 	NULL,					/* ZEND_MSHUTDOWN - Module shutdown */
5686 	NULL,					/* ZEND_RINIT - Request initialization */
5687 	ZEND_RSHUTDOWN(ffi),	/* ZEND_RSHUTDOWN - Request shutdown */
5688 	ZEND_MINFO(ffi),		/* ZEND_MINFO - Module info */
5689 	PHP_VERSION,			/* Version */
5690 	ZEND_MODULE_GLOBALS(ffi),
5691 	ZEND_GINIT(ffi),
5692 	ZEND_GSHUTDOWN(ffi),
5693 	NULL,
5694 	STANDARD_MODULE_PROPERTIES_EX
5695 };
5696 /* }}} */
5697 
5698 #ifdef COMPILE_DL_FFI
5699 # ifdef ZTS
5700 ZEND_TSRMLS_CACHE_DEFINE()
5701 # endif
5702 ZEND_GET_MODULE(ffi)
5703 #endif
5704 
5705 /* parser callbacks */
5706 void zend_ffi_parser_error(const char *format, ...) /* {{{ */
5707 {
5708 	va_list va;
5709 	char *message = NULL;
5710 
5711 	va_start(va, format);
5712 	zend_vspprintf(&message, 0, format, va);
5713 
5714 	if (EG(current_execute_data)) {
5715 		zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
5716 	} else {
5717 		zend_error(E_WARNING, "FFI Parser: %s", message);
5718 	}
5719 
5720 	efree(message);
5721 	va_end(va);
5722 
5723 	LONGJMP(FFI_G(bailout), FAILURE);
5724 }
5725 /* }}} */
5726 
5727 static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */
5728 {
5729 	if (!dcl->type) {
5730 		switch (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) {
5731 			case ZEND_FFI_DCL_VOID:
5732 				dcl->type = (zend_ffi_type*)&zend_ffi_type_void;
5733 				break;
5734 			case ZEND_FFI_DCL_CHAR:
5735 				dcl->type = (zend_ffi_type*)&zend_ffi_type_char;
5736 				break;
5737 			case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SIGNED:
5738 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint8;
5739 				break;
5740 			case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_UNSIGNED:
5741 			case ZEND_FFI_DCL_BOOL:
5742 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint8;
5743 				break;
5744 			case ZEND_FFI_DCL_SHORT:
5745 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED:
5746 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT:
5747 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5748 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint16;
5749 				break;
5750 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED:
5751 			case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5752 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint16;
5753 				break;
5754 			case ZEND_FFI_DCL_INT:
5755 			case ZEND_FFI_DCL_SIGNED:
5756 			case ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5757 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5758 				break;
5759 			case ZEND_FFI_DCL_UNSIGNED:
5760 			case ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5761 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5762 				break;
5763 			case ZEND_FFI_DCL_LONG:
5764 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5765 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5766 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5767 				if (sizeof(long) == 4) {
5768 					dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
5769 				} else {
5770 					dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5771 				}
5772 				break;
5773 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5774 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5775 				if (sizeof(long) == 4) {
5776 					dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
5777 				} else {
5778 					dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5779 				}
5780 				break;
5781 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG:
5782 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
5783 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
5784 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
5785 				dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
5786 				break;
5787 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
5788 			case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
5789 				dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
5790 				break;
5791 			case ZEND_FFI_DCL_FLOAT:
5792 				dcl->type = (zend_ffi_type*)&zend_ffi_type_float;
5793 				break;
5794 			case ZEND_FFI_DCL_DOUBLE:
5795 				dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5796 				break;
5797 			case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_DOUBLE:
5798 #ifdef _WIN32
5799 				dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
5800 #else
5801 				dcl->type = (zend_ffi_type*)&zend_ffi_type_long_double;
5802 #endif
5803 				break;
5804 			case ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_COMPLEX:
5805 			case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_COMPLEX:
5806 			case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_COMPLEX:
5807 				zend_ffi_parser_error("Unsupported type _Complex at line %d", FFI_G(line));
5808 				break;
5809 			default:
5810 				zend_ffi_parser_error("Unsupported type specifier combination at line %d", FFI_G(line));
5811 				break;
5812 		}
5813 		dcl->flags &= ~ZEND_FFI_DCL_TYPE_SPECIFIERS;
5814 		dcl->flags |= ZEND_FFI_DCL_TYPEDEF_NAME;
5815 	}
5816 }
5817 /* }}} */
5818 
5819 bool zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */
5820 {
5821 	zend_ffi_symbol *sym;
5822 	zend_ffi_type *type;
5823 
5824 	if (FFI_G(symbols)) {
5825 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5826 		if (sym) {
5827 			return (sym->kind == ZEND_FFI_SYM_TYPE);
5828 		}
5829 	}
5830 	type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5831 	if (type) {
5832 		return 1;
5833 	}
5834 	return 0;
5835 }
5836 /* }}} */
5837 
5838 void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
5839 {
5840 	zend_ffi_symbol *sym;
5841 	zend_ffi_type *type;
5842 
5843 	if (FFI_G(symbols)) {
5844 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5845 		if (sym && sym->kind == ZEND_FFI_SYM_TYPE) {
5846 			dcl->type = ZEND_FFI_TYPE(sym->type);
5847 			if (sym->is_const) {
5848 				dcl->attr |= ZEND_FFI_ATTR_CONST;
5849 			}
5850 			return;
5851 		}
5852 	}
5853 	type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
5854 	if (type) {
5855 		dcl->type = type;
5856 		return;
5857 	}
5858 	zend_ffi_parser_error("Undefined C type \"%.*s\" at line %d", name_len, name, FFI_G(line));
5859 }
5860 /* }}} */
5861 
5862 void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
5863 {
5864 	zend_ffi_symbol *sym;
5865 
5866 	if (UNEXPECTED(FFI_G(attribute_parsing))) {
5867 		val->kind = ZEND_FFI_VAL_NAME;
5868 		val->str = name;
5869 		val->len = name_len;
5870 		return;
5871 	} else if (FFI_G(symbols)) {
5872 		sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
5873 		if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
5874 			val->i64 = sym->value;
5875 			switch (sym->type->kind) {
5876 				case ZEND_FFI_TYPE_SINT8:
5877 				case ZEND_FFI_TYPE_SINT16:
5878 				case ZEND_FFI_TYPE_SINT32:
5879 					val->kind = ZEND_FFI_VAL_INT32;
5880 					break;
5881 				case ZEND_FFI_TYPE_SINT64:
5882 					val->kind = ZEND_FFI_VAL_INT64;
5883 					break;
5884 				case ZEND_FFI_TYPE_UINT8:
5885 				case ZEND_FFI_TYPE_UINT16:
5886 				case ZEND_FFI_TYPE_UINT32:
5887 					val->kind = ZEND_FFI_VAL_UINT32;
5888 					break;
5889 				case ZEND_FFI_TYPE_UINT64:
5890 					val->kind = ZEND_FFI_VAL_UINT64;
5891 					break;
5892 				default:
5893 					ZEND_UNREACHABLE();
5894 			}
5895 			return;
5896 		}
5897 	}
5898 	val->kind = ZEND_FFI_VAL_ERROR;
5899 }
5900 /* }}} */
5901 
5902 void zend_ffi_make_enum_type(zend_ffi_dcl *dcl) /* {{{ */
5903 {
5904 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
5905 	type->kind = ZEND_FFI_TYPE_ENUM;
5906 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ENUM_ATTRS);
5907 	type->enumeration.tag_name = NULL;
5908 	if (type->attr & ZEND_FFI_ATTR_PACKED) {
5909 		type->size = zend_ffi_type_uint8.size;
5910 		type->align = zend_ffi_type_uint8.align;
5911 		type->enumeration.kind = ZEND_FFI_TYPE_UINT8;
5912 	} else {
5913 		type->size = zend_ffi_type_uint32.size;
5914 		type->align = zend_ffi_type_uint32.align;
5915 		type->enumeration.kind = ZEND_FFI_TYPE_UINT32;
5916 	}
5917 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
5918 	dcl->attr &= ~ZEND_FFI_ENUM_ATTRS;
5919 }
5920 /* }}} */
5921 
5922 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) /* {{{ */
5923 {
5924 	zend_ffi_symbol *sym;
5925 	const zend_ffi_type *sym_type;
5926 	int64_t value;
5927 	zend_ffi_type *enum_type = ZEND_FFI_TYPE(enum_dcl->type);
5928 	bool overflow = 0;
5929 	bool is_signed =
5930 		(enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT8 ||
5931 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT16 ||
5932 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT32 ||
5933 		 enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT64);
5934 
5935 	ZEND_ASSERT(enum_type && enum_type->kind == ZEND_FFI_TYPE_ENUM);
5936 	if (val->kind == ZEND_FFI_VAL_EMPTY) {
5937 		if (is_signed) {
5938 			if (*last == 0x7FFFFFFFFFFFFFFFLL) {
5939 				overflow = 1;
5940 			}
5941 		} else {
5942 			if ((*min != 0 || *max != 0)
5943 			 && (uint64_t)*last == 0xFFFFFFFFFFFFFFFFULL) {
5944 				overflow = 1;
5945 			}
5946 		}
5947 		value = *last + 1;
5948 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
5949 		if (!is_signed && val->ch < 0) {
5950 			if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5951 				overflow = 1;
5952 			} else {
5953 				is_signed = 1;
5954 			}
5955 		}
5956 		value = val->ch;
5957 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
5958 		if (!is_signed && val->i64 < 0) {
5959 			if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
5960 				overflow = 1;
5961 			} else {
5962 				is_signed = 1;
5963 			}
5964 		}
5965 		value = val->i64;
5966 	} else if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
5967 		if (is_signed && val->u64 > 0x7FFFFFFFFFFFFFFFULL) {
5968 			overflow = 1;
5969 		}
5970 		value = val->u64;
5971 	} else {
5972 		zend_ffi_parser_error("Enumerator value \"%.*s\" must be an integer at line %d", name_len, name, FFI_G(line));
5973 		return;
5974 	}
5975 
5976 	if (overflow) {
5977 		zend_ffi_parser_error("Overflow in enumeration values \"%.*s\" at line %d", name_len, name, FFI_G(line));
5978 		return;
5979 	}
5980 
5981 	if (is_signed) {
5982 		*min = MIN(*min, value);
5983 		*max = MAX(*max, value);
5984 		if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5985 		 && *min >= -0x7FLL-1 && *max <= 0x7FLL) {
5986 			sym_type = &zend_ffi_type_sint8;
5987 		} else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5988 		 && *min >= -0x7FFFLL-1 && *max <= 0x7FFFLL) {
5989 			sym_type = &zend_ffi_type_sint16;
5990 		} else if (*min >= -0x7FFFFFFFLL-1 && *max <= 0x7FFFFFFFLL) {
5991 			sym_type = &zend_ffi_type_sint32;
5992 		} else {
5993 			sym_type = &zend_ffi_type_sint64;
5994 		}
5995 	} else {
5996 		*min = MIN((uint64_t)*min, (uint64_t)value);
5997 		*max = MAX((uint64_t)*max, (uint64_t)value);
5998 		if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
5999 		 && (uint64_t)*max <= 0xFFULL) {
6000 			sym_type = &zend_ffi_type_uint8;
6001 		} else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
6002 		 && (uint64_t)*max <= 0xFFFFULL) {
6003 			sym_type = &zend_ffi_type_uint16;
6004 		} else if ((uint64_t)*max <= 0xFFFFFFFFULL) {
6005 			sym_type = &zend_ffi_type_uint32;
6006 		} else {
6007 			sym_type = &zend_ffi_type_uint64;
6008 		}
6009 	}
6010 	enum_type->enumeration.kind = sym_type->kind;
6011 	enum_type->size = sym_type->size;
6012 	enum_type->align = sym_type->align;
6013 	*last = value;
6014 
6015 	if (!FFI_G(symbols)) {
6016 		FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6017 		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));
6018 	}
6019 	sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6020 	if (sym) {
6021 		zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6022 	} else {
6023 		sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6024 		sym->kind  = ZEND_FFI_SYM_CONST;
6025 		sym->type  = (zend_ffi_type*)sym_type;
6026 		sym->value = value;
6027 		zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6028 	}
6029 }
6030 /* }}} */
6031 
6032 void zend_ffi_make_struct_type(zend_ffi_dcl *dcl) /* {{{ */
6033 {
6034 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6035 	type->kind = ZEND_FFI_TYPE_STRUCT;
6036 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_STRUCT_ATTRS);
6037 	type->size = 0;
6038 	type->align = dcl->align > 1 ? dcl->align : 1;
6039 	if (dcl->flags & ZEND_FFI_DCL_UNION) {
6040 		type->attr |= ZEND_FFI_ATTR_UNION;
6041 	}
6042 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6043 	type->record.tag_name = NULL;
6044 	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));
6045 	dcl->attr &= ~ZEND_FFI_STRUCT_ATTRS;
6046 	dcl->align = 0;
6047 }
6048 /* }}} */
6049 
6050 static zend_result zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */
6051 {
6052 	if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6053 		zend_ffi_field *field = NULL;
6054 
6055 		ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) {
6056 			break;
6057 		} ZEND_HASH_FOREACH_END();
6058 		if (ZEND_FFI_TYPE(field->type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
6059 			zend_ffi_throw_parser_error("Flexible array member not at end of struct at line %d", FFI_G(line));
6060 			return FAILURE;
6061 		}
6062 	}
6063 	return SUCCESS;
6064 }
6065 /* }}} */
6066 
6067 static zend_result zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */
6068 {
6069 	if (type == struct_type) {
6070 		zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line));
6071 		return FAILURE;
6072 	} else if (zend_ffi_validate_var_type(type, 1) == FAILURE) {
6073 		return FAILURE;
6074 	} else if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6075 		if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
6076 			zend_ffi_throw_parser_error("Flexible array member in union at line %d", FFI_G(line));
6077 			return FAILURE;
6078 		}
6079 	}
6080 	return zend_ffi_validate_prev_field_type(struct_type);
6081 }
6082 /* }}} */
6083 
6084 void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl) /* {{{ */
6085 {
6086 	zend_ffi_field *field;
6087 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6088 	zend_ffi_type *field_type;
6089 
6090 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6091 	zend_ffi_finalize_type(field_dcl);
6092 	field_type = ZEND_FFI_TYPE(field_dcl->type);
6093 	if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6094 		zend_ffi_cleanup_dcl(field_dcl);
6095 		LONGJMP(FFI_G(bailout), FAILURE);
6096 	}
6097 
6098 	field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6099 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6100 		struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6101 	}
6102 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6103 		field->offset = 0;
6104 		struct_type->size = MAX(struct_type->size, field_type->size);
6105 	} else {
6106 		if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6107 			uint32_t field_align = MAX(field_type->align, field_dcl->align);
6108 			struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6109 		}
6110 		field->offset = struct_type->size;
6111 		struct_type->size += field_type->size;
6112 	}
6113 	field->type = field_dcl->type;
6114 	field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6115 	field->is_nested = 0;
6116 	field->first_bit = 0;
6117 	field->bits = 0;
6118 	field_dcl->type = field_type; /* reset "owned" flag */
6119 
6120 	if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6121 		zend_ffi_type_dtor(field->type);
6122 		pefree(field, FFI_G(persistent));
6123 		zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6124 	}
6125 }
6126 /* }}} */
6127 
6128 void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl) /* {{{ */
6129 {
6130 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6131 	zend_ffi_type *field_type;
6132 	zend_ffi_field *field;
6133 	zend_string *key;
6134 
6135 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6136 	zend_ffi_finalize_type(field_dcl);
6137 	field_type = ZEND_FFI_TYPE(field_dcl->type);
6138 	if (field_type->kind != ZEND_FFI_TYPE_STRUCT) {
6139 		zend_ffi_cleanup_dcl(field_dcl);
6140 		zend_ffi_parser_error("Declaration does not declare anything at line %d", FFI_G(line));
6141 		return;
6142 	}
6143 
6144 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6145 		struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
6146 	}
6147 	if (!(struct_type->attr & ZEND_FFI_ATTR_UNION)) {
6148 		if (zend_ffi_validate_prev_field_type(struct_type) == FAILURE) {
6149 			zend_ffi_cleanup_dcl(field_dcl);
6150 			LONGJMP(FFI_G(bailout), FAILURE);
6151 		}
6152 		if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
6153 			uint32_t field_align = MAX(field_type->align, field_dcl->align);
6154 			struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
6155 		}
6156 	}
6157 
6158 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&field_type->record.fields, key, field) {
6159 		zend_ffi_field *new_field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6160 
6161 		if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6162 			new_field->offset = field->offset;
6163 		} else {
6164 			new_field->offset = struct_type->size + field->offset;
6165 		}
6166 		new_field->type = field->type;
6167 		new_field->is_const = field->is_const;
6168 		new_field->is_nested = 1;
6169 		new_field->first_bit = field->first_bit;
6170 		new_field->bits = field->bits;
6171 		field->type = ZEND_FFI_TYPE(field->type); /* reset "owned" flag */
6172 
6173 		if (key) {
6174 			if (!zend_hash_add_ptr(&struct_type->record.fields, key, new_field)) {
6175 				zend_ffi_type_dtor(new_field->type);
6176 				pefree(new_field, FFI_G(persistent));
6177 				zend_ffi_parser_error("Duplicate field name \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
6178 				return;
6179 			}
6180 		} else {
6181 			zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6182 		}
6183 	} ZEND_HASH_FOREACH_END();
6184 
6185 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6186 		struct_type->size = MAX(struct_type->size, field_type->size);
6187 	} else {
6188 		struct_type->size += field_type->size;
6189 	}
6190 
6191 	zend_ffi_type_dtor(field_dcl->type);
6192 	field_dcl->type = NULL;
6193 }
6194 /* }}} */
6195 
6196 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) /* {{{ */
6197 {
6198 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
6199 	zend_ffi_type *field_type;
6200 	zend_ffi_field *field;
6201 
6202 	ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6203 	zend_ffi_finalize_type(field_dcl);
6204 	field_type = ZEND_FFI_TYPE(field_dcl->type);
6205 	if (zend_ffi_validate_field_type(field_type, struct_type) == FAILURE) {
6206 		zend_ffi_cleanup_dcl(field_dcl);
6207 		LONGJMP(FFI_G(bailout), FAILURE);
6208 	}
6209 
6210 	if (field_type->kind < ZEND_FFI_TYPE_UINT8 || field_type->kind > ZEND_FFI_TYPE_BOOL) {
6211 		zend_ffi_cleanup_dcl(field_dcl);
6212 		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));
6213 	}
6214 
6215 	if (bits->kind == ZEND_FFI_VAL_INT32 || bits->kind == ZEND_FFI_VAL_INT64) {
6216 		if (bits->i64 < 0) {
6217 			zend_ffi_cleanup_dcl(field_dcl);
6218 			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));
6219 		} else if (bits->i64 == 0) {
6220 			zend_ffi_cleanup_dcl(field_dcl);
6221 			if (name) {
6222 				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));
6223 			}
6224 			return;
6225 		} else if (bits->i64 > field_type->size * 8) {
6226 			zend_ffi_cleanup_dcl(field_dcl);
6227 			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));
6228 		}
6229 	} else if (bits->kind == ZEND_FFI_VAL_UINT32 || bits->kind == ZEND_FFI_VAL_UINT64) {
6230 		if (bits->u64 == 0) {
6231 			zend_ffi_cleanup_dcl(field_dcl);
6232 			if (name) {
6233 				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));
6234 			}
6235 			return;
6236 		} else if (bits->u64 > field_type->size * 8) {
6237 			zend_ffi_cleanup_dcl(field_dcl);
6238 			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));
6239 		}
6240 	} else {
6241 		zend_ffi_cleanup_dcl(field_dcl);
6242 		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));
6243 	}
6244 
6245 	field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
6246 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6247 		struct_type->align = MAX(struct_type->align, sizeof(uint32_t));
6248 	}
6249 	if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
6250 		field->offset = 0;
6251 		field->first_bit = 0;
6252 		field->bits = bits->u64;
6253 		if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6254 			struct_type->size = MAX(struct_type->size, (bits->u64 + 7) / 8);
6255 		} else {
6256 			struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4);
6257 		}
6258 	} else {
6259 		zend_ffi_field *prev_field = NULL;
6260 
6261 		if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
6262 			ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) {
6263 				break;
6264 			} ZEND_HASH_FOREACH_END();
6265 		}
6266 		if (prev_field && prev_field->bits) {
6267 			field->offset = prev_field->offset;
6268 			field->first_bit = prev_field->first_bit + prev_field->bits;
6269 			field->bits = bits->u64;
6270 		} else {
6271 			field->offset = struct_type->size;
6272 			field->first_bit = 0;
6273 			field->bits = bits->u64;
6274 		}
6275 		if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
6276 			struct_type->size = field->offset + ((field->first_bit + field->bits) + 7) / 8;
6277 		} else {
6278 			struct_type->size = field->offset + (((field->first_bit + field->bits) + 31) / 32) * 4;
6279 		}
6280 	}
6281 	field->type = field_dcl->type;
6282 	field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
6283 	field->is_nested = 0;
6284 	field_dcl->type = field_type; /* reset "owned" flag */
6285 
6286 	if (name) {
6287 		if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
6288 			zend_ffi_type_dtor(field->type);
6289 			pefree(field, FFI_G(persistent));
6290 			zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
6291 		}
6292 	} else {
6293 		zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
6294 	}
6295 }
6296 /* }}} */
6297 
6298 void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl) /* {{{ */
6299 {
6300 	zend_ffi_type *struct_type = ZEND_FFI_TYPE(dcl->type);
6301 
6302 	ZEND_ASSERT(struct_type->kind == ZEND_FFI_TYPE_STRUCT);
6303 	if (dcl->align > struct_type->align) {
6304 		struct_type->align = dcl->align;
6305 	}
6306 	if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
6307 		struct_type->size = ((struct_type->size + (struct_type->align - 1)) / struct_type->align) * struct_type->align;
6308 	}
6309 	dcl->align = 0;
6310 }
6311 /* }}} */
6312 
6313 void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl) /* {{{ */
6314 {
6315 	zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6316 	type->kind = ZEND_FFI_TYPE_POINTER;
6317 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_POINTER_ATTRS);
6318 	type->size = sizeof(void*);
6319 	type->align = _Alignof(void*);
6320 	zend_ffi_finalize_type(dcl);
6321 	if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6322 		zend_ffi_cleanup_dcl(dcl);
6323 		LONGJMP(FFI_G(bailout), FAILURE);
6324 	}
6325 	type->pointer.type = dcl->type;
6326 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6327 	dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
6328 	dcl->attr &= ~ZEND_FFI_POINTER_ATTRS;
6329 	dcl->align = 0;
6330 }
6331 /* }}} */
6332 
6333 static zend_result zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */
6334 {
6335 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
6336 		zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line));
6337 		return FAILURE;
6338 	} else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
6339 		zend_ffi_throw_parser_error("Only the leftmost array can be undimensioned at line %d", FFI_G(line));
6340 		return FAILURE;
6341 	}
6342 	return zend_ffi_validate_type(type, 0, 1);
6343 }
6344 /* }}} */
6345 
6346 void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */
6347 {
6348 	int length = 0;
6349 	zend_ffi_type *element_type;
6350 	zend_ffi_type *type;
6351 
6352 	zend_ffi_finalize_type(dcl);
6353 	element_type = ZEND_FFI_TYPE(dcl->type);
6354 
6355 	if (len->kind == ZEND_FFI_VAL_EMPTY) {
6356 		length = 0;
6357 	} else if (len->kind == ZEND_FFI_VAL_UINT32 || len->kind == ZEND_FFI_VAL_UINT64) {
6358 		length = len->u64;
6359 	} else if (len->kind == ZEND_FFI_VAL_INT32 || len->kind == ZEND_FFI_VAL_INT64) {
6360 		length = len->i64;
6361 	} else if (len->kind == ZEND_FFI_VAL_CHAR) {
6362 		length = len->ch;
6363 	} else {
6364 		zend_ffi_cleanup_dcl(dcl);
6365 		zend_ffi_parser_error("Unsupported array index type at line %d", FFI_G(line));
6366 		return;
6367 	}
6368 	if (length < 0) {
6369 		zend_ffi_cleanup_dcl(dcl);
6370 		zend_ffi_parser_error("Negative array index at line %d", FFI_G(line));
6371 		return;
6372 	}
6373 
6374 	if (zend_ffi_validate_array_element_type(element_type) == FAILURE) {
6375 		zend_ffi_cleanup_dcl(dcl);
6376 		LONGJMP(FFI_G(bailout), FAILURE);
6377 	}
6378 
6379 	type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6380 	type->kind = ZEND_FFI_TYPE_ARRAY;
6381 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ARRAY_ATTRS);
6382 	type->size = length * element_type->size;
6383 	type->align = element_type->align;
6384 	type->array.type = dcl->type;
6385 	type->array.length = length;
6386 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6387 	dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
6388 	dcl->attr &= ~ZEND_FFI_ARRAY_ATTRS;
6389 	dcl->align = 0;
6390 }
6391 /* }}} */
6392 
6393 static zend_result zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */
6394 {
6395 	if (type->kind == ZEND_FFI_TYPE_FUNC) {
6396 		zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line));
6397 		return FAILURE;
6398 	 } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6399 		zend_ffi_throw_parser_error("Function returning array is not allowed at line %d", FFI_G(line));
6400 		return FAILURE;
6401 	}
6402 	return zend_ffi_validate_incomplete_type(type, 1, 0);
6403 }
6404 /* }}} */
6405 
6406 void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl) /* {{{ */
6407 {
6408 	zend_ffi_type *type;
6409 	zend_ffi_type *ret_type;
6410 
6411 	zend_ffi_finalize_type(dcl);
6412 	ret_type = ZEND_FFI_TYPE(dcl->type);
6413 
6414 	if (args) {
6415 		int no_args = 0;
6416 		zend_ffi_type *arg_type;
6417 
6418 		ZEND_HASH_PACKED_FOREACH_PTR(args, arg_type) {
6419 			arg_type = ZEND_FFI_TYPE(arg_type);
6420 			if (arg_type->kind == ZEND_FFI_TYPE_VOID) {
6421 				if (zend_hash_num_elements(args) != 1) {
6422 					zend_ffi_cleanup_dcl(nested_dcl);
6423 					zend_ffi_cleanup_dcl(dcl);
6424 					zend_hash_destroy(args);
6425 					pefree(args, FFI_G(persistent));
6426 					zend_ffi_parser_error("void type is not allowed at line %d", FFI_G(line));
6427 					return;
6428 				} else {
6429 					no_args = 1;
6430 				}
6431 			}
6432 		} ZEND_HASH_FOREACH_END();
6433 		if (no_args) {
6434 			zend_hash_destroy(args);
6435 			pefree(args, FFI_G(persistent));
6436 			args = NULL;
6437 		}
6438 	}
6439 
6440 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
6441 	if (dcl->abi == ZEND_FFI_ABI_VECTORCALL && args) {
6442 		zend_ulong i;
6443 		zend_ffi_type *arg_type;
6444 
6445 		ZEND_HASH_PACKED_FOREACH_KEY_PTR(args, i, arg_type) {
6446 			arg_type = ZEND_FFI_TYPE(arg_type);
6447 # ifdef _WIN64
6448 			if (i >= 4 && i <= 5 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6449 # else
6450 			if (i < 6 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
6451 # endif
6452 				zend_ffi_cleanup_dcl(nested_dcl);
6453 				zend_ffi_cleanup_dcl(dcl);
6454 				zend_hash_destroy(args);
6455 				pefree(args, FFI_G(persistent));
6456 				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));
6457 				return;
6458 			}
6459 		} ZEND_HASH_FOREACH_END();
6460 	}
6461 #endif
6462 
6463 	if (zend_ffi_validate_func_ret_type(ret_type) == FAILURE) {
6464 		zend_ffi_cleanup_dcl(nested_dcl);
6465 		zend_ffi_cleanup_dcl(dcl);
6466 		if (args) {
6467 			zend_hash_destroy(args);
6468 			pefree(args, FFI_G(persistent));
6469 		}
6470 		LONGJMP(FFI_G(bailout), FAILURE);
6471 	}
6472 
6473 	type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6474 	type->kind = ZEND_FFI_TYPE_FUNC;
6475 	type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_FUNC_ATTRS);
6476 	type->size = sizeof(void*);
6477 	type->align = 1;
6478 	type->func.ret_type = dcl->type;
6479 	switch (dcl->abi) {
6480 		case ZEND_FFI_ABI_DEFAULT:
6481 		case ZEND_FFI_ABI_CDECL:
6482 			type->func.abi = FFI_DEFAULT_ABI;
6483 			break;
6484 #ifdef HAVE_FFI_FASTCALL
6485 		case ZEND_FFI_ABI_FASTCALL:
6486 			type->func.abi = FFI_FASTCALL;
6487 			break;
6488 #endif
6489 #ifdef HAVE_FFI_THISCALL
6490 		case ZEND_FFI_ABI_THISCALL:
6491 			type->func.abi = FFI_THISCALL;
6492 			break;
6493 #endif
6494 #ifdef HAVE_FFI_STDCALL
6495 		case ZEND_FFI_ABI_STDCALL:
6496 			type->func.abi = FFI_STDCALL;
6497 			break;
6498 #endif
6499 #ifdef HAVE_FFI_PASCAL
6500 		case ZEND_FFI_ABI_PASCAL:
6501 			type->func.abi = FFI_PASCAL;
6502 			break;
6503 #endif
6504 #ifdef HAVE_FFI_REGISTER
6505 		case ZEND_FFI_ABI_REGISTER:
6506 			type->func.abi = FFI_REGISTER;
6507 			break;
6508 #endif
6509 #ifdef HAVE_FFI_MS_CDECL
6510 		case ZEND_FFI_ABI_MS:
6511 			type->func.abi = FFI_MS_CDECL;
6512 			break;
6513 #endif
6514 #ifdef HAVE_FFI_SYSV
6515 		case ZEND_FFI_ABI_SYSV:
6516 			type->func.abi = FFI_SYSV;
6517 			break;
6518 #endif
6519 #ifdef HAVE_FFI_VECTORCALL_PARTIAL
6520 		case ZEND_FFI_ABI_VECTORCALL:
6521 			type->func.abi = FFI_VECTORCALL_PARTIAL;
6522 			break;
6523 #endif
6524 		default:
6525 			type->func.abi = FFI_DEFAULT_ABI;
6526 			zend_ffi_cleanup_dcl(nested_dcl);
6527 			if (args) {
6528 				zend_hash_destroy(args);
6529 				pefree(args, FFI_G(persistent));
6530 			}
6531 			type->func.args = NULL;
6532 			_zend_ffi_type_dtor(type);
6533 			zend_ffi_parser_error("Unsupported calling convention line %d", FFI_G(line));
6534 			break;
6535 	}
6536 	type->func.args = args;
6537 	dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6538 	dcl->attr &= ~ZEND_FFI_FUNC_ATTRS;
6539 	dcl->align = 0;
6540 	dcl->abi = 0;
6541 }
6542 /* }}} */
6543 
6544 void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl) /* {{{ */
6545 {
6546 	zend_ffi_type *type;
6547 
6548 	if (!*args) {
6549 		*args = pemalloc(sizeof(HashTable), FFI_G(persistent));
6550 		zend_hash_init(*args, 0, NULL, zend_ffi_type_hash_dtor, FFI_G(persistent));
6551 	}
6552 	zend_ffi_finalize_type(arg_dcl);
6553 	type = ZEND_FFI_TYPE(arg_dcl->type);
6554 	if (type->kind == ZEND_FFI_TYPE_ARRAY) {
6555 		if (ZEND_FFI_TYPE_IS_OWNED(arg_dcl->type)) {
6556 			type->kind = ZEND_FFI_TYPE_POINTER;
6557 			type->size = sizeof(void*);
6558 		} else {
6559 			zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6560 			new_type->kind = ZEND_FFI_TYPE_POINTER;
6561 			new_type->attr = FFI_G(default_type_attr) | (type->attr & ZEND_FFI_POINTER_ATTRS);
6562 			new_type->size = sizeof(void*);
6563 			new_type->align = _Alignof(void*);
6564 			new_type->pointer.type = ZEND_FFI_TYPE(type->array.type);
6565 			arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6566 		}
6567 	} else if (type->kind == ZEND_FFI_TYPE_FUNC) {
6568 		zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6569 		new_type->kind = ZEND_FFI_TYPE_POINTER;
6570 		new_type->attr = FFI_G(default_type_attr);
6571 		new_type->size = sizeof(void*);
6572 		new_type->align = _Alignof(void*);
6573 		new_type->pointer.type = arg_dcl->type;
6574 		arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
6575 	}
6576 	if (zend_ffi_validate_incomplete_type(type, 1, 1) == FAILURE) {
6577 		zend_ffi_cleanup_dcl(arg_dcl);
6578 		zend_hash_destroy(*args);
6579 		pefree(*args, FFI_G(persistent));
6580 		*args = NULL;
6581 		LONGJMP(FFI_G(bailout), FAILURE);
6582 	}
6583 	zend_hash_next_index_insert_ptr(*args, (void*)arg_dcl->type);
6584 }
6585 /* }}} */
6586 
6587 void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
6588 {
6589 	zend_ffi_symbol *sym;
6590 
6591 	if (!FFI_G(symbols)) {
6592 		FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6593 		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));
6594 	}
6595 	zend_ffi_finalize_type(dcl);
6596 	sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
6597 	if (sym) {
6598 		if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF
6599 		 && sym->kind == ZEND_FFI_SYM_TYPE
6600 		 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(dcl->type))
6601 		 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6602 			/* allowed redeclaration */
6603 			zend_ffi_type_dtor(dcl->type);
6604 			return;
6605 		} else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0
6606 		 || (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6607 			zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type);
6608 
6609 			if (type->kind == ZEND_FFI_TYPE_FUNC) {
6610 				if (sym->kind == ZEND_FFI_SYM_FUNC
6611 				 && zend_ffi_same_types(ZEND_FFI_TYPE(sym->type), type)) {
6612 					/* allowed redeclaration */
6613 					zend_ffi_type_dtor(dcl->type);
6614 					return;
6615 				}
6616 			} else {
6617 				if (sym->kind == ZEND_FFI_SYM_VAR
6618 				 && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), type)
6619 				 && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
6620 					/* allowed redeclaration */
6621 					zend_ffi_type_dtor(dcl->type);
6622 					return;
6623 				}
6624 			}
6625 		}
6626 		zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
6627 	} else {
6628 		if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF) {
6629 			if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) == FAILURE) {
6630 				zend_ffi_cleanup_dcl(dcl);
6631 				LONGJMP(FFI_G(bailout), FAILURE);
6632 			}
6633 			if (dcl->align && dcl->align > ZEND_FFI_TYPE(dcl->type)->align) {
6634 				if (ZEND_FFI_TYPE_IS_OWNED(dcl->type)) {
6635 					ZEND_FFI_TYPE(dcl->type)->align = dcl->align;
6636 				} else {
6637 					zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
6638 
6639 					memcpy(type, ZEND_FFI_TYPE(dcl->type), sizeof(zend_ffi_type));
6640 					type->attr |= FFI_G(default_type_attr);
6641 					type->align = dcl->align;
6642 					dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
6643 				}
6644 			}
6645 			sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6646 			sym->kind = ZEND_FFI_SYM_TYPE;
6647 			sym->type = dcl->type;
6648 			sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6649 			dcl->type = ZEND_FFI_TYPE(dcl->type); /* reset "owned" flag */
6650 			zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6651 		} else {
6652 			zend_ffi_type *type;
6653 
6654 			type = ZEND_FFI_TYPE(dcl->type);
6655 			if (zend_ffi_validate_type(type, (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN, 1) == FAILURE) {
6656 				zend_ffi_cleanup_dcl(dcl);
6657 				LONGJMP(FFI_G(bailout), FAILURE);
6658 			}
6659 			if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 ||
6660 			    (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
6661 				sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
6662 				sym->kind = (type->kind == ZEND_FFI_TYPE_FUNC) ? ZEND_FFI_SYM_FUNC : ZEND_FFI_SYM_VAR;
6663 				sym->type = dcl->type;
6664 				sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
6665 				dcl->type = type; /* reset "owned" flag */
6666 				zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
6667 			} else {
6668 				/* useless declaration */
6669 				zend_ffi_type_dtor(dcl->type);
6670 			}
6671 		}
6672 	}
6673 }
6674 /* }}} */
6675 
6676 void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete) /* {{{ */
6677 {
6678 	zend_ffi_tag *tag;
6679 	zend_ffi_type *type;
6680 
6681 	if (!FFI_G(tags)) {
6682 		FFI_G(tags) = pemalloc(sizeof(HashTable), FFI_G(persistent));
6683 		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));
6684 	}
6685 	tag = zend_hash_str_find_ptr(FFI_G(tags), name, name_len);
6686 	if (tag) {
6687 		zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
6688 
6689 		if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6690 			if (tag->kind != ZEND_FFI_TAG_STRUCT) {
6691 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6692 				return;
6693 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6694 				zend_ffi_parser_error("Redefinition of \"struct %.*s\" at line %d", name_len, name, FFI_G(line));
6695 				return;
6696 			}
6697 		} else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6698 			if (tag->kind != ZEND_FFI_TAG_UNION) {
6699 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6700 				return;
6701 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6702 				zend_ffi_parser_error("Redefinition of \"union %.*s\" at line %d", name_len, name, FFI_G(line));
6703 				return;
6704 			}
6705 		} else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6706 			if (tag->kind != ZEND_FFI_TAG_ENUM) {
6707 				zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
6708 				return;
6709 			} else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
6710 				zend_ffi_parser_error("Redefinition of \"enum %.*s\" at line %d", name_len, name, FFI_G(line));
6711 				return;
6712 			}
6713 		} else {
6714 			ZEND_UNREACHABLE();
6715 			return;
6716 		}
6717 		dcl->type = type;
6718 		if (!incomplete) {
6719 			type->attr &= ~ZEND_FFI_ATTR_INCOMPLETE_TAG;
6720 		}
6721 	} else {
6722 		zend_ffi_tag *tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent));
6723 		zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent));
6724 
6725 		if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
6726 			tag->kind = ZEND_FFI_TAG_STRUCT;
6727 			zend_ffi_make_struct_type(dcl);
6728 			type = ZEND_FFI_TYPE(dcl->type);
6729 			type->record.tag_name = zend_string_copy(tag_name);
6730 		} else if (dcl->flags & ZEND_FFI_DCL_UNION) {
6731 			tag->kind = ZEND_FFI_TAG_UNION;
6732 			zend_ffi_make_struct_type(dcl);
6733 			type = ZEND_FFI_TYPE(dcl->type);
6734 			type->record.tag_name = zend_string_copy(tag_name);
6735 		} else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
6736 			tag->kind = ZEND_FFI_TAG_ENUM;
6737 			zend_ffi_make_enum_type(dcl);
6738 			type = ZEND_FFI_TYPE(dcl->type);
6739 			type->enumeration.tag_name = zend_string_copy(tag_name);
6740 		} else {
6741 			ZEND_UNREACHABLE();
6742 		}
6743 		tag->type = ZEND_FFI_TYPE_MAKE_OWNED(dcl->type);
6744 		dcl->type = ZEND_FFI_TYPE(dcl->type);
6745 		if (incomplete) {
6746 			dcl->type->attr |= ZEND_FFI_ATTR_INCOMPLETE_TAG;
6747 		}
6748 		zend_hash_add_new_ptr(FFI_G(tags), tag_name, tag);
6749 		zend_string_release(tag_name);
6750 	}
6751 }
6752 /* }}} */
6753 
6754 void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi) /* {{{ */
6755 {
6756 	if (dcl->abi != ZEND_FFI_ABI_DEFAULT) {
6757 		zend_ffi_parser_error("Multiple calling convention specifiers at line %d", FFI_G(line));
6758 	} else {
6759 		dcl->abi = abi;
6760 	}
6761 }
6762 /* }}} */
6763 
6764 #define SIMPLE_ATTRIBUTES(_) \
6765 	_(cdecl) \
6766 	_(fastcall) \
6767 	_(thiscall) \
6768 	_(stdcall) \
6769 	_(ms_abi) \
6770 	_(sysv_abi) \
6771 	_(vectorcall) \
6772 	_(aligned) \
6773 	_(packed) \
6774 	_(ms_struct) \
6775 	_(gcc_struct) \
6776 	_(const) \
6777 	_(malloc) \
6778 	_(deprecated) \
6779 	_(nothrow) \
6780 	_(leaf) \
6781 	_(pure) \
6782 	_(noreturn) \
6783 	_(warn_unused_result)
6784 
6785 #define ATTR_ID(name)   attr_ ## name,
6786 #define ATTR_NAME(name) {sizeof(#name)-1, #name},
6787 
6788 void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len) /* {{{ */
6789 {
6790 	enum {
6791 		SIMPLE_ATTRIBUTES(ATTR_ID)
6792 		attr_unsupported
6793 	};
6794 	static const struct {
6795 		size_t len;
6796 		const char * const name;
6797 	} names[] = {
6798 		SIMPLE_ATTRIBUTES(ATTR_NAME)
6799 		{0, NULL}
6800 	};
6801 	int id;
6802 
6803 	if (name_len > 4
6804 	 && name[0] == '_'
6805 	 && name[1] == '_'
6806 	 && name[name_len-2] == '_'
6807 	 && name[name_len-1] == '_') {
6808 		name += 2;
6809 		name_len -= 4;
6810 	}
6811 	for (id = 0; names[id].len != 0; id++) {
6812 		if (name_len == names[id].len) {
6813 			if (memcmp(name, names[id].name, name_len) == 0) {
6814 				break;
6815 			}
6816 		}
6817 	}
6818 	switch (id) {
6819 		case attr_cdecl:
6820 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_CDECL);
6821 			break;
6822 		case attr_fastcall:
6823 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_FASTCALL);
6824 			break;
6825 		case attr_thiscall:
6826 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_THISCALL);
6827 			break;
6828 		case attr_stdcall:
6829 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_STDCALL);
6830 			break;
6831 		case attr_ms_abi:
6832 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_MS);
6833 			break;
6834 		case attr_sysv_abi:
6835 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_SYSV);
6836 			break;
6837 		case attr_vectorcall:
6838 			zend_ffi_set_abi(dcl, ZEND_FFI_ABI_VECTORCALL);
6839 			break;
6840 		case attr_aligned:
6841 			dcl->align = __BIGGEST_ALIGNMENT__;
6842 			break;
6843 		case attr_packed:
6844 			dcl->attr |= ZEND_FFI_ATTR_PACKED;
6845 			break;
6846 		case attr_ms_struct:
6847 			dcl->attr |= ZEND_FFI_ATTR_MS_STRUCT;
6848 			break;
6849 		case attr_gcc_struct:
6850 			dcl->attr |= ZEND_FFI_ATTR_GCC_STRUCT;
6851 			break;
6852 		case attr_unsupported:
6853 			zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6854 			break;
6855 		default:
6856 			/* ignore */
6857 			break;
6858 	}
6859 }
6860 /* }}} */
6861 
6862 #define VALUE_ATTRIBUTES(_) \
6863 	_(regparam) \
6864 	_(aligned) \
6865 	_(mode) \
6866 	_(nonnull) \
6867 	_(alloc_size) \
6868 	_(format) \
6869 	_(deprecated)
6870 
6871 void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */
6872 {
6873 	enum {
6874 		VALUE_ATTRIBUTES(ATTR_ID)
6875 		attr_unsupported
6876 	};
6877 	static const struct {
6878 		size_t len;
6879 		const char * const name;
6880 	} names[] = {
6881 		VALUE_ATTRIBUTES(ATTR_NAME)
6882 		{0, NULL}
6883 	};
6884 	int id;
6885 
6886 	if (name_len > 4
6887 	 && name[0] == '_'
6888 	 && name[1] == '_'
6889 	 && name[name_len-2] == '_'
6890 	 && name[name_len-1] == '_') {
6891 		name += 2;
6892 		name_len -= 4;
6893 	}
6894 	for (id = 0; names[id].len != 0; id++) {
6895 		if (name_len == names[id].len) {
6896 			if (memcmp(name, names[id].name, name_len) == 0) {
6897 				break;
6898 			}
6899 		}
6900 	}
6901 	switch (id) {
6902 		case attr_regparam:
6903 			if (n == 0
6904 			 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6905 			 && val->i64 == 3) {
6906 				zend_ffi_set_abi(dcl, ZEND_FFI_ABI_REGISTER);
6907 			} else {
6908 				zend_ffi_parser_error("Incorrect \"regparam\" value at line %d", FFI_G(line));
6909 			}
6910 			break;
6911 		case attr_aligned:
6912 			if (n == 0
6913 			 && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
6914 			 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6915 				dcl->align = val->i64;
6916 			} else {
6917 				zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6918 			}
6919 			break;
6920 		case attr_mode:
6921 			if (n == 0
6922 			 && (val->kind == ZEND_FFI_VAL_NAME)) {
6923 				const char *str = val->str;
6924 				size_t len = val->len;
6925 				if (len > 4
6926 				 && str[0] == '_'
6927 				 && str[1] == '_'
6928 				 && str[len-2] == '_'
6929 				 && str[len-1] == '_') {
6930 					str += 2;
6931 					len -= 4;
6932 				}
6933 				// TODO: Add support for vector type 'VnXX' ???
6934 				if (len == 2) {
6935 					if (str[1] == 'I') {
6936 						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))) {
6937 							/* inappropriate type */
6938 						} else if (str[0] == 'Q') {
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_CHAR;
6941 							break;
6942 						} else if (str[0] == 'H') {
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_SHORT;
6945 							break;
6946 						} else if (str[0] == 'S') {
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 							dcl->flags |= ZEND_FFI_DCL_INT;
6949 							break;
6950 						} else if (str[0] == 'D') {
6951 							dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
6952 							if (sizeof(long) == 8) {
6953 								dcl->flags |= ZEND_FFI_DCL_LONG;
6954 							} else {
6955 								dcl->flags |= ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG;
6956 							}
6957 							break;
6958 						}
6959 					} else if (str[1] == 'F') {
6960 						if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
6961 							/* inappropriate type */
6962 						} else if (str[0] == 'S') {
6963 							dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6964 							dcl->flags |= ZEND_FFI_DCL_FLOAT;
6965 							break;
6966 						} else if (str[0] == 'D') {
6967 							dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
6968 							dcl->flags |= ZEND_FFI_DCL_DOUBLE;
6969 							break;
6970 						}
6971 					}
6972 				}
6973 			}
6974 			zend_ffi_parser_error("Unsupported \"mode\" value at line %d", FFI_G(line));
6975 			// TODO: ???
6976 		case attr_unsupported:
6977 			zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
6978 			break;
6979 		default:
6980 			/* ignore */
6981 			break;
6982 	}
6983 }
6984 /* }}} */
6985 
6986 void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
6987 {
6988 	if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) {
6989 		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)
6990 		 && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
6991 			dcl->align = val->i64;
6992 		} else {
6993 			zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
6994 		}
6995 	} else {
6996 		/* ignore */
6997 	}
6998 }
6999 /* }}} */
7000 
7001 static zend_result zend_ffi_nested_type(zend_ffi_type *type, zend_ffi_type *nested_type) /* {{{ */
7002 {
7003 	nested_type = ZEND_FFI_TYPE(nested_type);
7004 	switch (nested_type->kind) {
7005 		case ZEND_FFI_TYPE_POINTER:
7006 			/* "char" is used as a terminator of nested declaration */
7007 			if (nested_type->pointer.type == &zend_ffi_type_char) {
7008 				nested_type->pointer.type = type;
7009 				return zend_ffi_validate_vla(ZEND_FFI_TYPE(type));
7010 			} else {
7011 				return zend_ffi_nested_type(type, nested_type->pointer.type);
7012 			}
7013 			break;
7014 		case ZEND_FFI_TYPE_ARRAY:
7015 			/* "char" is used as a terminator of nested declaration */
7016 			if (nested_type->array.type == &zend_ffi_type_char) {
7017 				nested_type->array.type = type;
7018 				if (zend_ffi_validate_array_element_type(ZEND_FFI_TYPE(type)) == FAILURE) {
7019 					return FAILURE;
7020 				}
7021 			} else {
7022 				if (zend_ffi_nested_type(type, nested_type->array.type) != SUCCESS) {
7023 					return FAILURE;
7024 				}
7025 			}
7026 			nested_type->size = nested_type->array.length * ZEND_FFI_TYPE(nested_type->array.type)->size;
7027 			nested_type->align = ZEND_FFI_TYPE(nested_type->array.type)->align;
7028 			return SUCCESS;
7029 			break;
7030 		case ZEND_FFI_TYPE_FUNC:
7031 			/* "char" is used as a terminator of nested declaration */
7032 			if (nested_type->func.ret_type == &zend_ffi_type_char) {
7033 				nested_type->func.ret_type = type;
7034 				return zend_ffi_validate_func_ret_type(ZEND_FFI_TYPE(type));
7035 			} else {
7036 				return zend_ffi_nested_type(type, nested_type->func.ret_type);
7037 			}
7038 			break;
7039 		default:
7040 			ZEND_UNREACHABLE();
7041 	}
7042 }
7043 /* }}} */
7044 
7045 void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl) /* {{{ */
7046 {
7047 	/* "char" is used as a terminator of nested declaration */
7048 	zend_ffi_finalize_type(dcl);
7049 	if (!nested_dcl->type || nested_dcl->type == &zend_ffi_type_char) {
7050 		nested_dcl->type = dcl->type;
7051 	} else {
7052 		if (zend_ffi_nested_type(dcl->type, nested_dcl->type) == FAILURE) {
7053 			zend_ffi_cleanup_dcl(nested_dcl);
7054 			LONGJMP(FFI_G(bailout), FAILURE);
7055 		}
7056 	}
7057 	dcl->type = nested_dcl->type;
7058 }
7059 /* }}} */
7060 
7061 void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl) /* {{{ */
7062 {
7063 	zend_ffi_finalize_type(align_dcl);
7064 	dcl->align = MAX(align_dcl->align, ZEND_FFI_TYPE(align_dcl->type)->align);
7065 }
7066 /* }}} */
7067 
7068 void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */
7069 {
7070 	switch (align_val->kind) {
7071 		case ZEND_FFI_VAL_INT32:
7072 		case ZEND_FFI_VAL_UINT32:
7073 			dcl->align = zend_ffi_type_uint32.align;
7074 			break;
7075 		case ZEND_FFI_VAL_INT64:
7076 		case ZEND_FFI_VAL_UINT64:
7077 			dcl->align = zend_ffi_type_uint64.align;
7078 			break;
7079 		case ZEND_FFI_VAL_FLOAT:
7080 			dcl->align = zend_ffi_type_float.align;
7081 			break;
7082 		case ZEND_FFI_VAL_DOUBLE:
7083 			dcl->align = zend_ffi_type_double.align;
7084 			break;
7085 #ifdef HAVE_LONG_DOUBLE
7086 		case ZEND_FFI_VAL_LONG_DOUBLE:
7087 			dcl->align = zend_ffi_type_long_double.align;
7088 			break;
7089 #endif
7090 		case ZEND_FFI_VAL_CHAR:
7091 		case ZEND_FFI_VAL_STRING:
7092 			dcl->align = zend_ffi_type_char.align;
7093 			break;
7094 		default:
7095 			break;
7096 	}
7097 }
7098 /* }}} */
7099 
7100 #define zend_ffi_expr_bool(val) do { \
7101 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7102 		val->kind = ZEND_FFI_VAL_INT32; \
7103 		val->i64 = !!val->u64; \
7104 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7105 		val->kind = ZEND_FFI_VAL_INT32; \
7106 		val->i64 = !!val->i64; \
7107 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7108 		val->kind = ZEND_FFI_VAL_INT32; \
7109 		val->i64 = !!val->d; \
7110 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7111 		val->kind = ZEND_FFI_VAL_INT32; \
7112 		val->i64 = !!val->ch; \
7113 	} else { \
7114 		val->kind = ZEND_FFI_VAL_ERROR; \
7115 	} \
7116 } while (0)
7117 
7118 #define zend_ffi_expr_math(val, op2, OP) do { \
7119 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7120 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7121 			val->kind = MAX(val->kind, op2->kind); \
7122 			val->u64 = val->u64 OP op2->u64; \
7123 		} else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7124 			val->u64 = val->u64 OP op2->i64; \
7125 		} else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7126 			val->u64 = val->u64 OP op2->i64; \
7127 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7128 			val->kind = op2->kind; \
7129 			val->d = (zend_ffi_double)val->u64 OP op2->d; \
7130 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7131 			val->u64 = val->u64 OP op2->ch; \
7132 		} else { \
7133 			val->kind = ZEND_FFI_VAL_ERROR; \
7134 		} \
7135 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7136 		if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7137 			val->i64 = val->i64 OP op2->u64; \
7138 		} else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7139 			val->i64 = val->i64 OP op2->u64; \
7140 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7141 			val->kind = MAX(val->kind, op2->kind); \
7142 			val->i64 = val->i64 OP op2->i64; \
7143 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7144 			val->kind = op2->kind; \
7145 			val->d = (zend_ffi_double)val->i64 OP op2->d; \
7146 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7147 			val->i64 = val->i64 OP op2->ch; \
7148 		} else { \
7149 			val->kind = ZEND_FFI_VAL_ERROR; \
7150 		} \
7151 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7152 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7153 			val->d = val->d OP (zend_ffi_double)op2->u64; \
7154 		} else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7155 			val->d = val->d OP (zend_ffi_double)op2->i64; \
7156 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7157 			val->kind = MAX(val->kind, op2->kind); \
7158 			val->d = val->d OP op2->d; \
7159 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7160 			val->d = val->d OP (zend_ffi_double)op2->ch; \
7161 		} else { \
7162 			val->kind = ZEND_FFI_VAL_ERROR; \
7163 		} \
7164 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7165 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7166 			val->kind = op2->kind; \
7167 			val->u64 = val->ch OP op2->u64; \
7168 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7169 			val->kind = ZEND_FFI_VAL_INT64; \
7170 			val->i64 = val->ch OP op2->i64; \
7171 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7172 			val->kind = op2->kind; \
7173 			val->d = (zend_ffi_double)val->ch OP op2->d; \
7174 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7175 			val->ch = val->ch OP op2->ch; \
7176 		} else { \
7177 			val->kind = ZEND_FFI_VAL_ERROR; \
7178 		} \
7179 	} else { \
7180 		val->kind = ZEND_FFI_VAL_ERROR; \
7181 	} \
7182 } while (0)
7183 
7184 #define zend_ffi_expr_int_math(val, op2, OP) do { \
7185 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7186 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7187 			val->kind = MAX(val->kind, op2->kind); \
7188 			val->u64 = val->u64 OP op2->u64; \
7189 		} else if (op2->kind == ZEND_FFI_VAL_INT32) { \
7190 			val->u64 = val->u64 OP op2->i64; \
7191 		} else if (op2->kind == ZEND_FFI_VAL_INT64) { \
7192 			val->u64 = val->u64 OP op2->i64; \
7193 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7194 			val->u64 = val->u64 OP (uint64_t)op2->d; \
7195 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7196 			val->u64 = val->u64 OP op2->ch; \
7197 		} else { \
7198 			val->kind = ZEND_FFI_VAL_ERROR; \
7199 		} \
7200 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7201 		if (op2->kind == ZEND_FFI_VAL_UINT32) { \
7202 			val->i64 = val->i64 OP op2->u64; \
7203 		} else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
7204 			val->i64 = val->i64 OP op2->u64; \
7205 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7206 			val->kind = MAX(val->kind, op2->kind); \
7207 			val->i64 = val->i64 OP op2->i64; \
7208 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7209 			val->u64 = val->u64 OP (int64_t)op2->d; \
7210 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7211 			val->i64 = val->i64 OP op2->ch; \
7212 		} else { \
7213 			val->kind = ZEND_FFI_VAL_ERROR; \
7214 		} \
7215 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7216 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7217 			val->kind = op2->kind; \
7218 			val->u64 = (uint64_t)val->d OP op2->u64; \
7219 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7220 			val->kind = op2->kind; \
7221 			val->i64 = (int64_t)val->d OP op2->i64; \
7222 		} else { \
7223 			val->kind = ZEND_FFI_VAL_ERROR; \
7224 		} \
7225 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7226 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7227 			val->kind = op2->kind; \
7228 			val->u64 = (uint64_t)val->ch OP op2->u64; \
7229 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7230 			val->kind = op2->kind; \
7231 			val->i64 = (int64_t)val->ch OP op2->u64; \
7232 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7233 			val->ch = val->ch OP op2->ch; \
7234 		} else { \
7235 			val->kind = ZEND_FFI_VAL_ERROR; \
7236 		} \
7237 	} else { \
7238 		val->kind = ZEND_FFI_VAL_ERROR; \
7239 	} \
7240 } while (0)
7241 
7242 #define zend_ffi_expr_cmp(val, op2, OP) do { \
7243 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
7244 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7245 			val->kind = ZEND_FFI_VAL_INT32; \
7246 			val->i64 = val->u64 OP op2->u64; \
7247 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7248 			val->kind = ZEND_FFI_VAL_INT32; \
7249 			val->i64 = val->u64 OP op2->u64; /*signed/unsigned */ \
7250 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7251 			val->kind = ZEND_FFI_VAL_INT32; \
7252 			val->i64 = (zend_ffi_double)val->u64 OP op2->d; \
7253 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7254 			val->kind = ZEND_FFI_VAL_INT32; \
7255 			val->i64 = val->u64 OP op2->d; \
7256 		} else { \
7257 			val->kind = ZEND_FFI_VAL_ERROR; \
7258 		} \
7259 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
7260 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7261 			val->kind = ZEND_FFI_VAL_INT32; \
7262 			val->i64 = val->i64 OP op2->i64; /* signed/unsigned */ \
7263 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7264 			val->kind = ZEND_FFI_VAL_INT32; \
7265 			val->i64 = val->i64 OP op2->i64; \
7266 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7267 			val->kind = ZEND_FFI_VAL_INT32; \
7268 			val->i64 = (zend_ffi_double)val->i64 OP op2->d; \
7269 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7270 			val->kind = ZEND_FFI_VAL_INT32; \
7271 			val->i64 = val->i64 OP op2->ch; \
7272 		} else { \
7273 			val->kind = ZEND_FFI_VAL_ERROR; \
7274 		} \
7275 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7276 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7277 			val->kind = ZEND_FFI_VAL_INT32; \
7278 			val->i64 = val->d OP (zend_ffi_double)op2->u64; \
7279 		} else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
7280 			val->kind = ZEND_FFI_VAL_INT32; \
7281 			val->i64 = val->d OP (zend_ffi_double)op2->i64; \
7282 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7283 			val->kind = ZEND_FFI_VAL_INT32; \
7284 			val->i64 = val->d OP op2->d; \
7285 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7286 			val->kind = ZEND_FFI_VAL_INT32; \
7287 			val->i64 = val->d OP (zend_ffi_double)op2->ch; \
7288 		} else { \
7289 			val->kind = ZEND_FFI_VAL_ERROR; \
7290 		} \
7291 	} else if (val->kind == ZEND_FFI_VAL_CHAR) { \
7292 		if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
7293 			val->kind = ZEND_FFI_VAL_INT32; \
7294 			val->i64 = val->ch OP op2->i64; /* signed/unsigned */ \
7295 		} else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
7296 			val->kind = ZEND_FFI_VAL_INT32; \
7297 			val->i64 = val->ch OP op2->i64; \
7298 		} else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
7299 			val->kind = ZEND_FFI_VAL_INT32; \
7300 			val->i64 = (zend_ffi_double)val->ch OP op2->d; \
7301 		} else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
7302 			val->kind = ZEND_FFI_VAL_INT32; \
7303 			val->i64 = val->ch OP op2->ch; \
7304 		} else { \
7305 			val->kind = ZEND_FFI_VAL_ERROR; \
7306 		} \
7307 	} else { \
7308 		val->kind = ZEND_FFI_VAL_ERROR; \
7309 	} \
7310 } while (0)
7311 
7312 void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3) /* {{{ */
7313 {
7314 	zend_ffi_expr_bool(val);
7315 	if (val->kind == ZEND_FFI_VAL_INT32) {
7316 		if (val->i64) {
7317 			*val = *op2;
7318 		} else {
7319 			*val = *op3;
7320 		}
7321 	}
7322 }
7323 /* }}} */
7324 
7325 void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7326 {
7327 	zend_ffi_expr_bool(val);
7328 	zend_ffi_expr_bool(op2);
7329 	if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7330 		val->i64 = val->i64 || op2->i64;
7331 	} else {
7332 		val->kind = ZEND_FFI_VAL_ERROR;
7333 	}
7334 }
7335 /* }}} */
7336 
7337 void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7338 {
7339 	zend_ffi_expr_bool(val);
7340 	zend_ffi_expr_bool(op2);
7341 	if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
7342 		val->i64 = val->i64 && op2->i64;
7343 	} else {
7344 		val->kind = ZEND_FFI_VAL_ERROR;
7345 	}
7346 }
7347 /* }}} */
7348 
7349 void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7350 {
7351 	zend_ffi_expr_int_math(val, op2, |);
7352 }
7353 /* }}} */
7354 
7355 void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7356 {
7357 	zend_ffi_expr_int_math(val, op2, ^);
7358 }
7359 /* }}} */
7360 
7361 void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7362 {
7363 	zend_ffi_expr_int_math(val, op2, &);
7364 }
7365 /* }}} */
7366 
7367 void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7368 {
7369 	zend_ffi_expr_cmp(val, op2, ==);
7370 }
7371 /* }}} */
7372 
7373 void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7374 {
7375 	zend_ffi_expr_cmp(val, op2, !=);
7376 }
7377 /* }}} */
7378 
7379 void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7380 {
7381 	zend_ffi_expr_cmp(val, op2, <);
7382 }
7383 /* }}} */
7384 
7385 void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7386 {
7387 	zend_ffi_expr_cmp(val, op2, >);
7388 }
7389 /* }}} */
7390 
7391 void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7392 {
7393 	zend_ffi_expr_cmp(val, op2, <=);
7394 }
7395 /* }}} */
7396 
7397 void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7398 {
7399 	zend_ffi_expr_cmp(val, op2, >=);
7400 }
7401 /* }}} */
7402 
7403 void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7404 {
7405 	zend_ffi_expr_int_math(val, op2, <<);
7406 }
7407 /* }}} */
7408 
7409 void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7410 {
7411 	zend_ffi_expr_int_math(val, op2, >>);
7412 }
7413 /* }}} */
7414 
7415 void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7416 {
7417 	zend_ffi_expr_math(val, op2, +);
7418 }
7419 /* }}} */
7420 
7421 void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7422 {
7423 	zend_ffi_expr_math(val, op2, -);
7424 }
7425 /* }}} */
7426 
7427 void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7428 {
7429 	zend_ffi_expr_math(val, op2, *);
7430 }
7431 /* }}} */
7432 
7433 void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7434 {
7435 	zend_ffi_expr_math(val, op2, /);
7436 }
7437 /* }}} */
7438 
7439 void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
7440 {
7441 	zend_ffi_expr_int_math(val, op2, %); // ???
7442 }
7443 /* }}} */
7444 
7445 void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7446 {
7447 	zend_ffi_finalize_type(dcl);
7448 	switch (ZEND_FFI_TYPE(dcl->type)->kind) {
7449 		case ZEND_FFI_TYPE_FLOAT:
7450 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7451 				val->kind = ZEND_FFI_VAL_FLOAT;
7452 				val->d = val->u64;
7453 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7454 				val->kind = ZEND_FFI_VAL_FLOAT;
7455 				val->d = val->i64;
7456 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7457 				val->kind = ZEND_FFI_VAL_FLOAT;
7458 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7459 				val->kind = ZEND_FFI_VAL_FLOAT;
7460 				val->d = val->ch;
7461 			} else {
7462 				val->kind = ZEND_FFI_VAL_ERROR;
7463 			}
7464 			break;
7465 		case ZEND_FFI_TYPE_DOUBLE:
7466 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7467 				val->kind = ZEND_FFI_VAL_DOUBLE;
7468 				val->d = val->u64;
7469 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7470 				val->kind = ZEND_FFI_VAL_DOUBLE;
7471 				val->d = val->i64;
7472 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7473 				val->kind = ZEND_FFI_VAL_DOUBLE;
7474 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7475 				val->kind = ZEND_FFI_VAL_DOUBLE;
7476 				val->d = val->ch;
7477 			} else {
7478 				val->kind = ZEND_FFI_VAL_ERROR;
7479 			}
7480 			break;
7481 #ifdef HAVE_LONG_DOUBLE
7482 		case ZEND_FFI_TYPE_LONGDOUBLE:
7483 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7484 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7485 				val->d = val->u64;
7486 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7487 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7488 				val->d = val->i64;
7489 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7490 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7491 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7492 				val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7493 				val->d = val->ch;
7494 			} else {
7495 				val->kind = ZEND_FFI_VAL_ERROR;
7496 			}
7497 			break;
7498 #endif
7499 		case ZEND_FFI_TYPE_UINT8:
7500 		case ZEND_FFI_TYPE_UINT16:
7501 		case ZEND_FFI_TYPE_UINT32:
7502 		case ZEND_FFI_TYPE_BOOL:
7503 			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) {
7504 				val->kind = ZEND_FFI_VAL_UINT32;
7505 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7506 				val->kind = ZEND_FFI_VAL_UINT32;
7507 				val->u64 = val->d;
7508 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7509 				val->kind = ZEND_FFI_VAL_UINT32;
7510 				val->u64 = val->ch;
7511 			} else {
7512 				val->kind = ZEND_FFI_VAL_ERROR;
7513 			}
7514 			break;
7515 		case ZEND_FFI_TYPE_SINT8:
7516 		case ZEND_FFI_TYPE_SINT16:
7517 		case ZEND_FFI_TYPE_SINT32:
7518 			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) {
7519 				val->kind = ZEND_FFI_VAL_INT32;
7520 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7521 				val->kind = ZEND_FFI_VAL_INT32;
7522 				val->i64 = val->d;
7523 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7524 				val->kind = ZEND_FFI_VAL_INT32;
7525 				val->i64 = val->ch;
7526 			} else {
7527 				val->kind = ZEND_FFI_VAL_ERROR;
7528 			}
7529 			break;
7530 		case ZEND_FFI_TYPE_UINT64:
7531 			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) {
7532 				val->kind = ZEND_FFI_VAL_UINT64;
7533 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7534 				val->kind = ZEND_FFI_VAL_UINT64;
7535 				val->u64 = val->d;
7536 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7537 				val->kind = ZEND_FFI_VAL_UINT64;
7538 				val->u64 = val->ch;
7539 			} else {
7540 				val->kind = ZEND_FFI_VAL_ERROR;
7541 			}
7542 			break;
7543 		case ZEND_FFI_TYPE_SINT64:
7544 			if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7545 				val->kind = ZEND_FFI_VAL_CHAR;
7546 				val->ch = val->u64;
7547 			} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7548 				val->kind = ZEND_FFI_VAL_CHAR;
7549 				val->ch = val->i64;
7550 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7551 				val->kind = ZEND_FFI_VAL_CHAR;
7552 				val->ch = val->d;
7553 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7554 			} else {
7555 				val->kind = ZEND_FFI_VAL_ERROR;
7556 			}
7557 			break;
7558 		case ZEND_FFI_TYPE_CHAR:
7559 			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) {
7560 				val->kind = ZEND_FFI_VAL_UINT32;
7561 			} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7562 				val->kind = ZEND_FFI_VAL_UINT32;
7563 				val->u64 = val->d;
7564 			} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7565 				val->kind = ZEND_FFI_VAL_UINT32;
7566 				val->u64 = val->ch;
7567 			} else {
7568 				val->kind = ZEND_FFI_VAL_ERROR;
7569 			}
7570 			break;
7571 		default:
7572 			val->kind = ZEND_FFI_VAL_ERROR;
7573 			break;
7574 	}
7575 	zend_ffi_type_dtor(dcl->type);
7576 }
7577 /* }}} */
7578 
7579 void zend_ffi_expr_plus(zend_ffi_val *val) /* {{{ */
7580 {
7581 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7582 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7583 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7584 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7585 	} else {
7586 		val->kind = ZEND_FFI_VAL_ERROR;
7587 	}
7588 }
7589 /* }}} */
7590 
7591 void zend_ffi_expr_neg(zend_ffi_val *val) /* {{{ */
7592 {
7593 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7594 		val->u64 = -val->u64;
7595 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7596 		val->i64 = -val->i64;
7597 	} else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7598 		val->d = -val->d;
7599 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7600 		val->ch = -val->ch;
7601 	} else {
7602 		val->kind = ZEND_FFI_VAL_ERROR;
7603 	}
7604 }
7605 /* }}} */
7606 
7607 void zend_ffi_expr_bw_not(zend_ffi_val *val) /* {{{ */
7608 {
7609 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
7610 		val->u64 = ~val->u64;
7611 	} else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
7612 		val->i64 = ~val->i64;
7613 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7614 		val->ch = ~val->ch;
7615 	} else {
7616 		val->kind = ZEND_FFI_VAL_ERROR;
7617 	}
7618 }
7619 /* }}} */
7620 
7621 void zend_ffi_expr_bool_not(zend_ffi_val *val) /* {{{ */
7622 {
7623 	zend_ffi_expr_bool(val);
7624 	if (val->kind == ZEND_FFI_VAL_INT32) {
7625 		val->i64 = !val->i64;
7626 	}
7627 }
7628 /* }}} */
7629 
7630 void zend_ffi_expr_sizeof_val(zend_ffi_val *val) /* {{{ */
7631 {
7632 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7633 		val->kind = ZEND_FFI_VAL_UINT32;
7634 		val->u64 = zend_ffi_type_uint32.size;
7635 	} else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7636 		val->kind = ZEND_FFI_VAL_UINT32;
7637 		val->u64 = zend_ffi_type_uint64.size;
7638 	} else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7639 		val->kind = ZEND_FFI_VAL_UINT32;
7640 		val->u64 = zend_ffi_type_float.size;
7641 	} else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7642 		val->kind = ZEND_FFI_VAL_UINT32;
7643 		val->u64 = zend_ffi_type_double.size;
7644 	} else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7645 		val->kind = ZEND_FFI_VAL_UINT32;
7646 #ifdef _WIN32
7647 		val->u64 = zend_ffi_type_double.size;
7648 #else
7649 		val->u64 = zend_ffi_type_long_double.size;
7650 #endif
7651 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7652 		val->kind = ZEND_FFI_VAL_UINT32;
7653 		val->u64 = zend_ffi_type_char.size;
7654 	} else if (val->kind == ZEND_FFI_VAL_STRING) {
7655 		if (memchr(val->str, '\\', val->len)) {
7656 			// TODO: support for escape sequences ???
7657 			val->kind = ZEND_FFI_VAL_ERROR;
7658 		} else {
7659 			val->kind = ZEND_FFI_VAL_UINT32;
7660 			val->u64 = val->len + 1;
7661 		}
7662 	} else {
7663 		val->kind = ZEND_FFI_VAL_ERROR;
7664 	}
7665 }
7666 /* }}} */
7667 
7668 void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7669 {
7670 	zend_ffi_type *type;
7671 
7672 	zend_ffi_finalize_type(dcl);
7673 	type = ZEND_FFI_TYPE(dcl->type);
7674 	val->kind = (type->size > 0xffffffff) ? ZEND_FFI_VAL_UINT64 : ZEND_FFI_VAL_UINT32;
7675 	val->u64 = type->size;
7676 	zend_ffi_type_dtor(dcl->type);
7677 }
7678 /* }}} */
7679 
7680 void zend_ffi_expr_alignof_val(zend_ffi_val *val) /* {{{ */
7681 {
7682 	if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
7683 		val->kind = ZEND_FFI_VAL_UINT32;
7684 		val->u64 = zend_ffi_type_uint32.align;
7685 	} else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
7686 		val->kind = ZEND_FFI_VAL_UINT32;
7687 		val->u64 = zend_ffi_type_uint64.align;
7688 	} else if (val->kind == ZEND_FFI_VAL_FLOAT) {
7689 		val->kind = ZEND_FFI_VAL_UINT32;
7690 		val->u64 = zend_ffi_type_float.align;
7691 	} else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
7692 		val->kind = ZEND_FFI_VAL_UINT32;
7693 		val->u64 = zend_ffi_type_double.align;
7694 #ifdef HAVE_LONG_DOUBLE
7695 	} else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
7696 		val->kind = ZEND_FFI_VAL_UINT32;
7697 		val->u64 = zend_ffi_type_long_double.align;
7698 #endif
7699 	} else if (val->kind == ZEND_FFI_VAL_CHAR) {
7700 		val->kind = ZEND_FFI_VAL_UINT32;
7701 		val->u64 = zend_ffi_type_char.size;
7702 	} else if (val->kind == ZEND_FFI_VAL_STRING) {
7703 		val->kind = ZEND_FFI_VAL_UINT32;
7704 		val->u64 = _Alignof(char*);
7705 	} else {
7706 		val->kind = ZEND_FFI_VAL_ERROR;
7707 	}
7708 }
7709 /* }}} */
7710 
7711 void zend_ffi_expr_alignof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
7712 {
7713 	zend_ffi_finalize_type(dcl);
7714 	val->kind = ZEND_FFI_VAL_UINT32;
7715 	val->u64 = ZEND_FFI_TYPE(dcl->type)->align;
7716 	zend_ffi_type_dtor(dcl->type);
7717 }
7718 /* }}} */
7719 
7720 void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len) /* {{{ */
7721 {
7722 	int u = 0;
7723 	int l = 0;
7724 
7725 	if (str[str_len-1] == 'u' || str[str_len-1] == 'U') {
7726 		u = 1;
7727 		if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7728 			l = 1;
7729 			if (str[str_len-3] == 'l' || str[str_len-3] == 'L') {
7730 				l = 2;
7731 			}
7732 		}
7733 	} else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7734 		l = 1;
7735 		if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
7736 			l = 2;
7737 			if (str[str_len-3] == 'u' || str[str_len-3] == 'U') {
7738 				u = 1;
7739 			}
7740 		} else if (str[str_len-2] == 'u' || str[str_len-2] == 'U') {
7741 			u = 1;
7742 		}
7743 	}
7744 	if (u) {
7745 		val->u64 = strtoull(str, NULL, base);
7746 		if (l == 0) {
7747 			val->kind = ZEND_FFI_VAL_UINT32;
7748 		} else if (l == 1) {
7749 			val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_UINT32 : ZEND_FFI_VAL_UINT64;
7750 		} else if (l == 2) {
7751 			val->kind = ZEND_FFI_VAL_UINT64;
7752 		}
7753 	} else {
7754 		val->i64 = strtoll(str, NULL, base);
7755 		if (l == 0) {
7756 			val->kind = ZEND_FFI_VAL_INT32;
7757 		} else if (l == 1) {
7758 			val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_INT32 : ZEND_FFI_VAL_INT64;
7759 		} else if (l == 2) {
7760 			val->kind = ZEND_FFI_VAL_INT64;
7761 		}
7762 	}
7763 }
7764 /* }}} */
7765 
7766 void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7767 {
7768 	val->d = strtold(str, NULL);
7769 	if (str[str_len-1] == 'f' || str[str_len-1] == 'F') {
7770 		val->kind = ZEND_FFI_VAL_FLOAT;
7771 	} else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
7772 		val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
7773 	} else {
7774 		val->kind = ZEND_FFI_VAL_DOUBLE;
7775 	}
7776 }
7777 /* }}} */
7778 
7779 void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7780 {
7781 	if (str[0] != '\"') {
7782 		val->kind = ZEND_FFI_VAL_ERROR;
7783 	} else {
7784 		val->kind = ZEND_FFI_VAL_STRING;
7785 		val->str = str + 1;
7786 		val->len = str_len - 2;
7787 	}
7788 }
7789 /* }}} */
7790 
7791 void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
7792 {
7793 	int n;
7794 
7795 	if (str[0] != '\'') {
7796 		val->kind = ZEND_FFI_VAL_ERROR;
7797 	} else {
7798 		val->kind = ZEND_FFI_VAL_CHAR;
7799 		if (str_len == 3) {
7800 			val->ch = str[1];
7801 		} else if (str[1] == '\\') {
7802 			if (str[2] == 'a') {
7803 			} else if (str[2] == 'b' && str_len == 4) {
7804 				val->ch = '\b';
7805 			} else if (str[2] == 'f' && str_len == 4) {
7806 				val->ch = '\f';
7807 			} else if (str[2] == 'n' && str_len == 4) {
7808 				val->ch = '\n';
7809 			} else if (str[2] == 'r' && str_len == 4) {
7810 				val->ch = '\r';
7811 			} else if (str[2] == 't' && str_len == 4) {
7812 				val->ch = '\t';
7813 			} else if (str[2] == 'v' && str_len == 4) {
7814 				val->ch = '\v';
7815 			} else if (str[2] >= '0' && str[2] <= '7') {
7816 				n = str[2] - '0';
7817 				if (str[3] >= '0' && str[3] <= '7') {
7818 					n = n * 8 + (str[3] - '0');
7819 					if ((str[4] >= '0' && str[4] <= '7') && str_len == 6) {
7820 						n = n * 8 + (str[4] - '0');
7821 					} else if (str_len != 5) {
7822 						val->kind = ZEND_FFI_VAL_ERROR;
7823 					}
7824 				} else if (str_len != 4) {
7825 					val->kind = ZEND_FFI_VAL_ERROR;
7826 				}
7827 				if (n <= 0xff) {
7828 					val->ch = n;
7829 				} else {
7830 					val->kind = ZEND_FFI_VAL_ERROR;
7831 				}
7832 			} else if (str[2] == 'x') {
7833 				if (str[3] >= '0' && str[3] <= '9') {
7834 					n = str[3] - '0';
7835 				} else if (str[3] >= 'A' && str[3] <= 'F') {
7836 					n = str[3] - 'A';
7837 				} else if (str[3] >= 'a' && str[3] <= 'f') {
7838 					n = str[3] - 'a';
7839 				} else {
7840 					val->kind = ZEND_FFI_VAL_ERROR;
7841 					return;
7842 				}
7843 				if ((str[4] >= '0' && str[4] <= '9') && str_len == 6) {
7844 					n = n * 16 + (str[4] - '0');
7845 				} else if ((str[4] >= 'A' && str[4] <= 'F') && str_len == 6) {
7846 					n = n * 16 + (str[4] - 'A');
7847 				} else if ((str[4] >= 'a' && str[4] <= 'f') && str_len == 6) {
7848 					n = n * 16 + (str[4] - 'a');
7849 				} else if (str_len != 5) {
7850 					val->kind = ZEND_FFI_VAL_ERROR;
7851 					return;
7852 				}
7853 				val->ch = n;
7854 			} else if (str_len == 4) {
7855 				val->ch = str[2];
7856 			} else {
7857 				val->kind = ZEND_FFI_VAL_ERROR;
7858 			}
7859 		} else {
7860 			val->kind = ZEND_FFI_VAL_ERROR;
7861 		}
7862 	}
7863 }
7864 /* }}} */
7865