Search code examples
cmacosioposix

The fprintf call throws EXC_BAD_ACCESS exception


When I ran the APUE sample code shown below on my Mac, it throws a EXC_BAD_ACCESS exception. I have checked the file cursor, and it is in the right position 12. I even try to replace the fprintf with fputc. After that, it works fine and the exception is gone. But I want to know what happened out there and why.

#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, "hello, world");
//  fputc('a',fp);
  fseek(fp,0,SEEK_SET);
  printf("after fseek: %s\n",buf);
  printf("len of string in buf = %ld\n", (long)strlen(buf));
}

Console out put as below:

/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

Last stack frame like this: it seems like that something is wrong with the file lock, I think.

stak frame


Solution

  • As already discussed in the comments, you passed the buffer buf to fprintf() and not the FILE pointer fp, which causes UB.

    Every reasonable compiler will print a warning when you trying to do something like that you enabled the warning flags. You can avoid a lot of debugging when you enable all compiler warnings and only disable specific warnings when you are sure you do not want a warning for some type of error. As mentioned here How to enable all compiler warnings in CLion?, you can enable warnings by adding the compiler flags to CMakeLists.txt. For all warnings for C code, adding this line:

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

    -Wall will enable all normal warnings, -Wextra will enable additional warnings, -Wpedantic will warn about not strictly following the C standard you specified and -Werror will turn every warning into a error, so you have to fix the error before you can compile the program. In case you get warnings you do not want, you can disable them the same way, like this:

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

    -Wno-cast-function-type will disable warnings about casting function pointers to different function pointers. You can read about all the warning options here