我在测试多线程(pthreads)应用程序时遇到问题,Helgrind在libcrypto.1.0.0中报告了CRYPTO_malloc()内的数百个可能的数据争用。
我已阅读并完全理解所有可用文档,包括Linux网络编程指南第255-259页和http://www.openssl.org/docs/crypto/threads.html。
我的代码正在初始化静态和动态锁结构和回调,并注册回调线程ID:
CRYPTO_THREADID_set_callback(ssl_mitm_thread_id);
CRYPTO_set_dynlock_create_callback(ssl_mitm_dyn_create_lock);
CRYPTO_set_dynlock_lock_callback(ssl_mitm_dyn_locking_callback);
CRYPTO_set_dynlock_destroy_callback(ssl_mitm_dyn_destroy_lock);
ssl_mitm_lock_mutexes = (pthread_mutex_t*)malloc(CRYPTO_num_locks() *
sizeof(pthread_mutex_t));
for(i = 0; i < CRYPTO_num_locks(); i++) {
pthread_mutex_init(&ssl_mitm_lock_mutexes[i], NULL);
}
CRYPTO_set_locking_callback(ssl_mitm_locking_callback);
SSL_library_init();
SSL_load_error_strings();
...etc...
我已将调试语句添加到锁定回调函数中,而openSSL仅调用折旧的CRYPTO_set_locking_callback(),而不使用新的动态锁定接口。
即便如此,它正在调用旧的静态锁定函数,因此正在尝试进行线程同步,但是Helgrind仍然认为有很多可能的数据争用。大多数(如果不是全部)都在CRYPTO_malloc()中。
那么,这个Helgrind是否会过度热心,还是OpenSSL / libcrypto中的一个错误?
e.g。
==20093== ----------------------------------------------------------------
==20093==
==20093== Possible data race during write of size 4 at 0x63BA368 by thread #3
==20093== Locks held: none
==20093== at 0x604F0FE: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==20093== by 0x57F4186: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093== by 0x57D20C4: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093== by 0x57D62E1: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093== by 0x57DF0B6: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
[snip] (SSL_connect() called)
==20093==
==20093== This conflicts with a previous write of size 4 by thread #6
==20093== Locks held: none
==20093== at 0x604F0FE: CRYPTO_malloc (in /lib/x86_64-linux-gnu/libcrypto.so.1.0.0)
==20093== by 0x57E1673: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
==20093== by 0x57DF359: ??? (in /lib/x86_64-linux-gnu/libssl.so.1.0.0)
[snip] (SSL_connect() called)
==20093==
==20093== ----------------------------------------------------------------
在CRYPTO_malloc()中还有其他数据争用示例,这些数据争用来自SSL_read,SSL_write,SSL_connect和SSL_accept等。
答案 0 :(得分:2)
以下片段中的最后一行是Helgrind抱怨的代码行:
void *CRYPTO_malloc(int num, const char *file, int line)
{
void *ret = NULL;
if (num <= 0) return NULL;
allow_customize = 0;
allow_customize
全局变量在静态初始化中初始化为1
。此值用于确保在调用分配例程后不调用malloc自定义函数(CRYPTO_set_mem...
和变量)。此值为0
的设置是在锁之外完成的。从技术上讲,如果一个线程在另一个线程试图为CRYPTO_...alloc
设置自定义函数时尝试调用CRYPTO
函数,则存在竞争条件,但这可以被视为应用程序错误。
答案 1 :(得分:0)
这里定义了CRYPTO_malloc
:
$ grep -R CRYPTO_malloc *
...
crypto/mem.c:void *CRYPTO_malloc_locked(int num, const char *file, int line)
crypto/mem.c:void *CRYPTO_malloc(int num, const char *file, int line)
...
CRYPTO_malloc_locked
试图将页面保留在内存中(而不是写入swap
);而不是线程安全的分配器。
这是CRYPTO_malloc
的作用:
void *CRYPTO_malloc(int num, const char *file, int line)
{
void *ret = NULL;
...
ret = malloc_ex_func(num,file,line);
...
return ret;
}
malloc_ex_func
在default_malloc_ex
中设为CRYPTO_set_mem_functions
。并default_malloc_ex
。但我似乎无法找到default_malloc_ex
的实现。
但是,CRYPTO_malloc_init
具有以下内容:
#define CRYPTO_malloc_init() CRYPTO_set_mem_functions( \
malloc, realloc, free)
因此看起来正在使用C运行时的malloc
。
您使用的OpenSSL版本是否支持线程?您可以通过包含<openssl/openssl.con.h>
进行测试,并测试是否定义了OPENSSL_THREADS
。
这也应该有效:
$ cat /usr/local/ssl/include/openssl/opensslconf.h | grep -B 1 -A 1 -i thread
#ifndef OPENSSL_THREADS
# define OPENSSL_THREADS
#endif