[問題] Override new/delete 與 3rd party library

看板C_and_CPP (C/C++)作者 (火神)時間9年前 (2016/05/26 15:48), 9年前編輯推噓2(2012)
留言14則, 4人參與, 最新討論串1/1
開發平台(Platform): (Ex: VC++, GCC, Linux, ...) VC++ (C++11) 額外使用到的函數庫(Library Used): (Ex: OpenGL, ...) Qt 5.6 問題(Question): 為了查一個記憶體問題, 嘗試 override new/delete 並記錄 new/delete 的配對 結果在使用 Qt 的某些 function 時會出現 delete 被傳入未經過我 new operator 配置的記憶體. 我的問題是, override new/delete 應該要直接 hide 原本的 new/delete 才對, 但 是為什麼會產生這種情況呢? 跟使用了 Qt library 這類 3rd party library 有關嗎? Qt 內部理論上應該全部使用的是 placement new/delete, 實際上 trigger assert 的 也是其回傳 std::string 的 destructor Override 的內容大略如下: overridenew.cpp ================================== static MyMap<void*, size_t> gMemMap; void *operator new(size_t Size) { void *p = malloc(Size); if (p == 0) throw std::bad_alloc(); gMemMap[p] = Size; return p; } void operator delete(void *p) { if (p == 0) return; assert(gMemMap.contains(p)); free(p); } main.cpp ======================================== int main() { QString FileName("D:/testerfile_debug/test.log"); QByteArray Array = FileName.toUtf8(); // 下面這行可以正常執行 printf("%s", std::string(Array.constData(), Array.length()).c_str()); // 下面這行會在 std::string 解構時發生 assertion failed printf("%s", Array.toStdString().c_str()); return 0; } 我有想過幾個原因, 雖然 QByteArray::toStdString() 是一個 inline function 但是否有機會因為 build Qt 時使用的環境與實際使用的 VC++ 不同而產生呼叫到 不同 new/delete 的情況? (不過 Qt 是自己 build 的理論上應該是一樣的環境啦...) 或者有其它可能的原因, 不知道各位先進有沒有什麼想法呢? P.S. 我後來使用 Windows 的 CRT Debug Heap 相關工具指出, 傳進來的 p 確定是 有 allocated 的, 只是它沒經過我的 new... -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 125.227.250.76 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1464248924.A.5E9.html

05/26 16:58, , 1F
void *operator new[](size_t s)
05/26 16:58, 1F

05/26 16:58, , 2F
這個是不是沒寫到?
05/26 16:58, 2F
我看 http://en.cppreference.com/w/cpp/memory/new/operator_new 寫道: The single-object version (1) is directly called by the standard library implementations of all other versions (2-4), so replacing that one function is sufficient to handle all allocations. (since C++11) 所以理論上應該 override 一個就可以了? 剛測試了一下, new/delete array 的確會呼叫到我 override 的版本

05/26 18:33, , 3F
你有考慮到 QByteArray::toStdString 根本沒用到 new
05/26 18:33, 3F

05/26 18:35, , 4F
的可能性嗎 XD http://d.pr/19jmF
05/26 18:35, 4F
我有追到這段 code XD 不過 assertion failed 的 call stack 是從 std::string::~string 來的 應該是 std::string inner buffer 解構時呼叫的 奇怪的是, 如果我把 toStdString() 移到我的程式裡面 將 const QByteArray& 當作參數 它就會正確的 call 到我的 new ...

05/26 23:29, , 5F
會不會是某種神奇的最佳化啊?例如編譯器知道 string 沒
05/26 23:29, 5F

05/26 23:29, , 6F
有被修改所以直接 implicit share 省一個 copy, 然後
05/26 23:29, 6F

05/26 23:29, , 7F
QByteArray 比 string 先被解構, 然後 compiler 把 data
05/26 23:29, 7F

05/26 23:30, , 8F
留著等到 std::string 解構時才刪除, 造成沒配對之類的
05/26 23:30, 8F
不知道耶, 有沒有證明這個可能性的方法啊 直接看 assembly code 嗎 XD 我試試看, 沒想過這個方式

05/27 04:29, , 9F
不怕 LGPL violation 的話,先試試看靜態連結 Qt XD
05/27 04:29, 9F
喔喔~ 為何會想到這個方法呢? XD 曾經 static link 常連不起來, 晚點來試試 ""

05/27 11:35, , 10F
只是想先確定問題是不是出在 DLL 使用方法上
05/27 11:35, 10F
找到原因了, 貼在下面, 不確定是否跟您說的有關? ======================================================= 找到問題了, 先說結論: 我的 Qt lib 也有 override new operator 導致 undefined behavior 不確定怎麼會產生這樣的結果的, 不過直接從 assembly 追進去看, QtCored 有一段這樣的東西: Qt5Cored!ILT+93430(??0QVariantQAEMZ): 0x66a97cfb jmp Qt5Cored!QVariant::QVariant (66dc81a0) Qt5Cored!ILT+93435(??2YAPAXIZ): 0x66a97d00 jmp Qt5Cored!operator new (66ee4890) Qt5Cored!ILT+93440(??$copyVconst_iterator?$QListVQByte... 0x66a97d05 jmp Qt5Cored!std::copy<QList<QByteArray>::const... (66beb610) Qt5Cored!ILT+93445(__alloca_probe): x66a97d0a jmp Qt5Cored!_chkstk (66ee6540) QByteArray::toStdString() 的 std::string 會 call 0x66a97d00 這個位址 然後 0x66ee4890 這個 operator new 不是我的: Qt5Cored!operator new [f:\dd\vctools\crt\vcstartup\src\heap\new_scalar.cpp]: 0x66ee4890 push ebp 0x66ee4891 <+0x0001> mov ebp,esp 0x66ee4893 <+0x0003> push ecx 0x66ee4894 <+0x0004> mov eax,dword ptr [ebp+8] 0x66ee4897 <+0x0007> push eax 0x66ee4898 <+0x0008> call Qt5Cored!malloc (66ee7bc8) ...... 裡面的 debug info 居然還有不知道哪來的 f:\dd\vctools 詭異路徑... 不知道這是 Qt 自己的還是因為 build 的過程中什麼參數沒設好造成的就是了 (畢竟在 Qt source code 中沒有這個檔案...) 囧

05/27 13:04, , 11F
f:\dd\vctools -> https://goo.gl/EJXBXy
05/27 13:04, 11F

05/27 13:06, , 12F
f:\dd\vctools\... 這個是從 MSVCRT.DLL 來的欸
05/27 13:06, 12F
所以... 這東東是 VC default 的 new 囉!? 理論上應該要被 override 吧, 怎麼會被叫到呢...

05/27 14:20, , 13F
現在擔心的就是 cross-DLL problem,但我沒時間詳細瞭解
05/27 14:20, 13F

05/27 14:20, , 14F
你遇到的這個問題 XD
05/27 14:20, 14F
我去查查相關的討論好了... 多謝提供關鍵字 XD 之前只遇過 mix debug/release library 直接炸掉的情況 現在這個問題很隱晦啊 ※ 編輯: Ebergies (125.227.250.76), 05/27/2016 14:56:41
文章代碼(AID): #1NHgfSNf (C_and_CPP)
文章代碼(AID): #1NHgfSNf (C_and_CPP)