1 puan yazan GN⁺ 3 시간 전 | 1 yorum | WhatsApp'ta paylaş
  • 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 strncpy API'sini nihayet kaldırdı
  • 6 yıla yayılan temizlik çalışmasının sonunda çekirdek içinde strncpy arayü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 strncpy kullanı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, strncpy API'sini kaldırdı
  • Aynı merge içinde son CPU başına mimariye özgü strncpy uygulaması da ortadan kaldırıldı

Çekirdek kodunda kullanılacak alternatif API'ler

  • strncpy yerine, kopyalanan hedefe ve sonlandırma koşuluna uygun işlev seçilmeli
    • strscpy(): NUL ile sonlandırılan hedeflerde kullanılır
    • strscpy_pad(): NUL ile sonlandırılan hedeflerde 0 dolgusu gerektiğinde kullanılır
    • strtomem_pad(): NUL ile sonlandırılmayan sabit genişlikli alanlarda kullanılır
    • memcpy_and_pad(): Açık dolgulama içeren sınırlı kopyalamalarda kullanılır
    • memcpy(): Uzunluğu bilinen bellek kopyalamalarında kullanılır

1 yorum

 
GN⁺ 3 시간 전
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

    • Walter Bright'ın 2007 tarihli yazısı burada: https://digitalmars.com/articles/C-biggest-mistake.html
      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ş
    • VLA, C11'de isteğe bağlı özelliğe indirildi ve bence bu iyi bir şeydi
      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
    • Ritchie'nin önerisinin bağlantısı: https://web.archive.org/web/20150611114358/https://www.bell-...
    • Ekip çalışmasında beni en çok rahatsız eden kalıp bu. A, B, C çözümleri var, her birinin artıları eksileri konuşuluyor, iki hafta tartışılıyor ve sonunda hiçbiri seçilmiyor
    • Bu sadece WG14'ün önceliklerinin nerede olduğunu gösteriyor
  • 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

    • ASCII alan/kayıt ayırıcı karakterlerle çerçevelenmiş veriyi dönüştüren bir projede çalıştım; gerçekten çok kolaydı
      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 artık daha fazla seçenek de sunuyor. EBCDIC'den gelmiş gibi duran NL Next line, Unicode'un tanımladığı LS Line separator ve PS Paragraph separator var
      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
    • Standart giriş/çıkışta UTF-8 gayet kusursuz çalışıyor. Tabii uluslararası metin kodlamasında hâlâ 90'ların başında yaşayan Windows'ta değilseniz
      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
    • LF en mantıklısı ama bir metin dosyasıysa iki taraf da olur. Sorun CSV'nin metin olmaması
      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
    • Bence her yerde doğrudan UTF-8 kullanılmalı
  • 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

    • Sebebi performans. Bunların çoğunu kapsayan güvenli, her işe yarayan tek bir fonksiyon iç dallanmalar yüzünden kaçınılmaz olarak daha yavaş olurdu; ayrıca hangi fonksiyonun seçildiği geliştiricinin niyetini de yansıtıyor
      Kodu okurken, sırf seçilen fonksiyondan geliştiricinin niyetinin açıkça anlaşılması bence daha iyi
    • strncpy'yi doğru kullanmak zaten en başından beri hep karmaşıktı
    • En azından isimleri biraz daha iyi olamaz mıydı
  • İş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

    • Neden onlarca yıllık ölçeğe yayıldığını anlıyorum. Kullanıcıların ve bağımlılıkların uzun kuyruğu gerçekten çok uzun
      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

    • Vernor Vinge’in A Deepness in the Sky eseri aklıma geliyor. Orada biri uzay gemisinin bakımını yazılım arkeolojisiyle yapıyordu
      Unix epoch’un ne olduğunu bilen tek kişi de oydu
    • 50 yıl sonra herkesin kaynak kodu anlamayı unutacağını sanmıyorum. İnsanların şeylerin nasıl çalıştığını bilme isteği o zaman da var olacaktır
    • Yapay zekanın ürettiği ucube kodların çok daha önce yönetilemez hale geleceğini düşünüyorum
  • Null sonlandırmalı dizgilerin bilişim tarihindeki en büyük hata olduğunu düşünüyorum. Pascal tarzı dizgiler çok daha güvenliydi

    • Visual Basic’in ve sonrasında COM’un seçtiği BSTR gibi orta yol çözümleri de var
      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 ölçüde katılıyorum ama boyut alanının veri türü konusunda kavga çıkardı. Sabit uzunluklu olmasaydı daha da fazla olurdu, değişken uzunluklu olsaydı da başka sorunlar çıkardı
      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
    • Null sonlandırmalı dizgiler son derece faydalı pek çok yazılımın temeliydi. Buna bilişimin en büyük hatası demek biraz abartı
      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
    • 255 karakter herkes için yeterli olmayacak mıydı?
    • Satır sonu ile biten satırlar kadar kötü
  • Tek bir dizgi veri türü olmadığı için yaşanan acı ve boşa kürek çekme çok fazla

    • Daha doğrusu sorun dizgi veri türünün hiç olmaması değil, C’de dizgi veri türü bulunmaması gerçeğini dolanmanın yarattığı acı ve boşa kürek çekme
    • Burada güçlü tipleme getirmek için ne tür bir yaklaşım mümkün olurdu? strncpy çevresindeki kodu da o tür ve işlevleri kullanacak şekilde büyük çaplı yeniden düzenlemek gerekmez miydi?
  • strncpy kullanım yerlerini yeniden yazmanın neden 6 yıl sürdüğünü merak ediyorum
    Kullanı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

    • Bu, SQL veritabanındaki char alanlarından gelen dizgiler yüzünden olabilir. varchar yerine char alanları boşlukla doldurulur
    • Bu davranışın kökü Pascal değil, büyük ihtimalle COBOLdur
    • Bunun nedeni, dizgi boyutu değiştiğinde yeniden tahsisi önleme isteği ya da CPU önbellek satırı hizalaması olabilir