にたまごほうれん草アーカイブ

はてなダイアリーで書いてた「にたまごほうれん草」という日記のアーカイブです。現在は「にたまごほうれん草ブログ」を運営中です。

擬似mallocを作ってみる

C言語mallocは便利だけれども、開発で多くの人が関わっている場合、他人のメモリリークや不正なアドレスへのアクセスなどのあおりを受けてSegmentation Faultなんていうことが結構あるそうな。
mallocで獲得したいメモリサイズが毎回固定の場合は、動的にメモリ領域を獲得するよりも、固定で予め確保しておいた中から使えるものを渡した方がよい。
既にmalloc前提でコードを書いている場合などは、擬似的なmallocを作ってあたかも動的に獲得しているように見せかけることは可能だろうということで、ちょっと書いてみた。
以下の例では、5つまではfreeせずに獲得可能だが、それを超えるとエラーを吐くように設定してある。実際の開発においては、無理のない上限値を設定することが重要だろう。

#include <stdio.h>

#define ARRAY_MAX 5

typedef struct _hoge_ {
    int hoge;
} Hoge;

typedef struct _cell_ {
    int in_use;
    Hoge item;
} Cell;

static Cell buffers[ARRAY_MAX];
static int  index = 0;

void* hoge_malloc(size_t size)
{
    /* 構造体決めうちなので引数なんて無視 */
    Hoge *ret;

    index = index % ARRAY_MAX;
    if (buffers[index].in_use > 0) {
        return NULL;
    }

    ret = &buffers[index].item;
    buffers[index].in_use = 1;
    index++; 
    
    return (void*)ret;
}

int hoge_free(void* ptr)
{
    int i;
    for (i=0; i<ARRAY_MAX; i++) {
        if (&buffers[i].item == ptr && buffers[i].in_use > 0) {
            fprintf(stdout, "i'm free!: %d\n", (int)ptr);
            buffers[i].in_use = 0;
            return 0;
        }
    }

    fprintf(stderr, "this pointer is not in use: %d\n", (int)ptr);
    return -1;
}

#define HOGE_MAX 10
int main(int argc, char* argv[])
{
    int i;
    Hoge *hoges[HOGE_MAX];
    
    for (i=0; i<HOGE_MAX; i++) {/* 初期化 */
        hoges[i] = NULL;
    }

    i = 0;
    while (1) {
        hoges[i] = (Hoge*)hoge_malloc(sizeof(Hoge));
        if (hoges[i] == NULL) {
            fprintf(stdout, "malloc error: %d\n", i);
            break;
        }
        fprintf(stdout, "allocated: %d\n", (int)hoges[i]);
        i++;
    }

    for (i=0; i<HOGE_MAX && hoges[i]!=NULL; i++) {
        hoge_free(hoges[i]);
    }

    return 0;
}

実行結果

$ ./nisemalloc
allocated: 134518884
allocated: 134518892
allocated: 134518900
allocated: 134518908
allocated: 134518916
malloc error: 5
i'm free!: 134518884
i'm free!: 134518892
i'm free!: 134518900
i'm free!: 134518908
i'm free!: 134518916

課題

hoge_freeの中で、該当する配列要素を見つけるのでいちいちfor文を回しているのが非効率的。
しかし、Cell構造体のin_useは外から見えない(わけでもないけど)ようにしたいのでこんな形になってしまった。きっともっとましな方法があるはず…。
あと、freeがランダムな順番で呼ばれた場合に、hoge_mallocは空きがあるのにエラーを返す羽目になってしまう。まだまだだなぁ。