【问题标题】:C program crashes with Seg Fault but work perfectly fine under LLDBC 程序因 Seg Fault 崩溃,但在 LLDB 下工作正常
【发布时间】:2017-07-31 23:53:36
【问题描述】:

我正在编写一个香草文件读取代码。

大部分看起来像这样。

首先是头文件file.h

// fheader.h
#ifndef __file_h__
#define __file_h__
// start from here
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void readFile(FILE *fr);

FILE* openFile(char *file_name);
#endif

主文件fmain.c

#include "fheader.h"


void readFile(FILE *fr) {
    // Added Printf
    printf("\n...\n");
    printf("\n...\n");
    printf("\n...\n");
    printf("\n...\n");
  char *buffer = calloc(sizeof(char),1);
  while(!feof(fr)) {
    fread(buffer,sizeof(char),1,fr);
    printf("%s\n",buffer);
  }
  free(buffer);
  return;
}


FILE* openFile(char *file_name) {
  // printf("the file name that is going to be opened is %s",file_name);
  FILE *fr;
  fr = fopen(file_name,"r");
  return fr;
}

int main(int argc,char *argv[]) {
  if(argc < 2) {
    printf("USAGE: ./file test.txt\n");
    return 1;
  }

  if (argc > 2) {
    printf("ERROR: Too many argument\n");
    return 1;
  }
  FILE *fr;
  char *file_name = calloc(strlen(argv[1]),sizeof(char));

  strncpy(file_name,argv[1],strlen(argv[1]));
  fr = openFile(file_name);
  printf("\nReading from file\n");
  readFile(fr);
  fclose(fr);
  free(file_name);
  return 0;
}

我使用以下命令编译了代码

gcc -g3 -Wall fmain.c -o file.o

当我运行代码时

./file.o "~/workspaces/myWork/C_experiment/test.txt"

我看到Segmentation fault: 11

但是当我在 lldb 中运行上述程序时,我工作并以返回码 0 退出

lldb ./file.o
(lldb) run "~/workspaces/myWork/C_experiment/test.txt"
// output of the file 
Process 28806 exited with status = 0 (0x00000000)
(lldb) quit

现在,我对如何调试代码并找到 Seg Fault 原因一无所知。

【问题讨论】:

  • 使用核心转储至少可以看到它崩溃时的位置。
  • 顺便说一句,您没有显示编译代码时使用的“以下命令”。 .o 文件扩展名让我怀疑该命令的正确性。
  • 你没有检查openFile成功。如果openFile 无法打开文件(例如因为它不存在),它会返回NULL 并且readfile 将表现出未定义的行为(很可能会崩溃)。可能还有更多问题。
  • char *buffer = calloc(sizeof(char),1); 如果缓冲区大小在编译时已知,则毫无意义,只需编写char buffer[1](无论如何都是错误的,请参阅下面的答案)。
  • @Ruslan 更新编译命令。

标签: c file segmentation-fault


【解决方案1】:

您忘记在文件名末尾添加“\0”,当您执行 fread 读取 1 个字符时,您没有在缓冲区末尾添加“\0”。 如果您只读取一个字符,则应使用 char 而不是 1 的数组。

错误在这里:

 char *file_name = calloc(strlen(argv[1]),sizeof(char));
  strncpy(file_name,argv[1],strlen(argv[1]));
  fr = openFile(file_name);

您复制了 argv[1],但没有在末尾添加 '\0'。那么 fopen 将如何知道您的字符串在哪里停止? 您应该为 calloc 添加 +1,在 strncpy 之后,您应该像这样添加 '\0':

file_name[strlen(argv[1])] = '\0';

第二个错误在这里:

 char *buffer = calloc(sizeof(char),1);
  while(!feof(fr)) {
    fread(buffer,sizeof(char),1,fr);
    printf("%s\n",buffer);
  }

您将 1 分配给缓冲区并读取 1,这没关系,但是当您将其发送到 printf 时,您没有在缓冲区中添加 '\0' 那么 printf 怎么知道在哪里停止呢? 你应该 calloc 2 而不是一个然后添加一个buffer[1] = '\0';

所以有了这些修复:

#include "fheader.h"


void readFile(FILE *fr) {
  char buffer;
  while(!feof(fr)) {
    fread(&buffer,sizeof(char),1,fr);
    printf("%c\n",buffer);
  }
  return;
}


FILE* openFile(char *file_name) {
  // printf("the file name that is going to be opened is %s",file_name);
  FILE *fr;
  fr = fopen(file_name,"r");
  return fr;
}

int main(int argc,char *argv[]) {
  if(argc < 2) {
    printf("USAGE: ./file test.txt\n");
    return 1;
  }

  if (argc > 2) {
    printf("ERROR: Too many argument\n");
    return 1;
  }
  FILE * fr = openFile(argv[1]);
  printf("\nReading from file\n");
  readFile(fr);
  fclose(fr);
  return 0;
}

【讨论】:

  • 无论如何,不​​要使用strncpy 它可能会留下没有NUL终止符的目标字符串。
  • 你也可以这样做 :) 但是 strncpy 对于连接字符串非常有用。
  • strncpy(file_name,argv[1],strlen(argv[1])); file_name[name_size] = '\0'; 可以替换为strcpy(file_name, argv[1]);
  • 并且int name_size = strlen(argv[1]);fr = openFile(file_name);之间的代码可以替换为fr = openFile(argv[1]);。你不需要复制argv[1]中的文件名。
  • @MichaelWalz 我用 strncpy 是因为我猜它们又更好了Buffer Overflow attackhttp://stackoverflow.com/questions/1258550/why-should-you-use-strncpy-instead-of-strcpy
猜你喜欢
  • 1970-01-01
  • 2011-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
相关资源
最近更新 更多