Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

c - Memory leaks and seg faults when using OpenMP and OpenSSL

I have a huge code (its my school project) where I use Openssl. Everything was working perfeclty, util I decided I will go multithreaded. I chose openmp as my threading environment, since its very simple and pretty easy to learn (at least the basis I need are easy).

My whole code looks like this:

struct mystr[10];
omp_set_num_threads(10);
#pragma omp parallel 
{
    mystr[omp_get_thread_num()] = call_fun_which_uses_openssl();
}
CRYPTO_cleanup_all_ex_data();

My call_fun_which_uses_openssl function uses low level openssls api functions (MD4((unsigned char*)&string, strlen(string), (unsigned char*)&digest); instead of MD4_CTX ctx etc). My function uses RSA, DSA, ... and does not have access to any global variables, every variable it uses is declared inside call_fun_which_uses_openssl, so doing a multithreading like I did should guarantee that those variables remain private. Although, I sometimes have seg faults with this code. I read that CRYPTO_cleanup_all_ex_data is not thread-safe (but I need it because of memory leaks) but I use it outside the parallel region, right? When I remove openmp calls everything works every time so there must be an issue with multithreading and openssl. Any ideas how to solve it?

In my opinion it should work, beacuse a threaded call of call_fun_which_uses_openssl creates its own private variables for every thread and there should be no problem ... Please, help :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Take a look at the example openssl/crypto/threads/mttest.c in the OpenSSL source code tree. Basically, you have to provide two callback functions:

  • one that implements locking and unlocking and
  • one that returns a unique thread ID.

Both are easily implemented using OpenMP:

omp_lock_t *locks;

// Locking callback
void openmp_locking_callback(int mode, int type, char *file, int line)
{
  if (mode & CRYPTO_LOCK)
  {
    omp_set_lock(&locks[type]);
  }
  else
  {
    omp_unset_lock(&locks[type]);
  }
}

// Thread ID callback
unsigned long openmp_thread_id(void)
{
  return (unsigned long)omp_get_thread_num();
}

Before you start, the locks have to be initialised and callbacks set:

void openmp_thread_setup(void)
{
  int i;

  locks = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(omp_lock_t));
  for (i=0; i<CRYPTO_num_locks(); i++)
  {
    omp_init_lock(&locks[i]);
  }

  CRYPTO_set_id_callback((unsigned long (*)())openmp_thread_id);
  CRYPTO_set_locking_callback((void (*)())openmp_locking_callback);
}

void openmp_thread_cleanup(void)
{
  int i;

  CRYPTO_set_id_callback(NULL);
  CRYPTO_set_locking_callback(NULL);
  for (i=0; i<CRYPTO_num_locks(); i++)
    omp_destroy_lock(&locks[i]);
  OPENSSL_free(locks);
}

You should call openmp_thread_setup() once in your program somewhere before the first parallel region and you should call openmp_thread_cleanup() once after the last parallel region:

// Program start

openmp_thread_setup();

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

#pragma omp parallel
{
   // Parallel OpenSSL calls are now data race free
}

openmp_thread_cleanup();

// Program should end now

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...