a26_txt03_001
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
* 川合のプログラミング言語自作のためのテキスト第四版#001
-(by [[K]], 2026.05.28)
--目次はこちらです。→[[a26_txt03]]
** (1) デバッグレベル
-acl4v2 には「デバッグレベル」という概念があります。
-このデバッグレベルは、コンパイラの最適化レベルのことだろ...
-コンパイラの最適化は、生成する機械語の質を上げるためなら...
-acl4v2 のデバッグレベルは最適化とは関係なくて、「このプ...
-デバッグレベルによるチェック強化は、すべて実行時チェック...
-デバッグレベルは a_DbgLv をdefineして指定します(ライブ...
--a_DbgLv=0 : リリース用のモードで、ライブラリ側でのエラ...
--a_DbgLv=1 : エラーチェックはa_DbgLv=0と同等にまで省略さ...
--a_DbgLv=2 : 処理速度があまり落ちないようなエラーチェッ...
--a_DbgLv=3 : レベル2とレベル5の間です。
--a_DbgLv=4 : レベル2とレベル5の間です。
--a_DbgLv=5 : どれだけ遅くなってもいいので、今実装されて...
-acl4v2では、このデバッグレベルの考え方を重視しています。...
-私自身は「まあこんなにチェックしても、自分がこのチェック...
-とまあ概念的なことばかり説明していてもよくわからないと思...
** (2) a_malloc(), a_free(), a_realloc()
-これからエラーチェック機能付きのmalloc/free/reallocを作...
--[1]a_DbgLv=0にした場合、標準関数のmalloc/free/reallocに...
--[2]a_DbgLv=2以上の場合は以下の機能を持ちます:
--[3]メモリを確保した場合に、その中身を 0x87 で塗りつぶし...
--[4]メモリを開放する場合にも、あえて中身を0x87で塗りつぶ...
--[5]メモリ確保の際には、前後にマージンを付けて確保します...
--[6]確保したメモリの一覧がいつでも表示できるように、情報...
** (3) a_ というマクロ
-acl4v2 ライブラリでは a_ という引数がちょくちょく現れま...
-ちなみに a_DbgLv=0 のときは、 a_ は「」になります。つま...
-なぜ a_malloc() や a_free() で a_ を渡す必要があるのか説...
-次に a_malloc() のほうです。 a_malloc() はメモリ不足以外...
-じゃあなぜ 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_chkAll a_malloc_chkAll
#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): DebugMes...
#define a_malloc_chkAll(flg) a_DbgLv2(a_MallocMgr_chkAll...
////
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...
#define Nod(w, i) a_MallocSub_Nod(w, i)
a_static void a_MallocSub_iniHed(a_MallocSub *w, intptr_...
{
Nod(w, i)->prv = i;
Nod(w, i)->nxt = i;
}
a_static void a_MallocSub_add(a_MallocSub *w, intptr_t p...
{
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 ...
{
intptr_t i;
memset(w->p + i0 * w->sz, 0, (i1 - i0 + 1) * w->sz);...
for (i = i1; i >= i0; i--)
a_MallocSub_add(w, HedFre, i, Nod(w, HedFre)->nx...
}
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_MallocMgr) {
a_MallocSub sub[1];
unsigned char *canary;
intptr_t szCanary, no;
unsigned char unuseMark;
};
a_static a_MallocMgr a_mallocMgr[1];
a_static void a_MallocMgr_ini(a_MallocMgr *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_MallocMgr_alc(a_MallocMgr *w, a_def int...
{
#if (a_DbgLv <= 1)
(void) w;
void *p = malloc(sz);
if (p == NULL)
a_errExit("a_malloc: out of memory: sz=%d", ...
return p;
#else
a_MallocSub *v = w->sub;
if (w->sub->rlc == NULL)
a_MallocMgr_ini(w, 16);
if (sz < 0)
a_errExit("%s(%d): a_malloc: sz=%d", a_fil, ...
char *p = malloc(sizeof (intptr_t) + w->szCanary...
if (p == NULL)
a_errExit("%s(%d): a_malloc: out of memory: ...
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, HedUs...
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_MallocMgr_chk(a_MallocMgr *w, intptr_t i,...
{
a_MallocSub *v = w->sub;
a_MallocInf *inf;
intptr_t j;
if (p == NULL) {
if (i < 2 || v->n <= i)
a_errExit("a_MallocMgr_chk: err: p=NULL, 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 = inf->nod->prv;
}
if (j != *(intptr_t *) ((char *) p - w->szCanary...
#endif
if (memcmp((char *) p - w->szCanary, w->canary, w->s...
j = *(intptr_t *) ((char *) p - w->szCanary - sizeof...
if (i < 2)
i = j;
if (i < 2 || v->n <= i) return 4; // malloc情報index...
if (i != j) return 5; // malloc情報indexが一致しない...
inf = (a_MallocInf *) Nod(v, i);
if (p != inf->p) return 6; // ポインタが一致しない(=...
if (sz < 0) sz = inf->sz;
if (sz != inf->sz) return 7; // サイズが一致しない.
if (memcmp((char *) p + sz, w->canary, w->szCanary) ...
return 0;
}
a_static intptr_t a_MallocMgr_chkErr(a_MallocMgr *w, a_d...
{
#if (a_DbgLv >= 2)
int chk = a_MallocMgr_chk(w, i, p, sz);
if (1 <= chk && chk <= 6)
a_errExit("%s(%d): %s: bad signature(i=%d, p...
char *p0 = (char *) p - w->szCanary - sizeof (in...
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...
(int) (intptr_t) p, (int) sz, (int) inf-...
}
#endif
return i;
}
a_static void a_MallocMgr_fre(a_MallocMgr *w, a_def void...
{
#if (a_DbgLv <= 1)
(void) w; (void) sz;
free(p);
#else
if (p == NULL) return;
intptr_t i = a_MallocMgr_chkErr(w, a_thr 0, p, s...
a_MallocInf *inf = (a_MallocInf *) Nod(w->sub, i);
char *p0 = (char *) p - w->szCanary - sizeof (in...
memset(p0, w->unuseMark, sizeof (intptr_t) + w->...
free(p0);
a_MallocSub_rmv(w->sub, i);
inf->p = NULL;
a_MallocSub_add(w->sub, HedFre, i, Nod(w->sub, H...
#endif
}
a_static void *a_MallocMgr_rlc(a_MallocMgr *w, a_def voi...
{
#if (a_DbgLv <= 1)
(void) w; (void) sz0;
p = realloc(p, sz);
if (p == NULL)
a_errExit("a_realloc: out of memory: sz=%d",...
return p;
#else
if (w->sub->rlc == NULL)
a_MallocMgr_ini(w, 16);
if (sz < 0)
a_errExit("%s(%d): a_realloc: p=0x%x, sz=%d"...
if (p != NULL) {
intptr_t i = a_MallocMgr_chkErr(w, a_thr 0, ...
a_MallocInf *inf = (a_MallocInf *) Nod(w->su...
sz0 = inf->sz;
if (sz0 == sz) return p;
char *q = malloc(sizeof (intptr_t) + w->szCa...
if (q == NULL)
a_errExit("%s(%d): a_realloc: out of mem...
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...
memset(p0, w->unuseMark, sizeof (intptr_t) +...
free(p0);
return q2;
}
return a_MallocMgr_alc(w, a_thr sz);
#endif
}
#if (a_DbgLv <= 1 && a_NoUse_OutOfMemoryCheck != 0)
#define a_malloc malloc
#define a_free free
#define a_realloc realloc
#define a_free1(p, sz) free(p)
#define a_realloc1(p, sz, sz0) realloc(p, sz)
#endif
#if (a_DbgLv <= 1 && a_NoUse_OutOfMemoryCheck == 0)
#define a_malloc(sz) a_MallocMgr_alc(NULL...
#define a_free(p) a_MallocMgr_fre(NULL...
#define a_realloc(p, sz) a_MallocMgr_rlc(NULL...
#define a_free1(p, sz) a_MallocMgr_fre(NULL...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(NULL...
#endif
#if (a_DbgLv >= 2)
#define a_malloc(sz) a_MallocMgr_alc(a_ma...
#define a_free(p) a_MallocMgr_fre(a_ma...
#define a_realloc(p, sz) a_MallocMgr_rlc(a_ma...
#define a_free1(p, sz) a_MallocMgr_fre(a_ma...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(a_ma...
#endif
a_static void a_MallocMgr_chkAll(a_MallocMgr *w, a_def i...
{
#if (a_DbgLv >= 2)
fprintf(stderr, "%s(%d): a_MallocMgr_chkAll: a_D...
a_MallocSub *v = w->sub;
intptr_t i = Nod(v, HedUse)->nxt, n = 0, total =...
for (;;) {
if (i == HedUse) break;
a_MallocInf *inf = (a_MallocInf *) Nod(v, i);
int chk = a_MallocMgr_chk(w, i, NULL, -1);
if ((flg & 1) != 0 || chk != 0) {
fprintf(stderr, " #%04d: chk=%d [i=%04d ...
(int) n, chk, (int) i, (int) (intptr...
if (chk != 0) nChk++;
}
total += inf->sz;
i = Nod(v, i)->nxt; n++;
}
fprintf(stderr, " n=%d, total=%d, nChk=%d\n", (i...
if (nChk > 0) exit(1);
#endif
}
#undef HedUse
#undef HedFre
#undef Nod
** (5) 解説
-''[5-1]'' まず最初に確認してもらいたいのは、最後のほうに...
#define a_malloc malloc
#define a_free free
#define a_realloc realloc
#define a_free1(p, sz) free(p)
#define a_realloc1(p, sz, sz0) realloc(p, sz)
-つまりここに書かれた関数はほぼ全部使わないことになって、...
-これに対して、 a_DbgLv>=2 であれば、以下のような読み替え...
#define a_malloc(sz) a_MallocMgr_alc(a_ma...
#define a_free(p) a_MallocMgr_fre(a_ma...
#define a_realloc(p, sz) a_MallocMgr_rlc(a_ma...
#define a_free1(p, sz) a_MallocMgr_fre(a_ma...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(a_ma...
-ついでなので、ここで a_free1() や a_realloc1() について...
-これは malloc() を自作してみるとわかりやすいのですが、も...
-それで、普段から free1() や realloc1() でアプリを書いて...
-''[5-2]'' それでじゃあ、まあ最初から眺めていくと、 a_err...
-この a_errExit() 関数は、基本的にエラーメッセージを表示...
-逆に、なんか高度なことをいろいろやってくれる大規模な関数...
-ということで a_errExit() は作られるべき関数の代表みたい...
-''[5-3]'' 次は DM関数です。これは DebugMessage の略です...
-''[5-4]'' 次は a_MallocSub クラスです。・・・まずこの名...
-この辺りからポインタを多用していて、なんかよくわからない...
-このクラスは、「双方向循環リスト」というデータ構造を使っ...
--双方向循環リストはここに説明があります: https://ja.wik...
-イメージとしては a_MallocInf の配列があって、それぞれの ...
-なぜ双方向循環リストを使うのか?・・・単純に考えたら、in...
-一方、 malloc したときには inf[i] を接続しなければいけま...
-実は a_MallocSub クラスでは、2つの双方向循環リストを持っ...
-実は未使用管理のほうは、双方向にする必要はなくて片方向で...
-a_MallocSub_iniHed(w, i): inf[i]を双方向循環リストの番兵...
-a_MallocSub_add(w, prv, i, nxt): inf[i]を双方向循環リス...
-a_MallocSub_rmv(w, i): inf[i]を双方向循環リストから切り...
-a_MallocSub_fre1(w, i0, i1): inf[i0]からinf[i1]を未使用...
-a_MallocSub_alc(w): 未使用リストから1つとってきます。も...
-''[5-5]'' 次は a_MallocMgr クラスです。 malloc のマネジ...
-これはメモリを確保するときに、[inf配列の番号][カナリア(...
-a_MallocMgr_ini(w, n): a_mallocMgr を初期化します。a_Dbg...
-a_MallocMgr_alc(w, sz): a_malloc() の処理をします。
-a_MallocMgr_chk(w, i, p, sz): iもしくはpで指定されたメモ...
-a_MallocMgr_chkErr(w, i, p, sz, f): 指定されたメモリブロ...
-a_MallocMgr_fre(w, p, sz): a_free() の処理をします。
-a_MallocMgr_rlc(w, p, sz, sz0): a_realloc() の処理をしま...
-a_MallocMgr_chkAll(w, flg): a_malloc() で確保済みのメモ...
-このプログラムでは intptr_t を int にキャストしてから pr...
** (6) サンプルコード sample001a.c
-以下のプログラムで試してみました。
#include <acl4v2.c>
int main(int argc, const char **argv)
{
char *a = malloc_(a_ 10);
char *b = malloc_(a_ 20);
char *c = malloc_(a_ 30);
free_(a_ b);
strcpy(a, "0123456789"); // 10文字だから大丈夫・・・...
malloc_chkAll(a_ 1); // プログラム終了前にこれを書く...
return 0;
}
-実行結果は以下の通りです。
sample001a.c(10): a_MallocMgr_chkAll: a_DbgLv=2
#0000: chk=8 [i=0002 p=0xfd084a98 sz=0010 no=0000 : sam...
#0001: chk=0 [i=0004 p=0xfd084ce8 sz=0030 no=0002 : sam...
n=2, total=40, nChk=1
-mallocされたがまだfreeしてないメモリは2つあり、それがaと...
-またaのほうはカナリア(フッター)が壊れているということ...
-sample001a.c くらいの記述量で、ここまで情報が取れるって...
-これはOSやCPUに依存するデバッガではないので、どんな環境...
** (7) サンプルコード sample001b.c
-以下のプログラムで試してみました。
// #define a_DbgLv 4
#include <acl4v2.c>
int main(int argc, const char **argv)
{
char *a = malloc_(a_ 10);
char *b = malloc_(a_ 20);
char *c = malloc_(a_ 30);
free_(a_ a);
free_(a_ b);
free_(a_ a); // ここで間違えて、二重freeをしている.
malloc_chkAll(a_ 1); // プログラム終了前にこれを書く...
return 0;
}
-実行結果は以下の通りです。
sample001b.c(11): a_free: bad signature(i=0, p=0xf3b5aea...
-二重freeのところでエラー終了したことが分かります。 chk=3...
-ちなみに a_DbgLv=4 でビルドすると、エラー終了の時の理由...
** (8) あとがき
-普通 mallocやfreeの自作をするとなったら、自作mallocはこ...
-ちなみにスーパーなプログラマがいい機能をどんどん作れる最...
* こめんと欄
#comment
終了行:
* 川合のプログラミング言語自作のためのテキスト第四版#001
-(by [[K]], 2026.05.28)
--目次はこちらです。→[[a26_txt03]]
** (1) デバッグレベル
-acl4v2 には「デバッグレベル」という概念があります。
-このデバッグレベルは、コンパイラの最適化レベルのことだろ...
-コンパイラの最適化は、生成する機械語の質を上げるためなら...
-acl4v2 のデバッグレベルは最適化とは関係なくて、「このプ...
-デバッグレベルによるチェック強化は、すべて実行時チェック...
-デバッグレベルは a_DbgLv をdefineして指定します(ライブ...
--a_DbgLv=0 : リリース用のモードで、ライブラリ側でのエラ...
--a_DbgLv=1 : エラーチェックはa_DbgLv=0と同等にまで省略さ...
--a_DbgLv=2 : 処理速度があまり落ちないようなエラーチェッ...
--a_DbgLv=3 : レベル2とレベル5の間です。
--a_DbgLv=4 : レベル2とレベル5の間です。
--a_DbgLv=5 : どれだけ遅くなってもいいので、今実装されて...
-acl4v2では、このデバッグレベルの考え方を重視しています。...
-私自身は「まあこんなにチェックしても、自分がこのチェック...
-とまあ概念的なことばかり説明していてもよくわからないと思...
** (2) a_malloc(), a_free(), a_realloc()
-これからエラーチェック機能付きのmalloc/free/reallocを作...
--[1]a_DbgLv=0にした場合、標準関数のmalloc/free/reallocに...
--[2]a_DbgLv=2以上の場合は以下の機能を持ちます:
--[3]メモリを確保した場合に、その中身を 0x87 で塗りつぶし...
--[4]メモリを開放する場合にも、あえて中身を0x87で塗りつぶ...
--[5]メモリ確保の際には、前後にマージンを付けて確保します...
--[6]確保したメモリの一覧がいつでも表示できるように、情報...
** (3) a_ というマクロ
-acl4v2 ライブラリでは a_ という引数がちょくちょく現れま...
-ちなみに a_DbgLv=0 のときは、 a_ は「」になります。つま...
-なぜ a_malloc() や a_free() で a_ を渡す必要があるのか説...
-次に a_malloc() のほうです。 a_malloc() はメモリ不足以外...
-じゃあなぜ 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_chkAll a_malloc_chkAll
#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): DebugMes...
#define a_malloc_chkAll(flg) a_DbgLv2(a_MallocMgr_chkAll...
////
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...
#define Nod(w, i) a_MallocSub_Nod(w, i)
a_static void a_MallocSub_iniHed(a_MallocSub *w, intptr_...
{
Nod(w, i)->prv = i;
Nod(w, i)->nxt = i;
}
a_static void a_MallocSub_add(a_MallocSub *w, intptr_t p...
{
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 ...
{
intptr_t i;
memset(w->p + i0 * w->sz, 0, (i1 - i0 + 1) * w->sz);...
for (i = i1; i >= i0; i--)
a_MallocSub_add(w, HedFre, i, Nod(w, HedFre)->nx...
}
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_MallocMgr) {
a_MallocSub sub[1];
unsigned char *canary;
intptr_t szCanary, no;
unsigned char unuseMark;
};
a_static a_MallocMgr a_mallocMgr[1];
a_static void a_MallocMgr_ini(a_MallocMgr *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_MallocMgr_alc(a_MallocMgr *w, a_def int...
{
#if (a_DbgLv <= 1)
(void) w;
void *p = malloc(sz);
if (p == NULL)
a_errExit("a_malloc: out of memory: sz=%d", ...
return p;
#else
a_MallocSub *v = w->sub;
if (w->sub->rlc == NULL)
a_MallocMgr_ini(w, 16);
if (sz < 0)
a_errExit("%s(%d): a_malloc: sz=%d", a_fil, ...
char *p = malloc(sizeof (intptr_t) + w->szCanary...
if (p == NULL)
a_errExit("%s(%d): a_malloc: out of memory: ...
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, HedUs...
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_MallocMgr_chk(a_MallocMgr *w, intptr_t i,...
{
a_MallocSub *v = w->sub;
a_MallocInf *inf;
intptr_t j;
if (p == NULL) {
if (i < 2 || v->n <= i)
a_errExit("a_MallocMgr_chk: err: p=NULL, 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 = inf->nod->prv;
}
if (j != *(intptr_t *) ((char *) p - w->szCanary...
#endif
if (memcmp((char *) p - w->szCanary, w->canary, w->s...
j = *(intptr_t *) ((char *) p - w->szCanary - sizeof...
if (i < 2)
i = j;
if (i < 2 || v->n <= i) return 4; // malloc情報index...
if (i != j) return 5; // malloc情報indexが一致しない...
inf = (a_MallocInf *) Nod(v, i);
if (p != inf->p) return 6; // ポインタが一致しない(=...
if (sz < 0) sz = inf->sz;
if (sz != inf->sz) return 7; // サイズが一致しない.
if (memcmp((char *) p + sz, w->canary, w->szCanary) ...
return 0;
}
a_static intptr_t a_MallocMgr_chkErr(a_MallocMgr *w, a_d...
{
#if (a_DbgLv >= 2)
int chk = a_MallocMgr_chk(w, i, p, sz);
if (1 <= chk && chk <= 6)
a_errExit("%s(%d): %s: bad signature(i=%d, p...
char *p0 = (char *) p - w->szCanary - sizeof (in...
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...
(int) (intptr_t) p, (int) sz, (int) inf-...
}
#endif
return i;
}
a_static void a_MallocMgr_fre(a_MallocMgr *w, a_def void...
{
#if (a_DbgLv <= 1)
(void) w; (void) sz;
free(p);
#else
if (p == NULL) return;
intptr_t i = a_MallocMgr_chkErr(w, a_thr 0, p, s...
a_MallocInf *inf = (a_MallocInf *) Nod(w->sub, i);
char *p0 = (char *) p - w->szCanary - sizeof (in...
memset(p0, w->unuseMark, sizeof (intptr_t) + w->...
free(p0);
a_MallocSub_rmv(w->sub, i);
inf->p = NULL;
a_MallocSub_add(w->sub, HedFre, i, Nod(w->sub, H...
#endif
}
a_static void *a_MallocMgr_rlc(a_MallocMgr *w, a_def voi...
{
#if (a_DbgLv <= 1)
(void) w; (void) sz0;
p = realloc(p, sz);
if (p == NULL)
a_errExit("a_realloc: out of memory: sz=%d",...
return p;
#else
if (w->sub->rlc == NULL)
a_MallocMgr_ini(w, 16);
if (sz < 0)
a_errExit("%s(%d): a_realloc: p=0x%x, sz=%d"...
if (p != NULL) {
intptr_t i = a_MallocMgr_chkErr(w, a_thr 0, ...
a_MallocInf *inf = (a_MallocInf *) Nod(w->su...
sz0 = inf->sz;
if (sz0 == sz) return p;
char *q = malloc(sizeof (intptr_t) + w->szCa...
if (q == NULL)
a_errExit("%s(%d): a_realloc: out of mem...
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...
memset(p0, w->unuseMark, sizeof (intptr_t) +...
free(p0);
return q2;
}
return a_MallocMgr_alc(w, a_thr sz);
#endif
}
#if (a_DbgLv <= 1 && a_NoUse_OutOfMemoryCheck != 0)
#define a_malloc malloc
#define a_free free
#define a_realloc realloc
#define a_free1(p, sz) free(p)
#define a_realloc1(p, sz, sz0) realloc(p, sz)
#endif
#if (a_DbgLv <= 1 && a_NoUse_OutOfMemoryCheck == 0)
#define a_malloc(sz) a_MallocMgr_alc(NULL...
#define a_free(p) a_MallocMgr_fre(NULL...
#define a_realloc(p, sz) a_MallocMgr_rlc(NULL...
#define a_free1(p, sz) a_MallocMgr_fre(NULL...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(NULL...
#endif
#if (a_DbgLv >= 2)
#define a_malloc(sz) a_MallocMgr_alc(a_ma...
#define a_free(p) a_MallocMgr_fre(a_ma...
#define a_realloc(p, sz) a_MallocMgr_rlc(a_ma...
#define a_free1(p, sz) a_MallocMgr_fre(a_ma...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(a_ma...
#endif
a_static void a_MallocMgr_chkAll(a_MallocMgr *w, a_def i...
{
#if (a_DbgLv >= 2)
fprintf(stderr, "%s(%d): a_MallocMgr_chkAll: a_D...
a_MallocSub *v = w->sub;
intptr_t i = Nod(v, HedUse)->nxt, n = 0, total =...
for (;;) {
if (i == HedUse) break;
a_MallocInf *inf = (a_MallocInf *) Nod(v, i);
int chk = a_MallocMgr_chk(w, i, NULL, -1);
if ((flg & 1) != 0 || chk != 0) {
fprintf(stderr, " #%04d: chk=%d [i=%04d ...
(int) n, chk, (int) i, (int) (intptr...
if (chk != 0) nChk++;
}
total += inf->sz;
i = Nod(v, i)->nxt; n++;
}
fprintf(stderr, " n=%d, total=%d, nChk=%d\n", (i...
if (nChk > 0) exit(1);
#endif
}
#undef HedUse
#undef HedFre
#undef Nod
** (5) 解説
-''[5-1]'' まず最初に確認してもらいたいのは、最後のほうに...
#define a_malloc malloc
#define a_free free
#define a_realloc realloc
#define a_free1(p, sz) free(p)
#define a_realloc1(p, sz, sz0) realloc(p, sz)
-つまりここに書かれた関数はほぼ全部使わないことになって、...
-これに対して、 a_DbgLv>=2 であれば、以下のような読み替え...
#define a_malloc(sz) a_MallocMgr_alc(a_ma...
#define a_free(p) a_MallocMgr_fre(a_ma...
#define a_realloc(p, sz) a_MallocMgr_rlc(a_ma...
#define a_free1(p, sz) a_MallocMgr_fre(a_ma...
#define a_realloc1(p, sz, sz0) a_MallocMgr_rlc(a_ma...
-ついでなので、ここで a_free1() や a_realloc1() について...
-これは malloc() を自作してみるとわかりやすいのですが、も...
-それで、普段から free1() や realloc1() でアプリを書いて...
-''[5-2]'' それでじゃあ、まあ最初から眺めていくと、 a_err...
-この a_errExit() 関数は、基本的にエラーメッセージを表示...
-逆に、なんか高度なことをいろいろやってくれる大規模な関数...
-ということで a_errExit() は作られるべき関数の代表みたい...
-''[5-3]'' 次は DM関数です。これは DebugMessage の略です...
-''[5-4]'' 次は a_MallocSub クラスです。・・・まずこの名...
-この辺りからポインタを多用していて、なんかよくわからない...
-このクラスは、「双方向循環リスト」というデータ構造を使っ...
--双方向循環リストはここに説明があります: https://ja.wik...
-イメージとしては a_MallocInf の配列があって、それぞれの ...
-なぜ双方向循環リストを使うのか?・・・単純に考えたら、in...
-一方、 malloc したときには inf[i] を接続しなければいけま...
-実は a_MallocSub クラスでは、2つの双方向循環リストを持っ...
-実は未使用管理のほうは、双方向にする必要はなくて片方向で...
-a_MallocSub_iniHed(w, i): inf[i]を双方向循環リストの番兵...
-a_MallocSub_add(w, prv, i, nxt): inf[i]を双方向循環リス...
-a_MallocSub_rmv(w, i): inf[i]を双方向循環リストから切り...
-a_MallocSub_fre1(w, i0, i1): inf[i0]からinf[i1]を未使用...
-a_MallocSub_alc(w): 未使用リストから1つとってきます。も...
-''[5-5]'' 次は a_MallocMgr クラスです。 malloc のマネジ...
-これはメモリを確保するときに、[inf配列の番号][カナリア(...
-a_MallocMgr_ini(w, n): a_mallocMgr を初期化します。a_Dbg...
-a_MallocMgr_alc(w, sz): a_malloc() の処理をします。
-a_MallocMgr_chk(w, i, p, sz): iもしくはpで指定されたメモ...
-a_MallocMgr_chkErr(w, i, p, sz, f): 指定されたメモリブロ...
-a_MallocMgr_fre(w, p, sz): a_free() の処理をします。
-a_MallocMgr_rlc(w, p, sz, sz0): a_realloc() の処理をしま...
-a_MallocMgr_chkAll(w, flg): a_malloc() で確保済みのメモ...
-このプログラムでは intptr_t を int にキャストしてから pr...
** (6) サンプルコード sample001a.c
-以下のプログラムで試してみました。
#include <acl4v2.c>
int main(int argc, const char **argv)
{
char *a = malloc_(a_ 10);
char *b = malloc_(a_ 20);
char *c = malloc_(a_ 30);
free_(a_ b);
strcpy(a, "0123456789"); // 10文字だから大丈夫・・・...
malloc_chkAll(a_ 1); // プログラム終了前にこれを書く...
return 0;
}
-実行結果は以下の通りです。
sample001a.c(10): a_MallocMgr_chkAll: a_DbgLv=2
#0000: chk=8 [i=0002 p=0xfd084a98 sz=0010 no=0000 : sam...
#0001: chk=0 [i=0004 p=0xfd084ce8 sz=0030 no=0002 : sam...
n=2, total=40, nChk=1
-mallocされたがまだfreeしてないメモリは2つあり、それがaと...
-またaのほうはカナリア(フッター)が壊れているということ...
-sample001a.c くらいの記述量で、ここまで情報が取れるって...
-これはOSやCPUに依存するデバッガではないので、どんな環境...
** (7) サンプルコード sample001b.c
-以下のプログラムで試してみました。
// #define a_DbgLv 4
#include <acl4v2.c>
int main(int argc, const char **argv)
{
char *a = malloc_(a_ 10);
char *b = malloc_(a_ 20);
char *c = malloc_(a_ 30);
free_(a_ a);
free_(a_ b);
free_(a_ a); // ここで間違えて、二重freeをしている.
malloc_chkAll(a_ 1); // プログラム終了前にこれを書く...
return 0;
}
-実行結果は以下の通りです。
sample001b.c(11): a_free: bad signature(i=0, p=0xf3b5aea...
-二重freeのところでエラー終了したことが分かります。 chk=3...
-ちなみに a_DbgLv=4 でビルドすると、エラー終了の時の理由...
** (8) あとがき
-普通 mallocやfreeの自作をするとなったら、自作mallocはこ...
-ちなみにスーパーなプログラマがいい機能をどんどん作れる最...
* こめんと欄
#comment
ページ名: