I am using OpenSSL in a multithreaded program in C and having issues. So I wrote a small program to try to narrow down what the problem is. The functions besides the main function were copy pasted from https://github.com/plenluno/openssl/blob/master/openssl/crypto/threads/mttest.c
My program is as follows.
#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();
}
I get the following error and backtrace, which tells me that BN_mod_exp(r,b,e,m,ctx) is the problem.
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
Update: I am using OpenSSL and OpenMP in a larger program, the above was just for debugging. In the larger program, I set up multiple threads and each is supposed to write to its own file (not the same file). From here: https://en.wikibooks.org/wiki/OpenSSL/Initialization they say that thread callbacks have to be set up before the initialization functions. I am assuming what this means is that first we call CRYPTO_thread_setup(), and then the OpenSSL library initialization functions. Where does CRYPTO_thread_setup() have to be called from, is it immediately after the first #pragma omp parallel and before the opening brace? When I put it there, along with the library initialization functions, I still get segmentation faults, this time relating to using fclose() within the threads. Any ideas on why this could be happening?