0

sometimes, fatal error occurs in my app with EXC_BAD_ADDRESS error log.

What is the cause of my code?

crash log

0. Crashed: GGMutableDictionary Isolation Queue
0  libobjc.A.dylib                0x184e2c150 objc_msgSend + 16
1  CoreFoundation                 0x1862e0d04 -[NSDictionary descriptionWithLocale:indent:] + 916
2  CoreFoundation                 0x1862e0dac -[NSDictionary descriptionWithLocale:indent:] + 1084
3  Foundation                     0x186da35a4 _NSDescriptionWithLocaleFunc + 76
4  CoreFoundation                 0x1863788bc __CFStringAppendFormatCore + 8440
5  CoreFoundation                 0x18637678c _CFStringCreateWithFormatAndArgumentsAux2 + 244
6  Foundation                     0x186da3418 +[NSString stringWithFormat:] + 68
7  app                            0x10019f4b8 -[TinyDB saveAsync] + 4296963256
8  app                            0x10019c86c __26-[TinyDB putString:value:]_block_invoke + 4296951916
9  libdispatch.dylib              0x18526e9a0 _dispatch_client_callout + 16
10 libdispatch.dylib              0x18527bee0 _dispatch_barrier_sync_f_invoke + 84
11 app                            0x10019c7e0 -[TinyDB putString:value:] + 4296951776

source file

This class is used asynchronously from many other class. This class should have thread safe. But EXC_BAD_ADDRESS fatal error occurs in saveAsync method. I think weakDictionaryRef or isolationQueue variables are deallocated. I want to fix this problem. What should I fix in this code? Thank you for your advice.

TinyDB.h file

@interface TinyDB : NSObject

@property (nonatomic, retain) NSString * docPath;
// @property (nonatomic, retain) NSMutableDictionary * dictionary;
@property (nonatomic, retain) NSFileManager * fileManager;
@property (nonatomic, retain) NSString * dir;
@property (nonatomic, assign) BOOL flagWrite;
- (instancetype)initWithFile:(NSString *)file;
- (NSString *)getDocPath;
- (void)putDouble:(NSString *)key value:(double)value;
- (void)putInt:(NSString *)key value:(NSInteger)value;
- (void)putMutableArray:(NSString *)key value:(NSMutableArray *)value;
- (void)putString:(NSString *)key value:(NSString *)value;
- (void)putTinyDB:(NSString *)key value:(TinyDB *)value;
- (void)putLong:(NSString *)key value:(NSInteger)value;
- (void)putBool:(NSString *)key value:(BOOL)value;
- (void)putDictionary:(NSString *)key value:(NSDictionary *)value;
- (id)get:(NSString *)key;
- (NSMutableArray *)getMutableArray:(NSString *)key;
- (BOOL)has:(NSString *)key;
- (void)saveAsync;
- (void)save;
- (NSString *)jsonString;
- (NSString *)stringify:(id)obj;
- (NSString *)getSet:(id)value;
- (NSString *)getPairSet:(NSString *)key value:(id)value;
- (NSMutableDictionary*)getMutableDictionary:(NSString*)key;
- (NSString *)getString:(NSString *)key;
- (BOOL)getBool:(NSString*)key;
- (NSArray *)allKeys;
- (void)removeObjectForKey:(NSString*)key;
@end

TinyDB.m file

@implementation TinyDB
{
@private dispatch_queue_t isolationQueue_;
@private __strong NSMutableDictionary * _myDictionary;
}
@synthesize docPath=docPath,fileManager=fileManager,dir=dir,flagWrite=flagWrite;
BOOL flagOnSave = false;
BOOL flagWrite = true;
NSString* dir;
NSString* docPath = @"";
NSLock* _dicLock=nil;
NSFileManager* fileManager;
__weak id _weakDictionaryRef;

-(id)initWithFile:(NSString *)file{
    self = [super init];
    docPath = file;
    // ##########################################
     isolationQueue_ = dispatch_queue_create([@"GGMutableDictionary Isolation Queue" UTF8String], DISPATCH_QUEUE_CONCURRENT);
    // ##########################################
    fileManager = [NSFileManager defaultManager];
    dir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) firstObject];
    dir = [NSString stringWithFormat:@"%@/myapp/",dir];
    BOOL flagFileExist = [fileManager fileExistsAtPath:[[NSString alloc] initWithFormat:@"%@/%@.myapp",dir,docPath]];
    _myDictionary = [[NSMutableDictionary alloc] init];
    if(flagFileExist){
        [BSDebugger log:[NSString stringWithFormat:@"DEBUG_myapp_CONFIG : File Found!!! %@ --> ",file]];
        @try{
            NSMutableDictionary* dic = [[NSMutableDictionary alloc] initWithContentsOfFile:[[NSString alloc] initWithFormat:@"%@/%@.myapp",dir,docPath]];
            _myDictionary = [[NSMutableDictionary alloc] initWithDictionary:dic];
        }@catch(NSException * e){
            _myDictionary = [[NSMutableDictionary alloc] init];
        }@finally{
        }
    }else{
        [BSDebugger log:[NSString stringWithFormat:@"DEBUG_myapp_CONFIG : File Not Found!!!--> %@ ",file]];
        _myDictionary = [[NSMutableDictionary alloc] init];
    }
    _weakDictionaryRef = _myDictionary;
    [self saveAsync];
    return self;
}
-(void)putString:(NSString*)key value:(NSString*)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        if(value == nil){
            return;
        }
        @try{
            [_myDictionary setObject:value forKey:key];
        }@catch(NSException* e){
            NSMutableDictionary* buff = [[NSMutableDictionary alloc] initWithDictionary:_myDictionary];
            _myDictionary = buff;
            _weakDictionaryRef = _myDictionary;
            dispatch_barrier_sync(isolationQueue_, ^{
                [_myDictionary setObject:value forKey:key];
            });
        }@finally{
        }
        [self saveAsync];
    });
}

- (void)putDouble:(NSString *)key value:(double)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        [_myDictionary setObject:[[NSNumber alloc] initWithDouble:value] forKey:key];
        [self saveAsync];
    });
}
- (void)putInt:(NSString *)key value:(NSInteger)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        @try{
            [_myDictionary setObject:[[NSNumber alloc] initWithInteger:value] forKey:key];
        }@catch(NSException* e){
            NSMutableDictionary* buff = [[NSMutableDictionary alloc] initWithDictionary:_myDictionary];
            _myDictionary = buff;
            _weakDictionaryRef = _myDictionary;
            [_myDictionary setObject:[[NSNumber alloc] initWithInteger:value] forKey:key];
        }@finally{
        }
        [self saveAsync];
    });
}
- (void)putMutableArray:(NSString *)key value:(NSMutableArray *)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        if( key != nil && value != nil ){
            [_myDictionary setObject:value forKey:key];
            [self saveAsync];
        }
    });
}
- (void)putTinyDB:(NSString *)key value:(TinyDB *)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        TinyDB* db = value;
        NSString* docuPath = [db getDocPath];
        @try{
            [_myDictionary setObject:docuPath forKey:key];
        }@catch(NSException* e){
            NSMutableDictionary* buff = [[NSMutableDictionary alloc] initWithDictionary:_myDictionary];
            _myDictionary = buff;
            _weakDictionaryRef = _myDictionary;
            dispatch_barrier_sync(isolationQueue_, ^{
                [_myDictionary setObject:docuPath forKey:key];
            });
        }@finally{

        }
        [self saveAsync];
    });
}
- (void)putLong:(NSString *)key value:(NSInteger)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        [_myDictionary setObject:[[NSNumber alloc] initWithInteger:value] forKey:key];
        [self saveAsync];
    });
}
- (void)putBool:(NSString *)key value:(BOOL)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        [_myDictionary setObject:[[NSNumber alloc] initWithBool:value] forKey:key];
        [self saveAsync];
    });
}
- (void)putDictionary:(NSString *)key value:(NSDictionary *)value{
    dispatch_barrier_sync(isolationQueue_, ^{
        [_myDictionary setObject:value forKey:key];
        [self saveAsync];
    });
}
-(void)removeObjectForKey:(NSString*)key{
    dispatch_barrier_sync(isolationQueue_, ^{
        if( _myDictionary != nil && [_myDictionary objectForKey:key] != nil ){
            [_myDictionary removeObjectForKey:key];
        }
    });
}
-(void) save{
    dispatch_barrier_sync(isolationQueue_, ^{
        @try {
            // NSLog([NSString stringWithFormat:@"writeToFile Error : orgPath = %@/%@.myapp / %@",dir,docPath, self.dictionary ]);
            // NSMutableDictionary* nsDic = self.dictionary;
            if( _myDictionary != nil ){
                NSDictionary * _dictionary =
                (__bridge NSDictionary *)(CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
                                                                       (__bridge CFPropertyListRef)(_myDictionary),
                                                                       kCFPropertyListImmutable));
                if( _dictionary != nil ){
                    [_dictionary writeToFile:[[NSString alloc] initWithFormat:@"%@/%@.myapp",dir,docPath]  atomically: false];
                }
            }
        }@catch (NSException *exception) {
            _myDictionary = [[NSMutableDictionary alloc] initWithDictionary:_myDictionary];
            _weakDictionaryRef = _myDictionary;
        }@finally {
        }
    });
}
// ################################################################
// normal function
- (NSString *)jsonString{
    __block NSString* buff = @"";
    dispatch_barrier_sync(isolationQueue_, ^{
        if( _myDictionary != nil ){
            NSDictionary * _dictionary = nil;
            // dispatch_barrier_sync(isolationQueue_, ^{
            _dictionary = (__bridge NSDictionary *)(CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
                                                                                 (__bridge CFPropertyListRef)(_myDictionary),
                                                                                 kCFPropertyListImmutable));
            if( _dictionary != nil ){
                buff = [self stringify:_dictionary];
            }
        }else{
            NSLog(@"buff = [self stringify:_myDictionary]; is nil ");
        }

    });
    return buff;
}
- (NSString *)stringify:(id)obj{
    if([obj isKindOfClass:[NSDictionary class]]){
        int idx = 0;
        NSString* buff = @"{";
        if( obj != nil ){
            NSDictionary* dic = [NSDictionary dictionaryWithDictionary:obj]; //obj;
            for(NSString* key in dic){
                id value = [dic objectForKey:key];
                if(idx != 0){
                    buff = [[NSString alloc] initWithFormat:@"%@%@",buff,@","];
                }
                buff = [[NSString alloc] initWithFormat:@"%@%@",buff,[self getPairSet:key value:value]];
                idx++;
            }
        }
        buff = [[NSString alloc] initWithFormat:@"%@%@",buff,@"}"];
        return buff;
    }else if([obj isKindOfClass:[NSArray class]]){
        int idx = 0;
        NSString* buff = @"[";
        if( obj != nil ){
            NSMutableArray* _a = [[NSMutableArray alloc] init];
            for( int ai = 0; ai < [obj count]; ai++){
                if( [obj objectAtIndex:ai] != nil ){
                    [_a addObject:[obj objectAtIndex:ai]];
                }
            }
            NSArray* arr = [NSArray arrayWithArray:_a]; //obj;
            for(id value in arr){
                if(idx != 0){
                    buff = [[NSString alloc] initWithFormat:@"%@%@",buff,@","];
                }
                buff = [[NSString alloc] initWithFormat:@"%@%@",buff,[self getSet:value]];
                idx++;
            }
        }
        buff = [[NSString alloc] initWithFormat:@"%@%@",buff,@"]"];
        return buff;
    }else{
        return [self getSet:obj];
    }
}
- (NSString *)getSet:(id)value{
    NSString* buff = @"";
    if([value isKindOfClass:[NSString class]]){
        buff = [[NSString alloc] initWithFormat:@"%@\"%@\"",buff,value];
    }else if([value isKindOfClass:[NSNumber class]]){
        NSNumber* val = value;
        buff = [[NSString alloc] initWithFormat:@"%@%@",buff,[val stringValue]];
    }else{
        buff = [[NSString alloc] initWithFormat:@"%@%@",buff,[self stringify:value]];
    }
    return buff;
}
- (NSString *)getPairSet:(NSString *)key value:(id)value{
    NSString* buff = @"";
    if([value isKindOfClass:[NSString class]]){
        buff = [[NSString alloc] initWithFormat:@"%@\"%@\":\"%@\"",buff,key,value];
    }else if([value isKindOfClass:[NSNumber class]]){
        buff = [[NSString alloc] initWithFormat:@"%@\"%@\":%@",buff,key,[value stringValue]];
    }else{
        buff = [[NSString alloc] initWithFormat:@"%@\"%@\":%@",buff,key,[self stringify:value]];
    }
    return buff;
}
-(NSMutableDictionary*)getMutableDictionary:(NSString*)key{
    NSMutableDictionary* dic = [[NSMutableDictionary alloc] init];
    id obj = [_myDictionary objectForKey:key];
    if(obj != nil){
        dic = [[NSMutableDictionary alloc] initWithDictionary:obj];
    }
    return dic;
}
-(NSArray *)allKeys{
    __block NSArray* arr = nil;
    dispatch_barrier_sync(isolationQueue_, ^{
        if( _myDictionary != nil ){
            arr = [_myDictionary allKeys];
        }
    });
    return arr;
}
- (NSString *)getDocPath{
    return docPath;
}
- (id)get:(NSString *)key{
    __block id _obj = nil;
    dispatch_barrier_sync(isolationQueue_, ^{
        _obj = [_myDictionary objectForKey:key];
    });
    return _obj;
}
- (NSString *)getString:(NSString *)key{
    __block NSString* returnStr = @"";
    dispatch_barrier_sync(isolationQueue_, ^{
        if([_myDictionary objectForKey:key]==nil){
            returnStr = @"";
        }
        if([[_myDictionary objectForKey:key] isKindOfClass:[NSString class]]){
            returnStr = [_myDictionary objectForKey:key];
        }else{
            returnStr = @"";
        }
    });
    return returnStr;
}
- (BOOL)getBool:(NSString*)key{
    __block BOOL flag = false;
    dispatch_barrier_sync(isolationQueue_, ^{
        if([_myDictionary objectForKey:key]==nil){
            flag = NO;
        }
        if([[_myDictionary objectForKey:key] isKindOfClass:[NSNumber class]]){
            NSNumber* boolValue = [_myDictionary objectForKey:key];
            if([boolValue boolValue] == YES){
                flag = YES;
            }else{
                flag = NO;
            }
        }else{
            flag = NO;
        }
    });
    return flag;
}
- (NSMutableArray *)getMutableArray:(NSString *)key{
    __block NSMutableArray* _arr = nil;
    dispatch_barrier_sync(isolationQueue_, ^{
        _arr =  [_myDictionary objectForKey:key];
    });
    return _arr;
}
- (BOOL)has:(NSString *)key{
    __block BOOL flag = false;
    dispatch_barrier_sync(isolationQueue_, ^{
        if([_myDictionary objectForKey:key] != nil){
            flag = true;
        }else{
            flag = false;
        }
    });
    return flag;
}
// #########################
// save function
int flagTest = 0;
bool mark = 0;
NSTimer* saveTimer = nil;
-(void)saveAsync{ 
    @try { 
        [BSDebugger log:[NSString stringWithFormat:@"_weakDictionaryRef : %@ ",_weakDictionaryRef ]];
        if( _myDictionary != nil ){
            if( _weakDictionaryRef != nil ){
                NSDictionary * _dictionary = nil;
                _dictionary = (__bridge NSDictionary *)(CFPropertyListCreateDeepCopy(kCFAllocatorDefault,
                                                                                     (__bridge CFPropertyListRef)(_myDictionary),
                                                                                     kCFPropertyListImmutable));
                @try{
                    flagOnSave = true;
                    UIBackgroundTaskIdentifier taskID = [myappCore beginBackgroundUpdateTask];
                    flagWrite = false;
                    NSString* orgPath = [[NSString alloc] initWithFormat:@"%@/%@.myapp",dir,docPath ];
                    @try {  
                        if( _dictionary != nil ){
                            [_dictionary writeToFile:orgPath atomically:YES];
                        }
                    }@catch (NSException *exception) {
                        [BSDebugger log:[NSString stringWithFormat:@"DEBUG_myapp_TINYDB : %@",[exception callStackSymbols]]];
                    }@finally {
                    }
                    flagWrite = true;
                    flagOnSave = false;
                    [myappCore endBackgroundUpdateTask:taskID];
                }@catch (NSException *exceptionMain) {
                    [BSDebugger log:[NSString stringWithFormat:@"DEBUG_myapp_TINYDB : %@",[exceptionMain callStackSymbols]]];
                }@finally {
                    _dictionary = nil;
                }
                return;
                // });
            }
        }
    }@catch (NSException *exception) {
    }@finally {
        // [_dicLock unlock];
    }
}
@end
Kunsoo Kim
  • 23
  • 1
  • 4

1 Answers1

0

Some ideas:

Turn on zombies (How to enable NSZombie in Xcode). You'll get more information about the object causing the crash when you do that.

If you can make the error happen at will, set a breakpoint at the top of saveAsync and step through it.

Change the stringWithFormat calls somehow so they don't reference anything that might be deallocated and see if the problem goes away. If it does, you'll know what was causing it.

I find it sometimes helps to override retain and release in objects I'm suspicious of and either print something out or set a breakpoint so I can see who might be over-releasing an object.

Craig
  • 3,253
  • 5
  • 29
  • 43