Julien
Julien

Reputation: 63

Objective-C crash with EXC_BAD_ACCESS after reading a file

A EXC_BAD_ACCESS is causing my app to crash. This issue normally occurs when you try to access unitialized or deallocated memory but I can't find where. I've tried to check with Zombie in Xcode without success. The app crash and instrument doesn't notice a zombie. I am using ARC.

The bad access occurs at the end of a method, on the closing curly bracket. (See screenshot). The issue only occurs in release mode (with optimizations) and only for a few devices.

enter image description here

To test, I've made a dummy project where the method is called right after didFinishLaunching.

Call Stack

  1. didFinishLaunchingWithOptions
  2. Alloc and init my custom object
  3. Call readFile on the newly created object
  4. Execute the code in readFile
  5. About to exit readFile, but app crash

Here's a simplified version of the code

- (void)readFromFile:(NSString *)fileName {
   if (!fileName) {
      return;
   }

   NSString* filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
   if (!filePath) {
      return;
   }

   FILE* file = fopen([filePath UTF8String], "r");
   if (file == NULL) {
       return;
   }

   size_t length;
   char *cLine = fgetln(file, &length);

   // I don't think it matters, but the file has about 400 000 lines
   while (length > 0) {
      char str[length - 1]; // All lines length are > 2
      strncpy(str, cLine, length);
      str[length - 1] = '\0'; // The crash would still occurs without this line, but less often

      // Custom code with str

      cLine = fgetln(file, &length);
   }
   fclose(file);
}

In case it could help you, here is the code of my reader object

@protocol MyReaderProtocol <NSObject>
 - (void)readFromFile:(NSString *)fileName;
@end

@interface MyReader : NSObject <MyReaderProtocol>
@end

// How I initialize the objet in the app delegate
MyReader myReader = [[MyReader alloc] init];
[myReader readFromFile:@"myFile.txt"];

Upvotes: 0

Views: 461

Answers (1)

CRD
CRD

Reputation: 53000

Based on reading your code only

The function call to fgetln() returns in length the number of characters in the line.

A C-array of characters with n elements is declared as char a[n] and the elements are addressed as a[0] to a[n-1].

You need to store length characters plus 1 for the EOS, you allocate an array of capacity length - 1 which is 2 too short.

Your strncpy() then writes past the end of the array.

Finally you write the EOS at index length - 1 when then maximum index is length - 2.

You are only overwriting by 1 byte (you write the EOS over the last character of the line), but that is enough to clobber whatever is next to the array on the stack (which might be cLine...)

HTH

Upvotes: 1

Related Questions