GCC-Memory Error Detection(Bellek Hatası Algılama) Part2
Bu makale serisinin ilk bölümüne buradan ulaşabilirsiniz.
Seçenek: “-Wformat-overflow”
“-Wformat-overflow=level” seçeneği,biçimlendirilmiş output(çıktı) fonksiyonlarının “sprintf” ailesine yapılan çağrılarda kesin ve olası buffer taşmasını algılar. Bu seçenek,statik veya dinamik olarak tahsis edilen hedef buffer boyutunu belirleyerek başlar.Ardından,output(çıktı)’da her bir sonucun byte sayısını hesaplar. Eğer söz konusu bir “string” veri ise,bunu “string” üzerinde yineleme yaparak sağlar.
Ancak söz konusu “string” dışında bir veri ise,örneğin “%i” ve “%x” gibi tam sayılar için,argümanın tam değerini veya değer aralığını belirleyerek sonuç üretir. Bu modeli benzer şekilde “%a” ve “%f” gibi kayan nokta veriler(float) ve “%s” gibi “string” veriler için de uygular. Bu model doğrultusunda,olası byte sayısının hedef buffer’da kalan alana sığmayacağını belirlediğinde bir uyarı fırlatır.
Bu seçenek optimizasyon olmadan etkinleştirilse bile,nesne boyutlarını ve argüman değerlerini en doğru şekilde belirleyebildiği “-O2” ve üstü ile en iyi şekilde çalışır. Ancak yanlış durumlardan kaçınmak için,bir argümanın tam değerini veya değer aralığını belirleyemediğinde ise,seçeneğin “level=1” seviyesi veriler hakkında oldukça tutucu varsayımlarda bulunur.Fakat hata bulma olasılığını arttırmak istiyorsanız “level=2” seviyeyi kullanmanız önerilir. Level=2 düzeyinde seçenek,bilinmeyen tam sayıların çıktıda en fazla byte ile sonuçlanan değere sahip olduğunu var sayar.
Örneğin aşağıda verilen kod parçasında,çıktı(output) “mod(%)” işlemi kullanılarak sınırlandırılmış olsa da,”mday” negatif bir değer olması durumunda 3 byte’a kadar sonuçlanabilirdi. Dolayısıyla “-Wformat-overflow” seçeneği bunu tanımlar-teşhis eder ve uyarı fırlatır.
void* f (int mday)
{
char *buf = malloc(3);
sprintf (buf, "%02i", mday % 100);
return buf;
}warning: 'sprintf may write a terminating nul past the end of the destination [-Wformat-overflow=]
note: 'sprintf' output between 3 and 4 bytes into a destination of size 3
Seçenek “-Wformat-truncation”
Bu seçenek(-Wformat-truncation=level) de “-Wformat-overflow” seçeneğine benzer şekilde biçimlendirilmiş output(çıktı) fonksiyonlarının “snprintf” ailesine yapılan çağrılarda kesin ve olası çıktı(output) kesmelerini algılar. Çıktı(output) kesilmesi taşma(overflow) kadar tehlikeli sayılmaz.
Ancak yine de,genellikle hata ayıklaması zor olan,potansiyel olarak ciddi güvenlik sonuçları olan hatalara yol açabilir.”-Wformat-truncation=1" seçeneğine ”-Wall”’a dahildir ve optimizasyon olmadan etkinleştirilir.
Ancak en iyi “-02” ve üstü ile çalışır.
Örneğin aşağıdaki kod parçası,”0x” öneki de dahil olmak üzere 0 ile 255 arasında bir tamsayıyı hexadecimal olarak dört karakterlik bir buffer’da biçimlendirmeye çalışır. Ancak output her zaman “NULL(\0)” karakteriyle sonlandırılması gerekir.Dolayısıyla böyle bir buffer yalnızca “+1” basamak önek sığacak kadar büyüktür.Bu nedenle “snprintf” çağrısı algılanır-teşhis edilir ve uyarı fırlatılır.
Uyarıdan kaçınmak için ya daha büyük bir buffer kullanılır,ya da fonksiyonun dönüş değerini inceler ve onun tarafından bildirilen kesme yönetilmelidir.
void f (unsigned x)
{
char d[4];
snprintf (d, sizeof d, "%#02x", x & 0xff);
…
}warning: 'snprintf' output may be truncated before the last format character [-Wformat-truncation=]
note: 'snprintf' output between 3 and 5 bytes into a destination of size 4
Seçenek “-Wnonnull”
Bu seçenek GCC’de sürüm 3.3'ten beri mevcuttur. Ancak “null” pointer sabit değikenleri algılamakla sınırlıydı ve diğer yanlış “null” pointer kullanımlarını tespit edemedi. GCC 7'de “-Wnonnull”,null olmayan bir argüman bekleyen fonksiyonlara(“nonnull” attribute ile belirtilmiş olanlar),”null” pointer iletme durumlarının çok daha geniş bir grubunu algılamak-tespit etmek için geliştirildi.Bu seçenekle optimizasyonlardan faydalanarak,önceki GCC sürümlerinde olduğundan daha fazla sorun-problem vakasını algılayabilir.
Seçenek “-Wstringop-overflow”
“-Wstringop-overflow=type” seçeneği,”memcpy” ve “strcpy” fonksiyonları işleyen “string” çağrılarında buffer taşmasını(buffer overflow) algılar. Bu seçenek nesne boyutu kontrolüne dayanır ve “_FORTIFY_SOURCE” makrosunu tanımlamaya benzer bir etkiye sahiptir. Seçenek için tür(type) argümanı,nesne boyut kontrol tipi +1'i ifade eder. Seçenek default olarak
“-Wstringop-overflow=1” dir.
Aşağıdaki örnekte “memcpy” çağrısı “b” dizisine boyutundan daha fazla byte kopyaladığı için algılanıyor-tespit ediliyor.
#define N 8
const int a[N] = { /* ... */ };void f (void)
{
int b[N];
unsigned n = N * sizeof *a;
memcpy (b, a, n * sizeof *a);
…
}warning: 'memcpy' writing 128 bytes into a region of size 32 overflows the destination [-Wstringop-overflow=]
Başka bir örnek olarak aşağıdaki kod parçasında,fonksiyona parametre olarak gelen değeri “d” dizisinin sonuna yine “d” boyutu kadar ekleme yapıyor ve bu nedenle tespit edilip uyarı fırlatılıyor.
void f (const char *fname)
{
char d[8];
strncpy (d, "/tmp/", sizeof d);
strncat (d, fname, sizeof d);
…
}warning: specified bound 8 equals the size of the destination [-Wstringop-overflow=]
Seçenek “-Wvla-larger-than”
“-Wvla-larger-than=size” seçeneği,yerel dizileri dinamik(çalışma zamanında) olarak boyutlandırmada belirtilen boyutun aşılmaması için kullanılır.
Bu tür diziler tehlikelidir ve dikkatli kullanılmadıklarında stack tükenmesine neden olur. Çünkü dizi boyutu çalışma anında verilir. Dolayısıyla dizi boyutun tehlikeli boyutlarda büyük olması büyük bir tehlikedir.
Aşağıdaki örnek kod parçası “-Wvla-larger-than=4096” seçeneği ile derlenmiştir. Bu örnek bir uyarı fırlatacaktır.Çünkü kod içinde dizi öğe sayısı(dizi boyutu) sınırlanmış olsa da,toplam boyut “n * sizeof(int)” olduğundan dolayı,1024'ten büyük bir n değeri 4KB’den fazla stack alanı ayrılmasına sebep olur.
int f (unsigned n)
{
if (n > 4096)
return -1;
int a [n];
…
}warning: argument to variable-length array may be too large [-Wvla-larger-than=]
note: limit is 4096 bytes, but argument may be as large as 16384
KAYNAKLAR:
https://gcc.gnu.org/
https://man7.org/linux/man-pages/man3/alloca.3.html
https://developers.redhat.com/blog/2017/02/22/memory-error-detection-using-gcc
https://www.gnu.org/software/libc/
https://access.redhat.com/blogs/766093/posts/1976213
https://gcc.gnu.org/gcc-7/changes.html
-end of