[英]heap-buffer-overflow with fprintf
我正在更新我的问题,非常抱歉以错误的方式提问。
现在我可以将我的问题提炼成一段独立的代码:
#include <stdio.h>
#include <stdlib.h>
static __inline__ char* fileRead(char* file){
FILE* fp;
long fileSize;
char* fileContents;
fp = fopen ( file , "rb" );
if(!fp){
perror(file);
exit(1);}
/* this block writes the size of the file in fileSize */
fseek( fp , 0L , SEEK_END);
fileSize = ftell( fp );
rewind( fp );
/* allocate memory for entire content */
fileContents = malloc(fileSize+1);
if(!fileContents){
fclose(fp);
fputs("memory alloc fails",stderr);
exit(1);}
/* copy the file into the buffer */
if(fread(fileContents, fileSize, 1, fp) != 1){
fclose(fp);
free(fileContents);
fputs("entire read fails",stderr);
exit(1);}
/* close the file */
fclose(fp);
return fileContents;}
int main (){
char* head10 = "";
char* fileName = "testhtml.html";
FILE* out = fopen(fileName, "w");
head10 = fileRead("head10.html");
printf("%s\n", head10);
out = fopen(fileName, "wb");
fprintf(out, "%s\n", head10);
fclose(out);
free(head10);
return 0;}
这里是head10.html文件。
我正在用-fsanitize=address
编译它,我得到了一个堆缓冲区溢出。 该错误似乎是在fprintf(out, "%s\n", head10);
行引起的。 . head10
是唯一的 malloc 变量,所以这是有道理的。
我可以使用 printf 毫无问题地打印它,但是当我尝试使用 fprintf 将其写入文件时,会生成堆缓冲区溢出。
===EDIT===看起来问题来自使用带有malloc'd var的fprintf,因为fprintf本身在引擎盖下使用malloc,所以原来的alloc丢失了,memory泄漏。
所以我在不使用 malloc 的情况下重写了我的函数:
#define _POSIX_C_SOURCE 200809L /* for getline() */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static __inline__ void fileReset(char* fileName){
FILE* out = fopen(fileName, "w");
fwrite("" , sizeof(char) , strlen("") , out );
fclose(out);}
static __inline__ void fileAppend(char* fileName, char* string){
FILE* out = fopen(fileName, "a"); /* using "a" to APPEND */
if(fwrite(string , sizeof(char) , strlen(string) , out ) != strlen(string)){
printf("==file write error\n");
exit(EXIT_FAILURE);}
fclose(out);}
static __inline__ void fileAppendFile(char* source, char* dest){
FILE* in = fopen(source, "r");
char *line = NULL;
size_t len = 0;
size_t read;
while ((read = getline(&line, &len, in)) != -1) {
fileAppend(dest, line);}
free(line);
fclose(in);}
int main (){
char* fileName = "testhtml.html";
char* theme = "dark";
fileReset(fileName);
fileAppendFile("head10.html", fileName);
fileAppend(fileName, theme);
return 0;}
非常感谢所有的帮助,这里非常菜鸟,不知道 -lasan 是什么,现在我知道了多么宝贵的工具!
==EDIT-2== 正如 EmployedRussian 所指出的,原始代码中的问题不是 fprintf,而是缺少终止 '\0',请查看下面的答案,它确实修复了我的原始代码:)
看起来问题来自使用带有 malloc'd var 的 fprintf,因为 fprintf 本身在引擎盖下使用 malloc,所以原来的 alloc 丢失了,memory 泄漏。
恐怕你在这里吸取了错误的教训。
虽然fprintf
可能确实在引擎盖下使用了malloc
,但您的问题与此无关。
我创建了一个包含abc\n
(4 个字符)的head10.html
文件。 使用生成的输入文件运行程序:
==10173==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x602000000015 at pc 0x7fb5db2c7054 bp 0x7ffd44e74de0 sp 0x7ffd44e74590
READ of size 6 at 0x602000000015 thread T0
#0 0x7fb5db2c7053 (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x4d053)
#1 0x5654101dd435 in main /tmp/foo.c:43
#2 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
#3 0x5654101dd199 in _start (/tmp/a.out+0x1199)
0x602000000015 is located 0 bytes to the right of 5-byte region [0x602000000010,0x602000000015)
allocated by thread T0 here:
#0 0x7fb5db381628 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.5+0x107628)
#1 0x5654101dd2db in fileRead /tmp/foo.c:20
#2 0x5654101dd425 in main /tmp/foo.c:42
#3 0x7fb5db0dde0a in __libc_start_main ../csu/libc-start.c:308
所以问题是您分配了 5 个字节(如预期的那样),但fprintf
试图从该缓冲区中读取第 6 个字符。
为什么会这样做? 因为您使用的格式: %s
期望找到一个终止NUL
字符(即它期望一个正确终止的 C 字符串),并且您给了它一个指向具有以下字节的非终止字符串的指针:
a b c \n X
第五个字节包含什么值? 它是未定义的(它来自malloc
,并且没有写入任何值)。 由于该值不是NUL
,因此fprintf
尝试读取下一个(第 6 个)字节,这就是 Address Sanitizer 发出错误信号并中止程序的时候。
正确的解决方法是NUL
终止字符串,如下所示:
if (fread(fileContents, fileSize, 1, fp) != 1){ ... handle error
fileContents[fileSize] = '\0'; // NUL-terminate the string.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.