Pertanyaan Pengujian pointer untuk validitas (C / C ++)


Adakah cara untuk menentukan (secara programatik, tentu saja) jika pointer yang diberikan "valid"? Memeriksa NULL itu mudah, tetapi bagaimana dengan hal-hal seperti 0x00001234? Ketika mencoba untuk dereference jenis pointer ini, eksepsi / crash terjadi.

Metode cross-platform lebih disukai, tetapi platform-spesifik (untuk Windows dan Linux) juga ok.

Pembaruan untuk klarifikasi: Masalahnya bukan dengan pointer basi / dibebaskan / terinisialisasi; sebagai gantinya, saya mengimplementasikan API yang mengambil pointer dari pemanggil (seperti pointer ke string, pegangan file, dll.). Penelepon dapat mengirim (dengan sengaja atau tidak sengaja) nilai yang tidak valid sebagai penunjuk. Bagaimana cara mencegah kecelakaan?


75
2018-02-15 15:45


asal


Jawaban:


Pembaruan untuk klarifikasi: Masalahnya bukan dengan pointer basi, dibebaskan atau terinisialisasi; sebagai gantinya, saya mengimplementasikan API yang mengambil pointer dari pemanggil (seperti pointer ke string, pegangan file, dll.). Penelepon dapat mengirim (dengan sengaja atau tidak sengaja) nilai yang tidak valid sebagai penunjuk. Bagaimana cara mencegah kecelakaan?

Anda tidak dapat melakukan pemeriksaan itu. Tidak ada cara Anda dapat memeriksa apakah pointer "valid". Anda harus percaya bahwa ketika orang menggunakan fungsi yang mengambil pointer, orang-orang itu tahu apa yang mereka lakukan. Jika mereka memberikan Anda 0x4211 sebagai nilai penunjuk, Anda harus memercayainya dengan menunjuk ke alamat 0x4211. Dan jika mereka "secara tidak sengaja" memukul objek, maka bahkan jika Anda akan menggunakan beberapa fungsi sistem operasi yang menakutkan (IsValidPtr atau apa pun), Anda masih akan masuk ke bug dan tidak cepat gagal.

Mulai gunakan null pointer untuk menandakan hal semacam ini dan beri tahu pengguna perpustakaan Anda bahwa mereka tidak boleh menggunakan pointer jika mereka cenderung secara tidak sengaja melewati pointer tidak valid, serius :)


68
2018-02-15 16:11



Mencegah kecelakaan yang disebabkan oleh penelepon yang mengirim penunjuk tidak valid adalah cara yang baik untuk membuat bug senyap yang sulit ditemukan.

Bukankah lebih baik bagi programmer yang menggunakan API Anda untuk mendapatkan pesan yang jelas bahwa kodenya palsu dengan menabraknya daripada menyembunyikannya?


30
2018-02-15 16:05



Pada Win32 / 64 ada cara untuk melakukan ini. Cobalah untuk membaca pointer dan menangkap eksekusi SEH yang dihasilkan yang akan dilemparkan pada kegagalan. Jika tidak dibuang, maka itu adalah penunjuk yang valid.

Masalah dengan metode ini adalah apakah ia hanya mengembalikan apakah Anda dapat membaca data dari pointer. Tidak ada jaminan tentang jenis keamanan atau sejumlah invariant lainnya. Secara umum metode ini bagus untuk hal lain selain mengatakan "ya, saya bisa membaca tempat tertentu di memori pada waktu yang sekarang telah berlalu".

Singkatnya, Jangan lakukan ini;)

Raymond Chen memiliki posting blog tentang hal ini: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx


26
2018-02-15 15:55



Berikut adalah tiga cara mudah untuk program C di Linux untuk mendapatkan introspeksi tentang status memori yang sedang berjalan, dan mengapa pertanyaan itu memiliki jawaban yang tepat dan canggih dalam beberapa konteks.

  1. Setelah memanggil getpagesize () dan membulatkan pointer ke halaman batas, Anda dapat memanggil mincore () untuk mencari tahu apakah halaman itu valid dan jika itu terjadi menjadi bagian dari proses kerja yang ditetapkan. Perhatikan bahwa ini membutuhkan beberapa sumber daya kernel, jadi Anda harus membandingkannya dan menentukan apakah memanggil fungsi ini benar-benar tepat di api Anda. Jika api Anda akan menangani interupsi, atau membaca dari port serial ke dalam memori, sangat tepat untuk memanggil ini agar tidak dapat diprediksi perilaku.
  2. Setelah memanggil stat () untuk menentukan apakah ada direktori / proc / self yang tersedia, Anda dapat membuka dan membaca / proc / self / maps untuk menemukan informasi tentang wilayah tempat penunjuk berada. Mempelajari halaman manual untuk proc, proses informasi pseudo-file sistem. Tentunya ini relatif mahal, tetapi Anda mungkin bisa lolos dengan caching hasil dari parse ke array Anda dapat secara efisien mencari menggunakan pencarian biner. Juga pertimbangkan / proc / self / smaps. Jika api Anda untuk komputasi berkinerja tinggi maka program akan ingin mengetahui tentang / proc / self / numa yang mana didokumentasikan di bawah halaman manual untuk numa, memori yang tidak seragam Arsitektur.
  3. Get_mempolicy (MPOL_F_ADDR) panggilan sesuai untuk kinerja api komputasi kinerja tinggi di mana ada beberapa utas eksekusi dan Anda mengelola pekerjaan Anda untuk memiliki afinitas untuk memori yang tidak seragam karena berkaitan dengan core cpu dan sumber daya socket. Seperti api tentu saja juga akan memberi tahu Anda apakah pointer itu valid.

Di bawah Microsoft Windows, ada fungsi QueryWorkingSetEx yang didokumentasikan di bawah Status Proses API (juga di NUMA API). Sebagai akibat dari pemrograman NUMA API yang canggih, fungsi ini juga akan memungkinkan Anda melakukan pekerjaan "penunjuk sederhana untuk validitas (C / C ++)" yang sederhana, karena itu sepertinya tidak akan ditinggalkan untuk setidaknya 15 tahun.


23
2018-05-12 17:22



AFAIK tidak ada jalan. Anda harus mencoba untuk menghindari situasi ini dengan selalu mengatur pointer ke NULL setelah membebaskan memori.


15
2018-02-15 15:48



Lihatlah ini dan ini pertanyaan. Juga lihatlah pointer pintar.


7
2018-02-15 15:51



Mengenai jawabannya sedikit di utas ini:

IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () untuk Windows.

Saran saya adalah menjauh dari mereka, seseorang telah memposting yang satu ini: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

Posting lain pada topik yang sama dan oleh penulis yang sama (saya pikir) adalah yang satu ini: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ("IsBadXxxPtr harus benar-benar disebut CrashProgramRandomly").

Jika pengguna API Anda mengirim dalam data buruk, biarkan crash. Jika masalahnya adalah bahwa data yang diteruskan tidak digunakan sampai nanti (dan yang membuatnya lebih sulit untuk menemukan penyebabnya), tambahkan mode debug di mana string dll. Dicatat pada entri. Jika mereka buruk itu akan menjadi jelas (dan mungkin crash). Jika ini sering terjadi, mungkin perlu memindahkan API Anda dari proses dan biarkan mereka menghentikan proses API, bukan proses utama.


7
2018-02-15 18:37