2015-12-29 1 views
6

J'apprends l'écriture d'extension PHP afin de faire quelques vieilles extensions fonctionnent avec PHP 7.Zend: Comment détruire correctement un objet personnalisé en PHP 7?

J'ai essayé de modifier l'extension de l'échantillon de http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/, mais il a continué provoquant segfaults quand destructing l'objet personnalisé. Toutes les autres fonctions ont fonctionné normalement. (Car est remplacé par BDict dans mon code.)

Voici mon code:

#define Z_BDICT_OBJ_P(zv) php_bdict_object_fetch_object(Z_OBJ_P(zv)) 

zend_object_handlers bdict_object_handlers; 

typedef struct _bdict_object { 
    BDict *bdict_data; 
    zend_object std; 
} bdict_object; 

zend_class_entry *bdict_ce; 

static void bdict_free_storage(zend_object *object TSRMLS_DC) 
{ 
    bdict_object *intern = (bdict_object *)object; 

    // ***Both the following two lines will cause segfault*** 
    delete intern->bdict_data; 
    zend_object_std_dtor(&intern->std TSRMLS_CC); 
} 

zend_object * bdict_object_new(zend_class_entry *ce TSRMLS_DC) 
{ 
    bdict_object *intern = (bdict_object *)ecalloc(1, 
      sizeof(bdict_object) + 
      zend_object_properties_size(ce)); 

    zend_object_std_init(&intern->std, ce TSRMLS_CC); 
    object_properties_init(&intern->std, ce); 

    intern->std.handlers = &bdict_object_handlers; 

    return &intern->std; 
} 

static inline bdict_object * php_bdict_object_fetch_object(zend_object *obj) 
{ 
    return (bdict_object *)((char *)obj - XtOffsetOf(bdict_object, std)); 
} 

PHP_METHOD(BDict, __construct) 
{ 
    long maxGear; 
    BDict *bdict = NULL; 

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) { 
     RETURN_NULL(); 
    } 

    bdict = new BDict(maxGear); 
    bdict_object *intern = Z_BDICT_OBJ_P(getThis()); 
    intern->bdict_data = bdict; 
} 

PHP_MINIT_FUNCTION(bencode) 
{ 
    zend_class_entry ce; 
    INIT_CLASS_ENTRY(ce, "BDict", bdict_methods); 
    bdict_ce = zend_register_internal_class(&ce TSRMLS_CC); 
    bdict_ce->create_object = bdict_object_new; 

    memcpy(&bdict_object_handlers, 
      zend_get_std_object_handlers(), sizeof(zend_object_handlers)); 

    bdict_object_handlers.offset = XtOffsetOf(bdict_object, std); 
    bdict_object_handlers.free_obj = bdict_free_storage; 

    return SUCCESS; 
} 

En changeant la séquence des deux lignes et l'exécution $dict = new BDict(10); unset($dict);, j'ai réussi à obtenir les informations d'erreur pour les deux d'entre eux.

/***** delete intern->bdict_data; *****/ 
Starting program: /opt/php-7.0.1/bin/php test.php 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 

Program received signal SIGSEGV, Segmentation fault. 
__GI___libc_free (mem=0xc002180800000001) at malloc.c:2933 

/***** zend_object_std_dtor(&intern->std TSRMLS_CC); *****/ 
Starting program: /opt/php-7.0.1/bin/php test.php 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000a45890 in zend_object_std_dtor (object=0x7ffff4001c90) at /home/frederick/php-7.0.1/Zend/zend_objects.c:59 
59      if (EXPECTED(!(GC_FLAGS(object->properties) & IS_ARRAY_IMMUTABLE))) { 

Je suis nouveau sur les extensions PHP et je suis vraiment confus maintenant. Toute aide serait grandement appréciée, merci.

MISE À JOUR

J'ai remarqué que l'objet réellement changé après la conversion en bdict_free_storage() qui était manifestement faux, mais je ne savais pas sur la façon de le corriger.

Voici le journal de débogage. Vous pouvez voir que les données de intern et object dans bdict_free_storage() sont totalement différentes et l'adresse de BDict est fausse.

(gdb) b bencode.cc:20 // bdict_free_storage():   bdict_object *intern = (bdict_object *)object; 
Breakpoint 1 at 0x7ffff36de608: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 20. 
(gdb) b bencode.cc:54 // PHP_METHOD(BDict, __construct): intern->bdict_data = bdict; 
Breakpoint 2 at 0x7ffff36de77e: file /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc, line 54. 
(gdb) r 
Starting program: /opt/php-7.0.1/bin/php test.php 
[Thread debugging using libthread_db enabled] 
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1". 

Breakpoint 2, zim_BDict___construct (execute_data=0x7ffff40140d0, return_value=0x7ffff40140b0) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:54 
54   intern->bdict_data = bdict; 
(gdb) n 
55  } 
(gdb) p intern->bdict_data 
$1 = (BDict *) 0x150c530 
(gdb) c 
Continuing. 

Breakpoint 1, bdict_free_storage (object=0x7ffff4001c88) at /home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:20 
20   bdict_object *intern = (bdict_object *)object; 
(gdb) n 
21   zend_object_std_dtor(&intern->std TSRMLS_CC); 
(gdb) p *object  // type = 8 means IS_OBJECT 
$2 = {gc = {refcount = 1, u = {v = {type = 8 '\b', flags = 24 '\030', gc_info = 49154}, type_info = 3221362696}}, handle = 1, ce = 0x14fe6e0, 
    handlers = 0x7ffff38e0300 <bdict_object_handlers>, properties = 0x0, properties_table = {{value = {lval = 48, dval = 2.3715151000379834e-322, counted = 0x30, str = 0x30, arr = 0x30, 
     obj = 0x30, res = 0x30, ref = 0x30, ast = 0x30, zv = 0x30, ptr = 0x30, ce = 0x30, func = 0x30, ww = {w1 = 48, w2 = 0}}, u1 = {v = {type = 232 '\350', type_flags = 237 '\355', 
      const_flags = 109 'm', reserved = 243 '\363'}, type_info = 4084067816}, u2 = {var_flags = 32767, next = 32767, cache_slot = 32767, lineno = 32767, num_args = 32767, 
     fe_pos = 32767, fe_iter_idx = 32767}}}} 
(gdb) p *intern  // type = 0 means IS_UNDEF, all other data are also different 
$3 = {bdict_data = 0xc002180800000001, std = {gc = {refcount = 1, u = {v = {type = 0 '\000', flags = 0 '\000', gc_info = 0}, type_info = 0}}, handle = 22013664, 
    ce = 0x7ffff38e0300 <bdict_object_handlers>, handlers = 0x0, properties = 0x30, properties_table = {{value = {lval = 140737277455848, dval = 6.9533453880162249e-310, 
      counted = 0x7ffff36dede8, str = 0x7ffff36dede8, arr = 0x7ffff36dede8, obj = 0x7ffff36dede8, res = 0x7ffff36dede8, ref = 0x7ffff36dede8, ast = 0x7ffff36dede8, zv = 0x7ffff36dede8, 
      ptr = 0x7ffff36dede8, ce = 0x7ffff36dede8, func = 0x7ffff36dede8, ww = {w1 = 4084067816, w2 = 32767}}, u1 = {v = {type = 0 '\000', type_flags = 131 '\203', 
      const_flags = 3 '\003', reserved = 1 '\001'}, type_info = 17007360}, u2 = {var_flags = 0, next = 0, cache_slot = 0, lineno = 0, num_args = 0, fe_pos = 0, fe_iter_idx = 0}}}}} 

que j'ai trouvé d'autres en utilisant

static void bdict_free_storage(void *object TSRMLS_DC) 

au lieu de

static void bdict_free_storage(zend_object *object TSRMLS_DC) 

Je l'ai essayé, mais il m'a donné une erreur de compilation.

/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc: In function ‘int zm_startup_bencode(int, int)’: 
/home/frederick/php-7.0.1/ext/php-bencode/bencode.cc:131:36: error: invalid conversion from ‘void (*)(void*)’ to ‘zend_object_free_obj_t {aka void (*)(_zend_object*)}’ [-fpermissive] 
    bdict_object_handlers.free_obj = bdict_free_storage; 
+0

Que diriez-vous de: '$ dict = null; désactivé ($ dict); – Hackerman

+0

Le problème n'est-il pas simplement que vous avez utilisé l'objet '(bdict_object *)' au lieu de' php_bdict_object_fetch_object'? – NikiC

+1

Je suggère également de faire toute l'initialisation 'bdict_object_handlers' dans MINIT (vous êtes en train d'assigner deux membres dans create_object) – NikiC

Répondre

0

Modifier "zend_object_handlers bdict_object_handlers;" à "zend_object_handlers bdict_object_handlers = std_object_handlers;" pouvez résoudre ce problème car vous n'avez pas initialisé la structure.