Linux, 6 yıl ve 360'tan fazla yamanın ardından `strncpy` API'sini kaldırdı
(phoronix.com/news)- Linux 7.2'de çekirdek içindeki strncpy API kullanım alanları ortadan kalktı ve uzun süredir kaldırılması planlanan bu string kopyalama arayüzü nihayet tamamen kaldırıldı
strncpy(), belirtilen bayt sayısı kadar kopyalar ancak NUL sonlandırma davranışı sezgisel değildir; bu yüzden çekirdekte yıllar boyunca hataların nedeni olmaya devam etti- Hedef tamponu gereksiz yere 0'larla doldurma özelliği performans sorunlarına da yol açtı ve bunun temizlenmesi için yaklaşık 6 yıl ve 362 commit gerekti
- Cuma günkü merge ile API'nin kendisinin yanı sıra son CPU başına mimariye özgü uygulama da kaldırıldı
- Çekirdek kodu artık kullanım amacına göre
strscpy(),strscpy_pad(),strtomem_pad(),memcpy_and_pad(),memcpy()gibi alternatif işlevlerden birini seçmek zorunda
Linux 7.2'de ortadan kalkan strncpy
- Linux 7.2, çekirdekte uzun süredir kaldırılması planlanan
strncpyAPI'sini nihayet kaldırdı - 6 yıla yayılan temizlik çalışmasının sonunda çekirdek içinde
strncpyarayüzünü kullanan hiçbir kod kalmadı - Bu değişiklik, basit bir fonksiyon değişiminden çok, eski string kopyalama alışkanlıklarının çekirdek genelinden sökülüp atılması anlamına geliyor
Kaldırmaya giden işin ölçeği
strncpy'nin kaldırılması için yaklaşık 362 commit gerekti- Çalışma, çekirdek içindeki
strncpykullanımını aşamalı olarak ortadan kaldıracak şekilde yürütüldü - Linux 7.2 ile bu temizlik süreci tamamlanmış oldu
strncpy çekirdekte neden sorunluydu?
strncpy, Linux çekirdeğinde yıllar boyunca sürekli hata kaynağı olarak görüldü- Özellikle iki davranışı sorun yarattı
- NUL sonlandırma anlamı ve davranışı sezgisel olmadığından kullanıcıların hata yapması kolaydı
- Hedef tamponun tekrar tekrar 0'larla doldurulması gereksiz performans maliyeti oluşturuyordu
Gerçek kaldırma merge'ü
- Cuma günü yapılan merge,
strncpyAPI'sini kaldırdı - Aynı merge içinde son CPU başına mimariye özgü
strncpyuygulaması da ortadan kaldırıldı
Çekirdek kodunda kullanılacak alternatif API'ler
strncpyyerine, kopyalanan hedefe ve sonlandırma koşuluna uygun işlev seçilmelistrscpy(): NUL ile sonlandırılan hedeflerde kullanılırstrscpy_pad(): NUL ile sonlandırılan hedeflerde 0 dolgusu gerektiğinde kullanılırstrtomem_pad(): NUL ile sonlandırılmayan sabit genişlikli alanlarda kullanılırmemcpy_and_pad(): Açık dolgulama içeren sınırlı kopyalamalarda kullanılırmemcpy(): Uzunluğu bilinen bellek kopyalamalarında kullanılır
1 yorum
Hacker News yorumları
Eskiden, dünya çapında en iyi C geliştiricileri sayılan Linux çekirdeği geliştiricilerinin stringbuffer ya da stringview türleri yapmayı bilmedikleriyle dalga geçilirdi; ama o zamanlar bu konuda bugünkü gibi bir uzlaşı yoktu, o yüzden bir ölçüde anlaşılabilir
Doğru yönü önceden görmüş kişi aslında Dennis Ritchie'ydi ve 1990'da C için fat pointer türü önermişti. C99'a girseydi mükemmel bir ek olurdu; komite bunu ekleseydi dünya epey farklı olabilirdi
2007'de Walter Bright'ın “C's greatest mistake” yazısıyla ikinci bir fırsat doğdu; bu da özünde Ritchie ile aynı fikir olan slice/stringview yaklaşımını daha açık anlatıyordu, ama C11'e de giremedi. C23'e geldik hâlâ yok; onun yerine _Generic ve VLA aldık, bari coşkuyla parti yapalım gibi bir durum
Ararken aynı konuda bir Reddit başlığına da rastladım; bike-shedding tartışması komikti: https://www.reddit.com/r/C_Programming/comments/90uq7c/cs_bi...
C dizilerinin pointer'a çökmesinin neden tasarlandığını merak ediyorum. Bunun, B kodunun en az değişiklikle C olarak derlenebilmesi için yapıldığı söyleniyor; B'de dizi bildirimi gerçekten hem pointer'ı hem diziyi tanımlıyor ve o pointer da dizinin ilk elemanını gösterecek şekilde başlatılıyormuş
Asıl daha büyük sorun, C standart kütüphanesinin hâlâ K&R dönemine bağlı kalması ve C99'da eklenen struct parametreleri ya da dönüş değerleri gibi dil özelliklerinin standart kütüphane API'lerine hiç yansımamış olması. Standart kütüphanede pointer/boyut çifti olan aralık struct'ları ve bunları kullanan yeni ya da güncellenmiş string fonksiyonları olsa bile durum epey iyileşirdi
Linux çekirdeğindeki strncpy'nin, sezgiye aykırı semantiği, NUL sonlandırma davranışı ve hedefi gereksiz yere sıfırlarla doldurmasının getirdiği performans sorunu yüzünden yıllarca “inatçı bir bug kaynağı” olduğu söyleniyor
Ne zaman C kodu incelemem istense strncpy ararım ve neredeyse her seferinde orada bir bug bulurum
40 yıldır sinir bozucu olan şeyler var. NUL sonlandırılmış string'ler ve artık buna giriş/çıkışta UTF-8 olmayan string'ler de dahil
Satır sonlarını LF, CR, CRLF olarak ele alma geleneği de öyle, alanları pipe ya da virgülle ayırmak da. GS, FS, RS gibi belirsiz olmayan ASCII karakterleri kullanılsaydı satır sonu kodlama/kod çözme işi giriş/çıkışın problemi olurdu; HT/VT/CR/LF/FF ise kelimenin tam anlamıyla çıktı ile ilgili kodlarda kalabilirdi
Virgülle ayrılmış veride ortaya çıkan o dağınık escape işleme derdi ortadan kalktığı için her şey çok daha basit oldu
Unicode standardı, CR, LF, CRLF ve bu karakterlerin yanı sıra vertical tab ile form feed'in de satır ayırıcı olarak ele alınması gerektiğini söylüyor
LF, CR, CRLF gibi satır sonları aynı zamanda işletim sistemi geleneği ve programlama dillerinin doğru satır sonunu “tahmin etmeye” çalışmaması daha iyi. Bu, çözdüğünden daha fazla sorun yaratıyor ve yine çoğunlukla Windows'a özgü bir problem; Microsoft'un Windows'u içinde bulunduğumuz yüzyıla getirmesi gerekiyor
En son bash içinde CSV dosyasıyla uğraşmam gerektiğinde, onu dahili olarak RS ve FS'ye çevirip öyle işlemiştim
Linux çekirdeği kodunda strncpy yerine, NUL sonlandırılmış hedefler için strscpy(), 0 padding gereken NUL sonlandırılmış hedefler için strscpy_pad(), NUL sonlandırması olmayan sabit genişlikli alanlar için strtomem_pad(), açık padding içeren sınır kopyaları için memcpy_and_pad(), uzunluğu bilinen bellek kopyaları için memcpy() kullanılması söyleniyor
Bu tam bir kâbus gibi ve bunun gerçekten bu kadar karmaşık olması gerekip gerekmediğini bilmiyorum
Kodu okurken, sırf seçilen fonksiyondan geliştiricinin niyetinin açıkça anlaşılması bence daha iyi
İşte tam da böyle sıkıcı, tekrar eden işlerde sistem mühendisliğinin gerçek işi yapılıyor
Linux çekirdeğini tüm süreç boyunca kullanılabilir tutarken daha güvenilir hâle getiren bu tür büyük altyapı projeleri birkaç ayda değil, on yıllara yayılan zaman dilimlerinde ilerliyor
Ama bu hızla uzun vadede anlamlı ilerleme üretmenin mümkün olup olmadığından emin değilim. Bu bir şikâyetten çok, çekirdek altyapının paradoksu gibi
Muazzam ve insanı alçakgönüllü yapan bir iş. Bu kadar çok insanın katkı vermiş olması şaşırtıcı
“Harika yeni özellikler” için takdir görmek daha kolaydır ama çekirdek gibi temel bir alanda kötü bir özelliği kaldırmak belki de daha da önemlidir
50 yıl sonra insanlar kaynak kod okumayı unutmuş, Claude/Codex tortusu sessizce birikmiş ve Dünya enerjisinin çoğunu yakıyor olduğunda, bu tür işler “kuruluş çağı” efsaneleri gibi kalacak gibi geliyor
Unix epoch’un ne olduğunu bilen tek kişi de oydu
Null sonlandırmalı dizgilerin bilişim tarihindeki en büyük hata olduğunu düşünüyorum. Pascal tarzı dizgiler çok daha güvenliydi
Hâlâ 0 ile biten bir karakter dizisini gösteren bir işaretçi, ama işaretçinin gösterdiği ilk bayttan hemen önce bir uzunluk alanı var. Gömülü NUL karakterleri olmadığı varsayılırsa C dizgileriyle de uyumludur ve BSTR türündeki işlevler uzunluk değerini kullanabilir
Bir dönem 16 bit bile fazla görünmüş olabilir, bugün ise 32 bit çok küçük görünebilir. “Güçlü tipli” bir dil olduğu söylenen C, asıl önemli yerlerde oldukça gevşek kalıyor
Pascal ile ilgili kodu 30 yıldan fazladır yazmadım ama o zaman bile dizgi sisteminin kullanmasının fazla zahmetli olduğunu düşündüğüme dair silik bir anım var
Tek bir dizgi veri türü olmadığı için yaşanan acı ve boşa kürek çekme çok fazla
strncpyçevresindeki kodu da o tür ve işlevleri kullanacak şekilde büyük çaplı yeniden düzenlemek gerekmez miydi?strncpykullanım yerlerini yeniden yazmanın neden 6 yıl sürdüğünü merak ediyorumKullanım alanı gerçekten bu kadar mı yaygındı, yoksa aynı dosyaya dokunmak gerektiğinde mi değiştirilen uzun soluklu bir işti, ya da başka zorluklar mı vardı, bilmek isterdim
Win32 uygulamalarında boşlukla doldurulmuş dizgiler kullanan kodlarla uğraşmıştım. Hedef dizgi boşluklarla dolduruluyordu ama son baytta yine de null karakter vardı
Uzunluk, kopyalama gibi işlemler için dizgi işlevlerinin özel sürümlerini kullanmak gerekiyordu. Neden öyleydi bilmiyorum ama kod tabanı çok eskiydi; belki Pascal yapı davranışından geliyordu
varcharyerinecharalanları boşlukla doldurulur