UIDocument loadFromContents fails with EXC_BAD_ACCESS [duplicate] - ios

This question already has an answer here:
EXC_BAD_ACCESS using iCloud on multiple devices
(1 answer)
Closed 9 years ago.
I have a pretty simple IOS app using iCloud document storage. Everything was working and then at some point I began encountering a EXC_BAD_ACCESS error in my document load method for at least one iCloud document, although most files load just fine.
- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
file = (NSFileWrapper*) contents;
NSFileWrapper *infoFile = [[file fileWrappers] objectForKey:InfoFile];
NSData *infoData = [infoFile regularFileContents];
if(nil != infoData) {
NSPropertyListFormat format = NSPropertyListBinaryFormat_v1_0;
NSError *propertyListError;
// EXC_BAD_ACCESS occurs here
NSDictionary *dictionary = [NSPropertyListSerialization propertyListWithData:infoData options:NSPropertyListImmutable format:&format error:&propertyListError];
if(nil == propertyListError) {
_name = [dictionary objectForKey:#"name"];
_date = [dictionary objectForKey:#"date"];
_index = [dictionary objectForKey:#"index"];
_paperSize = [GritzPaperSizeEnum enumWithType:[dictionary objectForKey:#"paperSize"]];
TFLog(#"loading doc %#", _name);
_pages = [[NSMutableArray alloc] init];
for (NSString *key in file.fileWrappers) {
NSFileWrapper *subDir = [[file fileWrappers] objectForKey:key];
if(subDir.isDirectory) {
GritzPage *page = [[GritzPage alloc] initFromFile:subDir];
[_pages addObject:page];
}
}
_currentPage = [_pages objectAtIndex:0];
return YES;
}
}
return NO;
}
I would expect that I can 'catch' and handle bad data and ignore the corrupt file; but I can't seem to figure out how. A EXC_BAD_ACCESS error causes the app to crash.
What should I be doing differently to determine ahead of time that the data or file is going to fail and skip it (or delete it).

verify it is a NSFileWrapper using isKindOfClass, else treating it as one is weird (also look at the given typeName :))
using a #try { .. } #catch construct to catch any exception wont work in THIS case though as you cause a BAD_ACCESS which is a UNIX SIGNAL

The NSPropertyListFormat variable format should be declare as point. And i think you should call the propertyListWithData: Method with format as pointer not with the address of format.

Related

ARC lead to crash CoreFoundation object

I have a part of code which sometimes crashes on OSX system on client side but I can't reproduce the crash. I have only few assumptions but I don't want to make blind fix. I just want to be convinced with the fix:
+ (NSArray *)loginItems:(NSError *__autoreleasing *)error {
LSSharedFileListRef list = [self loginItemsFileListRef];
NSMutableArray *result = [NSMutableArray array];
NSArray *items = [self loginItemsForFileListRef:list];
CFRelease(list);
for (id item in items) {
LSSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
[result addObject:[self loginItemFromItemRef:itemRef]];
}
return result;
}
+ (NSDictionary *)loginItemFromItemRef:(LSSharedFileListItemRef)itemRef {
NSMutableDictionary *itemDict = [NSMutableDictionary dictionary];
// Name
CFStringRef nameRef = LSSharedFileListItemCopyDisplayName(itemRef);
if (nameRef) {
NSString *name = (__bridge NSString *)nameRef;
itemDict[RESLoginItemsNameKey] = name.stringByDeletingPathExtension;
CFRelease(nameRef);
}
// Path
CFURLRef URLRef = NULL;
if (LSSharedFileListItemResolve(itemRef, 0, &URLRef, NULL) == noErr) {
if (URLRef) {
NSURL *URL = (__bridge NSURL *)URLRef;
NSString *path = URL.path;
if (path) {
itemDict[RESLoginItemsPathKey] = path;
}
CFRelease(URLRef);
}
}
// Hidden
CFBooleanRef hiddenRef = LSSharedFileListItemCopyProperty(itemRef,
kLSSharedFileListLoginItemHidden);
if (hiddenRef) {
if (hiddenRef == kCFBooleanTrue) {
itemDict[RESLoginItemsHiddenKey] = #YES;
}
CFRelease(hiddenRef);
}
return itemDict;
}
The crash inside loginItems: namely SharedFileListItemDeallocate cause the crash. When NSArray's items auto-released. I suppose that:
SSharedFileListItemRef itemRef = (__bridge LSSharedFileListItemRef)item;
breaks ARC behavior and when loop finished it lead to release concrete item of the array. And second release will be called on function return which will lead to the crash.
Has anyone can prove or disprove my idea? Thanks.
I think the problem is that you are releasing list before using the items returned by
[self loginItemsForFileListRef:list]
If the items returned depend on list being valid, because the release of list might also trigger the release of the items, then you might crash when you try to iterate the returned items. Try to move the release of list after the for-loop that iterates the items. Sometimes you get bitten if you try to be overzealous about memory usage.

iOS error read memory failed

I'm working on an iPad app.
When the app is launched, user have to enter a number. With this id, I check in a csv file to get informations about the user.
Informations are saved with a singleton. This singleton is causing me problems :
step 1 : initialization of my singleton
+(ASMagasin*) sharedInstance {
if (myMagasin == nil){
myMagasin = [[ASMagasin alloc]init];
}
return myMagasin;
}
step 2 : I call my function which work with the csv file
- (id)init {
if (self = [super init]) {
NSError * error;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString * num_magasin = [defaults objectForKey:kUserDefautNumMagasin];
[self loadMagFromCsv:filePathCsv withMagasin:num_magasin];
}
return self;
}
step 3 :
-(void)loadMagFromCsv:(NSString *)filePath withMagasin:(NSString *) num_magasin
{
NSError *error;
NSString *csvData = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
NSArray *gcRawData = [csvData componentsSeparatedByString:#"\n"];
NSArray *singleGC = [NSArray array];
for (int i = 0; i < gcRawData.count; i++)
{
NSString *nextGCString = [NSString stringWithFormat:#"%#", gcRawData[i]];
singleGC = [nextGCString componentsSeparatedByString:#","];
if ([singleGC[0]isEqualToString:num_magasin]){
_num=singleGC[0];
_libelle=singleGC[1];
_client_defaut_nom=singleGC[2];
_client_defaut_prenom=singleGC[3];
_client_defaut_tel=singleGC[4];
_client_defaut_mail=singleGC[5];
_cp=singleGC[6];
_ville=singleGC[7];
_pays=singleGC[8];
}
}
}
In this function, my variable error have this value before I initialize it :
(NSError *) error = 0x0000000000000001 domain: read memory from 0x19
failed (0 of 8 bytes read) - code: read memory from 0x11 failed (0 of
8 bytes read)
I don't know how to solve that and where is this error come from.
You are looking at random memory in the heap. It is meaningless. Your NSError hasn't even been initialised at this point, let alone assigned a value.
You can (and should) check error for a value after you execute the line
NSString *csvData = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];
Before that error doesn't have a useful value.
I am posting it with a hope that it might help others facing same issue. Not sure about its exact cause, but I was experiencing it on a variable with _block before it. Removing _block fixed this issue and didn't give any warning either. Not sure what is going on here as I experienced it after updating to iOS 14. Will update if i find anything more interesting.

Exception isn't thrown when nil inserted in NSDictionary

So I was working on pulling photos from user's Facebook album and for some reason NSDictionary doesn't throw an exception when nil is inserted.
I've tested it on a real device and on iOS simulator (both iOS 7).
Maybe debugger crashes, maybe it's Facebook SDK bug.
Anyway, I'm ready to listen to your opinion.
UPDATE: One more thing I forgot to mention. In debugger, after inserting nil object in dictionary, debugger itself continues program execution. And I'm not even pressing the buttong "Continue program execution".
Here's the snippet
- (void)downloadAlbumsWithCompletionBlock:(void (^)(NSArray *albums, NSError *error))completionBlock;
{
[FBRequestConnection startWithGraphPath:#"/me/albums"
parameters:nil
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error)
{
if (error)
{
NSLog(#"%#", error.localizedDescription);
completionBlock(nil, error);
}
else
{
NSMutableArray *data = [result objectForKey:#"data"];
NSMutableArray *albums = [NSMutableArray new];
for (NSMutableDictionary *dict in data)
{
NSString *albumID = dict[#"id"];
NSString *coverPhotoID = dict[#"cover_photo"];
// coverPhotoID gets nil and then successfully gets put in NSDictionary
// You can just write "NSString *coverPhotoID = nil;".
NSString *description = dict[#"description"];
NSString *name = dict[#"name"];
NSDictionary *album = #{#"album_id": albumID,
#"album_cover_photo_id": coverPhotoID,
#"album_description": description,
#"album_name": name };
// Here an exception should be thrown but for some reason
// we just quit out of the method. Result would be the same if we put
// empty "return;" statement.
// If we explicitly put nil, like
// #"album_cover_photo_id": nil
// we get compiler error.
[albums addObject:album];
}
completionBlock(albums, nil);
}
}];
}
You wrote:
// Here an exception should be thrown but for some reason
// we just quit out of the method. Result would be the same if we put empty "return;" statement.
Most likely the exception is caught somewhere. Try putting a breakpoint on Objective-C exception throws (In Xcode, go to the Breakpoint tab, click + in the bottom left corner and select Add Exception Breakpoint. Make sure the parameters are set to Objective-C exception and break On Throw).
You claim that
NSString *albumID = dict[#"id"];
NSString *coverPhotoID = nil;
NSString *description = dict[#"description"];
NSString *name = dict[#"name"];
NSDictionary *album = #{#"album_id": albumID,
#"album_cover_photo_id": coverPhotoID,
#"album_description": description,
#"album_name": name };
doesn't crash your app.
Honestly, I don't believe it. Either you're trolling or you're misinterpreting whats happening.
As the first line of your for cycle log the dict dictionary:
NSLog(#"dict var: %#", dict);
Does dict contains the key album_cover_photo_id?
If you get something like
"album_cover_photo_id" : null
then NSString *coverPhotoID = dict[#"cover_photo"] is assigning an NSNull instance to coverPhotoID. In that case the app doesn't crash because an NSNull instance is not nil.
NSString *coverPhotoID = nil;
is different then
NSString *coverPhotoID = [NSNull null];
It's very common for servers to return nulls in JSON instead of omitting the key (server people are weird).
You can also log album after you create it
NSLog(#"album var: %#", album);
And if you are 100 % sure you're adding a nil to a dictionary, take it to the Apple developer forum. I bet they'd love to know about that bug.
I hope this helps you in some way.

iOS FGallery objective c assigning string value dynamically

It is a bit complicated to explain my problem. I am using FGallery library https://github.com/gdavis/FGallery-iPhone and especially its feature to load images from URL addresses. When I hardcode the URL path it works super, but wen I pass a string variable to the class which I have created it doesn't work. I tried to debug it and it seems that everything is ok, there is a string assigned to the variable and everything, but do not show the picture. I am doing this in a loop and using ARC.
-(void) loadSoftia
{
//======================================================================================
//THIS WORKS CORRECTLY!!!
wcSofia = [[NSMutableArray alloc] init];
Webcam *s1 = [[Webcam alloc]init];
s1.description=#"Sofia";
s1.location = #"http://www.ampthillweatherstation.info/currentweather/webcamimage.jpg";
[wcSofia addObject:s1];
//======================================================================================
NSMutableString *urlGetOthersLocations =[NSMutableString stringWithFormat:#"http://%#/WebHandlers/%#", #"192.168.188.204", #"BGCam.ashx"];
ServerResponse *serverResponseOthersLocations = [HelperViewController getJsonDataFromTheServer:urlGetOthersLocations];
if(serverResponseOthersLocations.data!=nil)
{
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:serverResponseOthersLocations.data
options:NSJSONReadingMutableLeaves|NSJSONReadingMutableContainers
error:nil];
[wcSofia removeAllObjects];
Webcam *wc;
int i=0;
for (NSDictionary *locationsDic in dic){
NSString *key;
for ( key in locationsDic) {
NSLog(#"%# = %#", key, [locationsDic objectForKey: key]);
}
NSLog(#"%#", [locationsDic objectForKey:#"URL"]);
NSLog(#"%# = %#", locationsDic, [locationsDic objectForKey: locationsDic]);
NSString *url =[locationsDic objectForKey:#"URL"];
// NSLog(#"%#", url);
NSMutableString* theString = [NSString stringWithFormat:#"%i ",i];
wc = [[Webcam alloc]initWithLocation: [NSString stringWithFormat:#"%#", url] withDescription:#"description"];
wc.location = url;//DOESNT WORK!
wc.description =#"София";// theString;//[NSString stringWithFormat:#"%#", #"aa"]; // #"София";
wc.location = #"http://media.borovets-bg.com/cams/channel?channel=61";//IT WORKS BECAUSE IT IS HARDCODED
if(wcSofia!=nil)
{
[wcSofia addObject:wc];
NSLog(#"%#", wc.location);
}
i++;
}
}
}
I have commented a section of the code which works and which doesn't.
I suppose that you are not going to need the whole program, because it make requests to my local web server to get the URL addresses and descriptions, but trust me this thing works perfect.
Thank you for your help in solving that mystery.
Edit:
Complete source Code: https://dl.dropboxusercontent.com/u/46512232/FGallery.zip

A GKScore must contain an initialized value?

I am getting a SIGABRT crash sometimes with the crash saying: A GKScore must contain an initialized value.
So it tracked it down to this line:
[localScore reportScoreWithCompletionHandler:^(NSError* error) {}];
And localStore is created like this:
GKScore* localScore = [scores objectForKey:category];
-- category comes from...
for (NSString* category in categories)
-- categories comes from...
[GKLeaderboard loadCategoriesWithCompletionHandler:^(NSArray *categories, NSArray *titles, NSError *error)
-(void) initScores
{
NSString* libraryPath = [NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString* file = [libraryPath stringByAppendingPathComponent:currentPlayerID];
file = [file stringByAppendingString:kScoresFile];
id object = [NSKeyedUnarchiver unarchiveObjectWithFile:file];
if ([object isKindOfClass:[NSMutableDictionary class]])
{
NSMutableDictionary* loadedScores = (NSMutableDictionary*)object;
scores = [[NSMutableDictionary alloc] initWithDictionary:loadedScores];
}
else
{
scores = [[NSMutableDictionary alloc] init];
}
//NSLog(#"scores initialized: %d", scores.count);
}
Sorry for all the code but pretty much all this code comes from this library's file: https://github.com/csddavies/DDGameKitHelper/blob/master/DDGameKitHelper.m
Anyway how would I fix this?
Thanks!!!
From the GameKit reference:
To report a score to Game Center, your game allocates and initializes a new object, sets the value property to the score the player earned, and then calls the reportScoreWithCompletionHandler: method.
Most likely it's complaining because you haven't set the value property, but it's also possible that you're missing the first step too -- i.e. it doesn't like you submitting GKScore objects that came from a leaderboard instead of ones you create yourself.

Resources