Программа, использующая read (), входит в бесконечный цикл - PullRequest
1 голос
/ 18 февраля 2011
1oid ReadBinary(char *infile,HXmap* AssetMap)
{
    int fd; 
   size_t bytes_read, bytes_expected = 100000000*sizeof(char); 
   char *data;

   if ((fd = open(infile,O_RDONLY)) < 0) 
      err(EX_NOINPUT, "%s", infile);


   if ((data = malloc(bytes_expected)) == NULL)
      err(EX_OSERR, "data malloc");

   bytes_read = read(fd, data, bytes_expected);

   if (bytes_read != bytes_expected) 
      printf("Read only %d of %d bytes %d\n", \
         bytes_read, bytes_expected,EX_DATAERR);

   /* ... operate on data ... */
    printf("\n");
    int i=0;
    int counter=0;
    char ch=data[0];
    char message[512];
    Message* newMessage;
    while(i!=bytes_read)
    {

        while(ch!='\n')
        {
        message[counter]=ch;
        i++;
        counter++;
        ch =data[i];
        }
    message[counter]='\n';
    message[counter+1]='\0';
//---------------------------------------------------
    newMessage = (Message*)parser(message);
    MessageProcess(newMessage,AssetMap);
//--------------------------------------------------    
    //printf("idNUM %e\n",newMessage->idNum);
    free(newMessage);
    i++;
    counter=0;
    ch =data[i];
    }
   free(data);  

}

Здесь я выделил 100 МБ данных с помощью malloc и передал файл достаточно большого (не 500 МБ) размера около 926 КБ. Когда я передаю небольшие файлы, он читает и выходит, как талисман, но когда я передаю достаточно большой файл, программа выполняется до некоторой точки, после которой она просто зависает. Я подозреваю, что он либо вошел в бесконечный цикл, либо произошла утечка памяти.

РЕДАКТИРОВАТЬ Для лучшего понимания я убрал все ненужные вызовы функций и проверил, что происходит, когда в качестве входных данных используется большой файл. Я приложил измененный код

void ReadBinary(char *infile,HXmap* AssetMap)
{
    int fd; 
   size_t bytes_read, bytes_expected = 500000000*sizeof(char); 
   char *data;

   if ((fd = open(infile,O_RDONLY)) < 0) 
      err(EX_NOINPUT, "%s", infile);


   if ((data = malloc(bytes_expected)) == NULL)
      err(EX_OSERR, "data malloc");

   bytes_read = read(fd, data, bytes_expected);

   if (bytes_read != bytes_expected) 
      printf("Read only %d of %d bytes %d\n", \
         bytes_read, bytes_expected,EX_DATAERR);

   /* ... operate on data ... */
    printf("\n");
    int i=0;
    int counter=0;
    char ch=data[0];
    char message[512];
    while(i<=bytes_read)
    {

        while(ch!='\n')
        {
        message[counter]=ch;
        i++;
        counter++;
        ch =data[i];
        }
    message[counter]='\n';
    message[counter+1]='\0';
    i++;
    printf("idNUM \n");
    counter=0;
    ch =data[i];
    }
   free(data);  

}

Похоже, он печатает множество idNUM, а затем poof segmentation fault

Я думаю, что это интересное поведение, и мне кажется, что есть проблема с памятью

ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ Я вернул обратно i!=bytes_read, это не дает ошибки сегментации. Когда я проверяю i<=bytes_read, он выходит за пределы внутренней петли. (Любезно предоставлено GDB)

Ответы [ 3 ]

3 голосов
/ 18 февраля 2011

Наиболее вопиющая проблема заключается в следующем:

    while(ch!='\n')
    {
    message[counter]=ch;
    i++;
    counter++;
    ch =data[i];
    }

Если только последний символ файла (или блока, который вы только что прочитали) не равен \n, вы пройдете через конецмассив data, наиболее вероятно разбивающий стек по пути (так как вы не проверяете, находится ли ваша запись в message в пределах границ).

1 голос
/ 19 февраля 2011

Попробуйте следующий цикл. По сути, это рефакторинг вашей реализации, поэтому есть только одно место, где i увеличивается. Наличие двух мест - вот что доставляет вам неприятности.

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

int main()
{
    const char* data = "First line\nSecond line\nThird line";
    unsigned int bytes_read = strlen(data);

    unsigned int i = 0;
    unsigned int counter = 0;
    char message[512];

    while (i < bytes_read)
    {
        message[counter] = data[i];
        ++counter;
        if (data[i] == '\n')
        {
            message[counter] = '\0';
            printf("%s", message);
            counter = 0;
        }
        ++i;
    }

    // If data didn't end with a newline
    if (counter)
    {
        message[counter] = '\0';
        printf("%s\n", message);
    }

    return 0;
}

Или вы можете выбрать подход «не изобретать велосипед» и использовать стандартный strtok вызов:

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

int main()
{
    char data[] = "First line\nSecond line\nThird line";
    char* message = strtok(data, "\n");

    while (message)
    {
        printf("%s\n", message);
        message = strtok(NULL, "\n");
    }

        return 0;
}
0 голосов
/ 19 февраля 2011

Возможно ли, что в используемой вами системе 500 000 000 больше, чем самый большой size_t?Если это так, bytes_expected может переходить к некоторому меньшему значению.Тогда bytes_read следует примеру, и вы в конечном итоге берете меньший кусок данных, чем вы на самом деле ожидаете.В результате для больших данных последним символом данных вряд ли будет '\ n', поэтому вы проходите мимо этого внутреннего цикла и начинаете получать доступ к символам за концом данных.Segfault следует.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...