ios平台上一個由位元組對齊問題導致的crash

來源:互聯網
上載者:User
最近,我們負責開發的一個產品,一啟動就會Crash,但是我們自己在開發機上編譯出來的版本確又是正常的。DB不能工作了,很影響我們日常體驗開發中的版本,於是組織就派我來解決這個問題了。    第一個猜測,因為最近公司RDM的認證快到期了,於是就懷疑是認證的問題,找了平台那邊的同學幫忙查看,確認認證是沒有問題。不過平台那邊的編譯環境跟我們的開發環境有一點點版本的差異,於是有折騰平台那邊的同學幫忙升級環境。結果發現也不是環境的問題。    很自然的就想到了 debug  和 release 版本的問題了,DB版本的都是release,而我們自己開發編譯到手機上的都是debug版本。把項目設定修改一下,編譯到真機,crash重現。【能重現的bug跑不掉。:)】     找到了問題我就貼下相關的代碼。這裡有個相當詭異的bug。
 1 Byte *bytes = (Byte*)[ipData bytes];   2  //讀取總的ip列表組數   3  Byte cIPGroupCount = bytes[0];   4     5  if (cIPGroupCount == 0)   6  {   7      return YES;   8  }   9    10  int idx = sizeof(Byte);  11  for (Byte groupIdx = 0; groupIdx < cIPGroupCount; ++groupIdx)  12  {  13      //先讀取一個short位的下發清單類型  14      unsigned short type = NTOHS(*(unsigned short*)(bytes+idx));  15      idx += sizeof(unsigned short);  16        17      //讀取當前ip列表組總列表的ip數  18      Byte ipItemCount = (Byte)*(bytes + idx);  19      idx += sizeof(Byte);  20        21      NSMutableArray *ips = [[NSMutableArray alloc] initWithCapacity:ipItemCount];  22      NSMutableArray *ports = [[NSMutableArray alloc] initWithCapacity:ipItemCount];  23        24      for (Byte itemIdx = 0; itemIdx < ipItemCount; itemIdx ++)  25      {  26          //讀取ip地址資訊(IP 位址欄位不需要轉換位元組序)  27          unsigned int ip = *(unsigned int*)(bytes + idx);  28          idx += sizeof(unsigned int);  29          [ips addObject:[NSNumber numberWithInt:ip]];  30          //讀取連接埠資訊  31          unsigned int port = NTOHL(*(unsigned int*)(bytes + idx));  32          idx += sizeof(unsigned int);  33          [ports addObject:[NSNumber numberWithInt:port]];  34      }  35   }
   上面的代碼其實很簡單,就是解析一個2進位格式的資料。這段代碼運行也沒有問題,但是調整了下順序後,就導致了 release環境下的crash。 還是先貼代碼【只貼變化部分的代碼】。
 1    2   for (Byte itemIdx = 0; itemIdx < ipItemCount; itemIdx ++)   3    {   4       unsigned int ip = *(unsigned int*)(bytes + idx);  //這行代碼crash   5       idx += sizeof(unsigned int);   6       //讀取連接埠資訊   7       unsigned int port = NTOHL(*(unsigned int*)(bytes + idx));   8       idx += sizeof(unsigned int);   9          10        [ips addObject:[NSNumber numberWithInt:ip]];  11        [ports addObject:[NSNumber numberWithInt:port]];  12  }
把變化的部分加粗顯示了,相比上面的代碼,只是簡單的調換了下代碼執行的順序,沒有任何邏輯的修改。有注釋的那行代碼會crash,xcode給出的錯誤是位元組對齊錯誤。很鬱悶。後來寫代碼驗證了一下,請看下面的分析過程。    整個資料解析部分分兩個迴圈,在迴圈最外面還有一個位元組的讀取。於是資料的解析流程如下: 1.【1位元組】【讀取一個位元組的列表總數】   ---   2.外迴圈開始        【2位元組】【讀取兩位元組類型資訊】        【1位元組】【讀取一位元組的ip總數】--------         3.內迴圈開始              *【4位元組】【4位元組ip地址】             【4位元組】【4位元組連接埠號碼】      當執行上述流程 1 + 2×1(外迴圈執行一次) + 3×1(內迴圈執行一次) 的時候,整個位移量是 (1+2+1+4+4),是4的倍數。這裡不管 3(內迴圈)執行多少次,整個位移量都是4的倍數。但是只要 2(外迴圈)執行次數超過一次,上述流程執行到標記了 “*” 的那一行的時候,位移量就再也不是4的倍數了。這個時候 unsigned int ip = *(unsigned int*)(bytes + idx); 這行代碼在relase環境下就會crash。    過程分析完了,我還有一個疑問沒有解開,為什麼第一段代碼在同樣的資料下,確沒有Crash。我只能猜測是因為一行c的代碼間隔執行了一行oc的代碼。第2行代碼也許是編譯器最佳化導致的。如果對這個問題有研究的同學歡迎交流。    最後給出我現在的解決方案,對於解析這種緊湊格式的2進位資料,在做資料類型轉換的時候,最好使用下面的代碼來處理,這樣就可以避免位元組對齊的問題了。
1  //讀取ip地址資訊(IP 位址欄位不需要轉換位元組序)  2 unsigned int ip = 0;  3 memcpy(&ip, bytes + idx, sizeof(unsigned int));  4 idx += sizeof(unsigned int);  
很奇怪的一個問題,在進行強制資料類型轉換的時候,ios平台竟然要求記憶體位元組對齊。而debug環境又不要求。如果兩次強制類型轉換用oc的代碼隔開,release執行又是正確的,所以再次懷疑是xocde在編譯的時候,編譯器最佳化導致的。 --------------- 後面的討論----------   感謝 @springhu 指出錯誤,需要用memcpy,而不是memccpy【原來我一直理解錯了memccpy的用法】。   跟springhu討論了半天,我們分別單獨寫了demo工程來類比上面的case,結果發現在release環境下也並不會crash。問題只出現在我的工程裡面。經過一些列的測試,發現這個詭異的問題只出在我的情景代碼裡面,把解析部分單獨封裝個函數後,在應用裡面調用也是不會出問題的。      unsigned int ip = *(unsigned int*)(bytes + idx);  這種寫法理論上是沒有任何問題的,在應用裡面使用的時候也不需要考慮位元組對齊的問題,但是不怕一萬,就怕萬一啊。就怕編譯器好心幹壞事。  EXC_ARM_DA_ALIGN 用這個關鍵字可以google到很多相關的文章
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.