使用有效字符串调用strcmp时出现Segfault [关闭]

u3r8eeie  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(120)

**已关闭。**此问题需要debugging details。它目前不接受回答。

编辑问题以包括desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem。这将帮助其他人回答这个问题。
8天前关闭
Improve this question
我有一个函数,它在C中维护一个动态大小的数组。该程序读取一个文本文件,并创建一个列表,每个独特的词,以及这些词的频率。它有一个搜索功能,看起来像这样:

int vec_lsearch(vector* vec, char* target)
{
    for(int i = 0; i < vec->size; i++) {
        if(strcmp(vec->data[i].word, target) == 0) {
            return i;
        }
    }
    return -1;
}

当我的程序运行时,它有大约60%的时间发生segfaults。然而,它在Valgrind下运行时 * 从不 * 崩溃。使用GDB,我可以找到问题。它也只在我运行两个或更多线程时崩溃。以下是我的GDB日志:

Thread 3 "Evans_Griffin_H" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff6af1700 (LWP 13341)]
__strcmp_ssse3 () at ../sysdeps/x86_64/multiarch/../strcmp.S:173
173    ../sysdeps/x86_64/multiarch/../strcmp.S: No such file or directory.
(gdb) bt
#0  __strcmp_ssse3 () at ../sysdeps/x86_64/multiarch/../strcmp.S:173
#1  0x0000555555555283 in vec_find (vec=0x555555758490, target=0x7ffff72f381b "incomprehensible")
    at Evans_Griffin_HW4_main.c:153
#2  0x00005555555553f1 in count_words (arg=0x555555758500) at Evans_Griffin_HW4_main.c:193
#3  0x00007ffff7bbb6db in start_thread (arg=0x7ffff6af1700) at pthread_create.c:463
#4  0x00007ffff78e461f in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:95
(gdb) select-frame 1
(gdb) p vec->data[i]
$3 = {word = 0x7ffff0002000 "played", freq = 1}
(gdb) p target
$4 = 0x7ffff72f381b "incomprehensible"
(gdb) p vec->data[i].word
$5 = 0x7ffff0002000 "played"
(gdb) p vec->data[i].word[6]
$7 = 0 '\000'
(gdb) p target[16]
$8 = 0 '\000'

据我所知,这两个字符串似乎都有效。我在插入和更新数据时使用互斥锁,但在使用strcmp时不使用(尽管我在这里尝试锁定线程,但没有区别)。有人能帮我弄明白为什么我的程序会崩溃吗?
编辑:由于学术诚信政策,我不能随意提供我的程序的完整源代码。我已经包括了一些更多的片段,希望是有帮助的。

typedef struct {
    char* word;
    int freq;
} word_freq;

typedef struct {
    word_freq* data;
    size_t size;
    size_t capacity;
} vector;
void vec_push(vector* vec, char* e)
{
    word_freq wf;
    wf.freq = 1;
    wf.word = malloc(strlen(e) + 1);
    strcpy(wf.word, e);
    vec->data[vec->size++] = wf;

    // if vector is at capacity, realloc to double its capacity
    if (vec->size == vec->capacity) {
        vec->capacity *= 2;
        vec->data = realloc(vec->data, vec->capacity * sizeof(word_freq));
    }

    if (vec->data[vec->size - 1].word == NULL) {
        printf("Error inserting %s\n", e);
    }
}
void* count_words(void* arg)
{
    job_info* info = arg;
    vector* word_vec = info->words; // vector of word_freq structs
    char* buf = info->buffer;
    int thread_num = info->thread_num;

    char* saveptr;
    char* token = strtok_r(buf, delim, &saveptr);
    while(token != NULL) {
        trim_word(token);

        if(strlen(token) >= MIN_STRING_LENGTH && strlen(token) <= MAX_STRING_LENGTH) {
            // because the size of the vector may change, must lock the thread before
            // accessing it
            if (pthread_mutex_lock(&info->mutex)) {
                perror("mutex lock");
            }
            int index = vec_lsearch(word_vec, token);
            if(index != -1) {

                word_vec->data[index].freq++;   

            } else {
                vec_push(word_vec, token);
            }
            
            vec_health(word_vec);

            if (pthread_mutex_unlock(&info->mutex)) {
                perror("mutex unlock");
            }
        }

        token = strtok_r(NULL, delim, &saveptr);
    }
}
// given input string, convert it to lower case and discard any non-alphabet (a-z and A-Z) characters
void trim_word(char* in)
{
    int i = 0;
    int j = 0;
    char c;

    while (( c = in[i++]) != '\0') {
        if (isalpha(c)) {
            in[j++] = tolower(c);
        }
    }

    in[j] = '\0';
}
int vec_health(vector* vec) 
{
    if (vec->data == NULL) {
        return 1;
    }

    for(int i = 0; i < vec->size; i++) {

        if (vec->data[i].word == NULL) {
            fprintf(stderr, "data[%d] is null!\n", i);
            return 2;
        }

    }

    return 0;
}

我写了一个新的测试函数vec_health,它显示了我的结构体的某些成员是NULL,尽管我仍然不确定这是怎么回事。感谢@solomon-slow的启发性评论。
vec_health将在运行时警告我某些对象具有空值,例如

data[3583] is null!
data[6143] is null!

但是我在广发行检查的时候,好像没什么问题

(gdb) p vec->data[3583]
$2 = {word = 0x7fffe800dfc0 "bucket", freq = 1}
(gdb) p vec->data[6143]
$3 = {word = 0x7fffe80184a0 "defending", freq = 7}
1rhkuytd

1rhkuytd1#

这是一个延伸的评论。这不是一个“答案”。
如果vector只包含指向字符串的有效指针,并且如果给定的target是指向字符串的有效指针,则不应该发生segfault。所以,要么target有问题,要么向量有问题。
使用GDB.据我所知,这两个字符串似乎都是有效的。
多处理器机器上的线程可能很棘手。您在GDB中看到的内容可能与vec_find函数运行时看到的内容不同。
我在插入和更新数据时使用互斥锁,但在使用strcmp时不使用。
这是一个“严重”的问题。是什么阻止你的vec_find函数在其他线程添加另一个字符串的时候试图访问向量?谁知道那个时候矢量会处于什么状态?(提示:* 你 * 不知道,如果你不熟悉你的程序调用的库代码。
vec_find中没有任何锁定,您的程序是无效的。说这些都没意义
..
“锁定线程”是什么意思?你有没有一个版本的vec_find锁定 * 相同的互斥量 *,其他线程正在使用?如果不是同一个互斥体就不算数。
如果你想要一个有意义的答案,那么你应该用更多的代码来更新它。显示修改vector的所有代码。显示“锁定线程”的vec_find版本。解释哪个线程做什么。

o4tp2gmn

o4tp2gmn2#

我更新了我的代码以使用多线程。我不是多线程方面的Maven,但我建议你在所有会修改你的vector结构或其中数据的写操作上使用互斥锁,比如你的vec_push函数。只读操作应该是非关键的,比如vec_find。
下面是我更新的代码。我希望它能帮助你。

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <pthread.h>

typedef struct
{
    char *word;
    size_t freq;
} data;

typedef struct
{
    pthread_mutex_t mutex;
    size_t size;
    size_t capacity;
    data *data;
} vector;

vector *vec_init()
{
    vector *vec = malloc(sizeof(vector));
    pthread_mutex_init(&vec->mutex, NULL);
    vec->size = 0;
    vec->capacity = 64;
    vec->data = calloc(vec->capacity, sizeof(data));
    return vec;
}

void vec_free(vector *vec)
{
    // depends on your code if you need this
    // for (size_t i = 0; i < vec->size; i++)
    // {
    //   free(vec->data[i].word);
    // }
    pthread_mutex_destroy(&vec->mutex);
    free(vec->data);
    free(vec);
}

void vec_push(vector *vec, data value)
{
    pthread_mutex_lock(&vec->mutex);
    vec->data[vec->size++] = value;
    if (vec->size == vec->capacity)
    {
        vec->capacity *= 2;
        vec->data = reallocarray(vec->data, vec->capacity, sizeof(data));
    }
    pthread_mutex_unlock(&vec->mutex);
}

int vec_find(vector *vec, char *target)
{
    for (int i = 0; i < vec->size; i++)
    {
        if (strcmp(vec->data[i].word, target) == 0)
        {
            return i;
        }
    }
    return -1;
}

char *words[] = {
    "Serendipity",
    "Mellifluous",
    "Ephemeral",
    "Quixotic",
    "Labyrinthine",
    "Petrichor",
    "Ethereal",
    "Sonorous",
    "Incandescent",
    "Halcyon",
    "Resplendent",
    "Ineffable",
    "Vicissitude",
    "Nebulous",
    "Mellifluous",
    "Serendipity",
    "Enigmatic",
    "Luminous",
    "Penumbra",
    "Quintessential",
};

void *routine(void *arg)
{
    vector *vec = (vector *)arg;
    for (size_t i = 0; i < sizeof(words) / sizeof(*words); i++)
    {
        data value = {words[i], 1};
        vec_push(vec, value);
    }
    return NULL;
}

int main(int argc, char **argv)
{
    vector *vec = vec_init();

    pthread_t thread;
    pthread_create(&thread, NULL, routine, vec);

    while (1)
    {
        int index = vec_find(vec, "Penumbra");
        if (index >= 0)
        {
            printf("index: %d\r\n", index);
            break;
        }
    }

    pthread_join(thread, NULL);
    vec_free(vec);

    return 0;
}

相关问题