Güneşli bir sabah, dizüstü bilgisayarımın önünde oturup C# kodunu yeniden yapılandırıyordum. Her şey yolunda gidiyor ve verimli bir gün olacak. Sonra sabit sicire çok fazla eşit işareti ekledim ve işler patladı. Verimlilik kayboldu. Pazar günkü sakin yeniden yapılanma geride kaldı. Güneş bile bulutların arkasına saklanmaya karar verdi.
Neyi yanlış yaptığımı anlamaya çalıştığım için 30-40 dakika harcadıktan sonra, bunun ben değilim olduğunu fark ettim. It's Microsoft. Görünüşe göre Base64 kod çözme fonksiyonunda eski bir hata bulmuşum.Convert.FromBase64StringBu hata kesinlikle .NET 1.1'in 2003'te tanıtılmasından beri var. Vay! Bu eski. Ve çoğaltmak çok zor değil. Güzel iş:
Teknik olarak, bu yasadışı Base64. Yasal versiyonu "abc=". Sadece bir doldurma karakteri =. Base64 kodlaması, her 6 bitlik ikili girişi bir ASCII karakterinde temsil eder. Bu, Base64 kodlanmış bir dizide her 4 karakterin 3 baytı temsil ettiği anlamına gelir. Kodlanan veri 3 baytın katı olmadığında, Base64 kodlayıcısı bir doldurucu karakter ekler ve Base64'ü 4 karakterin katı yapar. Bu, doğru şekilde "abc=" ile doldurulmuş bir Base64 dizisi oluşturur. Başka bir = eklemek geçersiz hale gelir.
Base64 "abc=" iki bayt olarak çözülür [105, 183]. Doğru. Sonuna başka bir dolgu karakteri eklemek kodlanan değeri gerçekten değiştirmemeli. Bu, bir cümlenin sonuna boşluk eklemek gibi. Evet, orada ama cümlenin anlamını değiştirmez. Ama .NET böyle düşünmüyor. "abc==" bayt olarak çözülür [109]. Sadece kısaltmakla kalmadı, ki bu garipti çünkü girişi daha uzun yaptık. Ayrıca farklı hale geldi. İlk bayt 105'ten 109'a kadar gidiyor. Ve istisna da değildi. Bir başka = ekleyin ve bir istisna elde edersiniz. Şaşırtıcı!
Kod:
Çıktı:
'abc=' -> [105, 183] 'abc==' -> [109] Yıllardır kimsenin bunu fark etmemesi gerçekten şaşırtıcı. Ya da bulundu ama düzeltilmedi. Base64, ağda bilgi alışverişinde çok önemlidir. Her yerde görülebilir. Ancak .NET, hatalı Base64 kod çözücüsünden yıllardır kurtulmadı.
İlk başta inanamadım ve araştırmaya başladım. Bir süre Google'da aradım ama pek bir şey bulamadım. Sonra StackOverflow'da paylaşım yaptım ama pek şans alamadım. Ne olduğunu anladıktan sonra kendi sorularımı bile yanıtlamak zorunda kaldım. GitHub'da bir süre aradıktan sonra, Temmuz 2018'de .NET Core'da yapılan bir düzeltmeye rastladım. Yani en son .NET Core sürümü bu sorunu doğru şekilde ele alıyor ve bir istisna oluşturuyor:
Yönetilmeyen İstisna: System.FormatException: Girdi, temel olmayan 64 karakter, iki birden fazla doldurma karakteri veya yasadışı bir karakter içerdiği için geçerli bir Base-64 dizisi değildir Karakterleri doldurmak. at System.Convert.FromBase64CharPtr(Char* inputPtr, Int32 inputLength) System.Convert.FromBase64String(String s) adresinde Program.DecodeAndPrint (String base64) adresinde ./base64/Program.cs:line 13 içinde Program.main() adresinde ./base64/Program.cs:line 8 Sorunu bulup çözmeleri yaklaşık 15 yıl sürdü. İlginçtir ki, kimse bunu özel olarak düzeltmeye çalışmadı. Bu, kodu daha hızlı hale getirmek için yeniden yazıldığında oldu:
Convert.FromBase64() ise, dizinin sonunda yasa dışı şekilde doldurulmuş ikinci karakterin sondan önceki karakteri kaldırarak çözümlemenin "başarılı" olmasına neden olan ince bir hata vardır.
Buradayız. Bu hata, API NetCore 2.1'de optimize edildiğinde yanlışlıkla düzeltildi. Hataları kaydetmek için testler ekleyin ve geriye gitmediğimizden emin olun. Bu sorun .NET Core 2.2'de çözüldü. Ancak .NET Framework 4.7.2'nin güncel en son sürümünde hâlâ sorunlar var. Mono'da da bozuk gibi görünüyor.
.NET 4.7.2'deki çözüm, yanlış doldurulmuş diziyi şöyle bir şeyle doldurmaktır:
Özgün:Bağlantı girişi görünür.
|