我在C中的多线程程序中使用OpenSSL并遇到问题。所以我写了一个小程序来试图缩小问题的范围。主要功能以外的功能是从https://github.com/plenluno/openssl/blob/master/openssl/crypto/threads/mttest.c
复制粘贴的我的节目如下。
#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>
#include <strings.h>
#include <string.h>
#include <math.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include<omp.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/crypto.h>
#include <pthread.h>
#include <openssl/lhash.h>
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
static pthread_mutex_t *lock_cs;
static long *lock_count;
void pthreads_locking_callback(int mode, int type, char *file,
int line)
{
#if 0
fprintf(stderr,"thread=%4d mode=%s lock=%s %s:%d\n",
CRYPTO_thread_id(),
(mode&CRYPTO_LOCK)?"l":"u",
(type&CRYPTO_READ)?"r":"w",file,line);
#endif
#if 0
if (CRYPTO_LOCK_SSL_CERT == type)
fprintf(stderr,"(t,m,f,l) %ld %d %s %d\n",
CRYPTO_thread_id(),
mode,file,line);
#endif
if (mode & CRYPTO_LOCK)
{
pthread_mutex_lock(&(lock_cs[type]));
lock_count[type]++;
}
else
{
pthread_mutex_unlock(&(lock_cs[type]));
}
}
unsigned long pthreads_thread_id(void)
{
unsigned long ret;
ret=(unsigned long)pthread_self();
return(ret);
}
void CRYPTO_thread_setup(void)
{
int i;
lock_cs=OPENSSL_malloc(CRYPTO_num_locks() *
sizeof(pthread_mutex_t));
lock_count=OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long));
for (i=0; i<CRYPTO_num_locks(); i++)
{
lock_count[i]=0;
pthread_mutex_init(&(lock_cs[i]),NULL);
}
CRYPTO_set_id_callback((unsigned long (*)())pthreads_thread_id);
CRYPTO_set_locking_callback((void (*)())pthreads_locking_callback);
}
void thread_cleanup(void)
{
int i;
CRYPTO_set_locking_callback(NULL);
for (i=0; i<CRYPTO_num_locks(); i++)
{
pthread_mutex_destroy(&(lock_cs[i]));
}
OPENSSL_free(lock_cs);
OPENSSL_free(lock_count);
}
int main(){
BN_CTX *ctx;
ctx = BN_CTX_new();
omp_set_num_threads(158);
#pragma omp parallel
{
int ID = omp_get_thread_num();
BIGNUM *b,*e,*r,*m;
b = BN_new();
e = BN_new();
r = BN_new();
m = BN_new();
BN_set_word(b, 9);
BN_set_word(e, 3);
BN_set_word(m, 5);
BN_mod_exp(r,b,e,m,ctx);
char* result = BN_bn2dec(r);
printf("\n thread = %d result = %s", ID, result); fflush(stdout);
}
thread_cleanup();
}
我收到以下错误和回溯,它告诉我BN_mod_exp(r,b,e,m,ctx)是问题所在。
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7fffa9f69700 (LWP 151994)]
0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
(gdb) bt
#0 0x00007ffff7a97bb6 in BN_CTX_end () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
#1 0x00007ffff7a940cd in BN_div () from /lib/x86_64-linux-
gnu/libcrypto.so.1.0.0
#2 0x00007ffff7aa3dff in BN_MONT_CTX_set () from /lib/x86_64-
linux-gnu/libcrypto.so.1.0.0
#3 0x00007ffff7a963e5 in BN_mod_exp_mont_word () from /lib/x86_64-
linux-gnu/libcrypto.so.1.0.0
#4 0x0000000000400fef in main._omp_fn.0 () at
debuggingsession.c:106
#5 0x00007ffff77f734a in ?? () from /usr/lib/x86_64-linux-
gnu/libgomp.so.1
#6 0x00007ffff75d9184 in start_thread (arg=0x7fffa9f69700) at
pthread_create.c:312
#7 0x00007ffff730603d in clone () at
../sysdeps/unix/sysv/linux/x86_64/clone.S:111
(gdb) frame 4
#4 0x0000000000400fef in main._omp_fn.0 () at
debuggingsession.c:106
106 BN_mod_exp(r,b,e,m,ctx);
(gdb) print r
$1 = (BIGNUM *) 0x7fff8c000900
(gdb) x 0x7fff8c000900
0x7fff8c000900: 0x00000000
(gdb) print b
$2 = (BIGNUM *) 0x7fff8c0008c0
(gdb) x 0x7fff8c0008c0
0x7fff8c0008c0: 0x8c000940
(gdb) x 0x8c000940
0x8c000940: Cannot access memory at address 0x8c000940
(gdb) print b
$3 = (BIGNUM *) 0x7fff8c0008c0
(gdb) print e
$4 = (BIGNUM *) 0x7fff8c0008e0
(gdb) print m
$5 = (BIGNUM *) 0x7fff8c000920
(gdb) x
更新:我在一个更大的程序中使用OpenSSL和OpenMP,上面只是用于调试。在较大的程序中,我设置了多个线程,每个线程都应该写入自己的文件(不是同一个文件)。从这里:https://en.wikibooks.org/wiki/OpenSSL/Initialization他们说必须在初始化函数之前设置线程回调。我假设这意味着首先我们调用CRYPTO_thread_setup(),然后是OpenSSL库初始化函数。必须从哪里调用CRYPTO_thread_setup(),它是在第一个#pragma omp parallel之后和开始括号之前吗?当我把它放在那里,以及库初始化函数时,我仍然会遇到分段错误,这次涉及在线程中使用fclose()。关于为什么会发生这种情况的任何想法?