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