1. 程式人生 > 其它 >解析位元組對齊的資料_位元組對齊不慎引發的掛死問題

解析位元組對齊的資料_位元組對齊不慎引發的掛死問題

技術標籤:解析位元組對齊的資料

作者: 守望,Linux應用開發者,目前在公眾號【程式設計珠璣】分享Linux/C/C++/資料結構與演算法/工具等原創技術文章和學習資源。

前言

之前程式是32位的,切到64位之後,一些隱藏的問題就暴露了。這不,一個由位元組對齊導致的掛死問題就出來了。

位元組對齊和64位

關於位元組對齊,可參考《理一理位元組對齊的那些事》,而之前也分享過另一個切64位之後出現的問題,有興趣的可以檢視《記64位地址截斷引發的掛死問題》。

本文背景

本文出現的場景是,系統需要解析JSON檔案,但是出現部分功能解析正常,部分掛死,並且32位程式正常,而64位程式掛死。鑑於原系統比較複雜,本文將會簡化其過程,來看看到底是什麼導致了掛死。

本文示例程式碼主要引自《一個超輕量級的JSON解析器》。

簡化後示例程式碼

//來源:公眾號【程式設計珠璣】
//https://www.yanbinghu.com
#include
#include
#include
#include
#pragmapack(1)
#include"cJSON.h"
#pragmapack()

編譯執行結果:

$gcc-L.-oparseJsonparseJson.c-lcjson
$./parseJson
Segmentationfault(coredumped)

在實際中我們通過GDB觀察發現,在解析JSON內部檢視JSON資料是完好的,但是呼叫完解析JSON之後,再去訪問使用就不對了,並且我們發現,在不同的功能模組中,呼叫結果不一樣,大部分模組呼叫並沒有任何問題,而只有某個功能模組調用出現問題。

真相

到底是什麼導致的呢?問題的根源在於下面這幾行程式碼:

#pragmapack(1)
#include"cJSON.h"
#pragmapack()

另外補充,cJSON結構體如下:

typedefstructcJSON{//cJSON結構體
structcJSON*next,*prev;/*後驅節點和前驅節點*/
structcJSON*child;/*孩子節點*/
inttype;/*鍵的型別*/
char*valuestring;/*字串值*/
intvalueint;/*整數值*/
doublevaluedouble;/*浮點數值*/
char*string;/*鍵的名字*/
}cJSON;

#pragma指令說明了按一位元組對齊,而cJSON的標頭檔案也在其中,那麼就會導致裡面的cJSON結構體按照1位元組對齊,最終其結構體大小為56個位元組,而已經編譯好的cjson庫可並非如此,因此對於64位程式,它還是按照8位元組對齊,結構體大小為64位元組,而對於32位程式,按照4位元組和1位元組對齊,都是36位元組,因此也不會有問題。

同一個結構體的大小竟然在不同的程式碼中大小不一樣!

最終也就出現了我們遇到的情況,64位程式由於庫中申請結構體記憶體大小與外部呼叫不一樣,最終導致掛死,而32位程式解析JSON正常。

總結

幸運的是,本文示例中能夠很明顯的能看到問題所在,但在實際專案中,如果標頭檔案管理不規範,並且專案的產品多樣,通過編譯巨集來隔開使用的標頭檔案,就很難發現這樣的問題。

思考

什麼情況下需要1位元組對齊呢?

附錄


●編號551,輸入編號直達本文

●輸入m獲取文章目錄

C語言與C++程式設計

92953af45ac7fa1079b35434a1a8b50e.png

分享C/C++技術文章