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, , /MTdatau /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 someVarotherVar 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 , TRUEyang 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.

  • Detail timbunan debug CRT

    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.

Baca juga