C:Valgrind:使用大小为4的未初始化值和使用大小为4的未初始化值

时间:2013-05-24 23:19:52

标签: c valgrind

这两个错误出现了链表/低级文件读/ strtok程序。

==10982== Use of uninitialised value of size 4
==10982==    at 0x40C3899: strtok (strtok.S:197)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)
==10982== 
==10982== Use of uninitialised value of size 4
==10982==    at 0x40C38C1: strtok (strtok.S:223)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)
==10982== 
==10982== Conditional jump or move depends on uninitialised value(s)
==10982==    at 0x40C38C4: strtok (strtok.S:224)
==10982==    by 0x8048719: main (main.c:9)
==10982==  Uninitialised value was created by a stack allocation
==10982==    at 0x80487D2: buildList (functions.c:13)

这是函数buildList

void buildList(int fdin, int lines)
{
    char ara[4096];
    int num;
    double p;
    read(fdin, ara, 4096);
    char *nl = "\n";
    char *ws = " ";
    char *temp =  strtok(ara, " ");
    while(temp != NULL)
    {
        Stock *s = (Stock*)calloc(1, sizeof(Stock));
        s->c.symbol = (char*)calloc(strlen(temp)+1, sizeof(char));
        strcpy(s->c.symbol, temp);
        temp = strtok(NULL, "\n");
        s->c.name = (char*)calloc(strlen(temp)+1, sizeof(char));
        strcpy(s->c.name, temp);
        temp = strtok(NULL, "\n");
        sscanf(temp, "%lf", &p);
        temp = strtok(NULL, "\n");
        s->price = p;
        sscanf(temp, "%d", &num);
        s->shares = num;
        Node *n = (Node*)calloc(1, sizeof(Node));
        n->data = s;
        addOrdered(n);
        temp = strtok(NULL, " ");
    }
    close(fdin);
}

我无法弄清楚为什么会出现这种错误。从我读到的内容是因为我正在从strtok向char *分配东西,而没有为它们分配任何内存。不过这就是我过去的做法,我认为一切都很好。

3 个答案:

答案 0 :(得分:4)

正如其他人所推测的那样,valgrind抱怨strtok正在利用未初始化的记忆。然后问题转向为什么,因为它似乎正在被初始化:

read(fdin, ara, 4096);

但是,read()没有\0终止数据,而strtok期望\0终止字符串。确保输入正确终止:

ssize_t result = read(fdin, ara, sizeof[ara]-1); /* leave room for '\0' */
ara[result > 0 ? result : 0] = '\0';

Lee Daniel Crocker的memset(ara, 0, sizeof(ara));建议相当于同样的修复,但只有在文件包含少于sizeof(ara)个字节的输入时才有效。如果您从中读取的文件包含4096字节或更多数据,则仍会遇到类似问题。然后,strtok将被强制扫描超过缓冲区的末尾以查找\0,从而导致未定义的行为。

答案 1 :(得分:3)

  

read(fdin, ara, 4096);

......可以返回:

  • -1,表示读取错误,ara未填写;
  • 0,表示您点击了文件末尾,ara未填写;
  • 值< 4096,意味着文件中剩余的字节少于4096个,并且ara的所有字节都没有填写。

始终检查read()的返回值。

  

char * temp = strtok(ara,“”);

$ man strtok

...

The strtok() function is used to isolate sequential tokens in a null-ter-
minated string, str. ...

没有任何内容可以保证ara中包含空字符('\0'),因此您无法有效地将其传递给strtok()。如果您想确保其中包含char ara[4097],请在阅读后设为ara[4096] = '\0';并执行'\0'

或者,更好的是,如果read()的返回值在变量data_read中,并且您已经检查过以确保它不是-1,那么执行ara[data_read] = '\0';,将最后一个读取后的字节设置为'\0'

如果文件超过4096个字符并且您的read()调用读入了多个行,并且另一行的开头,会发生什么?鉴于此,您可能需要考虑使用fopen()打开文件并使用fgets()来读取行。

答案 2 :(得分:1)

read读取的数据末尾是否有空终结符?如果没有,那可能是个问题。