2015-12-29 21 views
6

Sto imparando scrittura estensione PHP per fare alcune vecchie estensioni lavorano con PHP 7.Zend: come distruggere correttamente un oggetto personalizzato in PHP 7?

Ho provato a modificare l'estensione del campione dal http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/ ma continuava a provocare segfaults quando distruggendo l'oggetto personalizzato. Tutte le altre funzioni hanno funzionato normalmente. (Car è sostituito dal BDict nel mio codice.)

Ecco il mio codice:

#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; 
} 

Cambiando la sequenza delle due linee e l'esecuzione di $dict = new BDict(10); unset($dict);, sono riuscito ad ottenere le informazioni di errore per entrambi.

Sono nuovo per le estensioni PHP e sono davvero confuso ora. Qualsiasi aiuto sarebbe molto apprezzato, grazie.

UPDATE

ho notato che l'oggetto effettivamente cambiato dopo la conversione in bdict_free_storage() che era ovviamente sbagliato, ma non avevo idea di come risolvere il problema.

Ecco il registro di debug. È possibile vedere che i dati di intern e object in bdict_free_storage() sono completamente diversi e l'indirizzo di BDict è errato.

(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}}}}} 

ho trovato alcuni altri usando

static void bdict_free_storage(void *object TSRMLS_DC) 

invece di

static void bdict_free_storage(zend_object *object TSRMLS_DC) 

ho provato ma mi ha dato un errore di compilazione.

/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

Come su: '$ dict = null; unset ($ dict); '? – Hackerman

+0

Non si tratta semplicemente del fatto che hai usato '(bdict_object *) object' invece di' php_bdict_object_fetch_object'? – NikiC

+1

Vorrei anche suggerire di eseguire l'inizializzazione di 'bdict_object_handlers' in MINIT (attualmente stai assegnando due membri in create_object) – NikiC

risposta

0

Modifica "zend_object_handlers bdict_object_handlers;" a "zend_object_handlers bdict_object_handlers = std_object_handlers;" puoi risolvere questo problema perché non hai inizializzato la struttura.