Teknik penelusuran kesalahan CRT
Saat Anda men-debug program yang menggunakan pustaka run-time C, teknik penelusuran kesalahan ini mungkin berguna.
Penggunaan pustaka debug CRT
Pustaka runtime C (CRT) menyediakan dukungan penelusuran kesalahan yang luas. Untuk menggunakan salah satu pustaka debug CRT, Anda harus menautkan dengan /DEBUG
dan mengkompilasi dengan /MDd
, , /MTd
atau /LDd
.
Definisi utama dan makro untuk penelusuran kesalahan CRT dapat ditemukan di<crtdbg.h>
file header.
Fungsi dalam pustaka debug CRT dikompilasi dengan informasi debug (/Z7, /Zd, /Zi, /ZI (Format Informasi Debug)) dan tanpa pengoptimalan. Beberapa fungsi berisi pernyataan untuk memverifikasi parameter yang diteruskan ke fungsi tersebut, dan kode sumber disediakan. Dengan kode sumber ini, Anda dapat melangkah ke fungsi CRT untuk mengonfirmasi bahwa fungsi berfungsi seperti yang diharapkan dan memeriksa parameter atau status memori yang buruk. (Beberapa teknologi CRT bersifat kepemilikan dan tidak menyediakan kode sumber untuk penanganan pengecualian, titik mengambang, dan beberapa rutinitas lainnya.)
Untuk mengetahui informasi selengkapnya tentang berbagai pustaka run-time yang dapat digunakan, lihat Pustaka C Run-Time.
Makro untuk pelaporan
Untuk penelusuran kesalahan, Anda dapat menggunakan _RPTn
makro dan _RPTFn
, yang ditentukan,<crtdbg.h>
untuk menggantikan penggunaan printf
pernyataan. Anda tidak perlu memasukkannya dalam #ifdef
arahan, karena secara otomatis menghilang dalam build rilis Anda saat _DEBUG
tidak ditentukan.
Makro | Deskripsi |
---|---|
_RPT0 , , _RPT1 _RPT2 , , _RPT3 ,_RPT4 |
Menghasilkan string pesan dan nol hingga empat argumen. Untuk _RPT1 melalui _RPT4 , string pesan berfungsi sebagai string pemformatan gaya cetak untuk argumen. |
_RPTF0 , , _RPTF1 _RPTF2 , , _RPTF3 ,_RPTF4 |
Sama seperti _RPTn , tetapi makro ini juga menghasilkan nama file dan nomor baris tempat makro berada. |
Pertimbangkan contoh berikut:
#ifdef _DEBUG
if ( someVar > MAX_SOMEVAR )
printf( "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n",
someVar, otherVar );
#endif
Kode ini menghasilkan nilai dan someVar
otherVar
ke stdout
. Anda dapat menggunakan panggilan ke _RPTF2
berikut untuk melaporkan nilai yang sama ini dan, selain itu, nama file dan nomor baris:
if (someVar > MAX_SOMEVAR) _RPTF2(_CRT_WARN, "In NameOfThisFunc( ), someVar= %d, otherVar= %d\n", someVar, otherVar );
Beberapa aplikasi mungkin memerlukan debug yang melaporkan bahwa makro yang disediakan dengan pustaka run-time C tidak menyediakan. Untuk kasus ini, Anda dapat menulis makro yang dirancang khusus agar sesuai dengan kebutuhan Anda sendiri. Di salah satu file header Anda, misalnya, Anda dapat menyertakan kode seperti berikut untuk menentukan makro yang disebut ALERT_IF2
:
#ifndef _DEBUG /* For RELEASE builds */
#define ALERT_IF2(expr, msg, arg1, arg2) do {} while (0)
#else /* For DEBUG builds */
#define ALERT_IF2(expr, msg, arg1, arg2) \
do { \
if ((expr) && \
(1 == _CrtDbgReport(_CRT_ERROR, \
__FILE__, __LINE__, msg, arg1, arg2))) \
_CrtDbgBreak( ); \
} while (0)
#endif
Satu panggilan untuk ALERT_IF2
dapat melakukan semua fungsi printf
kode:
ALERT_IF2(someVar > MAX_SOMEVAR, "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n", someVar, otherVar );
Anda dapat dengan mudah mengubah makro kustom untuk melaporkan lebih banyak atau lebih sedikit informasi ke tujuan yang berbeda. Pendekatan ini berguna seiring berkembangnya persyaratan penelusuran kesalahan Anda.
Men-debug penulisan fungsi kait
Anda dapat menulis beberapa jenis fungsi kait debug kustom yang memungkinkan Anda memasukkan kode ke dalam beberapa titik yang telah ditentukan sebelumnya di dalam pemrosesan normal debugger.
Klein memblokir fungsi kait
Jika Anda ingin memvalidasi atau melaporkan konten data yang disimpan dalam blok _CLIENT_BLOCK
, Anda dapat menulis fungsi khusus untuk tujuan ini. Fungsi yang Anda tulis harus memiliki prototipe yang mirip dengan yang berikut ini, seperti yang didefinisikan dalam<crtdbg.h>
:
void YourClientDump(void *, size_t)
Dengan kata lain, fungsi kait Anda harus menerima void
penunjuk ke awal blok alokasi, bersama dengan nilai jenis yang size_t
menunjukkan ukuran alokasi, dan mengembalikan void
. Jika tidak, kontennya terserah Anda.
Setelah Anda menginstal fungsi kait menggunakan _CrtSetDumpClient, fungsi tersebut akan dipanggil setiap kali _CLIENT_BLOCK
blok dibuang. Anda kemudian dapat menggunakan _CrtReportBlockType untuk mendapatkan informasi tentang jenis atau subjenis blok yang dicadangkan.
Penunjuk ke fungsi yang Anda teruskan _CrtSetDumpClient
berjenis _CRT_DUMP_CLIENT
, seperti yang didefinisikan dalam<crtdbg.h>
:
typedef void (__cdecl *_CRT_DUMP_CLIENT)
(void *, size_t);
Fungsi kait alokasi
Fungsi kait alokasi, yang diinstal menggunakan _CrtSetAllocHook
, disebut setiap kali memori dialokasikan, dialokasikan, atau dibeberkan. Anda dapat menggunakan jenis kait ini untuk berbagai tujuan. Gunakan untuk menguji bagaimana aplikasi menangani situasi memori yang tidak cukup, seperti untuk memeriksa pola alokasi, atau informasi alokasi log untuk dianalisis nanti.
Catatan
Perhatikan pembatasan tentang menggunakan fungsi pustaka runtime C dalam fungsi kait alokasi, yang dijelaskan dalam Kait Alokasi dan alokasi memori crt.
Fungsi alokasi harus memiliki prototipe seperti contoh berikut:
int YourAllocHook(int nAllocType, void *pvData,
size_t nSize, int nBlockUse, long lRequest,
const unsigned char * szFileName, int nLine )
Penunjuk yang Anda teruskan _CrtSetAllocHook
berjenis _CRT_ALLOC_HOOK
, seperti yang didefinisikan dalam<crtdbg.h>
:
typedef int (__cdecl * _CRT_ALLOC_HOOK)
(int, void *, size_t, int, long, const unsigned char *, int);
Ketika pustaka run-time memanggil hook Anda, nAllocType
argumen menunjukkan operasi alokasi apa yang akan dibuat (_HOOK_ALLOC
, _HOOK_REALLOC
, atau _HOOK_FREE
). Dalam alokasi gratis atau dalam alokasi ulang, pvData
memiliki penunjuk ke artikel pengguna dari blok yang akan dibebaskan. Namun untuk alokasi, pointer ini null, karena alokasi belum terjadi. Argumen yang tersisa berisi ukuran alokasi, jenis bloknya, nomor permintaan berurutan, dan penunjuk ke nama file. Jika tersedia, argumen juga menyertakan nomor baris tempat alokasi dibuat. Setelah fungsi kait melakukan analisis apa pun dan tugas lain yang diinginkan penulisnya, fungsi tersebut harus mengembalikan , TRUE
yang menunjukkan bahwa operasi alokasi dapat dilanjutkan, atau FALSE
, yang menunjukkan bahwa operasi harus gagal. Kait sederhana dari jenis ini mungkin memeriksa jumlah memori yang dialokasikan sejauh ini, dan mengembalikan FALSE
jika jumlah tersebut melebihi batas kecil. Aplikasi kemudian akan mengalami jenis kesalahan alokasi yang biasanya hanya terjadi ketika memori yang tersedia rendah. Kait yang lebih kompleks mungkin melacak pola alokasi, menganalisis penggunaan memori, atau melaporkan saat situasi tertentu terjadi.
Kait alokasi dan alokasi memori CRT
Pembatasan penting pada fungsi kait alokasi adalah bahwa mereka harus secara eksplisit mengabaikan _CRT_BLOCK
blok. Blok-blok ini adalah alokasi memori yang dibuat secara internal oleh fungsi pustaka runtime C jika mereka melakukan panggilan ke fungsi pustaka runtime C yang mengalokasikan memori internal. Anda dapat mengabaikan _CRT_BLOCK
blok dengan menyertakan kode berikut di awal fungsi kait alokasi Anda:
if ( nBlockUse == _CRT_BLOCK )
return( TRUE );
Jika kait alokasi Anda tidak mengabaikan _CRT_BLOCK
blok, maka fungsi pustaka run-time C apa pun yang dipanggil di kait Anda dapat menjebak program dalam perulangan tanpa akhir. Misalnya, printf
membuat alokasi internal. Jika kode kait Anda memanggil printf
, maka alokasi yang dihasilkan akan menyebabkan kait Anda dipanggil lagi, yang akan memanggil printf
lagi, dan sebagainya, sampai tumpukan meluap. Jika Anda perlu melaporkan _CRT_BLOCK
operasi alokasi, salah satu cara untuk menghindari pembatasan ini adalah dengan menggunakan fungsi API Windows, bukan fungsi runtime C, untuk pemformatan dan output. Karena API Windows tidak menggunakan timbunan pustaka runtime C, api tersebut tidak akan menjebak kait alokasi Anda dalam perulangan tanpa akhir.
Jika Anda memeriksa file sumber pustaka run-time, Anda akan melihat bahwa fungsi kait alokasi default, _CrtDefaultAllocHook
(yang hanya mengembalikan TRUE
), terletak di file terpisah sendiri, debug_heap_hook.cpp
. Jika Anda ingin kait alokasi Anda dipanggil bahkan untuk alokasi yang dibuat oleh kode startup run-time yang dijalankan sebelum fungsi aplikasi main
Anda, Anda dapat mengganti fungsi default ini dengan salah satu fungsi Anda sendiri, alih-alih menggunakan _CrtSetAllocHook
.
Melaporkan fungsi kait
Fungsi kait laporan, yang diinstal menggunakan _CrtSetReportHook
, dipanggil setiap kali _CrtDbgReport
menghasilkan laporan debug. Anda dapat menggunakannya, antara lain, untuk memfilter laporan agar fokus pada jenis alokasi tertentu. Fungsi hook laporan harus memiliki prototipe seperti contoh ini:
int AppReportHook(int nRptType, char *szMsg, int *retVal);
Pointer yang Anda teruskan adalah _CrtSetReportHook
jenis _CRT_REPORT_HOOK
, seperti yang didefinisikan dalam <crtdbg.h>
:
typedef int (__cdecl *_CRT_REPORT_HOOK)(int, char *, int *);
Saat pustaka run-time memanggil fungsi hook Anda, nRptType
argumen berisi kategori laporan (_CRT_WARN
, _CRT_ERROR
, atau _CRT_ASSERT
), szMsg
berisi penunjuk ke string pesan laporan yang sepenuhnya dirakit, dan retVal
menentukan apakah _CrtDbgReport
harus melanjutkan eksekusi normal setelah membuat laporan atau memulai debugger. (Nilai retVal
nol melanjutkan eksekusi, nilai 1 memulai debugger.)
Jika hook menangani pesan yang dimaksud sepenuhnya, sehingga tidak ada pelaporan lebih lanjut yang diperlukan, itu harus mengembalikan TRUE
. Jika mengembalikan FALSE
, _CrtDbgReport
akan melaporkan pesan secara normal.
Di bagian ini
Versi debug fungsi alokasi timbunan
Membahas versi Debug khusus dari fungsi alokasi timbunan, termasuk: bagaimana peta CRT memanggil, manfaat memanggilnya secara eksplisit, cara menghindari konversi, melacak jenis alokasi terpisah di blok klien, dan hasil tidak menentukan
_DEBUG
.-
Menjelaskan manajemen memori dan tumpukan debug, jenis blok pada tumpukan debug, fungsi pelaporan status timbunan, dan cara menggunakan tumpukan debug untuk melacak permintaan alokasi.
Menemukan kebocoran memori menggunakan pustaka CRT
Mencakup teknik untuk mendeteksi dan mengisolasi kebocoran memori dengan menggunakan debugger dan Pustaka C Run-Time.