2009-02-27 22 views
3

UTF8 manipülasyon kitaplığım için bir birim testi yazıyorum ve bir işlev arabellek taşmasına giderse testimi segfault yapmak istiyorum. Bu yüzden bellekte yan yana iki sayfa mmap yapma fikri ile geldim, ilk PROT_READ | PROT_WRITE ve PROT_NONE ile ikinci. Bu şekilde, herhangi bir taşma olursa, bir segfault garanti edilir. Örnek:arka arkaya iki sayfa mma


void *addr1, *addr2; /* these are the pages; mmap call left out for simplicity */ 
char *p = (char *) (addr1 + getpagesize() - 8); 

utf8_encode(aUtf8String, p, 8); // this shouldn't segfault 

Sorun, ikinci sayfayı eşlediğimde program bölümlerim. İlginçtir ki


#include <stdio.h> 
#include <errno.h> 
#include <string.h> 
#include <stdlib.h> 
#include <sys/mman.h> 

void checkMap(void *p) 
{ 
    if(p == MAP_FAILED) { 
     printf("error running mmap: %s\n", strerror(errno)); 
     exit(1); 
    } 
} 

int main(void) 
{ 
    void *addr1, *addr2; 
    size_t pagesize; 

    pagesize = getpagesize(); 
    checkMap(addr1 = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); 
    checkMap(addr2 = mmap(addr1 + pagesize, pagesize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0)); /* segfaults */ 
    munmap(addr1, pagesize); 
    munmap(addr2, pagesize); 

    return 0; 
} 
 

, ilk mmap'in önce printf() ifadesi() başarıyla çalıştırmak için program neden olur: Burada sorunu yeniden üreten bir örnek program (GNU/Linux). Mmap'ın neden segfaulting olduğunu bilen var mı? Hedefim mmap() kullanılarak ulaşılamıyorsa, kimsenin arabellek taşması için kodumu nasıl test edebileceğime dair başka tavsiyeleri var mı?

+0

Kodunuz benim için mükemmel çalışıyor. Tek şey getpageize() için unistd.h içermemenizdir. Derleyici türü tahmin edecektir. Bu 64bit sistemlerde sorunlara neden olabilir eğer 32bit int tahmin ederse düşünüyorum. –

+0

Ben de test ettim ve segfaulting'i aldım, fakat main() içinde değil. Aksine, glibc'nin kodunda, çıkışta çöküyor ... Gerçekten garip, bu. Çok sade bir 32-bit makinede test ettim. – unwind

+0

Sadece hangi sürümde/sürümde çalıştığınızı merak ediyor musunuz? Ben sadece 64-bit (#including unistd.h sonra) denedim ve şimdi munmap üzerinde başarısız olur. –

cevap

3

mmap() ile eşleştirilen bellekteki koruma bayraklarını değiştirmek için mprotect() numaralı telefonu arayabilirsiniz. Bu, farklı korumalara sahip iki bitişik sayfa olan mmap()'u denemekten daha iyi bir çözüm olabilir, çünkü bu sizin sorunlarınıza neden olan şey gibi görünüyor.

(Linux sen herhangi sayfa mprotect() aramaya verir, ancak POSIX sadece zaten mmap() tarafından tahsis edilmiş sayfaları sağlar.)

Bu Electric Fence arabellek taşmaları yakalamak için kullandığı hileler biridir.

+0

Bu mükemmel! Çok teşekkürler! –

+1

Ayrıca, mmap 2 sayfasının başlangıçta geçerli olacağını, ardından ikinci sayfanın üst kısmındaki yeni PROT_NONE sayfasının MAP_FIXED olduğunu da unutmayın. Geçerli olmayan, mevcut bir sayfanın yanında bir adres seçmek ve 'MAP_FIXED' ile eşlemek; zaten başka bir haritalamayla (örneğin libc'nin parçası gibi) meşgul olmadığını bilmenin hiçbir yolu yoktur. –

0

Sorunuzla tam olarak ilgili değilse (nihai hedefiniz gerçekten de test çalışmanızı sağlamıyorsa), ancak IMHO, bu tür bir hata işleme yöntemine güvenmek yanıltıcı olabilir (özellikle birden çok platformu hedefliyorsanız) Testin başarısız olması durumunda, bazı kusurlu davranışlar nedeniyle seg-fail'in tetiklenmemesi gerekiyordu).

Belki de farklı bir yaklaşım sizin için daha anlamlı olur, örneğin, gerektiğinden daha büyük bir arabellek ayırmak, sonunda bir işaretleyici yerleştirmek ve üzerine yazılıp yazılmadığını kontrol etmek? Diğerleri de belirttiğimiz gibi, daha karmaşık bir test ortamı kurmak istiyorsanız, elektrikli çit, valgind veya diğer araçlar muhtemelen analizlerinde daha ayrıntılıdır.

İlgili konular