11 puan yazan GN⁺ 2026-01-01 | 5 yorum | WhatsApp'ta paylaş
  • cURL projesi, daha önce strncpy() işlevini kaldırmasının ardından artık strcpy() kullanımını da kod tabanında tamamen yasakladı
  • strcpy() API’si basit olsa da buffer boyutu doğrulamasının ayrı düşmesi riski taşıdığı için, uzun vadeli bakım süreçlerinde güvenli değil
  • Bunun yerine curlx_strcopy() adlı yeni bir işlev eklendi; hedef buffer boyutunu ve dizge uzunluğunu parametre olarak alıp kopyalamanın mümkün olup olmadığını denetledikten sonra çalışıyor
  • Bu işlev içeride memcpy() kullanıyor ve null sonlandırma karakterinin işlenmesini de garanti ediyor
  • Bu değişiklikle güvenlik ve kod tutarlılığı artırılırken, yapay zekanın hatalı zafiyet raporları üretmesi sorunu da azaltılabiliyor

strcpy kaldırılmasının arka planı

  • cURL geçmişte tüm strncpy() çağrılarını kaldırmıştı; bu işlevin sezgisel olmayan API’si, null sonlandırmayı garanti etmemesi ve gereksiz 0 doldurma sorunlarına dikkat çekmişti
    • Kısmi dizge kopyalaması gereken durumlarda memcpy() kullanılıp null sonlandırma doğrudan ele alınacak şekilde değiştirildi
  • strcpy() API’si basit olsa da buffer boyutunu açıkça belirtmediği için, bakım sırasında doğrulama kodu ile kopyalama çağrısının birbirinden ayrılma riski bulunuyor
    • Kod onlarca yıl boyunca farklı geliştiriciler tarafından değiştirildiğinde, buffer boyutu doğrulamasının etkisiz hale gelme ihtimali var

Yeni dizge kopyalama işlevinin eklenmesi

  • Bu riski önlemek için curlx_strcopy() adlı alternatif bir işlev eklendi
    • Parametre olarak hedef buffer, buffer boyutu, kaynak buffer ve kaynak dizge uzunluğunu alıyor
    • Yalnızca hem kopyalama hem de null sonlandırma mümkün olduğunda memcpy() ile çalışıyor
    • Başarısız olursa hedef buffer’ı boş dizge olarak başlatıyor
  • Bu işlev strcpy()ye göre daha fazla parametre ve daha fazla kod gerektiriyor, ancak buffer doğrulamasını kopyalama işlemiyle sıkı biçimde bağlayarak güvenliği sağlıyor
  • cURL kod tabanında strcpy() kullanımı tamamen yasaklandı ve strncpy() gibi tamamen kaldırıldı

Uygulama ayrıntıları

  • İşlev tanımı örneği şöyle:
    void curlx_strcopy(char *dest, size_t dsize, const char *src, size_t slen)
    {
      DEBUGASSERT(slen < dsize);
      if(slen < dsize) {
        memcpy(dest, src, slen);
        dest[slen] = 0;
      }
      else if(dsize)
        dest[0] = 0;
    }
    
  • DEBUGASSERT ile geliştirme sırasında hatalar erken aşamada tespit ediliyor; gerçek dağıtım ortamında ise her zaman başarılı olacak şekilde tasarlanmış
  • strcpy gibi dönüş değeri yok; bunun yerine test ve fuzzing aşamalarında hataları yakalama yaklaşımı benimsenmiş

Topluluk tepkisi

  • Bazı geliştiriciler bunun strcpy_s() (C11 Annex K) ile benzer olduğunu belirtse de, cURL hâlâ C89 standardını kullanıyor
  • Başka görüşlerde ise dönüş değeri eklenmesi gerekliliği ya da buffer başarısızlığı durumundaki işleme yönteminin iyileştirilmesi önerildi
  • Buna karşılık cURL tarafı, “İşlev her zaman başarılı olacak şekilde tasarlandığı için dönüş değeri gereksiz” açıklamasını yaptı

Yapay zeka ile ilgili ek etki

  • Bu değişiklik sayesinde yapay zeka sohbet botlarının cURL kodunda strcpy kullanımını yanlış tespit edip ‘zafiyetli’ diye işaretlemesi sorunu önlenebilir
  • Ancak yazar, “yapay zeka başka sahte raporlar üretmeye devam edebilir” diyerek yapay zeka tabanlı kod analizinin sınırlarına değindi

5 yorum

 
ahwjdekf 2026-01-02

strcpy yerine snprintf kullanmak doğru olur. Kodda strcpy varsa, onu yazan geliştiricinin adresini bulmak gerekir.

 
winmain 2026-01-02

Bu, 25 yıl önce bir oyun şirketinde çalışırken debug koduyla kullandığım yöntemdi; sadece strcpy ile sınırlı mı sanıyorsunuz. Release sürümünde ise hız artışı için bunlar yeniden gevşetilmiş halde servise alınırdı. Aslında oyun tarafı bellek çakışmalarına en hassas alanlardan biri olduğu için, çalışırken de son derece dikkatli ve tetikte olunurdu; hatta bellek debugger'ını da kendimiz yapıp kullanırdık. Ama bugün dönüp bakınca, meğer o şey garbage collection yapıyormuş. Tatlı bir anıymış doğrusu.

 
secwind 2026-01-02

Hata C4996 'strcpy' : Bu işlev veya değişken güvenli olmayabilir. Bunun yerine strcpy_s kullanmayı düşünün. Kullanımdan kaldırma uyarısını devre dışı bırakmak için _CRT_SECURE_NO_WARNINGS kullanın. Ayrıntılar için çevrimiçi yardıma bakın.

 
GN⁺ 2026-01-01
Hacker News görüşleri
  • strcpy() yalnızca güvenlik açısından değil, performans açısından da iyi değil
    Eskiden, dizenin uzunluğu bilinmediğinde strcpy()'nin verimli olduğu düşünülürdü; ancak gerçekte yapısı gereği bir seferde bir bayt kopyalar, bu yüzden CPU'nun dal tahmini yapması gerekir ve bu da verimsizdir

    • Artık mümkün olduğunca null-terminated string kavramının kendisini bırakmamız gerektiğini düşünüyorum
    • Son zamanlarda strcpy'nin scalar loop kullandığını görmedim. Acaba bu yalnızca ARM mimarisinde mi böyle diye merak ediyorum
  • C'nin string rutinlerinin her biri büyük kısıtlamalara sahip olduğundan kullanışsız olduklarını düşündüm
    Bu yüzden string pointer'ıyla birlikte ayrılan bellek boyutunu da kaydeden bir kütüphanenin kesinlikle gerekli olduğunu düşünüyorum
    Örnek olarak bstring kütüphanesine bakılabilir

    • strncpy'nin ortaya çıkış nedeni sabit uzunluklu dosya adlarını kopyalamaktı. Ayrıntılı açıklama için bu StackOverflow yanıtına bakın
    • String'e uzunluk bilgisinin dahil edilmemesi geçmişte bellekten tasarruf etmek içindi. O dönemde tek bir bayt bile değerliydi
    • C'nin string fonksiyonlarının sorun çıkarmasının nedeni, tasarımcıların bunları sonuçlarını yeterince öngörmeden eklemiş olmasıydı. Dizilerin fonksiyon argümanlarında pointer'a zorla dönüştürülmesi de temel bir tasarım hatasıdır
    • Bu tür ek book-keeping eskiden yük sayılırdı ama bugün rahatlıkla karşılanabilecek bir düzeydedir
    • strncpy aslında sabit genişlikli string alanlarını işlemek için vardı. Örneğin char username[20] gibi alanları NUL ile doldurmak için kullanılırdı. İlgili belge için string_copying.7 man sayfasına bakın
  • curlx_strcopy'nin başarı durumunu döndürmemesi garip geliyor
    dest[0] kontrol edilebilir ama bu hata üretmeye çok açık ve sezgisel değil

    • Önceki sürüm hata döndürüyordu; şimdi ise sessizce başarısız olup boş string ayarlıyor. Bu tuhaf
    • Muhtemelen DEBUGASSERT(slen < dsize); geçerse bunu başarı sayıyorlar, ancak release build'de assert kaldırılabilir. Açık bir hata kodunun daha iyi olacağını düşünüyorum
    • Böyle bir tasarım ileride CVE çıkarmaya çok müsait görünüyor
  • strncpy() aslında null-terminated string için değil, sabit uzunluklu alanlar için yazılmıştı
    Sorun, statik analiz araçlarının strcpy yerine strncpy kullanılmasını önermesiyle başladı. Gerçek alternatifler snprintf veya strlcpy idi

    • strlcpy BSD kökenli bir fonksiyondur, POSIX'te yoktur. Resmî öneri stpecpy olsa da pratikte neredeyse hiç implementasyon yok. İlgili belgeye bakın
    • strncpy'nin null sonrasını doldurmasının nedeni, directory entry gibi sabit uzunluklu ad alanlarında verimli karşılaştırma yapabilmekti. ANSI C standardının gerekçe dokümanında da bu açıkça belirtiliyor
  • Bu API bana biraz Annex-K gibi geliyor. Hedef buffer boyutuna NUL alanı dahil ama kaynak boyutuna dahil değil
    Bu durumda memcpy'yi doğrudan kullanmanın daha iyi olduğunu düşünüyorum

  • Yazıdaki “strcpy, AI'ın hatalı güvenlik açığı raporları üretmesi için bir yem” ifadesi dikkat çekiciydi

    • Gerçekte AI yalnızca strcpy'yi sorunlu diye işaretlemiyor; aynı zamanda mantık hataları içeren karmaşık ispatlar üretip bakımcıların bunları doğrulamak için uğraşmasına neden oluyor
    • Bu tür hatalı raporları gönderen kişiler ya AI'ın yanılabileceğini bilmiyor ya da umursamıyor. Sonuçta yanlış rapor vermenin bir maliyeti yok
    • Sonunda sorun, AI'ı uygun olmayan amaçlar için kullanan insanlarda düğümleniyor
  • “Kontrolü kodun yakınında yap” ilkesi güzel ama verinin yaşam döngüsünün erken aşamalarında doğrulama yapmak gerektiğinde belirsizleşiyor
    Rust'taki Result tipi gibi, “doğrulanmış veri” olduğunu tür üzerinden ayırt edebilmek güzel olurdu

    • Result yalnızca başarı/başarısızlık taşır; doğrulanmış bir durumu garanti etmez. Bunun yerine ancak doğrulama sürecinden geçerek üretilebilen ayrı bir tip daha iyi olur. Bu, “parse, don’t validate” felsefesidir
    • Doğrulamanın tüketici koduna yakın değil, sistem sınırında mümkün olduğunca erken yapılması idealdir. Ancak bunun için ifade gücü yüksek bir tip sistemi gerekir
    • Böyle durumlarda Java'daki String ve CharSequence ayrımı gibi tipleri ayırarak kullanmak da bir yöntem olabilir
  • Buffer boyutu ile string uzunluğu arasındaki off-by-one farkı korkunç bir kullanılabilirlik sorunu. İleride de hata üretmeye çok açık

  • Yeni önerilen string kopyalama fonksiyonu, kopyalama mümkün değilse hedef buffer'ı boşaltıp void döndürüyor
    Ancak böyle durumların hata olarak ele alınması ve buffer'a hiç dokunulmaması daha iyi olurdu. Yalnızca DEBUGASSERT ile engellemek güven vermiyor

  • Projenin tamamlanmasını kutlarım. C/C++ tarafında da emek verilirse bellek güvenliği sağlanabilir
    Ancak mobil ortamda grafikteki yazı boyutu çok küçük olduğundan okunabilirlik düşüyor

    • strcpy'yi kaldırmak tek başına kodu bellek güvenli yapmaz
    • Grafikteki yazı tipi sanki baskı için tasarlanmış gibi. Blog için fazla küçük
 
hiongun 2026-01-04

Doğrudan C3 diline geçmek de iyi bir seçenek. C dilinin sözdizimini en az değişiklikle koruyup modern özellikler ekleyen bir proje olduğu için geçiş de kolay.