靜態(tài)庫中全局c方法被覆蓋導(dǎo)致bug的原因和分析

背景

給客戶提供了一個(gè)sdk,客戶那邊安裝了sdk后,發(fā)現(xiàn)另一個(gè)sdk的就會(huì)異常.....最后分析來分析去,發(fā)現(xiàn)只要添加我們的sdk就會(huì)有這樣的問題,于是,問題就到了我這了.

結(jié)論

先說結(jié)論吧,結(jié)論就是,我們的sdk中定義的一個(gè)全局c方法,覆蓋了另一個(gè)sdk中的全局c方法,然后,我們兩個(gè)c方法的作用又不一樣,從而導(dǎo)致出了不同的結(jié)果,導(dǎo)致問題.

分析

通常這種詭異的問題,調(diào)試分析是最頭痛的,因?yàn)橥耆恢绬栴}在哪,直接把對(duì)方的sdk和我們sdk的源碼加到一個(gè)測(cè)試工程里來,調(diào)試,發(fā)現(xiàn),確實(shí)是這樣,由于我們這個(gè)sdk中的文件數(shù)量不多,于是,一個(gè)個(gè)的刪除,定位到是由于一個(gè)包含全局c方法的文件中的c方法被對(duì)方sdk調(diào)用了...
也就是說,我們的c方法覆蓋了對(duì)方sdk中的同名方法了.

對(duì)于同樣都是靜態(tài)庫來說(靜態(tài)framework,.a文件),在編譯的時(shí)候,是會(huì)融合到宿主app的二進(jìn)制中去的,那么按理說,編譯階段,同名c方法,會(huì)被xcode提示出來啊,為什么這里會(huì)沒有提示呢?

我們隨便新建一個(gè)sdk,再建立一個(gè)宿主app,使用它.


image.png

在demo app中使用這個(gè)sdk


image.png

有幾個(gè)比較有意思的發(fā)現(xiàn):

宿主工程不加-ObjC的時(shí)候
主工程和庫工程中有重名的c方法的時(shí)候,xcode不會(huì)提示重復(fù)符號(hào),且能夠編譯運(yùn)行,至于哪個(gè)c方法會(huì)被調(diào)用,有如下的情況:
如果使用了c方法所在的文件中的類,那么調(diào)用的就是靜態(tài)庫中定義的c方法

- (void)viewDidLoad {
    [super viewDidLoad];
    convertSomething(@"");
    CustomAction *act = [CustomAction new];
   [act test1];
    // Do any additional setup after loading the view.
}
image.png

如果沒有使用,那么調(diào)用的就是宿主中定義的c方法.


image.png

宿主添加-ObjC的時(shí)候,xcode就會(huì)報(bào)錯(cuò)了,提示符號(hào)重復(fù)


image.png

這個(gè)也是我們通常認(rèn)為的結(jié)果!!

可是,使用方明明是加了 -ObjC的,按照我們的理解,有兩個(gè)重名的c方法,不是應(yīng)該報(bào)錯(cuò),提示符號(hào)重復(fù)么,為什么沒有?

然后,讓對(duì)方自己新建一個(gè)demo,添加-ObjC,看看,是不是會(huì)報(bào),結(jié)果對(duì)方告訴我,不會(huì)....
心里立馬萬馬奔騰啊,在群里和小伙伴們討論,群里有人提示可能是弱符號(hào).于是試了下弱符號(hào) attribute((weak))

image.png

再編譯一下,不報(bào)錯(cuò)了

這里插播一下弱符號(hào)是啥,有什么作用

弱符號(hào)

我們經(jīng)常在編程中碰到一種情況叫符號(hào)重復(fù)定義戒悠。多個(gè)目標(biāo)文件中含有相同名字全局符號(hào)的定義金拒,那么這些目標(biāo)文件鏈接的時(shí)候?qū)?huì)出現(xiàn)符號(hào)重復(fù)定義的錯(cuò)誤湃密。比如我們?cè)谀繕?biāo)文件A和目標(biāo)文件B都定義了一個(gè)全局函數(shù)/變量,并將它們都初始化乖坠,那么鏈接器將A和B進(jìn)行鏈接時(shí)會(huì)報(bào)錯(cuò).這種在全局中不能有重名的符號(hào),可以稱之為 strong symbol(強(qiáng)符號(hào)).
對(duì)于C/C++語言來說染突,編譯器默認(rèn)函數(shù)和初始化了的全局變量為強(qiáng)符號(hào)兼雄,未初始化的全局變量為弱符號(hào)梧税。
就如同我們上面的情況
為了解決這樣的問題,就引入了弱符號(hào)(weak symbol)的概念:用attribute((weak))修飾的全局變量/函數(shù)就是 弱符號(hào)
針對(duì)強(qiáng)弱符號(hào)的概念部默,鏈接器就會(huì)按如下規(guī)則處理與選擇被多次定義的全局符號(hào):
規(guī)則1:不允許強(qiáng)符號(hào)被多次定義(即不同的目標(biāo)文件中不能有同名的強(qiáng)符號(hào))侵蒙;如果有多個(gè)強(qiáng)符號(hào)定義,則鏈接器報(bào)符號(hào)重復(fù)定義錯(cuò)誤傅蹂。
規(guī)則2:如果一個(gè)符號(hào)在某個(gè)目標(biāo)文件中是強(qiáng)符號(hào)纷闺,在其他文件中都是弱符號(hào),那么選擇強(qiáng)符號(hào)份蝴。
規(guī)則3:如果一個(gè)符號(hào)在所有目標(biāo)文件中都是弱符號(hào)犁功,那么選擇其中占用空間最大的一個(gè)。比如目標(biāo)文件A定義全局變量global為int型婚夫,占4個(gè)字節(jié)浸卦;目標(biāo)文件B定義global為double型,占8個(gè)字節(jié)案糙,那么目標(biāo)文件A和B鏈接后限嫌,符號(hào)global占8個(gè)字節(jié)(盡量不要使用多個(gè)不同類型的弱符號(hào),否則容易導(dǎo)致很難發(fā)現(xiàn)的程序錯(cuò)誤)时捌。
更詳細(xì)的介紹可以看GCC的強(qiáng)符號(hào)和弱符號(hào)

繼續(xù)分析

以為發(fā)現(xiàn)了問題所在,興沖沖的讓對(duì)方去查下,是不是那個(gè)c方法用attribute((weak))修飾了,并且從內(nèi)心已經(jīng)認(rèn)定是這樣的了,準(zhǔn)備收工,可現(xiàn)實(shí)往往那么的出其不意..對(duì)方告訴我,全局搜索了下,沒有使用到 attribute((weak))....
我去,這,...還會(huì)有什么問題導(dǎo)致呢?

好吧,只能繼續(xù)分析了

對(duì)方也發(fā)來了他們的測(cè)試demo,說確實(shí)會(huì)出現(xiàn)可以在宿主中定義同他們的靜態(tài)庫中的c方法名字一樣的方法.

真的很奇怪,為啥我建立的demo,加了-ObjC,沒用attribute((weak))會(huì)報(bào)錯(cuò),他們建立的demo就不會(huì)呢?

一度懷疑,難道是我用的xcode和對(duì)方的有什么地方默認(rèn)的不一致?

再查看對(duì)方的demo

.....

對(duì)方的domo中,c方法所在的文件,只有c方法,沒有任何oc的類的定義.難道是這個(gè)導(dǎo)致的?

于是乎,試了下:

在demo中的sdk1中添加個(gè)只包含c方法的文件CustomeAction2
內(nèi)容是

//  CustomeAction2.h
#import <Foundation/Foundation.h>
NSString *convertSomething2(NSString * oriStr);
//  CustomeAction2.m
#import "CustomeAction2.h"
NSString *convertSomething2(NSString * oriStr){
    NSLog(@"convertSomething2 SDK1");
    return @"convertSomething2 SDK1 ";
}

然后在宿主中定義一個(gè)同名的

NSString *convertSomething2(NSString * oriStr){
    NSLog(@"convertSomething2 app");
    return @"convertSomething2 app ";
}

編譯,運(yùn)行,果然不報(bào)錯(cuò),
看來就是這個(gè)原因?qū)е碌牧?/p>

再添加 -all_load,不出意外,報(bào)錯(cuò)了


image.png

問題原因解讀

再度回憶 -ObjC的作用
-all_load Loads all members of static archive libraries.
-ObjC Loads all members of static archive libraries that implement an Objective-C class or category.

因?yàn)槎x的c方法所在的文件并沒有定義Objective-C的class或者category,所以 -ObjC并不會(huì)在符號(hào)表中導(dǎo)入他們,也即是這個(gè)-ObjC失效了,所以在宿主app中,就可以定義同名的方法了

當(dāng)然了解決方式很簡單
1 要求所有的宿主app,也就是接入方,在other linker flags中添加-all_load,這個(gè)來加載靜態(tài)庫中所有的方法,當(dāng)然了,這個(gè)解決方式不太好.
更好的解決方式是
2 在僅僅包含c方法的文件中添加一個(gè)類的定義

后記

最后,我還對(duì)比了下,在一個(gè)方法中添加不添加attribute((weak))最后的可執(zhí)行文件有什么不同

當(dāng)把一個(gè)方法定義為弱符號(hào)后
attribute((weak)) NSData * pasa_cipherOperation(NSData *contentData, NSData *keyData, CCOperation operation)
在最后的 靜態(tài)庫中出現(xiàn)的不同是:

在符號(hào)表 Symbol Table中對(duì)應(yīng)的方法


111.png

拿一個(gè)app的可執(zhí)行文件來試試
在other linker flags中 添加 -ObjC 和不添加,對(duì)于最后的二進(jìn)制的區(qū)別
當(dāng)然,由于xcode編譯兩次后,codesign部分會(huì)不一致,可以用
codesign --remove-signature 可執(zhí)行文件名 來移除簽名
然后用 beyond compare來進(jìn)行對(duì)比二進(jìn)制


E3C9173D-5F09-4D3E-BC0A-69048627BDBC.png

再在machoview中查看對(duì)應(yīng)的地址

DC24243A-D1CE-47D2-8A52-B03556765A8A.png

看來,這兩個(gè),改變的都是最后的mach-o文件中符號(hào)表Symbol Table所在的內(nèi)容.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末怒医,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奢讨,更是在濱河造成了極大的恐慌稚叹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件禽笑,死亡現(xiàn)場離奇詭異入录,居然都是意外死亡蛤奥,警方通過查閱死者的電腦和手機(jī)佳镜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凡桥,“玉大人蟀伸,你說我怎么就攤上這事∶骞簦” “怎么了啊掏?”我有些...
    開封第一講書人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衰猛。 經(jīng)常有香客問我迟蜜,道長,這世上最難降的妖魔是什么啡省? 我笑而不...
    開封第一講書人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任娜睛,我火速辦了婚禮髓霞,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘畦戒。我一直安慰自己方库,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開白布障斋。 她就那樣靜靜地躺著纵潦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪垃环。 梳的紋絲不亂的頭發(fā)上邀层,一...
    開封第一講書人閱讀 51,165評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音遂庄,去河邊找鬼被济。 笑死,一個(gè)胖子當(dāng)著我的面吹牛涧团,可吹牛的內(nèi)容都是我干的只磷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泌绣,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼钮追!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起阿迈,我...
    開封第一講書人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤元媚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后苗沧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刊棕,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年待逞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甥角。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡识樱,死狀恐怖嗤无,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情怜庸,我是刑警寧澤当犯,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站割疾,受9級(jí)特大地震影響嚎卫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宏榕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一拓诸、第九天 我趴在偏房一處隱蔽的房頂上張望胸懈。 院中可真熱鬧,春花似錦恰响、人聲如沸趣钱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽首有。三九已至,卻和暖如春枢劝,著一層夾襖步出監(jiān)牢的瞬間井联,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來泰國打工您旁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留烙常,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓鹤盒,卻偏偏與公主長得像蚕脏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侦锯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,097評(píng)論 1 32
  • 前言 Swift 貢獻(xiàn)給社區(qū) 作者 關(guān)于中文翻譯 條件語句 尤達(dá)表達(dá)式 nil 和 BOOL 檢查 黃金大道 復(fù)雜...
    一條魚的星辰大海閱讀 366評(píng)論 0 1
  • objc_getAssociatedObject返回與給定鍵的特定對(duì)象關(guān)聯(lián)的值驼鞭。ID objc_getAssoci...
    有一種再見叫青春閱讀 1,580評(píng)論 0 7
  • 有些東西在記憶深處,抹不去尺碰,忘不掉挣棕,組成生命中的溫暖。 有些話語就在嘴邊亲桥,說不出洛心,道不明,沉淀在心靈的深處题篷。 波濤...
    素琴雅韻閱讀 175評(píng)論 1 4
  • 多少父母望子成龍望女成鳳词身,何故?何求?一顆愛心無他求,不為攀龍附鳳只為兒女有一個(gè)幸福通達(dá)無悔的人生嗎?恐不盡然! ...
    跨馬涉遠(yuǎn)道閱讀 142評(píng)論 0 2