C - 通过调用fclose()转储核心

时间:2014-01-28 23:25:31

标签: c struct fclose

我的代码是segfaulting,我不知道出了什么问题。我已经尽可能地简化了它,但仍然找不到问题。

C File test.c:

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

struct container {
   void *A[3], *B[3], *C[3], *D[3];
   int x, y, z;
};

int main (int argc, char* argv[]) {
   struct container *cont = malloc (sizeof cont);
   FILE* fh = fopen( argv[1], "r" );
   if( fh == NULL ) return 0;
   fscanf(fh, "%d %d", &cont->y,  &cont->z);
   fclose( fh );
   free( cont );

   return 0;
}

test.txt的内容

1 1

执行并运行gdb:

$ gcc --version
gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ gcc -Wall -g test.c && gdb a.out 
GNU gdb (GDB) 7.6.1-ubuntu
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/dberg/ITX/Cells/test/a.out...done.
(gdb) break 26
Breakpoint 1 at 0x400739: file test.c, line 26.
(gdb) run test.txt
Starting program: /home/dberg/ITX/Cells/test/a.out test.txt

Breakpoint 1, main (argc=2, argv=0x7fffffffdf48) at test.c:26
26         fclose( fh );
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0x1) at malloc.c:2892
2892    malloc.c: No such file or directory.
(gdb) 

删除任何一个未使用的struct成员允许代码执行而不会出错。将任何未使用的struct成员移动到结构的末尾或减小任何1或所有数组的大小也允许代码成功执行。对于段错误,还需要存在fscanf()调用

我的语法在哪里错了,为什么结构的大小对这个bug如此重要?

2 个答案:

答案 0 :(得分:4)

*中缺少struct container *cont = malloc (sizeof cont);,您需要sizeof *cont

答案 1 :(得分:0)

Bzzzt!它不是失败的fclose,而是你没有malloc足够的空间来容纳(struct container)类型。这是一个语义而不是句法问题。

假设您有一个名为“stuff”的文件,其中包含:

1,2,3

你的程序名为doit.c,它读取这个文件(检查足够的参数,检查来自fopen和malloc的返回值等),

//you might want to carry a shorter name around,
typedef struct container_s
{
   void *A[3], *B[3], *C[3], *D[3];
   int x, y, z;
} container;
//how big is a (struct container)?  depends.  How big is a (void*) or an (int)?
//Suppose 32-bit, then you have 12x4+3*4=60 bytes.
//Suppose 64-bit pointer, and 32-bit integer, then you have 12x8+3*4=108 bytes.

int main (int argc, char* argv[])
{
   struct container* cont;
   FILE* fh = fopen( argv[1], "r" );
   char* filename=NULL;
   //you really should not examine argv[1] if there is no argument...
   if(argc<1) {
       printf("usage: stuff <filename>\n");
       exit(EXIT_FAILURE);
   }
   filename=argv[1];
   //allocate space for a (struct container_s)
   if( !(cont = malloc(sizeof(struct container))) ) {
        printf("error: cannot allocate container\n");
   }
   //check that file opens successfully,
   if(!(fh=fopen(filename,"r" ))) {
        printf("error: cannot open %s\n",filename);
        return 0;
   }
   //read your vector (x,y,z),
   fscanf(fh,"%d,%d,%d",&(cont->x),&(cont->y),&(cont->z));
   //for fun, print the (x,y,z) coordinates,
   printf("stuff(%d,%d,%d)\n",cont->x,cont->y,cont->z);
   fclose(fh);
   free(cont);

   return 0;
}

编译并运行上面的内容,然后就可以了,

./doit stuff
stuff(1,2,3)

请检查库函数(fopen,malloc)和边界检查数组(例如argv [])的返回值。哦,您可能想在容器中为A [],B [],C []和D []指定一个符号名称。