XCreateFontSet()のバグ

バグの概要

引数として指定されたフォントセットの名前が、XLFD的に完全に指定された(つまり名前に*が含まれない)場合、あるいはエイリアスで指定された場合、フォントセットの生成に余計に時間がかかるようになり、メモリリークが発生する。また、Xlibのバージョンによっては、生成時にsegmentation faultが生じる場合もある。

バグの詳細についてはバグレポートを参照して欲しい。

対象となるXlib

X11R6.5.1よりも古いバージョン。XFree86では4.1.0よりも古いバージョン。

バグの再現

xfontset.tar.gzをダウンロードして、次のようにコマンドを実行する。

% tar zcvf xfontset.tar.gz
% cd xfontset
% xmkmf -a ; make
% setenv LANG ja_JP.EUC
% make test1
...
% make test2
...
% make test3
...

test1は省略を含むフォントセット名を、test2はエイリアスを、test3は省略のないフォントセット名を指定して、フォントセットの生成と解放を2回実行する。例えばXFree86 3.3.3では、make test1の出力は次のような結果になる。(a)と(b)の行の値が同一なので、メモリリークがないことがわかる。

% make test1
time ./xfontset "-misc-fixed-medium-r-normal--14-130-75-75-c-*-iso8859-1,-misc-f
ixed-medium-r-normal--14-130-75-75-c-*-jisx0208.1983-0,-misc-fixed-medium-r-norm
al--14-130-75-75-c-*-jisx0201.1976-0"
1 0
2 89900
3 94178
4 197145
3 94186 <--- (a)
4 197145
5 94186 <--- (b)
6 89930
        0.17 real         0.03 user         0.01 sys

しかし、make test2とmake test3の出力は次のような結果になる。(c)と(d)の行の値の差、および(e)と(f)の行の差がリークしたメモリの量を示している。

% make test2
time ./xfontset a14,k14,r14
1 0
2 89900
3 94178
4 197484
3 94693 <--- (c)
4 197783
5 94992 <--- (d)
6 90528
        0.61 real         0.01 user         0.03 sys
% make test3
time ./xfontset "-misc-fixed-medium-r-normal--14-130-75-75-c-70-iso8859-1,-misc-
fixed-medium-r-normal--14-130-75-75-c-140-jisx0208.1983-0,-misc-fixed-medium-r-n
ormal--14-130-75-75-c-70-jisx0201.1976-0"
1 0
2 89900
3 94178
4 197585
3 94622 <--- (e)
4 197884
5 94921 <--- (f)
6 90528
        6.36 real         0.02 user         0.02 sys

XIMサーバへの影響

この現象が表面化することは少ないだろう。なぜなら、ほとんどの場合Xクライアントが指定するフォントセット名には*が含まれるからである。

しかし、XIMサーバにとってこの問題は致命的である。XIMクライアントが使用するフォントセット名をXIMサーバに伝える過程は、次のようなものである。

  1. XIMクライアントがフォントセットを生成する。このときのフォントセットの名前はXLFD的に省略されていたり、エイリアス名が含まれている。
  2. XIMクライアントはXICの属性にフォントセットを設定する。
  3. XIMクライアントのXlibは、指定されたフォントセットから「完全なXLFD表記のフォントセット名」を生成して、XIMサーバに送信する。この時点で省略は補われ、エイリアスも展開されている。
  4. XIMサーバはXLFD的に完全なフォントセット名を受け取る。

したがって、次のような実装のXIMサーバを使用している場合、XIMクライアントがXICのフォントセット属性を設定する度に時間がかかったり、メモリリークが生じてしまう。

  • XIMクライアントから受け取ったフォントセット名をそのまま使用してフォントセットを生成する。XIMクライアントと接続が切れたら、生成したフォントセットを解放する。
  • フォントセット属性が変更されたら、以前のフォントセットを解放して、新しいフォントセットを生成する。

XIMクライアントのなかにはキャレットを移動する度にフォントセット属性を設定し直すものもあるので、後者の実装では極端に性能が劣化してしまう場合もある。

解決策

XIMサーバは一度生成したフォントセットを、すべてのXIMクライアントで共有するように実装するべきである。また過去のバージョンのXlibを使用している場合は、XIMクライアントと接続が切れたときに、どのXIMクライアントも使用していないフォントセットがあっても、それを解放しないようにした方がよいだろう。