Sorunun geçmişi:
Rust başlangıçta bellek güvenliğinin öncelikli olduğu bir dil olarak tasarlandı. Ancak bazı görevlerde — örneğin, FFI veya düşük seviyeli tahsis edicilerle çalışırken — ham işaretçiler kullanmak ve dinamik belleği manuel olarak yönetmek gerekir. Bu görevler sistem programlamasında ve performans optimizasyonunda karşılaşılır. Bu nedenle Rust'ın bellek sızıntılarını, dangling pointer'ları ve use-after-free hatalarını nasıl önlediğini bilmek önemlidir.
Sorun:
Ham işaretçiler (*const T, *mut T) Rust'ın sahiplik ve referans kontrol sistemine entegre değildir: geçersiz bir bellek adresine işaret edebilir, hatalı bir şekilde serbest bırakılabilir veya hiç serbest bırakılmayabilir. Onlarla yapılan bir hata UB (tanımsız davranış), çökmeler, güvenlik açıklıkları veya bellek sızıntılarına yol açabilir.
Çözüm:
Ham işaretçiler yerine güvenli türler — Box, Rc, Arc kullanılması önerilir, geçici referanslar için ise borrow-referansları tercih edilir. Ancak ham işaretçilerden kaçış yoksa (örneğin, C API ile çalışmak için) tüm iş bölümleri unsafe blokları içerisine alınır, Drop dikkatlice organize edilir ve mümkünse NonNull gibi crate'ler kullanılır. Bir diğer teknik — RAII sarmalayıcıları ve işaretçinin yaşam döngüsünü minimize etmektir.
Kod örneği:
fn allocate_in_heap() -> Box<i32> { Box::new(100) } // bellek otomatik olarak serbest bırakılacak // ham işaretçi ile unsafe fn leak_memory() { let ptr = libc::malloc(4) as *mut i32; if !ptr.is_null() { *ptr = 42; // libc::free(ptr); // serbest bırakmayı unuturuzsa — sızıntı! } }
Ana özellikler:
Box'ın Box silindiğinde tüm iç içe değerlerin otomatik temizliğini garanti ediyor mu?
Evet, Box<T> silindiğinde, yapının içindeki tüm (Vec gibi) veri elemanlarını temizlemeden önce önce sarıcıyı temizleyen bir yıkıcı çağrılır.
Birkaç fonksiyonda ham işaretçi yapısını güvenli bir şekilde iletmek mümkün mü, use-after-free riski olmadan?
Hayır, ham işaretçi nesnenin yaşam süresi hakkında bilgi taşımaz. Derleyici güvenliği kontrol edemez, bu nedenle sorumluluk tamamen geliştiricide kalır: nesne serbest bırakıldıysa, ham işaretçi geçersiz bir adresi işaret edecektir.
Manuel serbest bırakma veya drop_in_place kullanırsak, Rust aynı adreste Drop'ı iki kez çağırabilir mi?
Evet, manuel serbest bırakmadan sonra bu bloğa işaret eden başka bir Box/işaretçi bırakırsanız, ikinci örneğin yok edilmesi sırasında Drop tekrar çağrılacak ve UB'ye yol açacaktır. Box, Vec vb. tarafından yönetilen şeyi asla manuel olarak serbest bırakmamalısınız.
Bir programcı dış bir C kütüphanesinden ham işaretçi aldı, kullanımdan sonra serbest bırakmadı veya perfndo-dealloc yaşam süresi ile başı dertteydi.
Artılar:
Eksiler:
RAII sarmalayıcı, işaretçi Box veya NonNull ile kapsüllenmiştir, her şey güvenli bir şekilde kapsam sona erdiğinde yok edilir.
Artılar:
Eksiler: