今天遇到一個(gè)問(wèn)題,調(diào)試了一天.
大致描述一下,移植一個(gè)開(kāi)源項(xiàng)目的代碼,原來(lái)在mips平臺(tái)上運(yùn)行正常,后來(lái)到arm平臺(tái)的機(jī)器上運(yùn)行,結(jié)果運(yùn)行時(shí)出錯(cuò)了.
一般的,這樣的問(wèn)題,腦子里面第一下的反應(yīng)就是由于字節(jié)序問(wèn)題造成的.
我起初也是這么想的.因?yàn)閺某鲥e(cuò)的現(xiàn)象來(lái)看,是某個(gè)字段不符合要求造成的出錯(cuò).于是沿著這個(gè)思路去找BUG.抓包來(lái)分析,看上去也是這樣的.但是,追蹤的過(guò)程中發(fā)現(xiàn),有多次收發(fā)報(bào)文的過(guò)程,這個(gè)字段,或者說(shuō)擁有這個(gè)字段的結(jié)構(gòu)體在多處都有使用,改了一處,在別的地方其它字段又有報(bào)錯(cuò).
回頭看代碼,發(fā)現(xiàn)在最開(kāi)始解析包頭的時(shí)候,已經(jīng)造成了緊跟著包頭的某個(gè)字段出現(xiàn)異常,于是,想到是不是在不同的平臺(tái)上,sizeof(某結(jié)構(gòu)體)的數(shù)值不一樣造成,要驗(yàn)證這一點(diǎn),給包頭結(jié)構(gòu)體的定義加上嚴(yán)格按照一個(gè)字節(jié)對(duì)齊的限制,重新運(yùn)行程序,可以了.
最后再來(lái)稍微詳細(xì)一些看這個(gè)問(wèn)題,假設(shè)包頭結(jié)構(gòu)體的定義是:
typedef unsigned short u16;
struct header
{
u16 a;
u16 b;
u16 c;
};
如果解析的時(shí)候,sizeof(struct header) != sizeof(u16) * 3,那么使用sizeof(struct header)解析接收到緩沖區(qū)的數(shù)據(jù)就會(huì)出現(xiàn)問(wèn)題,因?yàn)樗鼤?huì)對(duì)緊跟著的數(shù)據(jù)也造成影響.程序的異常正是源于此.在代碼的處理中,首先接收包頭,對(duì)包頭的數(shù)據(jù)進(jìn)行了字節(jié)序轉(zhuǎn)換,然后,又對(duì)緊挨著包頭的結(jié)構(gòu)體進(jìn)行了相同的字節(jié)序轉(zhuǎn)換,由于包頭結(jié)構(gòu)體的字節(jié)序轉(zhuǎn)換同時(shí)影響了緊挨著的結(jié)構(gòu)體中的數(shù)據(jù),所以這些數(shù)據(jù)實(shí)際上被進(jìn)行了兩次的字節(jié)序轉(zhuǎn)換,這才造成了這個(gè)問(wèn)題"看上去"是字節(jié)序轉(zhuǎn)換不當(dāng)造成的"表面原因",如果跟著這個(gè)原因繼續(xù)跟蹤下去,以這個(gè)思路解決問(wèn)題,治標(biāo)而不治本.
總結(jié):
1. 收發(fā)數(shù)據(jù)的結(jié)構(gòu)體定義需要嚴(yán)謹(jǐn)一些,如果不能確定如何對(duì)齊,最好自己定義一個(gè)對(duì)齊的標(biāo)準(zhǔn).
2. 經(jīng)驗(yàn)有的時(shí)候也不見(jiàn)得就是好事,有時(shí)候會(huì)讓自己陷入思維定式的怪圈,比如在這個(gè)問(wèn)題的處理上,由于問(wèn)題在切換了硬件平臺(tái)的時(shí)候才出現(xiàn),正好又是兩個(gè)字節(jié)序不一樣的硬件平臺(tái),所以經(jīng)驗(yàn)將我的思路導(dǎo)向了字節(jié)序不正確這個(gè)方向上.