川合のプログラミング言語自作のためのテキスト第四版#001

(1) デバッグレベル

(2) a_malloc(), a_free(), a_realloc()

(3) a_ というマクロ

(4) acl4v2_001.c

#if (!defined(a_DbgLv))
    #define a_DbgLv     2
#endif

#if (!defined(a_NoUse_OutOfMemoryCheck))
    #define a_NoUse_OutOfMemoryCheck    0
#endif

#if (a_Version > 0)
    #define DbgLv            a_DbgLv
    #define errExit          a_errExit
    #define DM               a_DM
    #define malloc_          a_malloc
    #define free_            a_free
    #define realloc_         a_realloc
    #define free1            a_free1
    #define realloc1         a_realloc1
    #define malloc_testAll   a_malloc_testAll
#endif

#if (a_DbgLv >= 1)
    #define a_DbgLv1(x) x
#else
    #define a_DbgLv1(x)
#endif

#if (a_DbgLv >= 2)
    #define a_DbgLv2(x) x
    #define a_          __FILE__, __LINE__,
    #define a__         __FILE__, __LINE__
    #define a_def       const char *a_fil, int a_lin,
    #define a_def_      const char *a_fil, int a_lin
    #define a_thr       a_fil, a_lin,
    #define a_thr_      a_fil, a_lin
#else
    #define a_DbgLv2(x)
    #define a_
    #define a__
    #define a_def
    #define a_def_
    #define a_thr
    #define a_thr_
#endif

////

a_static void a_errExit0(const char *f, ...)
{
    va_list ap;
    va_start(ap, f);
    vfprintf(stderr, f, ap);
    va_end(ap);
    fprintf(stderr, "\n");
    exit(1);
}

#if (!defined(a_errExit))
    #define a_errExit   a_errExit0
#endif

#define a_DM	a_DbgLv2( fprintf(stderr, "%s(%d): DebugMessage\n", __FILE__, __LINE__); )
#define a_malloc_testAll(flg)	a_DbgLv2(a_MallocMan_testAll(a_mallocMan, flg))

////

a_class(a_MallocSub_Node) {
    intptr_t prv, nxt;
};

a_class(a_MallocSub) {
    void *(*rlc)(void *, size_t);
    char *p;
    intptr_t sz, n;
};

#define HedUse                  0
#define HedFre                  1
#define a_MallocSub_Nod(w, i)   ((a_MallocSub_Node *) (w->p + i * w->sz))
#define Nod(w, i)               a_MallocSub_Nod(w, i)

a_static void a_MallocSub_iniHed(a_MallocSub *w, intptr_t i)
{
    Nod(w, i)->prv = i;
    Nod(w, i)->nxt = i;
}

a_static void a_MallocSub_add(a_MallocSub *w, intptr_t prv, intptr_t i, intptr_t nxt)
{
    Nod(w, i  )->prv = prv;
    Nod(w, i  )->nxt = nxt;
    Nod(w, nxt)->prv = i;
    Nod(w, prv)->nxt = i;
}

a_static void a_MallocSub_rmv(a_MallocSub *w, intptr_t i)
{
    intptr_t prv = Nod(w, i)->prv, nxt = Nod(w, i)->nxt;
    Nod(w, prv)->nxt = nxt;
    Nod(w, nxt)->prv = prv;
}

a_static void a_MallocSub_fre1(a_MallocSub *w, intptr_t i0, intptr_t i1)
{
    intptr_t i;
    for (i = i1; i >= i0; i--)
        a_MallocSub_add(w, HedFre, i, Nod(w, HedFre)->nxt);
}

a_static intptr_t a_MallocSub_alc(a_MallocSub *w)
{
    if (Nod(w, HedFre)->nxt == HedFre) {  // 未使用Nodeがないので自動拡張.
        w->p = w->rlc(w->p, w->sz * w->n * 2);
        if (w->p == NULL)
            a_errExit("a_MallocSub: out of memory");
        a_MallocSub_fre1(w, w->n, w->n * 2 - 1);
        w->n *= 2;
    }
    intptr_t i = Nod(w, HedFre)->nxt;
    a_MallocSub_rmv(w, i);
    return i;
}

////

a_class(a_MallocInf) {
    a_MallocSub_Node nod[1];
    intptr_t sz, lin, no;
    const char *fil;
    void *p;
};

a_class(a_MallocMan) {
    a_MallocSub sub[1];
    unsigned char *canary;
    intptr_t szCanary, no;
    unsigned char unuseMark;
};

a_static a_MallocMan a_mallocMan[1];

a_static void a_MallocMan_ini(a_MallocMan *w, intptr_t n)
{
    w->sub->rlc = realloc;
    w->sub->p = malloc(n * sizeof (a_MallocInf));
    w->sub->sz = sizeof (a_MallocInf);
    w->sub->n = n;
    a_MallocSub_iniHed(w->sub, HedUse);
    a_MallocSub_iniHed(w->sub, HedFre);
    a_MallocSub_fre1(w->sub, 2, n - 1);
    #if (a_DbgLv >= 4)
        w->szCanary = 1024 * sizeof (intptr_t);
    #elif (a_DbgLv == 3)
        w->szCanary =  256 * sizeof (intptr_t);
    #else
        w->szCanary =   16 * sizeof (intptr_t);
    #endif
    w->canary = malloc(w->szCanary);
    memset(w->canary, 0xa5, w->szCanary);
    w->unuseMark = 0x87;
    w->no = 0;
}

a_static void *a_MallocMan_alc(a_MallocMan *w, a_def intptr_t sz)
{
    #if (a_DbgLv <= 1)
        (void) w;
        void *p = malloc(sz);
        if (p == NULL)
            a_errExit("a_malloc: out of memory: sz=%d", sz);
        return p;
    #else
        a_MallocSub *v = w->sub;
        if (w->sub->rlc == NULL)
            a_MallocMan_ini(w, 16);
        if (sz < 0)
            a_errExit("%s(%d): a_malloc: sz=%d", a_fil, a_lin, (int) sz);
        char *p = malloc(sizeof (intptr_t) + w->szCanary * 2 + sz);
        if (p == NULL)
            a_errExit("%s(%d): a_malloc: out of memory: sz=%d", a_fil, a_lin, (int) sz);
        char *p1 = p + sizeof (intptr_t);
        memcpy(p1, w->canary, w->szCanary);
        char *p2 = p1 + w->szCanary;
        memset(p2, w->unuseMark, sz);
        memcpy(p2 + sz, w->canary, w->szCanary);
        intptr_t i = a_MallocSub_alc(v);
        *(intptr_t *) p = i;
        a_MallocSub_add(v, Nod(v, HedUse)->prv, i, HedUse);
        a_MallocInf *inf = (a_MallocInf *) Nod(v, i);
        inf->sz = sz;
        inf->lin = a_lin;
        inf->fil = a_fil;
        inf->p = p2;
        inf->no = w->no++;
        return p2;
    #endif
}

a_static int a_MallocMan_chk(a_MallocMan *w, intptr_t i, void *p, intptr_t sz)
{
    a_MallocSub *v = w->sub;
    a_MallocInf *inf;
    intptr_t j;
    if (p == NULL) {
        if (i < 2 || v->n <= i)
            a_errExit("a_MallocMan_chk: err: p=NULL, i=%d", i);
        inf = (a_MallocInf *) Nod(v, i);
        p = inf->p;
    }
    #if (a_DbgLv >= 4)
        j = Nod(v, HedUse)->prv; // 新しいものから(=最後尾から)順番に探す. 多分そのほうが速く見つかる.
        for (;;) {
            if (j == HedUse) return 1; // 不正ポインタ検出.
            inf = (a_MallocInf *) Nod(v, j);
            if (inf->p == p) break;
            j = Nod(v, j)->prv;
        }
        if (j != *(intptr_t *) ((char *) p - w->szCanary - sizeof (intptr_t))) return 2; // malloc情報indexが一致しない#1.
    #endif
    if (memcmp((char *) p - w->szCanary, w->canary, w->szCanary) != 0) return 3; // カナリア(ヘッダー)の破壊を検出.
    j = *(intptr_t *) ((char *) p - w->szCanary - sizeof (intptr_t));
    if (i < 2)
        i = j;
    if (i < 2 || v->n <= i) return 4; // malloc情報indexが異常値.
    if (i != j) return 5; // malloc情報I\indexが一致しない#2.
    inf = (a_MallocInf *) Nod(v, i);
    if (p != inf->p) return 6; // ポインタが一致しない(==ID値が壊されている).
    if (sz < 0) sz = inf->sz;
    if (sz != inf->sz) return 7; // サイズが一致しない.
    if (memcmp((char *) p + sz, w->canary, w->szCanary) != 0) return 8; // カナリア(フッター)の破壊を検出.
    return 0;
}

a_static intptr_t a_MallocMan_chkErr(a_MallocMan *w, a_def intptr_t i, void *p, intptr_t sz, const char *f)
{
    #if (a_DbgLv >= 2)
        int chk = a_MallocMan_chk(w, i, p, sz);
        if (1 <= chk && chk <= 6)
            a_errExit("%s(%d): %s: bad signature(i=%d, p=0x%x, sz=%d, chk=%d)", a_fil, a_lin, f, (int) i, (int) (intptr_t) p, (int) sz, chk);
        char *p0 = (char *) p - w->szCanary - sizeof (intptr_t);
        i = *(intptr_t *) p0;
        a_MallocInf *inf = (a_MallocInf *) Nod(w->sub, i);
        if (chk >= 7) {
            a_errExit("%s(%d): %s: bad signature(i=%d, p=0x%x, sz=%d, no=%d, chk=%d, [%s(%d): sz=%d])", a_fil, a_lin, f, (int) i,
                (int) (intptr_t) p, (int) sz, (int) inf->no, chk, inf->fil, (int) inf->lin, (int) inf->sz);
        }
    #endif
    return i;
}

a_static void a_MallocMan_fre(a_MallocMan *w, a_def void *p, intptr_t sz)
{
    #if (a_DbgLv <= 1)
        (void) w; (void) sz;
        free(p);
    #else
        if (p == NULL) return;
        intptr_t i = a_MallocMan_chkErr(w, a_thr 0, p, sz, "a_free");
        a_MallocInf *inf = (a_MallocInf *) Nod(w->sub, i);
        char *p0 = (char *) p - w->szCanary - sizeof (intptr_t);
        memset(p0, w->unuseMark, sizeof (intptr_t) + w->szCanary * 2 + inf->sz);
        free(p0);
        a_MallocSub_rmv(w->sub, i);
        a_MallocSub_add(w->sub, HedFre, i, Nod(w->sub, HedFre)->nxt);
    #endif
}

a_static void *a_MallocMan_rlc(a_MallocMan *w, a_def void *p, intptr_t sz, intptr_t sz0)
{
    #if (a_DbgLv <= 1)
        (void) w; (void) sz0;
        p = realloc(p, sz);
        if (p == NULL)
            a_errExit("a_realloc: out of memory: sz=%d", sz);
        return p;
    #else
        if (w->sub->rlc == NULL)
            a_MallocMan_ini(w, 16);
        if (sz < 0)
            a_errExit("%s(%d): a_realloc: p=0x%x, sz=%d", a_fil, a_lin, (int) (intptr_t) p, (int) sz);
        if (p != NULL) {
            intptr_t i = a_MallocMan_chkErr(w, a_thr 0, p, sz0, "a_realloc");
            a_MallocInf *inf = (a_MallocInf *) Nod(w->sub, i);
            sz0 = inf->sz;
            if (sz0 == sz) return p;
            char *q = malloc(sizeof (intptr_t) + w->szCanary * 2 + sz); // サイズが縮小する場合でもアドレスは変わる仕様.
            if (q == NULL)
                a_errExit("%s(%d): a_realloc: out of memory: sz=%d", a_fil, a_lin, (int) sz);
            char *q1 = q + sizeof (intptr_t);
            memcpy(q1, w->canary, w->szCanary);
            char *q2 = q1 + w->szCanary;
            if (sz > sz0) {
                memcpy(q2, p, sz0);
                memset(q2 + sz0, w->unuseMark, sz - sz0);
            } else
                memcpy(q2, p, sz);
            memcpy(q2 + sz, w->canary, w->szCanary);
            *(intptr_t *) q = i;
            inf->sz = sz;
            inf->p = q2;
            char *p0 = (char *) p - w->szCanary - sizeof (intptr_t);
            memset(p0, w->unuseMark, sizeof (intptr_t) + w->szCanary * 2 + sz0);
            free(p0);
            return q2;
        } else
            return a_MallocMan_alc(w, a_thr sz);
    #endif
}

こめんと欄


コメントお名前NameLink

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS