Mutex zehirlenmesi, bir panik gerçekleştiğinde atomik olarak true değerine ayarlanan kilidin iç durumundaki bir boolean bayrağı kullanır. Geri sarmada, bekçi iş parçacığı std::thread::panicking() ile panik durumunu algıladığında, bekçinin Drop uygulaması Mutex'i zehirli olarak işaretler ve temel işletim sistemi kilidini serbest bırakmadan önce zehirleme işlemini gerçekleştirir. Sonraki lock() çağrıları bu bayrağı kontrol eder; eğer ayarlıysa, Ok yerine Err(PoisonError<MutexGuard<T>>) döner, bu da çağırıcıyı, korunan verilerin bir panik tarafından kesilen kısmi bir değişiklik nedeniyle yapısal varsayımlarını ihlal edebileceğini kabul etmeye zorlar.
Dağıtılmış bir belge işleme motorunda, arka planda bir çalışan iş parçacığı, karmaşık bir formatlama rutini yürütürken büyük bir DocumentCache'i koruyan bir Mutex tutar. Önbelleğin iç BTreeMap indekslerini güncellerken, iş parçacığı beklenmedik bir bozuk giriş nedeniyle panik yapar. Geri sarma mekanizması bekçinin Drop uygulamasını tetikler, bu da panik durumunu algılar ve temel işletim sistemi seviyesindeki kilidi serbest bırakmadan önce atomik olarak Mutex'i zehirler, böylece bozulmuş kısmi ağaç yapısının diğer çalışanlar tarafından açık bir kabul olmaksızın erişilmesini engeller.
Bir kurtarma stratejisi, zehir hata algılandığında işlemi hemen sonlandırmayı içerir. Bu, hiçbir bozulmuş verinin kalıcı depolamaya veya istemci yanıtlarına ulaşmasını garantiler, katı bütünlük gereksinimlerini karşılar. Ancak bu yaklaşım erişilebilirliği feda eder, çünkü tüm hizmetin soğuk bir yeniden başlatmasını zorunlu kılar ve ilgisiz iş parçacıkları tarafından yapılan tüm geçerli işleri bozar, yüksek hacimli işleme pencereleri boyunca kabul edilemez bir kesinti yaratır.
İkinci bir yaklaşım, PoisonError::into_inner() kullanarak bekçeyi çıkarmak ve işlemlere devam etmektir; bu, verilerin muhtemelen yapısal olarak sağlam olduğu varsayımı altında zehir bayrağını etkili bir şekilde görmezden gelir. Bu, çalışma süresini korurken, sonraki okumalar bozuk göstericiler veya panik yapan iş parçacığı tarafından bırakılan varsayımsal ihlalleri ile karşılaştığında yıkıcı zincirleme hatalar riski taşır; bu potansiyel olarak ikincil paniklere veya yanıt verilerinin zarar görmesine yol açar ve bu da aşağı akış analitik boru hatlarına ve kalıcı veritabanlarına yayılabilir.
Seçilen çözüm, bir işlem geri alma mekanizması uygular: zehir hatasını yakaladığında, sistem kirlenmiş DocumentCache'i açıkça düşürür, ayrı bir NVMe biriminde saklanan bilinen iyi ve değişmez bir anlık görüntüyü bir Write-Ahead Log (WAL) ile geri yükler ve temiz bir durumla yeni bir çalışan iş parçacığı başlatır. Bu yaklaşım hatayı tek bir belge grubuna izole ederken, diğer istemciler için hizmetin erişilebilirliğini korur, böylece bozulmuş bellek uygulama mantığı tarafından hiçbir zaman referans alınamaz. Sonuç, saldırgan bulma testi sırasında %99.99'luk bir çalışma süresi metriği oldu, otomatik kurtarma 50 milisaniyenin altında tamamlandı ve belge işleme gecikmesi için katı SLA gereksinimlerini aşan bir başarı sağladı.
Neden RwLock de zehirlemeyi uygular, ancak standart kütüphanenin Mutex'i, basit Copy türlerini korumak için genellikle tercih edilir?
RwLock; Mutex ile aynı karmaşık varsayımları korur, ancak zehirlemesi hem okuma hem de yazma bekçilerini kapsar çünkü panik yapan bir yazar, sonraki okuyucular tarafından gözlemlenen durumu bozabilir. Ancak, basit Copy türleri, örneğin tam sayılar için Mutex tercih edilir; bu tercih zehirleme farklılıklarından değil — ikisi de aynı şekilde zehirlenir — ama çünkü Mutex, rekabet olmayan erişimlerde daha düşük yük sağlar. Ayrıca, zehirleme Copy türleri için anlamsal olarak önemsizdir, çünkü içsel varsayım ihlalleri gösteremezler; bir atama sırasında meydana gelen bir panik basitçe eski değeri intact tutar, bu da karmaşık doğrulama mantığı olmaksızın üzerine yazmaya devam ederek kurtarmayı basit hale getirir.
std::sync::PoisonError::new iç mekanizmasından nasıl farklıdır ve neden zehirlenmemiş bir Mutex için zehirli bir bekçi oluşturmak tehlikelidir?
PoisonError::new, hata varyantının manuel olarak oluşturulmasına izin veren bir genel yapıcıdır, ancak aslında altta yatan Mutex'in iç zehir bayrağını değiştirmez; sadece bir bekçeyi API uyumluluğu için hata türünde sarar. Uygulama akışına böyle bir hatayı manuel olarak enjekte etmek, zehir durumunun açık bir şekilde ele alınmasını gerektiren derleyici tarafından zorunlu kılınan güvenliği atlatır, bu da başka bir iş parçacığı tarafından aynı anda yeniden yapılandırılmaya çalışılan verilere erişime izin verebilir. Bu durum, iki iş parçacığının aynı anda kurtarma haklarının münhasır sahipleri olduklarını düşünmesiyle veri yarışına neden olur; bu da durum sıfırlama sırasında double-free veya kullanımdan sonra serbest bırakma senaryolarına yol açar.
Zehirlenme, Mutex'i yok etmeden güvenli bir şekilde "temizlenebilir" mi ve PoisonError::into_inner() bellek güvenliği garantileri hakkında neyi ifade ediyor?
into_inner() bekçeyi çıkarır ve hata sarıcısını atar, ancak Mutex'in iç zehir durumunu temizlemez; kilit gelecekteki tüm edinimler için sürekli olarak zehirli kalır, ta ki Mutex'in kendisi tamamen yok edilip yeniden oluşturulana kadar. Bu durum, into_inner() aracılığıyla erişilen herhangi bir verinin türünün varsayımlarını ihlal edebileceği anlamına gelir; bu nedenle, korunmuş durumu yeniden kullanmadan önce tam bir manuel doğrulama veya yeniden yapılandırma gerektirir. Adaylar genellikle into_inner()'ın otomatik bir kurtarma sağlamadığını, bunun yalnızca Err varyantının güvenliğini elden çıkardığını ve potansiyel olarak tehlikeli belleğe doğrudan erişim sağladığını, verilerin genel kullanım için güvenli kabul edilmeden önce varsayımları yeniden tesis etmek için unsafe mantığı gerektirdiğini gözden kaçırırlar.