2017-07-06 69 views
2

我不能在線程內emalloc內存任意數量的內存,而不會觸發https://github.com/php/php-src/blob/master/Zend/zend_alloc.c#L2409上的段錯誤。在PHP擴展中使用線程中的emalloc時發生Segfault

只有在PHP(ZTS)的線程安全版本上運行時纔會出現段錯誤(諷刺)。

當在普通的NTS版本上運行時,一切正常。

下面是一些可用於重現問題的代碼(我使用php-cpp簡化了擴展的創建)。

void* test(void* wrapper){ 
    emalloc(sizeof(Php::Value)); 
    return NULL; 
} 

void VoIP::__construct() 
{ 
    pthread_t a;  
    pthread_create(&a, NULL, test, this); 
} 
extern "C" { 
PHPCPP_EXPORT void *get_module() 
{ 
    static Php::Extension extension("php-libtgvoip", "1.0"); 

    Php::Class<VoIP> voip("VoIP"); 

    voip.method<&VoIP::__construct>("__construct", Php::Public | Php::Final); 
    Php::Namespace danog("danog"); 
    Php::Namespace MadelineProto("MadelineProto"); 

    MadelineProto.add(std::move(voip)); 
    danog.add(std::move(MadelineProto)); 
    extension.add(std::move(danog)); 

    return extension; 
} 
} 

部首:

#include <php.h> 
#include <php_ini.h> 
#include <ext/standard/info.h> 
#include <phpcpp.h> 

class VoIP : public Php::Base { 
public: 

    void __construct(); 

} 

的實例化的\ danog \ MadelineProto \的VoIP類引發段錯誤,在測試引起emalloc():

Thread 2 "php" received signal SIGSEGV, Segmentation fault. 
[Switching to Thread 0x7fffe91ff700 (LWP 4267)] 
0x0000555555cfc7ed in _emalloc (size=32, __zend_filename=0x7fffed9c88a8 "main.cpp", __zend_lineno=30, __zend_orig_filename=0x0, __zend_orig_lineno=0) 
    at /root/php-src/Zend/zend_alloc.c:2409 
2409   if (UNEXPECTED(AG(mm_heap)->use_custom_heap)) { 
(gdb) backtrace 
#0 0x0000555555cfc7ed in _emalloc (size=32, __zend_filename=0x7fffed9c88a8 "main.cpp", __zend_lineno=30, __zend_orig_filename=0x0, __zend_orig_lineno=0) 
    at /root/php-src/Zend/zend_alloc.c:2409 
#1 0x00007fffed94e80e in test (wrapper=0x555556a73310) at main.cpp:30 
#2 0x00007ffff572a494 in start_thread (arg=0x7fffe91ff700) at pthread_create.c:333 
#3 0x00007ffff206eaff in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:97 
(gdb) 

完整的源代碼可以發現@https://github.com/danog/php-libtgvoip

回答

2

我的答案可能相當明顯,但只是不使用emalloc以及php線程之外的所有其他php/zend方法。無論ZTS是打開還是關閉,您的代碼都會失敗。看看線下應用程序崩潰:

if (UNEXPECTED(AG(mm_heap)->use_custom_heap)) 

AG宣佈爲

#ifdef ZTS 

static int alloc_globals_id; 
#define AG(v) ZEND_TSRMG(alloc_globals_id, zend_alloc_globals *, v) 

#else 

#define AG(v) (alloc_globals.v) 
static zend_alloc_globals alloc_globals; 

#endif 

當ZTS上會有一個直線段錯誤,因爲調用線程沒有正確初始化爲PHP線程使用TSRMG(線程安全資源管理器),當ZTS關閉時,會有競爭條件來修改全局變量。

+0

謝謝你的回答!但是,我想知道如何將線程註冊爲php線程:只需調用tsrm_startup似乎不起作用。 – Danogentili

+0

@Danogentili你根本就沒有。我懷疑即使你將自己的線程初始化爲php線程,你也無法將php對象從它傳遞到原始線程。此外,使用php對象並在真正的php線程外調用php函數可能是一個糟糕的主意。你爲什麼要這樣做?在編寫php擴展時,最好儘可能少地跨越語言邊界。 – VTT

+0

我需要調用某些PHP回調,同時傳遞整數作爲參數。我一直在想使用php pthreads擴展(https://github.com/krakjoe/pthreads)的代碼,但我仍然沒有弄清楚它是如何管理線程的。 – Danogentili