我遇到了一个奇怪的问题,我在尝试关闭文件时收到分段错误。正确地将数据写入文件,fflush和fclose之间是否会出现某种竞争条件?
//main.c
#define filename "/home/test.txt";
char fbuf[255];
sprintf(fbuf, "%s, %f, %f,%f \n", "big", 8.0,0.0,0.8);
sendFile(&fbuf, sizeof(fbuf), (void *)filename);
static void
sendFile( void *data, int size, char *pName)
{
FILE *pFile = fopen(pName,"a");
char *buf = NULL;
buf = (char *)malloc(255);
memcpy(buf, data, sizeof(char *)*size);
if(pFile == NULL) {
logger(LOG_INFO, "Error opening file\n");
}
else {
fwrite(buf, 1, strlen(buf), pFile);
fflush(pFile);
fclose(pFile);
}
free (buf);
}
非常感谢任何帮助或建议。
答案 0 :(得分:3)
我认为问题出在memcpy(buf, data, sizeof(char *)*size)
。
不应该只是memcpy(buf, data, size)
吗?
查看您的示例,fbuf
(即data
)是255个字符,buf
也是255个字符。但memcpy
正在复制超过一千个字符,有效地将垃圾写入堆中,结果不可预测。
答案 1 :(得分:1)
这是一个有效的代码版本,其中包含有关为什么与发布的代码不同的嵌入式注释。
注意:在Linux(和其他操作系统)上,/home
目录在没有管理权限的情况下是不可写的。所以对fopen()
的调用总是会失败。
//main.c
#include <stdio.h> // fwrite, fopen, fclose, perror
#include <stdlib.h> // exit, EXIT_FAILURE
#include <string.h> // strlen, sprintf, memcpy
// note: no comments at end of #define statement as the comment would be copied into the code
// note no ';' at end of #define statement
#define filename "/home/test.txt"
// to avoid using 'magic' numbers in code
// and this name used throughout the code
#define BUF_SIZE (255)
// prototypes
void sendFile( char *, char *); // so compiler does not make incorrect assumptions
// and no second parameter needed
char fbuf[BUF_SIZE] = {'\0'}; // avoid 'magic' numbers
// avoid placing trash into output file
// however, will place many NUL bytes
// main() function to make executable platform for testing
int main( void )
{
sprintf(fbuf, "%s, %f, %f,%f \n", "big", 8.0, 0.0, 0.8);
// changed 3rd parameter type to match actual function parameter type
sendFile(fbuf, filename); // no '&' because in C
// array name degrades to address of array
return 0;
}
void sendFile( char *data, char *pName) // use actual parameter types
{
FILE *pFile = fopen(pName,"a");
if(pFile == NULL) // always check for error immediately after call to system function, not later
{ // then fopen failed
perror( "fopen failed" );
//logger(LOG_INFO, "Error opening file\n");
exit( EXIT_FAILURE); // exit, so no other code executed
}
// implied else, fopen successful
char *buf = NULL;
if(NULL == (buf = malloc(BUF_SIZE) ) ) // don't cast returned value
{ // then malloc failed -- always check for error immediately after call to system function
perror( "malloc for output buffer failed");
//logger(LOG_INFO, "malloc for BUF_SIZE failed");
fclose( pFile); // cleanup
exit(EXIT_FAILURE); // exit, so no other code executed
}
// implied else, malloc successful
memcpy(buf, data, BUF_SIZE); // using original 3rd parameter would move 4 times as many bytes,
// I.E. past the end of the source buffer and past the end of the destination buffer
// resulting in undefined behaviour, leading to a seg fault event
// this memcpy() and the destination buffer
// are unneeded as first passed in parameter
// contains ptr to the source buffer
// which can be used in the call to fwrite()
fwrite(buf, BUF_SIZE, 1, pFile); // buf will have NUL byte immediately after 'big' so strlen() would return 3
// and the syntax for fwrite is source buffer, size of one item, number of items, FILE*
// and this parameter order is best
// because, if error checking,
// can just compare returned value to 1
fflush(pFile); // not actually needed as the fclose() performs a flush
fclose(pFile);
free (buf); // original code did this even if malloc had failed
// and even if the fopen had failed
// which would have corrupted the 'heap' leading to a seg fault event
}