程序使用read()进入无限循环

时间:2011-02-18 17:36:39

标签: c linux gcc

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

}

这里,我已经用malloc分配了100MB的数据,并传递了一个足够大(不是500MB)大小的926KB的文件。当我传递小文件时,它会像魅力一样读取和退出,但是当我传递一个足够大的文件时,程序会执行到某个点,之后它就会挂起。我怀疑它要么进入无限循环,要么存在内存泄漏。

编辑为了更好地理解,我删除了所有不必要的函数调用,并在给出大文件作为输入时检查了会发生什么。我附上了修改后的代码

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 个答案:

答案 0 :(得分:3)

最明显的问题是:

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

除非文件的最后一个字符(或您刚读过的块)是\n,否则您将超过data数组的末尾,很可能会破坏堆栈方式(因为你没有检查你对message的写入是否在范围内)。

答案 1 :(得分:1)

尝试以下循环。基本上,它会重构您的实现,因此只有一个地方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;
}

答案 2 :(得分:0)

在您使用的系统上,500,000,000是否可能大于最大size_t?如果是这样,bytes_expected可能会滚动到某个较小的值。然后bytes_read紧随其后,你最终会获得比你实际期望的更小的数据块。结果是,对于大数据,数据的最后一个字符不太可能是'\ n',因此您在该内循环中直接通过它并开始访问超出数据末尾的字符。 Segfault紧随其后。