當您的程式碼不慎改寫由記憶體管理函數用來控制資料堆使用情形的控制資訊時,就可能發生資料堆錯誤。 您除錯的應用程式必須內建資料堆檢查功能。
在資料堆內配置的每一個記憶體區塊都有一個資料區, 此區域以配置函數所傳回的位址為開頭,鄰近資料區附近還有一個控制區, 當您解除配置記憶體時,記憶體管理函數需要此區域,才能適當地釋放記憶體。 如果您改寫資料堆中的控制結構(例如,寫入到已配置的陣列界限之外的元素,或將字串複製到配置太小的記憶體區塊), 則控制資訊會毀損,且可能導致不正確的程式行為,即使其他配置的區塊的資料區未改寫也一樣。
當您嘗試查明資料堆錯誤時,請考量下列要點:
若要偵測資料堆錯誤,您可以將程式編譯成可以使用具有資料堆檢查版本的記憶體管理函數 (如需 -qheapdebug 編譯選項的相關資訊,請參閱相關的除錯編譯選項主題)。 當您執行以這個選項來編譯的程式時,每一次呼叫記憶體管理函數都會在預設資料堆上執行資料堆檢查。 此資料堆檢查動作會檢查資料堆內配置的每一個記憶體區塊的控制結構,確定沒有任何結構被改寫。 如果發生錯誤,則程式會終止執行,且標準錯誤中會寫入資訊, 包括發生資料堆毀損的位址、前次偵測到有效資料堆狀態的程式檔和行號, 以及偵測到記憶體錯誤的程式檔和行號。
只有在每一個執行檔所用的預設資料堆上會進行資料堆檢查。 如果除錯版的記憶體管理函數未回報資料堆毀損,但您仍然認為有問題, 則表示您可能還使用其他資料堆且已破壞這些資料堆。
在除錯器內,只要確定造成錯誤的資料堆是預設資料堆, 您可以將資料堆無效的最後一行與發生毀損的第一行之間的差距不斷地縮小,即可查明資料堆錯誤的原因。 請結合執行指令、逐步指令、行岔斷點和函數岔斷點及在停止時執行資料堆檢查設定,以縮小搜尋的範圍。 如需這項設定的相關資訊,請參閱相關主題。
對於語意不正確的程式,在停止時執行資料堆檢查是一種侵害性的作法, 可能因為程式錯誤地存取堆疊上的資料而導致不同結果。 這是因為對於正在除錯的程序和執行緒,在停止時執行資料堆檢查會在每次停止執行時導致這些執行緒去呼叫資料堆檢查函數, 此資料堆檢查函數會以堆疊框來局部改寫堆疊的安全區,以致於該區域受到影響。 比方說,如果被呼叫的函數傳回一個區域變數的位址,只要後續的呼叫不改寫被呼叫的函數所使用的堆疊框, 則該區域變數的內容就可由發出呼叫的函數來存取,且不會有變動。 然而,當在停止時執行資料堆檢查已啟用時, 如果您從被呼叫的函數中發出跳出副程序的指令,則從被呼叫的函數返回時,將會立即呼叫資料堆檢查函數, 且傳回的指標所指向的記憶體可能已被資料堆檢查函數的堆疊框所改寫。
在除錯器內執行資料堆檢查會加重逐步指令的工作負荷,因為每完成一步就會檢查資料堆。 如果您逐步執行大量程式碼區段,或經常在岔斷點上停止,且發現除錯效能太慢, 請試著只在您懷疑造成資料堆錯誤的區域中才啟用在停止時執行資料堆檢查。