crash之野指針

例子一

堆棧信息

image.png

根據(jù)堆棧分析:
1,野指針
2搅荞,有對應(yīng)的堆棧
查看堆棧代碼,看那些有可能野指針:

+ (NSURLSessionDataTask *)httpAsyncPostWithUrl:(NSString *)urlHost
                                    dictionary:(NSDictionary *)dictionary
                                     userAgent:(NSString *)userAgent
                               completionBlock:(BDHKNetworkServiceResponse)block {
    
    [self setupNetworkService];
    
    // 檢查網(wǎng)絡(luò)
    if ([BDHKNetworkInfoManager currentNetworkStatus] == BDHKNetworkInfoStatusNotReachable) {
        if (block) {
            NSError *error = [NSError errorWithDomain:kBDHKNetworkingErrorDomain
                                                 code:kBDHKNetworkingUnreachableCode
                                             userInfo:nil];
//            [BDHKCoreDataCheck apiErrorCheckApi:urlHost tab:@"haokan" tag:@"haokan" videoType:@"video" vid:@"" error:error extraDict:@{}];
            block(nil, error);
        }
        return nil;
    }
    
    if ([Pyramid.bdhk_commonParams boolUploadZid]) {
        [Pyramid.bdhk_commonParams zid];   //更新zid
    }
    
    NSTimeInterval startTime = [[NSDate date] timeIntervalSince1970];
    __block NSDictionary *timeDic = nil;
    BDHKNetworkingResult resultBlock = ^(NSURLSessionTask * _Nullable task,
                                         NSDictionary * _Nullable response,
                                         NSError * _Nullable error) {
        // passposrt下沉后已修改
        if (!HK_isEmptyDictionary(response)) {
            [[BDHKCorePassportService sharedInstance] updatePassportStatusWithLoginInfo:response];
        }
       
//        if (!HK_isEmptyDictionary(response)) {
//            @try {
//                id obj = [NSClassFromString(@"BDHKPassportService") performSelector:@selector(sharedInstance)];
//                [obj performSelector:@selector(updatePassportStatusWithLoginInfo:) withObject:response afterDelay:0];
//            } @catch (NSException *exception) {
//
//            }
//        }
        if (error.code == kBDHKNetworkingUntrustCerErrorCode) {
            bdhk_toast(@"檢測到代理連接,關(guān)閉代理后可正常使用");
            NSDictionary *errorInfo = @{@"k": @"hk_stability",
                                        @"v": @"untrust_user_cer",
                                        @"url": urlHost};
            [BDHKNewLogService send760PackLogWithLogExtra:@{@"extra": errorInfo}];
            NSString * apiName = [dictionary.allKeys objectAtIndexCheck:0];
            [BDHKCoreDataCheck apiErrorCheckApi:apiName?:urlHost tab:@"haokan" tag:@"haokan" videoType:@"video" vid:@"" error:error extraDict:errorInfo];
        }
        
        if (block) {
            block(response, error);
        }
        
        // 打點
        NSTimeInterval responseTime = [[NSDate date] timeIntervalSince1970];
        BOOL isTurbo = [BDHKNetworking isTurboSession:task.bdhkSession];
        NSInteger errorCode = error ? error.code : 0;
        
        [BDHKNetWorkService apiRequestTime:startTime
                  type:isTurbo ? @"turbo" : @"native"
                  code:errorCode
               message:error.description
              response:task.response
            dictionary:dictionary
        responseObject:response
               timeDic:timeDic
                   url:urlHost
          responseTime:responseTime];
        
        if (error && error.code != NSURLErrorCancelled) {
            BOOL isEmpty = HK_isEmptyDictionary(response);
            [BDHKNetWorkService pageErrorLogDic:dictionary
                                           type:isEmpty ? @"2" : @"0"
                                          error:error];
            NSString * apiName = [dictionary.allKeys objectAtIndexCheck:0];
            [BDHKCoreDataCheck apiErrorCheckApi:apiName?:urlHost tab:@"haokan" tag:@"haokan" videoType:@"video" vid:@"" error:error extraDict:@{}];
        }
    };
    
    NSURLSessionDataTask *dataTask = nil;
    if (@available(iOS 10.0, *)) {
        dataTask = [BDHKNetworking postHost:urlHost
                           apiAndParameters:dictionary
                                  userAgent:userAgent
                            completionBlock:[resultBlock copy]
                               metricsBlock:^(NSURLSessionTask * _Nullable task,
                                              NSURLSessionTaskMetrics * _Nullable metrics) {
                timeDic = [self dicFromMetrics:metrics];
        }];
    } else {
        dataTask = [BDHKNetworking postHost:urlHost
                           apiAndParameters:dictionary
                                  userAgent:userAgent
                            completionBlock:[resultBlock copy]];
    }
    if ([dictionary objectForKey:@"feed"] != nil) {
        dataTask.priority = NSURLSessionTaskPriorityHigh; // 將feed請求調(diào)為最高優(yōu)先級
    }
    return dataTask;
}

分析所有參數(shù):
urlHost,dictionary构蹬,userAgent悔据, block, startTime科汗, timeDic,dataTask
以上所有參數(shù)怖亭,除了timeDic坤检,其他的都不存在多線程讀寫安全的問題,因為他們要不就是個真正的局部變量早歇,或者不存在一個線程在讀另一個線程在寫的可能
只有timeDic,在當(dāng)前函數(shù)的下方有賦值的寫操作晨另,但是在block里面有讀操作衅码,并且不能保證當(dāng)前函數(shù)的線程和block回調(diào)的線程是在同一個線程,所以是有造成多線程讀寫crash的

解決方案

對timeDic 讀寫進行加鎖操作

@synchronized (self) {
        timeDic = [self dicFromMetrics:metrics];
  }

讀操作這里用了copy,因為這個方法調(diào)用用到了timeDic割捅,沒法直接加鎖
如果強行加鎖只能把整個方法加鎖

@synchronized (self) {
            [BDHKNetWorkService apiRequestTime:startTime
                      type:isTurbo ? @"turbo" : @"native"
                      code:errorCode
                   message:error.description
                  response:task.response
                dictionary:dictionary
            responseObject:response
                   timeDic:tmpTimeDic
                       url:urlHost
              responseTime:responseTime];
        }

這種加鎖方式風(fēng)險極高亿驾,因為你不知道這個方法實現(xiàn)內(nèi)部是否有耗時操作,如果有,這里就會造成阻塞郭蕉,所以把timeDic直接加鎖拷貝喂江,因為方法內(nèi)部沒有對timeDic修改,只是獲取內(nèi)容获询,沒有修改的操作,所以copy也不影響梢薪,最終修改方案如下:

NSDictionary *tmpTimeDic = nil;
        @synchronized (self) {
            tmpTimeDic = [timeDic copy];
        }
        [BDHKNetWorkService apiRequestTime:startTime
                  type:isTurbo ? @"turbo" : @"native"
                  code:errorCode
               message:error.description
              response:task.response
            dictionary:dictionary
        responseObject:response
               timeDic:tmpTimeDic
                   url:urlHost
          responseTime:responseTime];

Q&A

多線程同時讀寫為什么會造成crash:
1尝哆,基本數(shù)據(jù)類型(非指針類型):不會造成crash,就是讀取到的數(shù)據(jù)可能不對畜疾,不一致
2印衔,指針類型:由于指針類型是直接賦值的操作,多線程多寫瞎暑,a線程讀的時候与帆,b線程可能剛好給重新賦值,因此a線程拿到的指針就指向了一個異常內(nèi)存玄糟,造成crash

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末阵翎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子郭卫,更是在濱河造成了極大的恐慌,老刑警劉巖玻蝌,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異帘腹,居然都是意外死亡许饿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門胸完,熙熙樓的掌柜王于貴愁眉苦臉地迎上來翘贮,“玉大人,你說我怎么就攤上這事狸页。” “怎么了址遇?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵斋竞,是天一觀的道長。 經(jīng)常有香客問我浸剩,道長鳄袍,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任重罪,我火速辦了婚禮哀九,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘勾栗。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布界牡。 她就那樣靜靜地躺著,像睡著了一般宿亡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上克胳,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天圈匆,我揣著相機與錄音,去河邊找鬼笆搓。 笑死纬傲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的算墨。 我是一名探鬼主播汁雷,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼摔竿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起熬苍,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤袁翁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后柄驻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體焙压,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡抑钟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年在塔,在試婚紗的時候發(fā)現(xiàn)自己被綠了拨黔。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡贺待,死狀恐怖零截,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞻润,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布正勒,位于F島的核電站傻铣,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏非洲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一败京、第九天 我趴在偏房一處隱蔽的房頂上張望梦染。 院中可真熱鬧,春花似錦泛粹、人聲如沸肮疗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钾怔。三九已至砍艾,卻和暖如春巍举,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蜓谋。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工炭分, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人观堂。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓呀忧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親而账。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容