OpenSSL线程和Helgrind

时间:2013-07-11 18:28:02

标签: multithreading openssl valgrind

我正在实现一个多线程应用程序,它广泛使用OpenSSL加密库。

我已在此处的几个帖子(Tutorial on Using OpenSSL with pthreadsOpenSSL and multi-threads),网站(例如libcurl opensslthreadlock.c)中遵循指南,主要是加密/ threads / mttest中的示例代码OpenSSL源代码中包含的.c 程序。其中引用的示例主要涉及OpenSSL的静态锁回调函数。但是,根据OpenSSL关于此事的文档(OpenSSL: threads(3))和The Definitive Guide to Linux Network Programming (第255-259页),有时可能需要为动态锁管理定义一些函数。

因此,我已经实现了初始化和清理功能,它们设置了两种类型的锁管理功能(静态和动态)。这些功能如下:

static unsigned long _thread_id_function(void) {
  return ((unsigned long) pthread_self());
}

static void _locking_function(int mode, int id, const char *file, int line) {
  if(mode & CRYPTO_LOCK) {
    pthread_mutex_lock(&mutex_buffer[id]);
  } else {
    pthread_mutex_unlock(&mutex_buffer[id]);
  }
}

static struct CRYPTO_dynlock_value* _dyn_create_func(const char *file, int line) {
  struct CRYPTO_dynlock_value *value;
  value = (struct CRYPTO_dynlock_value *) malloc(sizeof(struct CRYPTO_dynlock_value));
  pthread_mutex_init(&value->mutex,NULL);
  return value;
}

static void _dyn_destroy_func(struct CRYPTO_dynlock_value *l, 
  const char *file, int line) {
  pthread_mutex_destroy(&l->mutex);
  free(l);
  return;
}

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

static int _static_init() {

  int i;

  mutex_buffer = (pthread_mutex_t *) malloc(CRYPTO_num_locks()*sizeof(pthread_mutex_t));

  for(i=0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_init(&mutex_buffer[i], NULL);
  }

  CRYPTO_set_id_callback(_thread_id_function);
  CRYPTO_set_locking_callback(_locking_function);

  return 0;

}

static int _static_cleanup() {

  int i;

  CRYPTO_set_id_callback(NULL);
  CRYPTO_set_locking_callback(NULL);

  for(i=0; i<CRYPTO_num_locks(); i++) {
    pthread_mutex_destroy(&mutex_buffer[i]);
  }

  free(mutex_buffer); mutex_buffer = NULL;
  return 0;
}

static int _dyn_init() {
  CRYPTO_set_dynlock_create_callback(_dyn_create_func);
  CRYPTO_set_dynlock_lock_callback(_dyn_lock_func);
  CRYPTO_set_dynlock_destroy_callback(_dyn_destroy_func);
  return 0;
}

static int _dyn_cleanup() {
  CRYPTO_set_dynlock_create_callback(NULL);
  CRYPTO_set_dynlock_lock_callback(NULL);
  CRYPTO_set_dynlock_destroy_callback(NULL);
  return 0;
}

int cryptothread_init() {
  _static_init();
  _dyn_init();
  return 0;
}

int cryptothread_cleanup() {
  _static_cleanup();
  _dyn_cleanup();
  return 0;
}

从我的主程序中,我调用 cryptothread_init 函数来初始化回调。 但是,如果我运行Valgrind的Helgrind工具,会出现几种竞争条件,例如:

  

== 18797 ==线程#3在0x75D2F28写入大小4期间可能的数据竞争

     

== 18797 ==持有的锁:无

     

== 18797 ==在0x7276DCA:CRYPTO_malloc(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72F6290:EVP_MD_CTX_copy_ex(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72FD57B:EVP_SignFinal(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x407007:sign_data(main.c:919)

     

== 18797 == by 0x4C2B5AD:??? (在/usr/lib/valgrind/vgpreload_helgrind-amd64-linux.so中)

     

== 18797 == by 0x5CACB4F:start_thread(pthread_create.c:304)

     

== 18797 == by 0x6F4EA7C:clone(clone.S:112)

     

== 18797 ==

     

== 18797 ==这与线程#4的先前写入大小4相冲突

     

== 18797 ==持有的锁:无

     

== 18797 ==在0x7276DCA:CRYPTO_malloc(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72B0086:??? (在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72B05AC:bn_expand2(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72B08C9:BN_set_word(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72B1317:BN_CTX_get(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72AD68A:BN_div(在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72D1841:??? (在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 == by 0x72D2B9A:??? (在/usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0中)

     

== 18797 ==

但是,锁定回调不会抛出任何错误/警告消息。关于我可能遗失的任何暗示?

1 个答案:

答案 0 :(得分:0)

你应该完全阅读。 openSSL提供了两种设置回调以进行锁定的可能性。

所谓的“静态”和“动态”方式。您正在配置两者。我使用老式的静态,没有问题。我认为只有你应该使用动态的东西:减少用过的内存。但这对于使用过的记忆来说是荒谬的。

最后,您可以在“注释”部分的线程(3).html中看到静音的动态方式未启用。