如果调用 pthread_create,则 gcc 分段错误

gcc segmentation fault if pthread_create is called

这段代码似乎抛出段错误,但如果注释掉 pthread_create 行,段错误就会消失。

pthread_t thread_id[device_count];

if (params.revision == 3) {
    startTime = time(NULL);
    unsigned long number = 0;

    deviceParams = get_device_params(platform_id, workWithUser ? "check_pdfs_user" : "check_pdfs_owner", program_buffer, program_size);

    int password_len = strlen(password_prefix) + password_digits + strlen(password_suffix);

    int j;

    unsigned long password_per_thread;

    password_t password;
    char pad[33];
    sprintf(pad, "%%s%%0%dd%%s", password_digits);

    while (number < max_password) {
        // how many passwords need to be generated
        password_per_thread = (max_password - number) / device_count;
        if (password_per_thread > batch_size)
            password_per_thread = batch_size;

        pthread_mutex_init(&lock, NULL);
        ThreadArg thread_arg;

        for (j = 0; j < device_count; j++) {
            // for (i = 0; i < password_per_thread; i++) {
            //  password.size_bytes = password_len;
            //  sprintf(password.password, pad, password_prefix, number++, password_suffix);
            //  numbers[i] = password;
            // }
            printf("%d\n", j);
            thread_arg.device_params = deviceParams[j];
            printf("A2\n");
            thread_arg.pdf_params = params;
            printf("1\n");
            thread_arg.start = number;
            printf("2\n");
            thread_arg.prefix = password_prefix;
            printf("3\n");
            thread_arg.prefix_length = strlen(password_prefix);
            printf("4\n");
            thread_arg.suffix = password_suffix;
            printf("5\n");
            thread_arg.suffix_length = strlen(password_suffix);
            thread_arg.length = password_len;
            thread_arg.count = password_per_thread;
            printf("6\n");
            pthread_create(&thread_id[j], NULL, runOnThread, &thread_arg);
        }
        void *status;
        for (i = 0; i < device_count; i++) {
            pthread_join(thread_id[i], &status);
            if ((bool *) status) {
                found = true;
            }
        }
        if (found) {
            break;
        }
    }
}

段错误发生在:

thread_arg.device_params = deviceParams[j];

但如果注释了以下行,则段错误消失:

pthread_create(&thread_id[j], NULL, runOnThread, &thread_arg);

这是段错误:

Thread 2 received signal SIGSEGV, Segmentation fault.
0x000000010000113b in runCrack () at pdfcrack.c:138
138                 thread_arg.device_params = deviceParams[j];

这是 gdb bt 的输出:

(gdb) bt
#0  0x000000010000113b in runCrack () at pdfcrack.c:138
#1  0x0000000100000bf6 in main (argc=<optimized out>, argv=0x7ffeefbff9c8) at main.c:250

您不应该像现在这样重复使用 thread_arg,那会导致数据竞争。请改用此类 arg 的数组。参见

how not to use the pthread_create arg

这是一个简单的比赛示例,在我的机器上它打印 2,然后 3,然后 3。

#include <pthread.h>
#include <stdexcept>
#include <iostream>

using std::cout;

const int NR_THREADS = 3;
pthread_t tid[NR_THREADS];

void* threadfunc(void* arg)
{
    int val = *(int* )arg;

    cout << "Thread got arg " << val << '\n';

    return 0;
}

int main()
{
    int retval;

    for (int i = 0; i < NR_THREADS; i++) {
        retval = pthread_create(&tid[i], NULL, threadfunc, &i);
        if (retval) throw std::runtime_error("Pthread create failed!");
    }

    for (int i = 0; i < NR_THREADS; i++) {
        pthread_join(tid[i], NULL);
        if (retval) throw std::runtime_error("Pthread join failed!");
    }

    return 0;
}

这是我需要避免构建错误的差异(还必须更改 header 位置和 Ubuntu 上的 .so 库位置,并删除 -framework gcc 标志)

diff pdfcrack/pdfcrack.c pdfcrack_modded/pdfcrack.c
116c116
<       pthread_t thread_id = malloc(sizeof(pthread_t) * device_count);
---
>       pthread_t* thread_id = malloc(sizeof(pthread_t) * device_count);
154c154
<               pthread_join(&thread_id[i], &status);
---
>               pthread_join(thread_id[i], &status);