C++記憶體問題大集合(指標問題,以及字串拷貝問題,確實挺危險的)

來源:互聯網
上載者:User

標籤:date   data   本質   成員   svc   invalid   library   ++   並且   

作者:rendao.org,著作權聲明,轉載必須徵得同意。

記憶體越界,變數被篡改

memset時間長度度參數超出了數組長度,但memset當時並不會報錯,而是操作了不應該操作的記憶體,導致變數被無端篡改

還可能導致記憶體越界的函數有memset、memcpy、memmove、strcpy、strncpy、strcat、sprintf等等

 

臨時指標問題,std::string、wstring的c_str()是個臨時指標

c_str()傳回值是個char*/wchar_t*指標,這個數組的資料是臨時的,當有一個改變這些資料的成員函數被調用後,其中的資料就會失效。此時,用strlen、wcslen、strcpy、wcscpy等操作都是不可預知的,程式會崩潰。因此要麼現用先轉換,要麼把它的資料複製到使用者自己可以管理的記憶體中。

string s=”1234″;

const char* c = s.c_str();

這樣的寫法是錯誤的。因為重複使用的c指向內容實際上很容易失效。
delete char*時程式崩潰

1、記憶體越界
char* newstr = new char[strlen(s1) + strlen(s2) + 1];

sprintf(newpath, “%s\\%s”, s1, s2);

然後這個newstr在被delete時崩潰了,原因是開闢的記憶體空間不夠,記憶體越界,無法容納結束符0,如果把strlen(s1) + strlen(s2) + 1改成strlen(s1) + strlen(s2) + 2就OK了。

2、刪除的指標不屬於自己的堆棧

如果對於堆來說,每個DLL有自己的堆,那麼從DLL中動態分分配的記憶體最好是從DLL中刪除。如果從DLL中分配記憶體,然後再EXE中或者另外一個DLL中刪除,很可能導致程式崩潰。並且,輸出報錯為Invalid Address specified to RtlValidateHeap。

3、重複delete
重複delete同一個指標會崩潰,有時不易發現,可能的情況之一就是某類存在char*成員(需要new開闢記憶體),而此類是淺拷貝,若不同對象A、B間發生拷貝,A銷毀時釋放了char*指向記憶體,B仍認為自己的char*指標是有效。有時現象更加隱秘,你曉得有淺拷貝這回事還不夠,比如拷貝的發生不一定是你自己的代碼中直接導致的,比如vector的push_back操作就會不停的導致類對象的拷貝,而你不瞭解push_back的本質的話就不曉得發生了拷貝。

4、不同工程使用了不同的執行階段程式庫設定
具體現象是delete指標時程式崩潰,並輸出提示Invalid Address specified to RtlValidateHeap,這是因為在不同模組(工程)之間傳遞 C++ 類,而這兩個模組用了不同的執行階段程式庫(C/C++ -> Code Generation -> Use runtime library)設定。例如:EXE 模組調用 DLL 模組裡傳遞 C++ 類的函數,DLL模組使用靜態連結(Release 是Multi-threaded (/MT) 、Debug 是 Multi-threaded Debug (/MTd) )方式編譯,而 EXE 模組使用動態連結(Release 是 Multi-threaded DLL (/MD) 、Debug 是 Multi-threaded Debug DLL (/MDd) )方式編譯。可以對比這兩個模組的Use Runtime Library ,看看設定是否一樣,如果不一樣要改成一樣的。

以上是網路上的解釋,而且這個原因可能和第3條有關聯,可能是由於執行階段程式庫的設定不同,導致調用另外模組的類的方法時,導致這時new出來的記憶體所屬堆歸屬有問題,所以delete時就出錯了。這一段是簡單的猜測,很可能猜錯了,但這個問題已經消耗了非常多時間了,抓緊,實踐證明,我在EXE(Peer)和DLL(Reg)中使用了相同的類(Xstr),並都是源碼加入工程編譯的,EXE中建立類對象,把對象指標傳入DLL,DLL中調用類的某方法(會new一段記憶體)來容納返回的資料,而這個類對象在EXE中別銷毀時就出現了delete wchar_t*崩潰的問題,提示Invalid Address specified to RtlValidateHeap。此時檢查執行階段程式庫設定,發現的確不同,而且正如網上摘錄中舉得例子一樣,如果把EXE和DLL中的該設定都改為Multi-threaded DLL/  Multi-threaded Debug DLL,則問題解決。 Multi-threaded與Multi-threaded DLL,前者是指使用多線程版本的執行階段程式庫但靜態編譯,後者的差別就是動態連結。

關於Use runtime library的含義,微軟和C有兩種C運行期函數庫,一種是普通的函數庫:LIBC.LIB,不支援多線程。另外一種是支援多線程的: msvcrt.lib。如果一個工程裡,這兩種函數庫混合使用,可能會引起這個錯誤,一般情況下它需要MFC的庫先於C運行期函數庫被連結,因此建議使用支援多線程的msvcrt.lib。所以在使用第三方的庫之前首先要知道它連結的是什麼庫,否則就可能造成LNK2005錯誤。如果不得不使用第三方的庫,可以嘗試按下面所說的方法修改,但不能保證一定能解決問題,前兩種方法是微軟提供的: A、選擇VC菜單Project->Settings->Link->Catagory選擇Input,再在Ignore   libraries   的Edit 欄中填入你需要忽略的庫,如:Nafxcwd.lib;Libcmtd.lib。然後在Object/library   Modules的Edit欄中填入正確的庫的順序,這裡需要你能確定什麼是正確的順序.(最好不要這麼做)

B、選擇VC菜單Project->Settings->Link頁,然後在Project   Options的Edit欄中輸入/verbose:lib,這樣就可以在編譯連結程式過程中在輸出視窗看到連結的順序了。 C、選擇VC菜單Project->Settings->C/C++頁,Catagory選擇Code   Generation後再在User   Runtime   libraray中選擇MultiThread   DLL等其他庫,逐一嘗試。

5、指標所指記憶體位址不再是new出來的首地址
char* p = new char[10];
strcpy(p, “hello”);
p++;
delete p; //運行到這回崩潰

 

記憶體泄露的解決

1、  尋找new和delete,malloc/realloc/calloc/strdup和free,VirtualAlloc和VirtualFree是否成對

2、  檢查new char之後是否誤用了小括弧,因為使用小括弧的話,是賦初值,方括弧才是指定長度。Debug時可能越界執行而不立即報錯,但程式在退出時則會提示記憶體泄露了。當然,如果是release,估計程式執行到這裡將立即崩潰。

3、  有時候,VC的記憶體泄露提示行代碼中new出來的類對象出現記憶體泄露,而實際上檢查發現該類對象的的確確是delete了的,實際上是提示不夠精確
可能1:實際發現還可能不是該類對象new了未釋放,而是該類對象中的代碼、包括調用的函數中出現了new但未釋放的情況,比如new CmySiteRoot中調用了xml_INIeasyget,而xml_INIeasyget中調用了只new不delete的charenc_strutf8toansi,進而導致記憶體泄露的,但報錯位置卻是new CmySiteRoot
可能2:事實證明,甚至可能和報錯的new位置new出來的那個東西毫不相干的,此時還是乖乖按照步驟解決方案1去尋找,反而快些,基本肯定的是,按照步驟1去找,總可以找到不匹配的地方,不一定過於相信VC的輸出提示位置

 

減少數組越界讀寫的方法

boost::array(debug時檢查數組下標,release時效率和普通數組一樣)、智能指標、vector

 

記憶體泄露、越界檢查工具

BoundsCheck、pageheap、gflags(Windebug中帶的)、WinDebug

 

字串拷貝注意要點

一定要注意結束符,經過實際驗證,strncpy、wcsncpy、memcpy、wcstombs等等函數都只會拷貝指定個數的字元,而不理會是否在末尾有結束符,如果忘記了自己補上結束符,可能導致訪問這個字串時訪問到別人的記憶體喔。

Related Posts:
  1. boost配置(VC/CodeBlocks)與編譯(bjam+msvc/mingW)

Tags: C++, 記憶體

http://rendao.org/blog/224/

C++記憶體問題大集合(指標問題,以及字串拷貝問題,確實挺危險的)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.