2010-05-28 142 views
1

我讀過很多,其中包括here on SO,這表明這是一個非常糟糕的主意,而且您唯一可以安全行事的就是退出程序。我不確定這是否屬實。在這種情況下捕獲訪問衝突安全嗎?

這是一個將大量分配移交給malloc的池化內存分配器。在pool_free()期間,指針需要被檢查,它屬於一個池或被分配了malloc。通過將地址四捨五入到最接近的1MB邊界,我得到一個指向池中內存塊開始的指針,如果使用了malloc,則指向undefined。在第一種情況下,我可以輕鬆驗證內存塊是否屬於池,但是,如果不是,我將通過此驗證,我將得到訪問衝突(請注意,這是一個只讀過程)。我能不能用SEH(Windows)來處理這個問題,或者處理信號(POSIX),並簡單地將其視爲驗證失敗? (即只有在使用malloc的情況下才可能,所以通過ptr釋放())

編輯:人們似乎錯過了上面的OR。如果指針是用malloc分配的,我不希望獲得訪問衝突,但這是一個可能的結果。使用指向塊開始的指針(在1MB邊界處)的過程是驗證幻數,然後跟隨一個指向內存池的指針,並檢查它是否實際上包含上述指向塊的指針。如果這些只讀步驟中的任何一個產生訪問衝突,那麼驗證失敗,就像任何單個步驟失敗一樣。

+1

任何可用的_undefined_行爲都應該固定。其他一切都是瘋狂的。 – LukeN 2010-05-28 22:11:50

回答

1

沒有必要實施反應機制。

  1. 的Windows:_aligned_malloc(size, 1<<20)
  2. Unix的:memalign(1<<20, size)

使用這種方法,四捨五入到1 MB保證您可以通過對齊堆分配到1 MB邊界在面前的難題得到指向一個已分配的內存塊,你只需要辨別該地址是在池中還是在外部(在這種情況下,顯然是malloc ed)。

你需要謹慎,你只使用對齊的堆分配真正的大對象。如果你使用它,例如size> 100 kB,分配器會在對象之間留下巨大的空隙。理想情況下,僅將它用於不適合1 MB池塊的對象。

+0

在我的情況下,大對象並不是那麼大,所以這不是一個好主意。 – Eloff 2010-05-28 22:44:08

+0

如果泳池物體比泳池塊要小得多,那麼你可以將它放到一個更細的邊界上,該邊界接近你想要放置在泳池中的最大物體,並在這些邊界的整個區域放置幻數。在調用一致的malloc時,您將使用相同的較小粒度。當然,使用較小的游泳池塊會更簡單。 – 2010-05-28 23:03:23

+0

是的,改爲64k池塊會使這個非常可行。在windows上使用VirtualAlloc/VirtualFree,這可以確保內存與64k地址或unix上的memalign保持一致,這將留下小小的空白,但仍然有效。沒有未定義的行爲。我喜歡。 – Eloff 2010-05-29 00:29:00

2

您需要更好的測試。如果使用了malloc,則不能保證你會得到AV,因爲舍入點也可能已經分配給你的應用程序,因此你可以訪問該內存。

+0

這不是測試。我完全期望大部分時間都可以訪問。 – Eloff 2010-05-28 22:43:00

0

我認爲它應該是安全的。但可能是一個壞主意。

但是,如果您需要將池分配的內存與非池分配的內存混合,我認爲您需要在某處存儲有關該信息的信息。也許每個使用pool_alloc()分配的內存分配都可能有一個小的頭,在實際分配之前「隱藏」。這個頭可以保存關於它如何分配的信息。所以char * block =(char *)pool_alloc(32)實際上會分配32 + sizeof(BlockHeader)字節。而block-sizeof(BlockHeader)將提供對頭部的訪問。

IsBadReadPtr根據MSDN是過時:

重要,此功能已過時,不應使用。儘管它的名字,它並不能保證指針是有效的,或指出的內存是安全的使用。有關更多信息,請參閱此頁面上的註釋。

0

好吧,inazaruk發帖稱被嚴重downvoted答案,然後刪除建議使用IsBadReadPtr + VirtualQuery來的(以避免後衛還是沒有訪問頁。)讀他發佈提醒我的事實,鏈接,閱讀隨機內存區域比訪問衝突具有更糟的潛在副作用。

意外地訪問線程堆棧末尾的保護頁,將導致程序突然終止,如果該線程堆棧增長。

因此,捕獲訪問衝突可能是不安全的。這回答了這個問題。