c++parallel-processingopensslsegmentation-faultopenmp

Bus error or Segmentation fault (core dumped) using #pragma omp parallel for


I'm practicing brute force with 2 threads using C++ and OMP library:

#include <iomanip>
#include <sstream>
#include <openssl/md5.h>
#include <cstring> 
#include <iostream>
#include <omp.h>
#define NUM_THREADS 2

int main() {
    unsigned char digest[MD5_DIGEST_LENGTH];
    std::cout << "Enter hash: ";
    std::string target;
    std::cin >> target; 
    char password[11] = "0000000000";
    bool flag = true;
    std::ostringstream password_stream;
    std::ostringstream hex_hash;
    while (flag) {
        #pragma omp parallel for num_threads(NUM_THREADS)
        for (unsigned long long i = 0; i <= 9999999999ULL; ++i) {
    password_stream <<  std::setfill('0') << std::setw(10)  << i;
        std::string  password_str = password_stream.str();

        MD5(reinterpret_cast<const unsigned char*>(password_str.c_str()), password_str.length(), digest);
    
        for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
            #pragma omp critical
            hex_hash << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i];
        }
        std::string hex_hash_str = hex_hash.str();

    //std::cout << omp_get_thread_num() << std::endl;
        if (hex_hash_str == target) {
    #pragma omp critical
            std::cout << "Orginal password: " <<  password_str << std::endl;
            flag = false;
        }

        if (i % 100000 == 0) {
            std::cout << "Wrong: " << password_str << " " << hex_hash_str << " Trying again..." << std::endl;
        }
        }
    }

    return 0;
}

But they either trying to write in one stream or I'm getting wrong calculations of hash in hex digit or it's segmentation fault or bus error.

I'm trying to use #pragma omp critical in order to avoid threads writing in one stream. Also I tried to put variables with password and hex-hash of it into global variable before #pragma omp parallel for. All of them result in wrong calculations of hash or segmentation fault.

The password consists of 10 digits


Solution

  • The purpose of the while loop is unclear. The program would run infinitely, if no match is found or the while loop would run exactly one time. It is also best practice to specify the number of threads using OMP_NUM_THREADS rather than the clause. The following code tries to abort the OpenMP work-sharing loop with cancellation. If cancellation is not supported, the flag will allow to skip the costly part of the loop while finishing the remaining iteration. This builds on @Rob 's solution

    #include <cstring>
    #include <iomanip>
    #include <iostream>
    #include <atomic>
    #include <omp.h>
    #include <openssl/md5.h>
    #include <sstream>
    
    int main() {
      std::cout << "Enter hash: ";
      std::string target;
      std::cin >> target;
      std::atomic<bool> flag{false};
    #pragma omp parallel for
        for (unsigned long long i = 0; i <= 9999999999ULL; ++i) {
          if (flag)
            continue;
          std::ostringstream password_stream, hex_hash;
          password_stream << std::setfill('0') << std::setw(10) << i;
          
          std::string password_str = password_stream.str();
    
          unsigned char digest[MD5_DIGEST_LENGTH];
          MD5(reinterpret_cast<const unsigned char *>(password_str.c_str()),
              password_str.length(), digest);
    
          for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) {
            hex_hash << std::hex << std::setw(2) << std::setfill('0')
                     << (int)digest[i];
          }
          std::string hex_hash_str = hex_hash.str();
    
          if (hex_hash_str == target) {
            std::cout << "Orginal password: " << password_str << std::endl;
            flag = true;
            #pragma omp cancel for
            continue;
          }
    
          if (i % 100000 == 0) {
            std::cout << "Wrong: " << password_str << " " << hex_hash_str
                      << " Trying again..." << std::endl;
          }
        }
    
      return 0;
    }
    

    When compiled with -fsanitize=thread, ThreadSanitizer does not report any data race for this version of the code. TSAN_OPTIONS='ignore_noninstrumented_modules=1' OMP_CANCELLATION=true OMP_NUM_THREADS=4 ./a.out enables cancellation and sets the number of threads.