Kullanımdan Kaldırılmış İşlevler
Güvensiz
Böyle bir işlevin mükemmel bir örneği gets () ' dır, çünkü ona hedef arabelleğin ne kadar büyük olduğunu söylemenin bir yolu yoktur. Sonuç olarak, gets () kullanarak girişi okuyan herhangi bir programda bir arabellek taşması güvenlik açığı vardır . Benzer nedenlerden dolayı, bir kullanmalıdır strncpy () yerine strcpy () ve strncat () yerine strcat işlevinin () .
Yine de bazı örnekler, geçici dosyaların üzerine yazılmasıyla ilgili potansiyel güvenlik sorunları nedeniyle tmpfile () ve mktemp () işlevini içerir ve bunların yerini daha güvenli mkstemp () işlevi almıştır.
Yeniden Giren Olmayan
Diğer örnekler arasında , evresel olmayan (ve bu nedenle, iş parçacığı güvenli olması garanti edilmeyen) ve yeniden girişli getaddrinfo () ve freeaddrinfo () tarafından değiştirilen gethostbyaddr () ve gethostbyname () bulunur .
Burada bir model fark ediyor olabilirsiniz ... ya güvenlik eksikliği (muhtemelen imzaya, muhtemelen güvenli bir şekilde uygulamak için yeterli bilgiyi dahil etmemekle) ya da yeniden giriş yapılmaması yaygın kullanımdan kaldırma kaynaklarıdır.
Eski, Taşınabilir Olmayan
Diğer bazı işlevler, işlevselliği kopyaladıkları ve diğer varyantlar kadar taşınabilir olmadıkları için kullanımdan kaldırılır. Örneğin, bzero () , memset () lehine kullanımdan kaldırılmıştır .
İş Parçacığı Güvenliği ve Yeniden Giriş Gönderinizde
iş parçacığı güvenliği ve yeniden giriş hakkında soru sordunuz. Ufak bir fark var. Bir işlev, herhangi bir paylaşılan, değiştirilebilir durum kullanmıyorsa, evreseldir. Bu nedenle, örneğin, ihtiyaç duyduğu tüm bilgiler işleve aktarılırsa ve ihtiyaç duyulan tamponlar da işleve aktarılırsa (işleve yapılan tüm çağrılar tarafından paylaşılmak yerine), bu durumda evreseldir. Bu, farklı iş parçacığının bağımsız parametreler kullanarak kazara paylaşma durumunu riske atmayacağı anlamına gelir. Yeniden giriş, iplik güvenliğinden daha güçlü bir garantidir. Bir işlev, aynı anda birden çok evre tarafından kullanılabiliyorsa, iş parçacığı açısından güvenlidir. Bir işlev şu durumlarda güvenlidir:
- Evreseldir (yani aramalar arasında herhangi bir durumu paylaşmaz) veya:
- Evresel değildir, ancak paylaşılan durum için gerektiği gibi senkronizasyon / kilitleme kullanır.
Genel olarak, Tek UNIX Spesifikasyonu ve IEEE 1003.1'de (yani "POSIX"), evresel olması garanti edilmeyen herhangi bir işlevin iş parçacığı için güvenli olduğu garanti edilmez. Bu nedenle, başka bir deyişle, yalnızca evresel olması garanti edilen işlevler, çok iş parçacıklı uygulamalarda taşınabilir olarak kullanılabilir (harici kilitleme olmadan). Ancak bu, bu standartların uygulamalarının evresel olmayan bir işlevi evreleri güvenli hale getirmeyi seçemeyeceği anlamına gelmez. Örneğin, Linux, iş parçacığı güvenliğinin garantisini (Tek UNIX Belirtiminin ötesinde) eklemek için sık sık evresel olmayan işlevlere eşitleme ekler.
Dizeler (ve Genel olarak Bellek Tamponları)
Dizeler / dizilerle ilgili bazı temel kusurlar olup olmadığını da sordunuz. Bazıları durumun böyle olduğunu iddia edebilir, ancak ben hayır, dilde temel bir kusur olmadığını iddia ediyorum. C ve C ++, bir dizinin uzunluğunu / kapasitesini ayrı ayrı geçirmenizi gerektirir (diğer bazı dillerde olduğu gibi bu bir ".length" özelliği değildir). Bu aslında bir kusur değil. Herhangi bir C ve C ++ geliştiricisi, uzunluğu gerektiği yerde parametre olarak ileterek doğru kodu yazabilir. Sorun, bu bilgiyi gerektiren birkaç API'nin bunu bir parametre olarak belirtememesidir. Veya bazı MAX_BUFFER_SIZE sabitinin kullanılacağı varsayıldı. Bu tür API'ler artık kullanımdan kaldırılmış ve dizi / arabellek / dize boyutlarının belirtilmesine izin veren alternatif API'ler ile değiştirilmiştir.
Scanf (Son Sorunuzun Cevabında)
Şahsen, C ++ iostreams kitaplığını (std :: cin, std :: cout, << ve >> operatörleri, std :: getline, std :: istringstream, std :: ostringstream kullanıyorum , vb.), bu yüzden genellikle bununla ilgilenmiyorum. Ben saf C kullanmak zorunda olsaydı, olsa da, ben şahsen sadece kullanmak istiyorsunuz fgetc () veya getchar () ile kombinasyon halinde strtol () , strtoul () Ben büyük bir hayranı değilim, çünkü elle vs. ve ayrıştırma şeyler varargs veya biçim dizeleri. Bununla birlikte, bildiğim kadarıyla , [f] scanf () , [f] printf () ile ilgili bir sorun yok dedi., vb. biçim dizelerini kendiniz oluşturduğunuz sürece, rasgele biçim dizelerini asla iletmezsiniz veya kullanıcı girdisinin biçim dizeleri olarak kullanılmasına izin vermezsiniz ve uygun olduğunda <inttypes.h> içinde tanımlanan biçimlendirme makrolarını kullanırsınız . (Not, snprintf () , sprintf () yerine kullanılmalıdır , ancak bunun, biçim dizgilerinin kullanılmaması değil, hedef arabelleğin boyutunun belirlenememesiyle ilgisi vardır). Ayrıca, C ++ 'da boost :: format'ın varargs olmadan printf benzeri biçimlendirme sağladığını da belirtmeliyim.