Blog

Rust'ın Gözünden Kaçanlar: Derleyicinin Yakalayamadığı Hatalar

Alper Kocan 29 April 2026 45 görüntülenme

Selamlar, ben Alper. Bugün biraz popüler ve bir o kadar da sevdiğimiz Rust programlama dili hakkında konuşalım istiyorum. Rust denince hepimizin aklına gelen ilk şey, o meşhur Borrow Checker (Ödünç Alma Denetleyicisi) ve "Hafıza güvenliği (memory safety) garantisi" oluyor. Evet, Rust bizi C++'taki gibi korkunç segmentation fault hatalarından veya dangling pointer (boşta kalan işaretçi) dertlerinden büyük oranda kurtarıyor. Ancak, Rust öğrenmeye başlayanların veya profesyonel projelerde kullananların sıkça düştüğü bir yanılgı var: "Eğer kod derleniyorsa, hatasızdır."

Keşke her şey bu kadar kolay olsaydı! Rust bir güvenlik ağı sunar ama bu ağın delikleri de vardır. Bu yazıda, Rust derleyicisinin bile durduramadığı, çalışma zamanında (runtime) başımızı ağrıtabilecek hata türlerine değineceğiz. Gelin, bu "yakalanamayan" hatalara birlikte bakalım.

1. Mantıksal Hatalar (Logic Errors)

Bu aslında tüm dillerin ortak derdi ama Rust'ın katı yapısı bazen bizi rehavete sokabiliyor. Derleyici sizin bir indirim hesaplama fonksiyonunda toplama yerine çıkarma yaptığınızı anlayamaz. Örneğin, bir kullanıcının bakiyesinden para düşerken yanlışlıkla bakiye ekleyen bir kod yazdığınızda, Rust derleyicisi "Harika, tipler uyuşuyor, bellek güvenli!" diyerek kodu onaylar. Business logic dediğimiz iş mantığı hataları, her zaman olduğu gibi yine bizim sorumluluğumuzda. Bu yüzden birim testleri (unit tests) yazmak, Rust dünyasında da en az C# veya Python dünyasındaki kadar kritiktir.

2. Kilitlenmeler (Deadlocks)

Rust, Data Race (veri yarışı) hatalarını derleme aşamasında engelleyerek rakiplerine büyük fark atıyor. Ancak, Deadlock (kilitlenme) dediğimiz durum için aynı şeyi söyleyemeyiz. İki farklı iş parçacığının (thread), birbirinin elinde tuttuğu kaynağı (Mutex) beklemesi durumu Rust'ta hala mümkündür. Derleyici, hangi Mutex'in hangi sırayla kilitleneceğini takip edemez. Eğer A thread'i önce Mutex1'i sonra Mutex2'yi kilitliyorsa, aynı anda B thread'i önce Mutex2'yi sonra Mutex1'i kilitlemeye çalışırsa, programınız sonsuza kadar beklemeye geçer. Bu bir bellek hatası değildir, dolayısıyla Rust buna müdahale etmez.

3. Bellek Sızıntıları (Memory Leaks)

Şaşırtıcı gelebilir ama Rust'ta bellek sızdırmak (memory leak) tamamen "güvenli" (safe) kabul edilir. Rust dokümantasyonu bile bunu açıkça belirtir. Genellikle Rc (Reference Counted) veya Arc (Atomic Reference Counted) akıllı işaretçilerini kullanırken birbirini gösteren yapılar (circular references) oluşturursanız, bu nesnelerin referans sayacı asla sıfıra düşmez ve bellekten silinmezler. Ayrıca Box::leak fonksiyonuyla bilerek bir belleği sızdırıp programın ömrü boyunca orada kalmasını sağlayabilirsiniz. Yani "Rust kullanıyorum, RAM asla şişmez" demek doğru bir yaklaşım değildir.

4. Tamsayı Taşmaları (Integer Overflow)

İşte burası oldukça ilginç bir nokta. Rust'ta bir tamsayıyı kapasitesinden fazla artırırsanız ne olur? Cevap, kodun nasıl derlendiğine göre değişir. Eğer kodunuzu debug modunda çalıştırıyorsanız, Rust bir panic (programın çökmesi) fırlatır ve hatayı yakalarsınız. Ancak kodunuzu release modunda (yani canlı ortamda) derlediğinizde, performans kaygılarıyla bu kontrol devre dışı bırakılır ve "wrapping" (başa sarma) gerçekleşir. Örneğin, 255 değerindeki bir u8 değişkenine 1 eklerseniz sonuç 0 olur. Bu durum, finansal hesaplamalar gibi hassas noktalarda ciddi güvenlik açıklarına veya hatalı sonuçlara yol açabilir.

5. Panikler ve Beklenmeyen Çökmeler (Unwrap ve Expect)

Rust'ın hata yönetimi (Result ve Option) harikadır, ancak biz yazılımcılar bazen tembellik edip .unwrap() veya .expect() metotlarını kullanırız. Bu metotlar, bir değerin var olduğundan veya işlemin başarılı olduğundan emin olduğumuzu söyler. Eğer yanılıyorsak, program o noktada "panic" eder ve aniden kapanır. Derleyici bu kullanımın güvenli olup olmadığını kontrol etmez. Canlı ortamda çalışan bir sunucunun, bir veritabanı bağlantısı anlık koptuğu için unwrap() yüzünden tamamen kapanması, Rust'ın değil bizim hatamızdır. Bu yüzden her zaman pattern matching (desen eşleme) veya ? operatörü ile hataları zarif bir şekilde yönetmeliyiz.

Sonuç Olarak

Rust bize inanılmaz güçlü bir zırh veriyor ama bu zırhın içinde hala bir insan var. Derleyici bizim en iyi dostumuz olsa da, mantıksal kurguyu kurmak, kilitlenmeleri öngörmek ve hata yönetimini doğru tasarlamak hala bizim görevimiz. "Rust güvenlidir" cümlesini "Rust hafıza yönetimi konusunda güvenli bir zemin sunar" şeklinde okumak, bizi daha dikkatli ve başarılı birer geliştirici yapacaktır. Unutmayın, en iyi hata ayıklama aracı hala dikkatli bir çift göz ve kapsamlı test senaryolarıdır.

Bir sonraki yazıda görüşmek üzere, kodunuz hatasız, kahveniz taze olsun!

Yorumlar (0)
Yorum Yap