0

我正在尝试调试一个给出错误的程序:Abort (core dumped)。Valgrind 检测到堆栈粉碎并给出一个泄漏摘要,其中 1 个块仍然可以到达。它向函数 downloadAndOpen 的第 12 行发出信号,其中我有一个我认为在 main 结束时关闭的 fopen,但似乎不是。我将不胜感激有关此错误的帮助。valgrind 输出为:

*** stack smashing detected ***: ./mtg terminated
==9594== 
==9594== HEAP SUMMARY:
==9594==     in use at exit: 352 bytes in 1 blocks
==9594==   total heap usage: 1 allocs, 0 frees, 352 bytes allocated
==9594== 
==9594== 352 bytes in 1 blocks are still reachable in loss record 1 of 1
==9594==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==9594==    by 0x40BE62B: __fopen_internal (iofopen.c:73)
==9594==    by 0x40BE70A: fopen@@GLIBC_2.1 (iofopen.c:103)
==9594==    by 0x8048729: downloadAndOpen (downloadAndOpen.c:12)
==9594==    by 0x80485B5: main (mtg.c:15)
==9594== 
==9594== LEAK SUMMARY:
==9594==    definitely lost: 0 bytes in 0 blocks
==9594==    indirectly lost: 0 bytes in 0 blocks
==9594==      possibly lost: 0 bytes in 0 blocks
==9594==    still reachable: 352 bytes in 1 blocks
==9594==         suppressed: 0 bytes in 0 blocks
==9594== 
==9594== For counts of detected and suppressed errors, rerun with: -v
==9594== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Aborted (core dumped)

编辑:在解决第一个问题后,程序正常工作直到第 18 页后,我得到了一个类似的问题。 Valgrind 报告是:

==11845== Invalid read of size 4
==11845==    at 0x40C5F35: getc (getc.c:38)
==11845==    by 0x80487EA: download (download.c:12)
==11845==    by 0x2020201F: ???
==11845==  Address 0x420ba20 is 248 bytes inside a block of size 352 free'd
==11845==    at 0x402B358: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==11845==    by 0x40BDDB9: fclose@@GLIBC_2.1 (iofclose.c:85)
==11845==    by 0x804866B: main (mtg.c:26)
==11845== 
==11845== Invalid read of size 4
==11845==    at 0x40C5F3E: getc (getc.c:38)
==11845==    by 0x80487EA: download (download.c:12)
==11845==    by 0x2020201F: ???
==11845==  Address 0x420ba68 is 320 bytes inside a block of size 352 free'd
==11845==    at 0x402B358: free (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==11845==    by 0x40BDDB9: fclose@@GLIBC_2.1 (iofclose.c:85)
==11845==    by 0x804866B: main (mtg.c:26)
==11845== 
==11845== Invalid read of size 4
==11845==    at 0x40C5F48: getc (getc.c:38)
==11845==    by 0x80487EA: download (download.c:12)
==11845==    by 0x2020201F: ???
==11845==  Address 0x8 is not stack'd, malloc'd or (recently) free'd
==11845== 
==11845== 
==11845== Process terminating with default action of signal 11 (SIGSEGV)
==11845==  Access not within mapped region at address 0x8
==11845==    at 0x40C5F48: getc (getc.c:38)
==11845==    by 0x80487EA: download (download.c:12)
==11845==    by 0x2020201F: ???
==11845==  If you believe this happened as a result of a stack
==11845==  overflow in your program's main thread (unlikely but
==11845==  possible), you can try to increase the size of the
==11845==  main thread stack using the --main-stacksize= flag.
==11845==  The main thread stack size used in this run was 8388608.
==11845== 
==11845== HEAP SUMMARY:
==11845==     in use at exit: 352 bytes in 1 blocks
==11845==   total heap usage: 18 allocs, 17 frees, 6,336 bytes allocated
==11845== 
==11845== 352 bytes in 1 blocks are still reachable in loss record 1 of 1
==11845==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==11845==    by 0x40BE62B: __fopen_internal (iofopen.c:73)
==11845==    by 0x40BE70A: fopen@@GLIBC_2.1 (iofopen.c:103)
==11845==    by 0x8048729: downloadAndOpen (downloadAndOpen.c:12)
==11845==    by 0x80485B5: main (mtg.c:15)
==11845== 
==11845== LEAK SUMMARY:
==11845==    definitely lost: 0 bytes in 0 blocks
==11845==    indirectly lost: 0 bytes in 0 blocks
==11845==      possibly lost: 0 bytes in 0 blocks
==11845==    still reachable: 352 bytes in 1 blocks
==11845==         suppressed: 0 bytes in 0 blocks
==11845== 
==11845== For counts of detected and suppressed errors, rerun with: -v
==11845== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

我已经隔离了问题,但我仍然看不出有什么问题:

#include <stdio.h>
#include <stdlib.h> // for using system calls
#include <stdbool.h>

int main (void)
{
    char url[200], cmd[200];
    int pos = 0, c, j;
    bool found = false;
    FILE *fp;
    fp = fopen ("file.txt", "w+");
    fprintf (fp, "\"http://4.bp.blogspot.com/-mIE4JlppKMU/T9_mxKR__wI/AAAAAAAAASs/deHLBL21ZbE/s640/Temple Garden.png\"");
    while (!found)
    {
        if ( (c = getc (fp)) == EOF ) {
            printf ("Image not found\n");
            return 1;
        }
        printf ("%c", c);
        url[pos] = c;
        if ( pos > 0 && url[pos-1] == 'g' && url[pos] == '\"' )
        {
            found = true;
        }
        ++pos;
    }
    --pos;
    char url2[pos];
    for ( j = 1; j < pos; j++ )
    {
        url2[j - 1] = url[j];
    }
    url2[j - 1] = '\0';

    //http://joequery.me/code/snprintf-c/
    // wget -q for quiet -nc, --no-clobber   skip downloads that would download to existing files (no sobreescribir)
    snprintf(cmd, 200, "wget -q -nc -O /home/arturo/Dropbox/Digital_Renders/%d \'%s\'", 1, url2);
    system(cmd);
    return 0;
}

下面是主函数的代码:

#include "helpers.h"

char  postBegin[] = "forum-post-body-content", postEnd[] = "p-comment-notes", img[] = "img src=";
int length1 = 22, length2 = 14, length3 = 7;
int pos1 = 0, pos2 = 0, pos3 = 0;

int main ()
{
    bool inPost = false;
    FILE *fp;
    int c;

    for ( int i = 1; i <= 151; i++ )
    {
        downloadAndOpen (&fp, i);
        while ( (c = getc (fp)) != EOF ) {
            if ( search (postBegin, length1, c, &pos1) )
                inPost = true;
            if (inPost) {
                if ( search (postEnd, length2, c, &pos2) )
                    inPost = false;
                if ( search (img, length3, c, &pos3) )
                    download (&fp);
            }
        }
        fclose (fp);
    }
}

这就是 Valgrind 抱怨的功能:

#include "helpers.h"

    void downloadAndOpen (FILE **fp, int i)
    {
        char cmd[128]={0}, file[20];
        // download web page
        sprintf (cmd, "wget -q -O page%d.txt 'http://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=%d'", i, i);
        system (cmd);

        // open text file
        sprintf (file, "page%d.txt", i);
        *fp = fopen (file, "r");
    }

程序的其余部分在这里:

#include <stdio.h>
#include <stdlib.h> // for using system calls
#include <stdbool.h>
#include <string.h> // for strlen

void downloadAndOpen (FILE **fp, int i);
bool search (char needle[], int length, char c, int *pos);
void download (FILE* *fp);

#include "helpers.h"

void download (FILE **fp)
{
    char url[128], cmd[128];
    int pos = 0, c, j;
    static int num = 1;
    bool found = false;

    while (!found)
    {
        if ( (c = getc (*fp)) == EOF ) {
            printf ("Image not found\n");
            return;
        }
        url[pos] = c;
        if ( pos > 0 && url[pos-1] == 'g' && url[pos] == '\"' )
        {
            found = true;
        }
        ++pos;
    }
    --pos;
    char url2[pos];
    for ( j = 1; j < pos; j++ )
    {
        url2[j - 1] = url[j];
    }
    url2[j - 1] = '\0';
    sprintf(cmd, "wget -q -O /home/arturo/Dropbox/Digital_Renders/%d \'%s\'", num++, url2);
    system(cmd);
}

#include "helpers.h"

bool search (char needle[], int length, char c, int *pos)
{
    if (needle[*pos] == c)
    {
        if (*pos == length)
        {
            return true;
            *pos = -1;
        }
        (*pos)++;
    }
    else
    {
        if(*pos > 0)
        *pos = 0;
    }
    return false;
}

和Makefile:

CC = gcc
CFLAGS = -ggdb3 -O0 -std=c99 -Wall -Werror

all: mtg

mtg: mtg.c downloadAndOpen.c search.c download.c helpers.h
    $(CC) $(CFLAGS) -o mtg mtg.c downloadAndOpen.c search.c download.c

clean:
    rm -f *.o a.out core mtg
4

1 回答 1

6

您可能在这两个sprintf命令中都有缓冲区溢出:

char cmd[128]={0}, file[20];

sprintf (cmd, "wget -q -O page%d.txt 'http://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=%d'", i, i);
sprintf (file, "page%d.txt", i);

与其尝试分析特定实例是否溢出,不如修复您的代码:

int n = snprintf(cmd, sizeof cmd, "............
if ( n < 0 || n >= sizeof cmd )
    exit(EXIT_FAILURE);    // or other error handling

n = snprintf(file, sizeof file, "page%d.txt", i);
if ( n < 0 || n >= sizeof file )
    exit(EXIT_FAILURE);    // or other error handling

如果您进行此更改但仍然遇到问题,请更新您的帖子。

于 2014-12-22T22:40:51.533 回答