为什么这个缓冲区指向不可寻址的字节?

时间:2016-04-13 21:44:00

标签: c sizeof fread

编辑:感谢回复,我已将fread更改为(... sizeof buffer,1,...),但现在我在valgrind中收到此错误:

==2409== Invalid read of size 4
==2409==    at 0x51AB8D0: fread (iofread.c:41)
==2409==    by 0x4007B6: main (recover2.c:31)
==2409==  Address 0x5502000 is not stack'd, malloc'd or (recently) free'd
==2409== 
==2409== Use of uninitialised value of size 8
==2409==    at 0x51B8787: _IO_sgetn (genops.c:495)
==2409==    by 0x51AB93E: fread (iofread.c:42)
==2409==    by 0x4007B6: main (recover2.c:31)
==2409== 
==2409== Invalid read of size 8
==2409==    at 0x51B8787: _IO_sgetn (genops.c:495)
==2409==    by 0x51AB93E: fread (iofread.c:42)
==2409==    by 0x4007B6: main (recover2.c:31)
==2409==  Address 0x40 is not stack'd, malloc'd or (recently) free'd
==2409== 
==2409== 
==2409== Process terminating with default action of signal 11 (SIGSEGV)
==2409==  Access not within mapped region at address 0x40
==2409==    at 0x51B8787: _IO_sgetn (genops.c:495)
==2409==    by 0x51AB93E: fread (iofread.c:42)
==2409==    by 0x4007B6: main (recover2.c:31)
==2409==  If you believe this happened as a result of a stack
==2409==  overflow in your program's main thread (unlikely but
==2409==  possible), you can try to increase the size of the
==2409==  main thread stack using the --main-stacksize= flag.
==2409==  The main thread stack size used in this run was 8388608.

我是新来的,所以我希望这是有道理的。我正在编写此代码以从文件中检索数据并将其复制到jpeg文件。该代码旨在通过其标头查找jpg文件,然后将其写入文件。代码是:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

int main(int argc, char* argv[])
{

FILE* file = fopen("card.raw", "r");
if (file == NULL)
{ 
    printf("Could not open file!\n");
    return 1;
}

char title[7];
int currentImage = 0;
uint8_t buffer[512];
FILE* img;
while (fread(buffer, sizeof(buffer), 512, file) == 1)
{
printf("found data!\n");
if (buffer[0] == 0xff && buffer[1] == 0xd8 && buffer[2] == 0xff)
{
    if (buffer[3] == 0xe0 || buffer[3] == 0xe1 || buffer[3] == 0xe2 || buffer[3] == 0xe3 || buffer[3] == 0xe4 || buffer[3] == 0xe5 || buffer[3] == 0xe6 || buffer[3] == 0xe7 || buffer[3] == 0xe8 || buffer[3] == 0xe9 || buffer[3] == 0xea || buffer[3] == 0xeb || buffer[3] == 0xec || buffer[3] == 0xed || buffer[3] == 0xee || buffer[3] == 0xef)
    {
        printf("Found new jpg!\n");
        sprintf(title, "%03d.jpg", currentImage);
        img = fopen(title, "a");
        currentImage++;
        printf("size of buffer to print is %lu\n", sizeof(buffer));
        fwrite(buffer, sizeof(buffer), 1, img);
        }
}
else if (currentImage > 0)
{ 
        fwrite(buffer, sizeof(buffer), 1, img);


}

}
}

一旦找到jpeg,我就会遇到分段错误,然后执行fwrite,然后返回到while循环。

valgrind错误是:

==1866== Syscall param read(buf) points to unaddressable byte(s)
==1866==    at 0x5228810: __read_nocancel (syscall-template.S:81)
==1866==    by 0x51B63B8: _IO_file_xsgetn (fileops.c:1438)
==1866==    by 0x51AB93E: fread (iofread.c:42)
==1866==    by 0x4007C3: main (recover2.c:31)
==1866==  Address 0xfff001000 is not stack'd, malloc'd or (recently) free'd
==1866== 
==1866== Jump to the invalid address stated on the next line
==1866==    at 0x0: ???
==1866==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==1866== 
==1866== 
==1866== Process terminating with default action of signal 11 (SIGSEGV)
==1866==  Bad permissions for mapped region at address 0x0
==1866==    at 0x0: ???

我是新手,所以还在学习记忆等等,所以任何理解为什么出错都会有所帮助。

2 个答案:

答案 0 :(得分:6)

通过这样做

fread(buffer, sizeof(buffer), 512, file)

您要求fread读取512个块,每个块长度为sizeof(buffer)个字节。即您试图将512 * 512 = 262144字节读入声明为uint8_t buffer[512]的数组中。这当然不适合。

如果您只想将数据读入buffer数组,则可能是

fread(buffer, sizeof buffer, 1, file)

fread(buffer, 1, sizeof buffer, file)

或者,如果您愿意,

fread(buffer, sizeof *buffer, sizeof buffer / sizeof *buffer, file)

取决于您在读取操作中认为是“原子”数据块的内容。

另外

sprintf(title, "%03d.jpg", currentImage);

将生成至少7个字符长的字符串(例如001.jpg),这意味着title必须至少有8个字符长才能容纳零终结符。但是,您的title被声明为

char title[7];

这太小了。

答案 1 :(得分:1)

根据fread()的{​​{3}},签名为

  

size_t fread(void *ptr, size_t size, size_t nmemb, FILE * stream );

描述是

  

函数fread()nmemb指向的流中读取size个数据元素,每个stream个字节长,将它们存储在{ptr给出的位置1}}。

所以,你的代码应该是

 while (fread(buffer, sizeof(buffer[0]), 512, file) == 1)

否则,您最终要求读取和存储512个大小为512字节每个的块,这是错误的并且会导致缓冲区溢出,如valgrind报告的那样。