C ***检测到堆栈崩溃***中止(堆芯转储)

C ***检测到堆栈崩溃***中止(堆芯转储),c,valgrind,stack-overflow,coredump,stack-smash,C,Valgrind,Stack Overflow,Coredump,Stack Smash,我试图调试一个程序,该程序给出错误:中止(内核转储)。Valgrind检测到堆栈破裂,并给出泄漏摘要,其中1个区块仍然可以到达。它向函数downloadAndOpen的第12行发送信号,在那里我有一个我认为在main末尾关闭的fopen,但看起来不是。如果您能帮我解决这个问题,我将不胜感激。valgrind输出为: *** stack smashing detected ***: ./mtg terminated ==9594== ==9594== HEAP SUMMARY: ==9594==

我试图调试一个程序,该程序给出错误:中止(内核转储)。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 <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;
}

这两个
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
int n=snprintf(cmd,sizeof cmd,“。。。。。。。。。。。。
如果(n<0 | | n>=sizeof cmd)
exit(exit_FAILURE);//或其他错误处理

n=snprintf(文件,大小文件,“第%d.txt页”,i);
如果(n<0 | | n>=sizeof文件)
exit(exit_FAILURE);//或其他错误处理

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

这两个
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
int n=snprintf(cmd,sizeof cmd,“。。。。。。。。。。。。
如果(n<0 | | n>=sizeof cmd)
exit(exit_FAILURE);//或其他错误处理

n=snprintf(文件,大小文件,“第%d.txt页”,i);
如果(n<0 | | n>=sizeof文件)
exit(exit_FAILURE);//或其他错误处理

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

是否执行
“wget-q-O页面%d.txt”http://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=%d'"
实际上最终与
cmd
的128个字符相匹配?看起来您可能没有足够的空间来容纳终止的空字符,而且如果您需要太多的数字来计算
%d
的结果,您就没有足够的空间了。我以前用一个函数尝试过,长度为122。
\include\include int main(void){char*link=“wget-q-O page1.txthttp://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=1“printf(“%i\n”,strlen(link));}
@JoshuaTaylor是对的。一旦你达到i=10,cmd字符串就有127字节长。如果i是三位数字,你就会破坏堆栈,在主循环中,
i
超过99,就是这样。当i=100时,你需要130个字符来保存带有尾随
'\0'
的字符串。同时请注意,尽管它不能帮助你分配足够的space,如果使用绑定与缓冲区匹配的snprintf,您将无法尝试在缓冲区外写入。然后,您可以使用简单的printf来查看cmd最终是什么,很明显它不适合。请注意,在您的“我尝试过”示例中,您省略了URL周围的单个勾号,这会添加两个字节。Does
“wget-q-O页面%d.txt”http://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=%d'"
实际上最终与
cmd
的128个字符相匹配?看起来您可能没有足够的空间来容纳终止的空字符,而且如果您需要太多的数字来计算
%d
的结果,您就没有足够的空间了。我以前用一个函数尝试过,长度为122。
\include\include int main(void){char*link=“wget-q-O page1.txthttp://www.mtgsalvation.com/forums/creativity/artwork/340782-official-digital-rendering-thread?page=1“printf(“%i\n”,strlen(link));}
@JoshuaTaylor是对的。一旦你达到i=10,cmd字符串就有127字节长。如果i是三位数字,你就会破坏堆栈,在主循环中,
i
超过99,就是这样。当i=100时,你需要130个字符来保存带有尾随
'\0'
的字符串。同时请注意,尽管它不能帮助你分配足够的space,如果使用绑定与缓冲区匹配的snprintf,您将无法尝试在缓冲区外写入。然后,您可以使用简单的printf来查看cmd最终是什么,很明显它不适合。注意,在您的“我尝试过”示例中,您省略了URL周围的单个勾号,这会添加两个字节。or、 更好的是,malloc有足够大的区域,然后在调用system(cmd)后释放它;是的,尽管您仍然需要使用
snprintf
(可能包装在类似asprintf的函数中)我发现了这个问题并修复了它。有一个空的图像环境,getc一直在获取字符,直到缓冲区溢出。无论如何,我将更改sprintf。或者,更好的是,malloc一个足够大的区域,然后在调用系统(cmd)后释放它;是的,尽管您仍然必须使用
snprintf
(可能是封装在类似asprintf的函数中)我发现了问题并修复了它。有一个空的映像环境,getc一直在获取字符,直到缓冲区溢出。无论如何,我将更改sprintf。
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