2015-09-03 4 views
0

У меня возникла странная проблема, когда я получаю ошибку сегментации при попытке закрыть файл. Данные записываются в файл правильно, может ли быть какое-то состояние гонки между fflush и fclose?C - Ошибка сегментации при закрытии файла

//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); 
} 

Любая помощь или предложения приветствуются.

+2

Почему, по вашему мнению, это 'fclose', что вызывает segfault? –

+3

Пожалуйста, не выдавайте результат malloc. – Martin

+1

Почему вы выделяете 255 байтов для 'buf', а' size' легко доступен? Не мог ли он переполнить его? –

ответ

3

Я думаю, проблема в memcpy(buf, data, sizeof(char *)*size).

Не должно быть memcpy(buf, data, size)?

Глядя на ваш пример, (т. Е. data) составляет 255 символов, а buf - 255 символов. Но memcpy копирует более тысячи символов, эффективно записывая мусор в кучу с непредсказуемыми результатами.

+0

Это не изменит ситуацию. Одна из реальных проблем - это то, что происходит, если 'size' больше 255, разделенных размером' char * '. –

+1

@AndrewHenle: ну, это будет иметь значение, так как 'sizeof (char *) * size' намного больше, чем' size' (4 или 8 раз 'size', в зависимости от реализации) –

+1

Да, но он также используя 'strlen()', не гарантируя, что скопированные данные прекращаются. Просто напишите строку в файл. Есть много проблем с только что отправленным кодом. –

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 
} 
Смежные вопросы