fprintf调用引发EXC_BAD_ACCESS异常

问题描述

当我在Mac上运行下面显示的APUE示例代码时,它将引发EXC_BAD_ACCESS异常。我已经检查了文件光标,它在正确的位置12。我什至尝试将fprintf替换为fputc。之后,它可以正常工作,并且异常消失了。但是我想知道那里发生了什么以及为什么。

#include "apue.h"

#define BSZ 48

int main(){
  FILE *fp;
  char buf[BSZ];

  memset(buf,'a',BSZ-2);
  buf[BSZ-2]='\0';
  buf[BSZ-1]='X';
  if ((fp = fmemopen(buf,BSZ,"w+")) == NULL)
      err_sys("fmemopen Failed");
  printf("initial buffer contents: %s\n",buf);
  fprintf(fp,"hello,world");
  printf("before flush: %s\n",buf);
  fflush(fp);
  printf("after fflush: %s\n",buf);
  printf("len of string in buf = %ld\n",(long)strlen(buf));

  memset(buf,'b',BSZ-2);
  buf[BSZ-2]='\0';
  buf[BSZ-1]='X';
  fprintf(buf,world");
//  fputc('a',fp);
  fseek(fp,SEEK_SET);
  printf("after fseek: %s\n",(long)strlen(buf));
}

控制台输出如下:

/Users/heping/Documents/APUE-Example-Code/stdio/cmake-build-debug/memstr
initial buffer contents: 
before flush: hello,world
after fflush: hello,world
len of string in buf = 12
Exception: EXC_BAD_ACCESS (code=1,address=0x8)

Process finished with exit code 9

最后一个堆栈框架是这样的:我认为文件锁定似乎有问题。

stak frame

解决方法

正如注释中已经讨论的那样,您将缓冲区buf传递给fprintf()而不是FILE指针fp传递给了UB。

当您尝试执行启用警告标志之类的操作时,每个合理的编译器都会打印警告。当启用所有编译器警告时,可以避免进行大量调试,并且仅在确定不希望针对某种类型的错误发出警告时才禁用特定警告。 如此处How to enable all compiler warnings in CLion?所述,您可以通过向CMakeLists.txt添加编译器标志来启用警告。对于C代码的所有警告,请添加以下行:

set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror")

-Wall将启用所有常规警告,-Wextra将启用其他警告,-Wpedantic将警告您未严格遵循您指定的C标准,并且-Werror会关闭所有警告变成错误,因此您必须先修正错误,然后才能编译程序。万一收到不需要的警告,可以用相同的方式将其禁用,如下所示:

set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wpedantic -Werror -Wno-cast-function-type")

-Wno-cast-function-type将禁用有关将函数指针转换为其他函数指针的警告。您可以阅读所有警告选项here