尝试使用valgrind的输出调试c程序分段错误

时间:2011-08-19 14:26:36

标签: c debugging segmentation-fault valgrind

我的CLI程序编译并在Windows上运行良好。在linux上编译很好,但在运行时会导致分段错误。

我转向stackoverflow寻求帮助,发现了一些类似于我要问的建议valgrind的问题,我刚刚安装了它(哇!)。

所以我通过valgrind运行我的程序,得到了令人沮丧的大量输出,但我将从第一条错误消息开始:

==11951== Command: ./vt
==11951== 
Loading...
Load default database? (y/n)y
Opened input file vtdb.~sv, reading contents...
==11951== Invalid write of size 1
==11951==    at 0x400FA9: readnumberfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==    by 0x400C21: getrecordsfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==    by 0x401FFD: main (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==  Address 0x53b05bb is 0 bytes after a block of size 11 alloc'd
==11951==    at 0x4C28FAC: malloc (vg_replace_malloc.c:236)
==11951==    by 0x400EAC: readnumberfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==    by 0x400C21: getrecordsfromfile (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951==    by 0x401FFD: main (in /home/rob/Documents/programming/c/vocabtest/vt)
==11951== 
...finished.
1180 entries read from vtdb.~sv.

问题似乎出现在readnumberfromfile中,我已经仔细查看了,我似乎无法找到它的错误!

任何人都能解释一下吗?

int readnumberfromfile (int maxvalue,char separator)
{
    int number, i=0;
    char ch;
    char * buff = (char *)malloc(11);//allocate enough space for an 10-digit number and a terminating null
    if (!buff) {printf("Memory allocation failed!\n");return 0;}//return 0 and print error if alloc failed
    if (!maxvalue) maxvalue=MAXINTVALUE;

    ch=getc(inputfile);
    while (!isdigit(ch))
    {
        if (ch == separator||ch=='\n'||ch==EOF) {fprintf(stderr,"Format error in file\n");return 0;}//if no number found(reached separator before digit), print error and return 0
        ch = getc(inputfile);//cycle forward until you reach a digit
    }
    while (i<11 && ch!=separator && ch!='\n')//stop when you reach '~', end of line, or when number too long
    {
        buff[i++]=ch;
        ch = getc(inputfile); //copy number from file to buff, one char at a time
    }
    buff[i] = '\0';//terminate string
    number = atoi(buff)<=maxvalue ? atoi(buff) : maxvalue;//convert string to number and make sure it's in range
    free(buff);
    return number;
}

如果有任何用途,则从getrecordsfromfile调用:

void getrecordsfromfile(char * inputfilename,char separator)
{
    int counter = 0;
    struct vocab * newvocab;
    struct listinfo * newvocablist;
    if (!(inputfile = fopen(inputfilename, "r")))
    {
        printf("Unable to read input file. File does not exist or is in use.\n");
    }    
    else
    {
        printf("Opened input file %s, reading contents...\n",inputfilename);
        while (!feof(inputfile))
        {
            newvocab = (struct vocab *)malloc(sizeof(struct vocab));
            if (!newvocab)
            {
                printf("Memory allocation failed!\n");
                return;
            }
            else
            {
                newvocab->question=readtextfromfile(MAXTEXTLENGTH,separator);
                newvocab->answer=readtextfromfile(MAXTEXTLENGTH,separator);
                newvocab->info=readtextfromfile(MAXTEXTLENGTH,separator);
                newvocab->hint=readtextfromfile(MAXTEXTLENGTH,separator);
                newvocab->right=readnumberfromfile(1,separator);
                newvocab->counter=readnumberfromfile(0,separator);
                newvocab->known=readnumberfromfile(3,separator);

                switch (newvocab->known)
                {
                    case 0: newvocablist = &n2l;break;
                    case 1: newvocablist = &norm;break;
                    case 2: newvocablist = &known;break;
                    case 3: newvocablist = &old;break;
                }

                addtolist(newvocab,newvocablist);
                if (newvocab->question==NULL||newvocab->answer==NULL)
                {
                    printf("Removing empty vocab record created from faulty input file...\n");
                    removefromlist(newvocab,newvocablist,1);
                }
                else counter++;
            }
        }
        fclose(inputfile);
        printf("...finished.\n%i entries read from %s.\n\n",counter,inputfilename);
    }
    return;
}

可以从https://github.com/megamasha/Vocab-Tester

获取完整来源

一些注意事项:我正在努力帮助自己,我已经完成了我的研究,查看了类似的问题,并亲自了解了valgrind。

我仍然是一个相对初学者,虽然我很欣赏解决方案(要做什么来解决它),但更有用的是知识(如何在下次修理或避免它)。我在这里(非常热衷于)学习。

4 个答案:

答案 0 :(得分:7)

buff[i] = '\0';//terminate string

在这里i == 11,因为你只分配了11个字符,而条件在i = 11时结束。
所以,你访问一个你没有分配的内存。

未定义此情况的行为。

您可以通过在malloc上分配一个额外字符来解决此问题。

答案 1 :(得分:3)

int number, i=0;
...
while (i<11 ...

对于i = 0,1,2,3,4,5,6,7,8,9和10,您最多读取11位数字。然后尝试将\0粘贴在第12个插槽中{ {1}}。

它被称为“off by one error”。

因此修复取决于您想要更改的内容。如果你想接受11个字符,请更改buff的malloc。如果您只想接受10,则更改while条件。

答案 2 :(得分:2)

  

写入大小为1的无效

你可能正在写一个字符

  

地址0x53b05bb在大小为11的块

后为0字节

你只是满身大小11的东西

readnumberfromfile

这与猜测有关(按大小):

char * buff = (char *)malloc(11);

这将在循环之后使用i = 11完成,这超过了分配的结束:

buff[i] = '\0'

正如wormsparty所说,通过在二进制文件中获取调试符号,你可以让valgrind更有帮助。

答案 3 :(得分:1)

以后,如果使用-g进行编译,valgrind将向您显示segfault发生的确切位置。