Valgrind:条件跳转或移动取决于使用哈希函数时的未初始化值

Valgrind: Conditional jump or move depends on uninitialised value(s) when using hash function

我这样实现了 djb2 hash function

unsigned int hash(const char *word)
{
    unsigned int hash = 5381;
    int c;

    while ((c = *word++))
    {
        hash = ((hash << 5) + hash) + c;
    }

    return hash % N;
}

在其他地方,我通过这个函数使用散列函数:

bool check_word(const char *word)
{
    const char *word_lower = strlwr(word); // need word_lower because hash function is case sensitive
    node *iterator = table[hash(word_lower)];
    free((void*) word_lower);
    while (iterator != NULL) // traverse linked list, looking for the given word via strcasecmp
    {
        if (strcasecmp(iterator->word, word) == 0)
        {
            return true;
        }
        iterator = iterator->next;
    }
    return false;
}

还有这个函数:

void fill_hash_table(const char *dictionary)
{
    FILE *dict_ptr = fopen(dictionary, "r");
    if (dict_ptr == NULL)
    {
        return;
    }

    // prepare char array for every word with size LENGTH + 1 because LENGTH is the guaranteed max length
    char curr_word[LENGTH + 1];
    while (fscanf(dict_ptr, "%s", curr_word) != EOF)
    {
        [...]
        unsigned int table_pos = hash(curr_word);
        [...]
    }
    [...]
}

其中 dictionary 表示包含以行分隔的字符串的文本文件,如下所示:

a
ab
abc

运行 Valgrind 产生 Conditional jump or move depends on uninitialized value(s),更具体地说,指的是 while ((c = *word++))word

有没有办法避免这种情况?


strlwr()函数是这样实现的:

// returns same string but lower-cased
const char *strlwr(const char *string)
{
    char *string_to_lower = malloc(LENGTH + 1);
    for (int i = 0; string[i]; i++)
    {
        string_to_lower[i] = tolower(string[i]);
    }
    return string_to_lower;
}

这个:

while ((c = *word++))

仅当您传递的 word 未正确初始化且以 NUL 结尾的字符串时才会导致此类警告。

您的代码中的问题很可能是由您的 strlwr() 函数引起的,该函数未正确以 NUL 终止字符串。您在终止符处退出 for 循环,但未能将其添加到结果字符串中。

正确的代码是:

const char *strlwr(const char *string)
{
    char *string_to_lower = malloc(LENGTH + 1);
    unsigned i;

    for (i = 0; string[i]; i++)
    {
        string_to_lower[i] = tolower(string[i]);
    }

    string_to_lower[i] = '[=11=]'; // Ensure NUL terminator!
    return string_to_lower;
}

其次,我建议你修改这个:

while (fscanf(dict_ptr, "%s", curr_word) != EOF)

您正在使用 %s 作为格式说明符,这是自找麻烦。您不能保证正在读取的数据不会溢出缓冲区。

使用包含缓冲区长度的正确格式说明符,如下所示:

fscanf(dict_ptr, "%45s", curr_word);

或者,更好的是,使用 fgets(),它专为以安全方式读取字符串而设计:

fgets(cur_word, LENGTH, dict_ptr);

最后:

  • 您应该检查 malloc() 的 return 值。
  • 您应该避免像这样转换传递给 free 的指针:free((void*) word_lower)。任何指针自动转换from/tovoid*。强制转换仅在变量不是指针的情况下隐藏潜在错误。
  • 如果值变为负数没有意义,您应该使用 unsigned(甚至 size_t)而不是 int