看板 C_and_CPP 關於我們 聯絡資訊
開發平台(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
descent: void *operator new[](size_t s) 05/26 16:58
descent: 這個是不是沒寫到? 05/26 16:58
我看 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 的版本
uranusjr: 你有考慮到 QByteArray::toStdString 根本沒用到 new 05/26 18:33
uranusjr: 的可能性嗎 XD http://d.pr/19jmF 05/26 18:35
我有追到這段 code XD 不過 assertion failed 的 call stack 是從 std::string::~string 來的 應該是 std::string inner buffer 解構時呼叫的 奇怪的是, 如果我把 toStdString() 移到我的程式裡面 將 const QByteArray& 當作參數 它就會正確的 call 到我的 new ...
uranusjr: 會不會是某種神奇的最佳化啊?例如編譯器知道 string 沒 05/26 23:29
uranusjr: 有被修改所以直接 implicit share 省一個 copy, 然後 05/26 23:29
uranusjr: QByteArray 比 string 先被解構, 然後 compiler 把 data 05/26 23:29
uranusjr: 留著等到 std::string 解構時才刪除, 造成沒配對之類的 05/26 23:30
不知道耶, 有沒有證明這個可能性的方法啊 直接看 assembly code 嗎 XD 我試試看, 沒想過這個方式
tinlans: 不怕 LGPL violation 的話,先試試看靜態連結 Qt XD 05/27 04:29
喔喔~ 為何會想到這個方法呢? XD 曾經 static link 常連不起來, 晚點來試試 ""
tinlans: 只是想先確定問題是不是出在 DLL 使用方法上 05/27 11:35
找到原因了, 貼在下面, 不確定是否跟您說的有關? ======================================================= 找到問題了, 先說結論: 我的 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 中沒有這個檔案...) 囧
EdisonX: f:\dd\vctools -> https://goo.gl/EJXBXy 05/27 13:04
uranusjr: f:\dd\vctools\... 這個是從 MSVCRT.DLL 來的欸 05/27 13:06
所以... 這東東是 VC default 的 new 囉!? 理論上應該要被 override 吧, 怎麼會被叫到呢...
tinlans: 現在擔心的就是 cross-DLL problem,但我沒時間詳細瞭解 05/27 14:20
tinlans: 你遇到的這個問題 XD 05/27 14:20
我去查查相關的討論好了... 多謝提供關鍵字 XD 之前只遇過 mix debug/release library 直接炸掉的情況 現在這個問題很隱晦啊 ※ 編輯: Ebergies (125.227.250.76), 05/27/2016 14:56:41