Apakah ada cara untuk menentukan (secara programatik, tentu saja) jika sebuah pointer "valid"? Memeriksa NULL itu mudah, tetapi bagaimana dengan 0x00001234? Ketika mencoba untuk membedakan penunjuk jenis ini pengecualian / crash terjadi.
Metode lintas platform lebih disukai, tetapi khusus platform (untuk Windows dan Linux) juga tidak masalah.
Pembaruan untuk klarifikasi: Masalahnya bukan pada petunjuk basi / bebas / tidak diinisialisasi; sebaliknya, saya mengimplementasikan API yang mengambil pointer dari pemanggil (seperti pointer ke string, pegangan file, dll.). Penelepon dapat mengirim (secara sengaja atau tidak sengaja) nilai yang tidak valid sebagai penunjuk. Bagaimana cara mencegah crash?
Jawaban:
Anda tidak dapat melakukan pemeriksaan itu. Tidak ada cara untuk memeriksa apakah sebuah pointer "valid". Anda harus percaya bahwa saat orang menggunakan fungsi yang mengambil penunjuk, orang tersebut tahu apa yang mereka lakukan. Jika mereka melewatkan Anda 0x4211 sebagai nilai penunjuk, maka Anda harus mempercayainya menunjuk ke alamat 0x4211. Dan jika mereka "secara tidak sengaja" mengenai suatu objek, bahkan jika Anda akan menggunakan beberapa fungsi sistem operasi yang menakutkan (IsValidPtr atau apapun), Anda masih akan tergelincir ke dalam bug dan tidak gagal dengan cepat.
Mulailah menggunakan pointer nol untuk memberi isyarat hal semacam ini dan beri tahu pengguna perpustakaan Anda bahwa mereka tidak boleh menggunakan pointer jika mereka cenderung secara tidak sengaja meneruskan pointer yang tidak valid, serius :)
sumber
Berikut adalah tiga cara mudah untuk program C di Linux untuk mendapatkan introspektif tentang status memori tempat program tersebut berjalan, dan mengapa pertanyaan tersebut memiliki jawaban canggih yang sesuai dalam beberapa konteks.
Di bawah Microsoft Windows ada fungsi QueryWorkingSetEx yang didokumentasikan di bawah API Status Proses (juga di API NUMA). Sebagai akibat wajar dari pemrograman NUMA API yang canggih, fungsi ini juga akan memungkinkan Anda melakukan pekerjaan sederhana "pointer pengujian untuk validitas (C / C ++)", karena itu sepertinya tidak akan digunakan lagi setidaknya selama 15 tahun.
sumber
Mencegah crash yang disebabkan oleh pemanggil yang mengirimkan pointer yang tidak valid adalah cara yang baik untuk membuat bug diam yang sulit ditemukan.
Bukankah lebih baik bagi programmer yang menggunakan API Anda untuk mendapatkan pesan yang jelas bahwa kodenya palsu dengan cara menabraknya daripada menyembunyikannya?
sumber
Di Win32 / 64 ada cara untuk melakukan ini. Mencoba membaca pointer dan menangkap hasil eksekusi SEH yang akan dilemparkan jika gagal. Jika tidak melempar, maka itu penunjuk yang valid.
Masalah dengan metode ini adalah bahwa ia hanya mengembalikan apakah Anda dapat membaca data dari penunjuk atau tidak. Tidak ada jaminan tentang keamanan tipe atau sejumlah invarian lainnya. Secara umum metode ini baik untuk hal lain selain mengatakan "ya, saya dapat membaca tempat tertentu dalam ingatan pada waktu yang sekarang telah berlalu".
Singkatnya, Jangan lakukan ini;)
Raymond Chen memiliki entri blog tentang subjek ini: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx
sumber
AFAIK tidak mungkin. Anda harus mencoba menghindari situasi ini dengan selalu mengatur pointer ke NULL setelah mengosongkan memori.
sumber
Lihatlah ke ini dan ini pertanyaan. Lihat juga petunjuk cerdas .
sumber
Mengenai jawabannya sedikit di utas ini:
Saran saya adalah menjauh dari mereka, seseorang telah memposting yang ini: http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx
Posting lain tentang topik yang sama dan oleh penulis yang sama (menurut saya) adalah yang ini: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ("IsBadXxxPtr seharusnya benar-benar disebut CrashProgramRandomly ").
Jika pengguna API Anda mengirimkan data yang buruk, biarkan itu mogok. Jika masalahnya adalah bahwa data yang diteruskan tidak digunakan sampai nanti (dan itu membuat lebih sulit untuk menemukan penyebabnya), tambahkan mode debug di mana string, dll. Dicatat saat masuk. Jika mereka buruk maka akan terlihat jelas (dan mungkin crash). Jika ini sering terjadi, mungkin ada baiknya Anda mengeluarkan API dari proses dan membiarkannya merusak proses API alih-alih proses utama.
sumber
Pertama, saya tidak melihat ada gunanya mencoba melindungi diri Anda dari penelepon yang dengan sengaja mencoba menyebabkan kecelakaan. Mereka dapat dengan mudah melakukan ini dengan mencoba mengakses sendiri melalui penunjuk yang tidak valid. Ada banyak cara lain - cara ini dapat menimpa memori atau tumpukan Anda. Jika Anda perlu melindungi dari hal semacam ini maka Anda perlu menjalankan dalam proses terpisah menggunakan soket atau IPC lain untuk komunikasi.
Kami menulis cukup banyak perangkat lunak yang memungkinkan mitra / pelanggan / pengguna untuk memperluas fungsionalitas. Tidak dapat dipungkiri bahwa setiap bug dilaporkan kepada kami terlebih dahulu sehingga berguna untuk dapat dengan mudah menunjukkan bahwa masalahnya ada pada kode plugin. Selain itu, ada masalah keamanan dan beberapa pengguna lebih dipercaya daripada yang lain.
Kami menggunakan sejumlah metode berbeda tergantung pada kinerja / persyaratan throughput dan kepercayaan. Dari yang paling disukai:
proses terpisah menggunakan soket (sering melewatkan data sebagai teks).
proses terpisah menggunakan memori bersama (jika sejumlah besar data lewat).
proses yang sama memisahkan utas melalui antrian pesan (jika sering pesan singkat).
proses yang sama, utas terpisah, semua data yang lewat dialokasikan dari kumpulan memori.
proses yang sama melalui panggilan prosedur langsung - semua data yang lewat dialokasikan dari kolam memori.
Kami mencoba untuk tidak pernah menggunakan apa yang Anda coba lakukan saat berurusan dengan perangkat lunak pihak ketiga - terutama ketika kami diberi plug-in / library sebagai biner daripada kode sumber.
Penggunaan kumpulan memori cukup mudah dalam banyak situasi dan tidak perlu tidak efisien. Jika ANDA mengalokasikan data di tempat pertama maka itu mudah untuk memeriksa pointer terhadap nilai yang Anda alokasikan. Anda juga dapat menyimpan durasi yang dialokasikan dan menambahkan nilai "ajaib" sebelum dan sesudah data untuk memeriksa jenis data yang valid dan pembengkakan data.
sumber
Di Unix Anda harus dapat menggunakan kernel syscall yang melakukan pemeriksaan pointer dan mengembalikan EFAULT, seperti:
#include <unistd.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> #include <stdbool.h> bool isPointerBad( void * p ) { int fh = open( p, 0, 0 ); int e = errno; if ( -1 == fh && e == EFAULT ) { printf( "bad pointer: %p\n", p ); return true; } else if ( fh != -1 ) { close( fh ); } printf( "good pointer: %p\n", p ); return false; } int main() { int good = 4; isPointerBad( (void *)3 ); isPointerBad( &good ); isPointerBad( "/tmp/blah" ); return 0; }
kembali:
bad pointer: 0x3 good pointer: 0x7fff375fd49c good pointer: 0x400793
Mungkin ada syscall yang lebih baik untuk digunakan daripada open () [mungkin akses], karena ada kemungkinan hal ini dapat mengarah ke jalur kode pembuatan file aktual, dan persyaratan penutupan berikutnya.
sumber
Saya mendapat banyak simpati dengan pertanyaan Anda, karena saya sendiri dalam posisi yang hampir sama. Saya menghargai apa yang dikatakan banyak balasan, dan mereka benar - rutinitas yang memasok penunjuk harus menyediakan penunjuk yang valid. Dalam kasus saya, hampir tidak dapat dibayangkan bahwa mereka dapat merusak penunjuk - tetapi jika memang demikian berhasil, itu akan menjadi MY perangkat lunak yang crash, dan ME yang akan disalahkan :-(
Persyaratan saya bukanlah saya melanjutkan setelah kesalahan segmentasi - itu akan berbahaya - saya hanya ingin melaporkan apa yang terjadi pada pelanggan sebelum menghentikan sehingga mereka dapat memperbaiki kode mereka daripada menyalahkan saya!
Beginilah cara saya melakukannya (di Windows): http://www.cplusplus.com/reference/clibrary/csignal/signal/
Untuk memberikan sinopsis:
#include <signal.h> using namespace std; void terminate(int param) /// Function executed if a segmentation fault is encountered during the cast to an instance. { cerr << "\nThe function received a corrupted reference - please check the user-supplied dll.\n"; cerr << "Terminating program...\n"; exit(1); } ... void MyFunction() { void (*previous_sigsegv_function)(int); previous_sigsegv_function = signal(SIGSEGV, terminate); <-- insert risky stuff here --> signal(SIGSEGV, previous_sigsegv_function); }
Sekarang ini tampaknya berperilaku seperti yang saya harapkan (ini mencetak pesan kesalahan, lalu menghentikan program) - tetapi jika seseorang dapat menemukan kesalahan, beri tahu saya!
sumber
exit()
, ini mengelak dari RAII dan dengan demikian dapat menyebabkan kebocoran sumber daya.exit()
dan Bel Alarm C ++ Portabel saya mulai berdering. Seharusnya tidak masalah dalam situasi khusus Linux ini, di mana program Anda akan keluar, maaf untuk kebisingannya.man 2 signal
di Linux memiliki paragraf yang menjelaskan alasannya.Tidak ada ketentuan dalam C ++ untuk menguji validitas pointer sebagai kasus umum. Seseorang dapat dengan jelas berasumsi bahwa NULL (0x00000000) itu buruk, dan berbagai kompiler dan pustaka suka menggunakan "nilai khusus" di sana-sini untuk membuat debugging lebih mudah (Misalnya, jika saya pernah melihat penunjuk muncul sebagai 0xCECECECE di studio visual, saya tahu Saya melakukan sesuatu yang salah) tetapi kenyataannya adalah karena pointer hanyalah indeks ke dalam memori, hampir tidak mungkin untuk mengetahui hanya dengan melihat pointer apakah itu indeks yang "benar".
Ada berbagai trik yang dapat Anda lakukan dengan dynamic_cast dan RTTI seperti untuk memastikan bahwa objek yang ditunjuk adalah jenis yang Anda inginkan, tetapi semuanya mengharuskan Anda menunjuk ke sesuatu yang valid di tempat pertama.
Jika Anda ingin memastikan bahwa program Anda dapat mendeteksi pointer yang "tidak valid" maka saran saya adalah: Setel setiap pointer yang Anda deklarasikan ke NULL atau alamat yang valid segera setelah pembuatan dan setel ke NULL segera setelah membebaskan memori yang ditunjuknya. Jika Anda rajin melakukan praktik ini, maka memeriksa NULL adalah semua yang Anda butuhkan.
sumber
Tidak ada cara portabel untuk melakukan ini, dan melakukannya untuk platform tertentu bisa jadi sulit dan tidak mungkin. Bagaimanapun, Anda tidak boleh menulis kode yang bergantung pada pemeriksaan semacam itu - jangan biarkan penunjuk mengambil nilai yang tidak valid sejak awal.
sumber
Mengatur pointer ke NULL sebelum dan sesudah menggunakan adalah teknik yang baik. Ini mudah dilakukan di C ++ jika Anda mengelola pointer dalam kelas misalnya (string):
class SomeClass { public: SomeClass(); ~SomeClass(); void SetText( const char *text); char *GetText() const { return MyText; } void Clear(); private: char * MyText; }; SomeClass::SomeClass() { MyText = NULL; } SomeClass::~SomeClass() { Clear(); } void SomeClass::Clear() { if (MyText) free( MyText); MyText = NULL; } void SomeClass::Settext( const char *text) { Clear(); MyText = malloc( strlen(text)); if (MyText) strcpy( MyText, text); }
sumber
Bukan kebijakan yang sangat baik untuk menerima pointer arbitrer sebagai parameter input dalam API publik. Lebih baik memiliki tipe "data biasa" seperti integer, string atau struct (maksud saya struct klasik dengan data biasa di dalamnya, tentu saja; secara resmi apa pun bisa menjadi struct).
Mengapa? Nah karena seperti yang dikatakan orang lain tidak ada cara standar untuk mengetahui apakah Anda telah diberi penunjuk yang valid atau yang menunjuk ke sampah.
Namun terkadang Anda tidak punya pilihan - API Anda harus menerima pointer.
Dalam kasus ini, adalah tugas pemanggil untuk memberikan pointer yang baik. NULL dapat diterima sebagai nilai, tetapi bukan penunjuk ke junk.
Bisakah Anda memeriksa ulang dengan cara apa pun? Nah, apa yang saya lakukan dalam kasus seperti itu adalah mendefinisikan invarian untuk jenis yang ditunjuk pointer, dan memanggilnya ketika Anda mendapatkannya (dalam mode debug). Setidaknya jika invarian gagal (atau crash) Anda tahu bahwa Anda diberikan nilai yang buruk.
// API that does not allow NULL void PublicApiFunction1(Person* in_person) { assert(in_person != NULL); assert(in_person->Invariant()); // Actual code... } // API that allows NULL void PublicApiFunction2(Person* in_person) { assert(in_person == NULL || in_person->Invariant()); // Actual code (must keep in mind that in_person may be NULL) }
sumber
Seperti yang dikatakan orang lain, Anda tidak dapat dengan andal mendeteksi pointer yang tidak valid. Pertimbangkan beberapa bentuk yang mungkin diambil penunjuk yang tidak valid:
Anda bisa memiliki penunjuk nol. Itu salah satu yang dapat dengan mudah Anda periksa dan lakukan sesuatu.
Anda dapat memiliki penunjuk ke suatu tempat di luar memori yang valid. Apa yang merupakan memori valid bervariasi tergantung pada bagaimana lingkungan waktu proses sistem Anda mengatur ruang alamat. Pada sistem Unix, ini biasanya berupa ruang alamat virtual yang dimulai dari 0 dan menuju sejumlah besar megabyte. Pada sistem tertanam, ukurannya bisa sangat kecil. Ini mungkin tidak dimulai dari 0, dalam hal apapun. Jika aplikasi Anda berjalan dalam mode supervisor atau yang setara, penunjuk Anda mungkin merujuk ke alamat asli, yang mungkin dicadangkan dengan memori asli atau tidak.
Anda dapat memiliki penunjuk ke suatu tempat di dalam memori valid Anda, bahkan di dalam segmen data, bss, stack, atau heap, tetapi tidak mengarah ke objek yang valid. Variannya adalah pointer yang digunakan untuk menunjuk ke objek yang valid, sebelum sesuatu yang buruk terjadi pada objek tersebut. Hal-hal buruk dalam konteks ini termasuk deallocation, kerusakan memori, atau kerusakan pointer.
Anda bisa saja memiliki penunjuk ilegal yang jelas, seperti penunjuk dengan penyelarasan ilegal untuk hal yang dirujuk.
Masalah menjadi lebih buruk ketika Anda mempertimbangkan arsitektur berbasis segmen / offset dan implementasi pointer aneh lainnya. Hal semacam ini biasanya disembunyikan dari pengembang oleh kompiler yang baik dan penggunaan tipe yang bijaksana, tetapi jika Anda ingin menembus tabir dan mencoba mengakali sistem operasi dan pengembang kompiler, yah, Anda bisa, tetapi tidak ada satu cara umum untuk melakukannya yang akan menangani semua masalah yang mungkin Anda hadapi.
Hal terbaik yang dapat Anda lakukan adalah membiarkan crash dan mengeluarkan beberapa informasi diagnostik yang baik.
sumber
Artikel ini MEM10-C. Definisikan dan gunakan fungsi validasi pointer mengatakan itu mungkin untuk melakukan pemeriksaan sampai taraf tertentu, terutama di bawah OS Linux.
sumber
Secara umum, hal itu tidak mungkin dilakukan. Inilah satu kasus yang sangat buruk:
struct Point2d { int x; int y; }; struct Point3d { int x; int y; int z; }; void dump(Point3 *p) { printf("[%d %d %d]\n", p->x, p->y, p->z); } Point2d points[2] = { {0, 1}, {2, 3} }; Point3d *p3 = reinterpret_cast<Point3d *>(&points[0]); dump(p3);
Pada banyak platform, ini akan dicetak:
[0 1 2]
Anda memaksa sistem runtime untuk salah menafsirkan bit memori, tetapi dalam kasus ini tidak akan mogok, karena semua bit masuk akal. Ini adalah bagian dari desain bahasa (lihat C-gaya polimorfisme dengan
struct inaddr
,inaddr_in
,inaddr_in6
), sehingga Anda tidak dapat dipercaya melindungi terhadap itu pada platform apapun.sumber
Sulit dipercaya betapa banyak informasi menyesatkan yang dapat Anda baca di artikel di atas ...
Dan bahkan dalam dokumentasi microsoft msdn IsBadPtr diklaim dilarang. Baiklah - Saya lebih suka aplikasi yang berfungsi daripada mogok. Bahkan jika jangka waktu bekerja mungkin tidak berfungsi dengan benar (selama pengguna akhir dapat melanjutkan aplikasi).
Dengan googling, saya belum menemukan contoh berguna untuk windows - menemukan solusi untuk aplikasi 32-bit,
http://www.codeproject.com/script/Content/ViewAssociatedFile.aspx?rzp=%2FKB%2Fsystem%2Fdetect-driver%2F%2FDetectDriverSrc.zip&zep=DetectDriverSrc%2FDetectDriver%2FsRc%2Ftcidp2 = 2
tetapi saya juga perlu mendukung aplikasi 64-bit, jadi solusi ini tidak berhasil untuk saya.
Tapi saya telah memanen kode sumber anggur, dan berhasil memasak jenis kode serupa yang akan berfungsi untuk aplikasi 64-bit juga - dengan melampirkan kode di sini:
#include <typeinfo.h> typedef void (*v_table_ptr)(); typedef struct _cpp_object { v_table_ptr* vtable; } cpp_object; #ifndef _WIN64 typedef struct _rtti_object_locator { unsigned int signature; int base_class_offset; unsigned int flags; const type_info *type_descriptor; //const rtti_object_hierarchy *type_hierarchy; } rtti_object_locator; #else typedef struct { unsigned int signature; int base_class_offset; unsigned int flags; unsigned int type_descriptor; unsigned int type_hierarchy; unsigned int object_locator; } rtti_object_locator; #endif /* Get type info from an object (internal) */ static const rtti_object_locator* RTTI_GetObjectLocator(void* inptr) { cpp_object* cppobj = (cpp_object*) inptr; const rtti_object_locator* obj_locator = 0; if (!IsBadReadPtr(cppobj, sizeof(void*)) && !IsBadReadPtr(cppobj->vtable - 1, sizeof(void*)) && !IsBadReadPtr((void*)cppobj->vtable[-1], sizeof(rtti_object_locator))) { obj_locator = (rtti_object_locator*) cppobj->vtable[-1]; } return obj_locator; }
Dan kode berikut dapat mendeteksi apakah pointer valid atau tidak, Anda mungkin perlu menambahkan beberapa pemeriksaan NULL:
CTest* t = new CTest(); //t = (CTest*) 0; //t = (CTest*) 0x12345678; const rtti_object_locator* ptr = RTTI_GetObjectLocator(t); #ifdef _WIN64 char *base = ptr->signature == 0 ? (char*)RtlPcToFileHeader((void*)ptr, (void**)&base) : (char*)ptr - ptr->object_locator; const type_info *td = (const type_info*)(base + ptr->type_descriptor); #else const type_info *td = ptr->type_descriptor; #endif const char* n =td->name();
Ini mendapat nama kelas dari pointer - Saya pikir itu harus cukup untuk kebutuhan Anda.
Satu hal yang saya masih khawatirkan adalah kinerja pemeriksaan penunjuk - di snipet kode di atas sudah ada 3-4 panggilan API yang dibuat - mungkin berlebihan untuk aplikasi kritis waktu.
Akan lebih baik jika seseorang dapat mengukur overhead pemeriksaan pointer dibandingkan, misalnya dengan panggilan C # / managed c ++.
sumber
Memang, sesuatu dapat dilakukan dalam keadaan tertentu: misalnya jika Anda ingin memeriksa apakah string penunjuk string valid, menggunakan write (fd, buf, szie) syscall dapat membantu Anda melakukan keajaiban: biarkan fd menjadi deskriptor file sementara file yang Anda buat untuk pengujian, dan buf yang menunjuk ke string yang Anda uji, jika pointer tidak valid write () akan mengembalikan -1 dan errno disetel ke EFAULT yang menunjukkan bahwa buf berada di luar ruang alamat Anda yang dapat diakses.
sumber
Berikut ini berfungsi di Windows (seseorang menyarankannya sebelumnya):
static void copy(void * target, const void* source, int size) { __try { CopyMemory(target, source, size); } __except(EXCEPTION_EXECUTE_HANDLER) { doSomething(--whatever--); } }
Fungsi tersebut harus metode statis, mandiri atau statis dari beberapa kelas. Untuk menguji di read-only, salin data di buffer lokal. Untuk menguji menulis tanpa mengubah isinya, tulislah kembali. Anda hanya dapat menguji alamat pertama / terakhir. Jika pointer tidak valid, kontrol akan diteruskan ke 'doSomething', dan kemudian di luar tanda kurung. Hanya saja, jangan gunakan apa pun yang membutuhkan destruktor, seperti CString.
sumber
Di Windows saya menggunakan kode ini:
void * G_pPointer = NULL; const char * G_szPointerName = NULL; void CheckPointerIternal() { char cTest = *((char *)G_pPointer); } bool CheckPointerIternalExt() { bool bRet = false; __try { CheckPointerIternal(); bRet = true; } __except (EXCEPTION_EXECUTE_HANDLER) { } return bRet; } void CheckPointer(void * A_pPointer, const char * A_szPointerName) { G_pPointer = A_pPointer; G_szPointerName = A_szPointerName; if (!CheckPointerIternalExt()) throw std::runtime_error("Invalid pointer " + std::string(G_szPointerName) + "!"); }
Pemakaian:
unsigned long * pTest = (unsigned long *) 0x12345; CheckPointer(pTest, "pTest"); //throws exception
sumber
IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr () untuk Windows.
Ini membutuhkan waktu yang sebanding dengan panjang blok, jadi untuk pemeriksaan kewarasan saya hanya memeriksa alamat awal.
sumber
Saya telah melihat berbagai perpustakaan menggunakan beberapa metode untuk memeriksa memori yang tidak direferensikan dan semacamnya. Saya percaya mereka hanya "menimpa" alokasi memori dan metode deallocation (malloc / free), yang memiliki beberapa logika yang melacak petunjuknya. Saya kira ini berlebihan untuk kasus penggunaan Anda, tetapi ini akan menjadi salah satu cara untuk melakukannya.
sumber
Secara teknis, Anda dapat mengganti operator new (dan menghapus ) dan mengumpulkan informasi tentang semua memori yang dialokasikan, sehingga Anda dapat memiliki metode untuk memeriksa apakah memori heap valid. tapi:
Anda masih memerlukan cara untuk memeriksa apakah pointer dialokasikan di stack ()
Anda perlu menentukan apa itu penunjuk 'valid':
a) memori pada alamat itu dialokasikan
b) memori di alamat itu dimulai objek (misalnya alamat bukan di tengah array besar)
c) memori pada alamat itu adalah alamat awal dari objek yang diharapkan jenis yang
Intinya : pendekatan yang dimaksud bukanlah cara C ++, Anda perlu mendefinisikan beberapa aturan yang memastikan bahwa fungsi menerima petunjuk yang valid.
sumber
Tidak ada cara untuk melakukan pemeriksaan itu di C ++. Apa yang harus Anda lakukan jika kode lain memberikan Anda penunjuk yang tidak valid? Anda harus crash. Mengapa? Lihat tautan ini: http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx
sumber
Tambahan pada jawaban yang diterima:
Asumsikan bahwa penunjuk Anda hanya dapat menampung tiga nilai - 0, 1 dan -1 di mana 1 menandakan penunjuk yang valid, -1 yang tidak valid dan 0 yang lain tidak valid. Berapa probabilitas pointer Anda adalah NULL, semua nilai kemungkinannya sama? 1/3. Sekarang, keluarkan kasus yang valid, jadi untuk setiap kasus yang tidak valid, Anda memiliki rasio 50:50 untuk menangkap semua kesalahan. Terlihat bagus kan? Skala ini untuk penunjuk 4-byte. Ada 2 ^ 32 atau 4294967294 kemungkinan nilai. Dari jumlah tersebut, hanya SATU nilai yang benar, satu adalah NULL, dan Anda masih memiliki 4294967292 kasus tidak valid lainnya. Hitung ulang: Anda memiliki tes untuk 1 dari (4294967292+ 1) kasus tidak valid. Probabilitas 2.xe-10 atau 0 untuk sebagian besar tujuan praktis. Begitulah kesia-siaan pemeriksaan NULL.
sumber
Anda tahu, driver baru (setidaknya di Linux) yang mampu melakukan ini mungkin tidak akan sulit untuk ditulis.
Di sisi lain, adalah bodoh untuk membangun program Anda seperti ini. Kecuali Anda memiliki beberapa penggunaan yang benar-benar spesifik dan tunggal untuk hal seperti itu, saya tidak akan merekomendasikannya. Jika Anda membangun aplikasi besar yang dimuat dengan pemeriksaan validitas penunjuk konstan, kemungkinan akan sangat lambat.
sumber
Jika tidak berfungsi - pembaruan windows berikutnya akan memperbaikinya? Jika mereka tidak bekerja pada level konsep - fungsi mungkin akan dihapus dari api windows sepenuhnya.
Dokumentasi MSDN mengklaim bahwa mereka dilarang, dan alasan untuk ini mungkin adalah cacat dari desain aplikasi lebih lanjut (misalnya umumnya Anda tidak boleh makan petunjuk yang tidak valid secara diam-diam - jika Anda bertanggung jawab atas desain seluruh aplikasi, tentu saja), dan kinerja / waktu pemeriksaan penunjuk.
Tetapi Anda tidak boleh mengklaim bahwa mereka tidak berfungsi karena beberapa blog. Dalam aplikasi pengujian saya, saya telah memverifikasi bahwa mereka berfungsi.
sumber
tautan ini mungkin berguna
_CrtIsValidPointer Memverifikasi bahwa kisaran memori yang ditentukan valid untuk membaca dan menulis (hanya versi debug). http://msdn.microsoft.com/en-us/library/0w1ekd5e.aspx
_CrtCheckMemory Mengonfirmasi integritas blok memori yang dialokasikan di heap debug (hanya versi debug). http://msdn.microsoft.com/en-us/library/e73x0s4b.aspx
sumber