From: Serdar Koylu (serdarkoylu@fisek.com.tr)
Date: Mon 02 Jun 2003 - 16:51:29 EEST
Selamlar..
Soyle ozetliyelim. Eger bolca pointer aritmetigi kullanmak durumundaysaniz, daha ust duzey dillerde oldugu gibi bellek yonetimini biraz daha elle tutulur hale getirmek faydalidir. Ornegin, bilhassa dinamik olarak bellek ayiriyorsaniz, bellek boyutu calisma esnasinda belirleniyorsa, ardindan siz bu bolgede memset/memcpy gibi operasyonlar yapacaksaniz, tum bu operasyonlarin ayrilmis bloklari bilen bir altsistem tarafindan yurutulmesi mantikli olur.
Bu sayede bilhassa buffer overflow vakalarini daha kolay gorebilirsiniz. Ayrica bir arabellegin sonuna bir baskasini eklemek vs. islevleri son derece kolaylasir. Bilhassa soket programlamaya girince bu konu daha bir hassasiyet kazanir.
Ama bilhassa multithread bir uygulama icin bu son derece guctur. Fakat olursa cok leziz olur.
Asil onemli olan standartlarda yazmayan seylerdir. Her function digerinden tamamen bagimsiz olmalidir. Oyleki bir fonksiyonun bir digerinin ayirdigi bellek bolgesini free etmesi bile istenmez. Hatta, bir fonksiyon hic bir zaman kendi allokasyon yapip geriye arabellek dondurmemelidir. Elbette bu her zaman mumkun olmaz.
Kisacasi, sistem belleginin yonetimi kernel VM tarafindan nasil tek elden yonetiliyorsa program icinde de bellek yonetiminin tek elden yurutulmesi akillica olur. Bilhassa ornek uygulamada oldugu gibi enteresan durumlarin olusmasinin onune gecilmis olur. Bu noktada memset yerine
int mymemset(void *buffer, off_t start, size_t size, char value)
gibi bir fonksiyon kullanilmasi, ayrilan bellek bloklarini takip eden bir uygulama ile birlikte kullanilsaydi b sorun yasanmayabilirdi:
typedef struct {
void *data;
size_t size;
void *next;
char *owner;
int allocline;
} memblocks;
memblocks *mem;
void initialize() {
mem = calloc(sizeof(memblocks), 1);
}
void *mymalloc(size_t allocsize, char *func, int line) {
memblocks *newmem, *prev;
newmem = mem;
while (newmem->next) newmem = (memblocks *)newmem->next;
prev = newmem;
newmem = malloc(sizeof(memblock));
newmem->size = allocsize;
newmem->data = malloc(allocsize);
newmem->next = NULL;
newmem->owner = func;
newmem->allocline = line;
prev->next = newmem;
return newmem->data;
}
void mymemset(void *buffer, off_t start, size_t len, char value, char *func, int line) {
memblocks *ptr;
ptr = mem;
while (ptr) {
if (ptr->data == buffer) {
break;
}
ptr = ptr->next;
}
if (ptr) {
if (ptr->size < start len) {
memset((void *)((unsigned int)ptr->data) start), len, value);
} else {
printf("Oooppss ! Buffer overflow from : %s line : %d n", func, line);
}
} else {
printf("Ahhaaa.. Bug buldum: Fonksiyon: %s Satir %d gecersiz bir pointer ile memset cagirdin", func, line);
}
}
/* Bir kac makro hayati kolaylastirir: */
#define malloc((a)) mymalloc((a), __FUNCTION__, __LINE__)
#define memset((.........)) mymemset(........., __FUNCTION__, __LINE__)
int main() {
void *buffer;
buffer = malloc(1024);
memset(buffer, 5, 512, 0);
}
Velhasil, bu sekilde bir duzenlemeyle benzer hatalarin yapilmasinin onune kolayca gecilir. free, memcpy vs. hepsi icin benzer birer fonksiyon tanimlanabilir. Sonucta mesela yukaridaki ornek size hatali fonksiyon ve satiri kolayca gosterebilir.
Bilhassa yeni baslayanlarin oncelikle kendilerine benzer bir arabirim yazmalari tavsiye edilir. Yukardaki surada ayak ustu yazilmis basit bir kod. Calisacagi bile supheli. Ama saniyorum ne yapilmasi gerektigini orneklemeye yeterlidir.
Saygi ve sevgiler
02 Jun 2003 17:12 EEST tarihinde yazmışsınız:
> Ayrica *alloc fonksiyonlari bilindigi uzere 'first fit', 'best fit' gibi
> algoritmalarla yazilma ihtimalleri var ve bu spec'de acik olarak
> belirtilmedigi icin library'i ureticeleri esnek davranabilmektedir ama bircogu
> 'best fit' algoritmasi kullandiklari icin 'garbage collector' kullanma
> ihtiyaciniza gerek kalmayacaktir dolayisiyla performans degerlendirmesinde kod
> ayiklama durumuna dusmenize ayrica gerek yok.
>