ToDo:
NotePCを FreeBSD/i386 6.3-PRERELEASEから 7.0-BETA4へアップデートして ports類を再コンパイルしてから表題のとおり、「かんな」が 動かなくなりました。(cannastatとかはできるけど、まともにクライアントが 接続するとcannaserverが core dumpする Orz)
で、ホテルでごそごそ調査をしてましたが、結論からいうと物凄く単純なバグ で、いままで運良く動いていただけのようです。修正は、わずか 2文字追加で完了
--- lib/RK/ncache.c~ 2003-09-17 10:50:30.000000000 +0200 +++ lib/RK/ncache.c 2007-12-21 02:05:00.000000000 +0100 @@ -26,7 +26,7 @@ #include "RKintern.h" -#define NCHASH 101 +#define NCHASH 101UL #define hash(x) ((int)((x)%NCHASH)) static struct ncache Nchash[NCHASH];
え?なんで直るかが判らないって? hash(x)は、整数型変数 xを 0〜(NCHASH-1)の整数にハッシュするための 関数で、それをインデックスにして Nchash[]配列をアクセスするコードが lib/RK/ncache.cにあります。で、修正前だと hash(x)が負になったりする ので、当然 signal 11で core dumpするわけです。
NCHASHでとる剰余だから、0〜(NCHASH-1)が返るのは当り前だと思う人は、 もう一度 Cの仕様書を読みましょう
ISO C99以前と以降で違いがあるのですが、 少なくとも整数演算における剰余の振舞は次の恒等式を満たします
a = (a / b) * b + (a % b)
さて、問題は整数値(a/b)がどうなるかです
少なくとも a, bともに正の場合は切り下げと定義されています。 が、その他の組合せの場合はどうでしょう。 驚くなかれ、ISO C99以前は未定義なため実装依存です。 ISO C99では、常に 0へ向かって丸めることになりました。 つまり、剰余 a % bの値域は -abs(b) + 1〜 abs(b) - 1なのです
で、問題のかんなの件ですが、実は hash()への入力は long型の アドレス情報で、FreeBSD 6.3-PRERELEASE -> 7.0-BETA4での VM空間の割り当て変更によって 2GB境界を跨いだために負に なっていました。
では、なぜこの修正で直るのでしょう? xが long型だとして、NCHASHを ULで修飾した unsigned long定数とすると 整数演算 x % NCHASHでは型の不一致を long型の xを unsigned longへ 昇格することで解決します。unsigned long型同士の剰余は 必ず unsigned longです。したがって、hash(x)が負になる問題は解決です。
ここでの剰余は、ハッシュとして使うのが目的なのでこれで解決ですが、 剰余 a % b を0若しくは正の値に正規化する必要があるときは、 剰余が負の場合に 商 a / bから abs(b)/bを引いて、 剰余に abs(b)を加える操作が必要になります。
カテゴリー: Admin | Emacs | EPICS | Fortran | FreeBSD | GCC | hgsubversion | IPv6 | KEKB | LHC | Lisp | LLVM | MADX | Ryzen | SAD | samba | tDiary | unix | WWW | YaSAI | お仕事 | イベント | 出張 | 宴会 | 数学 | 艦これ | 買いもの | 追記 | 雑記