Mecburi saçmalıklar

Şirketteki ilk projelerimden biri, bir ürünü DBMS destekli bir hale getirmekti. Önceki versiyon Codebase denen bir sistemle yazılmıştı ve sık sık veri kaybına ya da bozukluklarına yol açmaktaydı. Transaksiyon kontrolü de zordu o sistemde. DBMS olarak MySQL’i seçtik ve projeye başladık. Programlama dili olarak C++ ve geliştirme ortamı olarak da Visual Studio 2003 ve MFC (Microsoft Foundation Classes) kullandık. MFC, ODBC (Open Database Connectivity) üzerinden veri tabanıyla iletişim imkanı sunuyordu. CDatabase nesneleri filan vardı. Değişik dilleri desteklemek zorunda olduğumuzdan da Unicode desteğini aktifleştirmiştik. Başka veri tabanlarını destekleme durumu ortaya çıkabilir diye hem şema hem de veritabanı tabloları için ayrı kütüphaneler de yazdık. Bu tür sistemler o sıralarda Java için çok yaygındı ama C++ için hoşumuza giden bir çözüm bulamamıştık. Projeyi beraber yaptığım arkadaş da o sıralarda C++’tan başka bir dile geçmeye yanaşmıyordu.

İlk basit denemelerden sonra ümit vadeden planımız garip bir sorunla karşılaşmıştı. Nerede olduğunu bilmediğimiz bir Access Violation hatasına çarpıp duruyorduk. Tabii ki hata anındaki stack trace (o anda programda işletilen komutların hiyerarşik listesi) hiçbir şey ifade etmiyordu. Anlaşılan bayağı şiddetli bir buffer overrun (program yanlış yerlere veri yazarak başka nesneleri ve dolayısıyla programın çalışmasını bozuyor) sorunuyla karşı karşıyaydık. Tabii hatanın tam olarak hangi komutta ortaya çıktığını bilmediğimizden internette de aratamıyorduk. Sonuçta buffer overrun ya da access violation nedeni bulmak için oldukça genel terimlerdi. Stack trace, hatanın fark edildiği anda okunamaz  durumda (daha doğrusu bizim durumumuzda anlamsız) olduğundan gözümüz kapalı yavaş yavaş uçuruma doğru yürüme yolunu seçtik. Problemin tek iyi tarafı tekrarlanabilir olmasıydı. Bu sayede defalarca uçuruma gelip hangi anda düşmeye başladığımızı anlamaya çalışacaktık.

Standard yöntem programı hata ayıklayıcı ile çalıştırıp adım adım işletmek olabilirdi. Hata mesajının geldiği yere bakarak programın maksimum nereye kadar ilerlediğini tahmin edebiliyorduk ve baştan oraya gitmek epey zaman alacaktı. Bunun üzerine programın çeşitli yerlerine breakpointler (Program o satıra kadar işletilir ve o noktada otomatik olarak durdurulur) koyarak nereye kadar gidebildiğine baktık. Bu yerleri de genelde hep ikiye bölerek bu aramayı hızlandırdık, yani bir nevi binary search algoritması kullandık. Bir süre sonra hata mesajının nerede ortaya çıktığını bulduk ama bu çok işe yaramıyordu çünkü buffer overrun daha önce olmuş olmalıydı. Biz sadece en geç ne zaman olmuş olabileceğini bulmuş oldu.

Program unit test gibi yöntemler kullanılmadan yazılmış olduğundan parçaları tek tek hızla test etme şansımız da yoktu. Elimizdeki tek araç visual studio içindeki hata ayıklayıcısıydı. Nesnelerin değerleri filan normal gözüküyordu. Bununla oynarken sadece nesnelerin değerlerini değil aynı zamanda bu nesnelerin bulunduğu adreslerdeki (ve bu adreslerin çevrelerinde) değişiklikleri de görebildiğimizi fark ettik. Visual studio her işletilen satır için seçilen adres bölgelerindeki değişiklikleri kırmızı gösterebiliyordu. Çaresizlikten buralara bakayım dedim. Sonuçta hatanın yaklaşık hangi satırlarda olduğunu bulabilmiştim. O satırlardaki nesnelerin hangi adreslerde olduğunu da buldum. Ondan sonra dürbünümü o alana tutup programı satır satır işletmeye başladım. Her satırda ufak tefek kırmızı değişiklikler görünüyordu ama bunlar aradığım şey değildi. O nesnelerin büyüklüklerini bildiğimden bu kırmızı bölgelerin nesnenin içinde mi dışında mı olduğunu hesaplayabiliyordum. Böyle motivasyonumu kaybetmiş bir şekilde satırları tek tek işletirken birden adres ekranı havayi fişek patlaması gibi kıpkırmızı oldu. En son hangi satırda olduğuma baktım hemen ve veri tabanıyla bağlantı kurma komutunu gördüm. İnternette arattım. CDatabase, buffer overrun filan dedim ve binlerce sonuç aldım. Meğer MFC’nin o versiyonu unicode ile bir hesap hatası yapıyormuş ve bu sayede epeyce bir adres alanına yanlış değerler yazıyormuş. Böyle olunca da program bir sonraki adımda nereye gideceği bilgilerini de bozmuş oluyor. Evet, sorunu bulmuştum ama çözüm neydi? Forumlara bakılırsa Microsoft yakında bir yama yayımlamayı düşünmüyordu ama biz programı müşteriye söz vermiştik.

Sonuçta çaresizliğimizin doruğunda visual studio’nun küçük boyutlarda yaptığı bir şeyi yapmaya karar verdim. Veri tabanı nesnesinin sağına ve soluna dev gibi yasak bölgeler inşa ettim. Yanlış hatırlamıyorsam 10 kB büyüklüğünde boş alan koydum. Bir nevi hendek yöntemi. Bu şekilde diğer nesneleri veri tabanı nesnesindeki hatalardan korumayı başardım. Şansımıza veri tabanı nesnesi sınırları içinde bir sorun çıkmamıştı. Aylar sonra gelen Microsoft yaması ile bu utanç verici çözümü de kaldırdık ama bence bu utancın büyük kısmı Microsoft’a aittir. Bütün bu hatayı arama ve düzeltme süreci neredeyse iki hafta sürdü. Aslında bu iki haftada hatanın adını aramış olduk, adı konulunca kendimizi sanki herkesin aynı sorundan muzdarip olduğu bir ortamda bulduk.

Bir yanıt yazın