【问题标题】:Use of uninitialised value of size 8 in spell-checker在拼写检查器中使用大小为 8 的未初始化值
【发布时间】:2017-06-19 12:49:00
【问题描述】:

我编写了一个拼写检查器,它使用 trie 存储和检查单词是否有拼写错误。它将文本文件字典加载到内存中,接受单词以检查拼写错误并卸载内存。程序编译成功,但运行时会产生分段错误。基于 valgrind,问题似乎是在我的插入函数中使用了未初始化的值。

//If word not present, inserts word into trie
//If the word is a prefix of a node, marks the "leaf node" (end-of-word node)
void insert(struct node *root, const char *word)
{
int length = strlen(word);
int index = 0;

//start from root node
struct node *tempNode = root;

for(int i = 0; i < length; i++)
{
    //if the current letter in word is a letter
    if(word[i] != '\'')

        //convert the alphabet to it's respective index number
        index = CHAR_TO_INDEX(tolower(word[i]));

    else
        //assign index number 27 (for apostrophe)
        index = INPUT_SIZE;

    //create a new node if path doesn't exist (is NULL)
    if(!(tempNode->children[index]))
        tempNode->children[index] = getNode();

        //go to next node  
        tempNode = tempNode->children[index];
        }
    //mark last node as leaf
    tempNode->isWord = true;
}

insert(将单词放在 trie 中)由 load 调用(将单词从字典 txt 文件移动到内存中):

bool load(const char *dictionary)
{
//initialise variables
char ch;
char word[LENGTH] = "";
int counter = 0;

struct node *root = getNode();

//open file to start inserting words
FILE *file = fopen(dictionary, "r");

//load words in dictionary into memory
while (EOF)
{
    while((ch = fgetc(file)) != '\n')
    {
        word[counter] = ch;
        counter++;
    }
    //whole word found, insert word and reset counter, increment word count
    insert(root, word);
    counter = 0;
    word_Count++;
}

//close all open files if EOF is reached, else loading has failed- return false
if(EOF == true)
    {
    fileLoaded = true;
    fclose(file);
    return true;
    }
else return false;
}

和 getNode() 创建一个初始化为 NULL 的新节点:

    //Returns new trie node initialised to NULL
    struct node *getNode(void)
    {
    //initialise new node
    struct node *newNode = NULL;

    newNode = malloc(sizeof(struct node));

    //proceed if enough memory to allocate
    if(newNode) 
    {
    //initialise pointers
    for(int i = 0; i < INPUT_SIZE; i++)
        newNode->children[i] = NULL;

    newNode->isWord = false;
    }
    else return false;

    return newNode;
    }

结构节点的定义:

    //Returns new trie node initialised to NULL
struct node *getNode(void)
{
    //initialise new node
    struct node *newNode = NULL;

    newNode = malloc(sizeof(struct node));

    //proceed if enough memory to allocate
    if(newNode) 
    {
        //initialise pointers
        for(int i = 0; i < INPUT_SIZE; i++)
            newNode->children[i] = NULL;

        newNode->isWord = false;
    }
    else return false;

    return newNode;
}

根据 valgrind 的错误:

    Conditional jump or move depends on uninitialised value(s)
==9334==    at 0x4011DD: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Uninitialised value was created by a heap allocation
==9334==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9334==    by 0x4010CB: getNode (dictionary.c:40)
==9334==    by 0x4011E7: insert (dictionary.c:85)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334== 
==9334== Use of uninitialised value of size 8
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Uninitialised value was created by a heap allocation
==9334==    at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==9334==    by 0x4010CB: getNode (dictionary.c:40)
==9334==    by 0x4011E7: insert (dictionary.c:85)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334== 
==9334== Invalid read of size 8
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)
==9334==  Address 0x91 is not stack'd, malloc'd or (recently) free'd
==9334== 
==9334== 
==9334== Process terminating with default action of signal 11 (SIGSEGV)
==9334==  Access not within mapped region at address 0x91
==9334==    at 0x4011D5: insert (dictionary.c:84)
==9334==    by 0x4014D1: load (dictionary.c:188)
==9334==    by 0x40095D: main (speller.c:40)

valgrind 使用 --leak-check=full、--leak-check=full 和 --show-leak-kinds=all 运行。我尝试从以前的帖子中引用类似的错误,但是上下文的差异使得我很难确定我应该做什么。第 84 行是读取 if(!(tempNode->children[index])) 的行。这似乎(在我看来)是问题的根本原因。

谢谢!

【问题讨论】:

  • 您的调试器可能会告诉您更多信息
  • 什么是结构节点? children 是指针数组吗?
  • minimal reproducible example 可能会有所帮助。
  • 我已经添加了结构节点的定义。谢谢你的提问。 @Elan

标签: c memory-leaks


【解决方案1】:
while((ch = fgetc(file)) != '\n')
{
    word[counter] = ch;
    counter++;
}
//whole word found, insert word and reset counter, increment word count
insert(root, word);

这是导致未定义行为的代码部分。

您的字符串word 不是以空值结尾的,但insert 期望它是(因为它所做的第一件事是调用strlen,它期望以空值结尾的字符串)。

简单的解决方法是

word[counter] = '\0';

在调用insert 之前假设一切都在界限内。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 1970-01-01
    相关资源
    最近更新 更多