本文介绍了二进制文件中存储的int的fread()失败,出现分段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎有10个问题的级别,并且(大多数)成功解决了C语言中fread()滥用引起的分段错误的答案.话虽如此,我遇到了这样的问题,但没有找到解决方案.

我有一个二进制文件,其中包含一个int(称为 nbins )和一个由float s组成的数组(大小为 nbins ).当我尝试读取此文件时,它会成功打开并指向文件句柄,但在读取 nbins int时会出现分段错误错误.这是一个最小的示例:

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

#define BPATH "/path/to/file"

int main(int agrc, char **argv)
{
    FILE *fd;
    int num;
    char fname[500]={};

    int nbins;
    float *coords;

    num = 5;
    sprintf(fname,"%s/file%d.dat", BPATH, num);

    if(!(fd=fopen(fname,"rb")))
    {
        printf("Can't open file: %s\n\n",fname);
        exit(0);
    }

    printf("Reading input file:\n");
    printf("%p: %s\n", fd, fname);       // prints successfully

    fread(&nbins, sizeof(int), 1, fd);
    printf("nbins = %d", nbins);         // seg faults before this print

    /*  the above print isn't properly flushed without an \n
     * The seg fault was not caused by the fread(), but the lack of
     * the above print lead to the confusion                         */

    coords = malloc(nbins * sizeof(float));
    fread(coords, sizeof(float), nbins, fd);

    fclose(fd);
    free(coords);

    return(0);
}

该文件是使用以下格式创建的:

int nbins[1];
nbins[0] = 5;                          // this 5 is just an example...
fwrite(nbins, sizeof(int), 1, file_ptr);
fwrite(coords, sizeof(float), nbins[0], file_ptr);

我也尝试使用:

int *nbins = malloc(sizeof(int));
fread(nbins, sizeof(int), 1, fd);

但这不能解决问题.该文件确实存在并且可读;我可以使用Python和NumPy的fromfile()很好地阅读它.我缺少明显的东西吗?谢谢!

解决方案

您可能具有 未定义行为 ,并具有以下情况:

  • int nbins;不会初始化nbins,因此它包含垃圾数据,可能非常大.

  • fread(&nbins, sizeof(int), 1, fd);未经过测试,因此可能会失败并保持nbins未初始化.阅读有关 fread 的信息.

  • printf("nbins = %d", nbins);没有\n,并且后面没有显式的fflush,因此请勿显示任何内容(因为通常是 行缓冲)./p>

  • coords = malloc(nbins * sizeof(float));将请求大量内存,因此将失败并在coords

  • 中获得NULL
  • fread(coords, sizeof(float), nbins, fd);写入NULL指针,由于UB

  • ,因此出现了分段冲突

您很幸运.事情可能会更糟(我们所有人都可能被黑洞所淹没).您还可以尝试一些鼻恶魔,或更糟糕的是,有一些执行似乎看起来可行的执行.

下次,请避免使用 UB .我不想消失在黑洞中,所以请忍受.

顺便说一句,如果您使用 GCC ,请编译所有警告和调试信息:gcc -Wall -Wextra -g.它会警告您.如果没有,您将在gdb调试器下获得SEGV.在Linux上, valgrind strace 也可以提供帮助.

请注意,无用的初始化(例如您的情况下为 explicit int nbins = 0;)在实践中不会造成损害.如果它们没有用(并且当它们不是无用的时(如您的情况,它们很快)),则优化编译器可能会删除它们.

必读

Lattner的博客: 什么每个C程序员都应该了解UB .相关概念:如果"规则.

还请阅读您正在使用的每个函数的文档(甚至与printf相同).

There seem to be of the order of 10 questions and (mostly) successful answers solving segmentation faults cause by misused fread()'s in C. That being said, I am having such a problem but have not found a solution.

I have a binary file containing an int (call it nbins) and an array of floats (of size nbins). When I try to read this file, it successfully opens and points to the file handle, but then gives a segmentation fault error when reading the nbins int. Here is a minimal example:

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

#define BPATH "/path/to/file"

int main(int agrc, char **argv)
{
    FILE *fd;
    int num;
    char fname[500]={};

    int nbins;
    float *coords;

    num = 5;
    sprintf(fname,"%s/file%d.dat", BPATH, num);

    if(!(fd=fopen(fname,"rb")))
    {
        printf("Can't open file: %s\n\n",fname);
        exit(0);
    }

    printf("Reading input file:\n");
    printf("%p: %s\n", fd, fname);       // prints successfully

    fread(&nbins, sizeof(int), 1, fd);
    printf("nbins = %d", nbins);         // seg faults before this print

    /* EDIT: the above print isn't properly flushed without an \n
     * The seg fault was not caused by the fread(), but the lack of
     * the above print lead to the confusion                         */

    coords = malloc(nbins * sizeof(float));
    fread(coords, sizeof(float), nbins, fd);

    fclose(fd);
    free(coords);

    return(0);
}

The file was created with the following formatting:

int nbins[1];
nbins[0] = 5;                          // this 5 is just an example...
fwrite(nbins, sizeof(int), 1, file_ptr);
fwrite(coords, sizeof(float), nbins[0], file_ptr);

I have also tried using:

int *nbins = malloc(sizeof(int));
fread(nbins, sizeof(int), 1, fd);

but this did not solve the problem.The file does exist and is readable; I can read it just fine using Python, with NumPy's fromfile(). Am I missing something obvious? Thanks!

解决方案

You may have undefined behavior, with the following scenario:

  • int nbins; does not initialize nbins, so it contains junk data, potentially a very large number.

  • fread(&nbins, sizeof(int), 1, fd); is not tested so could fail and keep nbins uninitialized. Read about fread.

  • printf("nbins = %d", nbins); has no \n and is not followed by an explicit fflush so don't show anything (since stdout is usually line-buffered).

  • coords = malloc(nbins * sizeof(float)); would request a huge amount of memory, so would fail and get NULL in coords

  • fread(coords, sizeof(float), nbins, fd); writes to the NULL pointer, giving a segmentation violation, since UB

You are very lucky. Things could be worse (we all could be annihilated by a black hole). You could also experiment some nasal demons, or even worse, have some execution which seems to apparently work.

Next time, please avoid UB. I don't want to disappear in a black hole, so bear with us.

BTW, if you use GCC, compile with all warnings and debug info : gcc -Wall -Wextra -g. It would have warned you. And if it did not, you'll get the SEGV under the gdb debugger. On Linux both valgrind and strace could have helped too.

Notice that useless initialization (e.g. an explicit int nbins = 0; in your case) don't harm in practice. The optimizing compiler is likely to remove them if they are useless (and when they are not useless, as in your case, they are very fast).

Mandatory read

Lattner's blog: What Every C Programmer should know about UB. Related notion: the As-if rule.

Read also the documentation of every function you are using (even as common as printf).

这篇关于二进制文件中存储的int的fread()失败,出现分段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-13 14:19