gsoap相关崩溃分析

一、崩溃背景      

        实际项目中,新版程序发生了崩溃。查看崩溃堆栈,发现崩溃在了DeviceBindingProxy或MediaBindingProxy等于Gsoap相关的对象的析构中。检查代码后未发现明显问题。旧版本程序与新版程序不同在于,新版程序使用多线程方式调用Gsoap。因此怀疑与多线程有关。

二、好好读Gsoap文档

        通过阅读官方文档,发现了至关重要的一段:

In addition to the source code shown in the previous section, all OpenSSL versions prior to 1.1.0 require locks to support multi-threading. To do so we recommend to use the gSOAP portable threads in plugin/threads.h and plugin/threads.c located in the gSOAP package. Then add OpenSSL locks as follows:

#include "plugin/threads.h"

soap_ssl_init();           // start your program by initializing SSL and setting up locks
// soap_ssl_no_init();     // or prevent init OpenSSL when already initialized elsewhere in an application
if (CRYPTO_thread_setup()) // OpenSSL thread mutex setup
  ... // error

... // code goes here

CRYPTO_thread_cleanup();   // OpenSSL thread mutex cleanup
exit(EXIT_SUCCESS);        // exit program

The set up and clean up should be done only once in your application. The OpenSSL-specific code for these set up and clean up functions is not shown here. Get it from thread_setup.c to add to your code.

OpenSSL 1.1.0 and greater does not require these locks to be set up. If you are not sure which version of OpenSSL you may be using with your multi-threaded application, then set up the locks as shown.

三、修改代码

增加如下代码:

soap_ssl_init(); /* init OpenSSL (skipping this or calling multiple times is OK, since the engine will init SSL automatically) */
/* soap_ssl_noinit(); */ /* do not init OpenSSL (if SSL is already initialized elsewhere in this application) */
if (CRYPTO_thread_setup()) /* old OpenSSL < 1.1.0 thread mutex setup */
{
    fprintf(stderr, "Cannot setup thread mutex for OpenSSL\n");
    return;
}

struct CRYPTO_dynlock_value
{
    MUTEX_TYPE mutex;
};

static MUTEX_TYPE *mutex_buf = NULL;

static struct CRYPTO_dynlock_value *dyn_create_function(const char *file, int line)
{
    struct CRYPTO_dynlock_value *value;
    (void)file; (void)line;
    value = (struct CRYPTO_dynlock_value*)OPENSSL_malloc(sizeof(struct CRYPTO_dynlock_value));
    if (value)
        MUTEX_SETUP(value->mutex);
    return value;
}

static void dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, const char *file, int line)
{
    (void)file; (void)line;
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(l->mutex);
    else
        MUTEX_UNLOCK(l->mutex);
}

static void dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int line)
{
    (void)file; (void)line;
    MUTEX_CLEANUP(l->mutex);
    OPENSSL_free(l);
}

static void locking_function(int mode, int n, const char *file, int line)
{
    (void)file; (void)line;
    if (mode & CRYPTO_LOCK)
        MUTEX_LOCK(mutex_buf[n]);
    else
        MUTEX_UNLOCK(mutex_buf[n]);
}

static unsigned long id_function()
{
    return (unsigned long)THREAD_ID;
}

static int CRYPTO_thread_setup()
{
    int i;
    mutex_buf = (MUTEX_TYPE*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(MUTEX_TYPE));
    if (!mutex_buf)
        return SOAP_EOM;
    for (i = 0; i < CRYPTO_num_locks(); i++)
        MUTEX_SETUP(mutex_buf[i]);
    CRYPTO_set_id_callback(id_function);
    CRYPTO_set_locking_callback(locking_function);
    CRYPTO_set_dynlock_create_callback(dyn_create_function);
    CRYPTO_set_dynlock_lock_callback(dyn_lock_function);
    CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function);
    return SOAP_OK;
}

static void CRYPTO_thread_cleanup()
{
    int i;
    if (!mutex_buf)
        return;
    CRYPTO_set_id_callback(NULL);
    CRYPTO_set_locking_callback(NULL);
    CRYPTO_set_dynlock_create_callback(NULL);
    CRYPTO_set_dynlock_lock_callback(NULL);
    CRYPTO_set_dynlock_destroy_callback(NULL);
    for (i = 0; i < CRYPTO_num_locks(); i++)
        MUTEX_CLEANUP(mutex_buf[i]);
    OPENSSL_free(mutex_buf);
    mutex_buf = NULL;
}
增加后不再崩溃。

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值