XGetIMValues()が不正なアドレスをfree()に渡し、メモリをリークする。 - 症状 XGetIMValues()を呼び出して、XNQueryIMValuesListやXNQueryICValuesListな どの内部リソースを取得しようとすると、次のメッセージが表示される。 in free(): warning: chunk is already free. xc/lib/X11/imDefIm.cの関数_XimProtoGetIMValues()では、preplyを宣言する (1432行目)。lenが0でないとき、preplyは値を代入される(1493,1496,1499行 目)。しかし、lenが0のときはpreplyは不定なままreplyと比較され(1522行目)、 ほとんどの場合preplyはXfree()で解放される(1523行目)。 (なおXFree86-4.2.0以降では、この点については修正されている。) ... 1432 XPointer preply; ... 1475 if (len) { ... 1492 if(ret_code == XIM_TRUE) { 1493 preply = reply; 1494 } else if(ret_code == XIM_OVERFLOW) { 1495 if(len <= 0) { 1496 preply = reply; 1497 } else { 1498 buf_size = len; 1499 preply = (XPointer)Xmalloc(buf_size); ... 1506 } 1507 } else 1508 return arg->name; ... 1518 } ... 1522 if (reply != preply) 1523 Xfree(preply); また、作業用に確保したメモリを解放しないので、XGetIMValues()で内部リソー スを取得する度にメモリをリークする。xc/lib/X11/imDefIm.cの関数 _XimProtoGetIMValues()では、bufにbuf_sizeのメモリを確保する(1467行目)。 lenが0でないときはbufは解放される(1488行目)。しかし、lenが0のときは bufは解放されないまま関数から戻る(1526行目または1528行目)。 ... 1467 if (!(buf = (CARD8 *)Xmalloc(buf_size))) 1468 return arg->name; ... 1475 if (len) { ... 1488 Xfree(buf); ... 1518 } ... 1525 if (decode_name) 1526 return decode_name; 1527 else 1528 return makeid_name; ... - 再現 % cat Imakefile DEPLIBS = $(DEPXONLYLIB) LOCAL_LIBRARIES = $(XONLYLIB) SRCS = xgetimvalues.c OBJS = $(SRCS:.c=.o) ComplexProgramTarget(xgetimvalues) % cat xgetimvalues.c #include #include #include #include #include int main(void) { Display *disp; XIM im; XIMValuesList *vl; int k; char *p; if ((disp = XOpenDisplay("")) == NULL) { errx(1, "cannot open display."); } if (setlocale(LC_ALL, "") == NULL) { errx(1, "cannot set locale."); } if (XSupportsLocale() == False) { errx(1, "locale not supported."); } if (XSetLocaleModifiers("") == NULL) { errx(1, "cannot set locale modifiers."); } if ((im = XOpenIM(disp, NULL, NULL, NULL)) == NULL) { errx(1, "cannot open input method."); } printf("XNQueryIMValuesList:\n"); if ((p = XGetIMValues(im, XNQueryIMValuesList, &vl, NULL)) != NULL) { errx(1, "XGetIMValues(XNQueryIMValuesList): %s", p); } for (k = 0; k < vl->count_values; ++k) { printf("supported_values[%d]: %s\n", k, vl->supported_values[k]); } XFree(vl); printf("XNQueryICValuesList:\n"); if ((p = XGetIMValues(im, XNQueryICValuesList, &vl, NULL)) != NULL) { errx(1, "XGetIMValues(XNQueryICValuesList): %s", p); } for (k = 0; k < vl->count_values; ++k) { printf("supported_values[%d]: %s\n", k, vl->supported_values[k]); } XFree(vl); exit(0); return; } % コンパイルして実行する。 % xmkmf -a ; make ... % setenv MALLOC_OPTIONS A % ./xgetimvalues XNQueryIMValuesList: supported_values[0]: queryInputStyle XNQueryICValuesList: xgetimvalues in free(): error: chunk is already free. Abort (core dumped) % gdbでcoreをロードする。 % gdb xgetimvalues xgetimvalues.core GDB is free software and you are welcome to distribute copies of it under certain conditions; type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.16 (i386-unknown-freebsd), Copyright 1996 Free Software Foundation, Inc... Core was generated by `xgetimvalues'. Program terminated with signal 6, Abort trap. Cannot access memory at address 0x20064080. #0 0x200c23f1 in ?? () (gdb) bt #0 0x200c23f1 in ?? () #1 0x200c1c53 in ?? () #2 0x200c0632 in ?? () #3 0x200c0670 in ?? () #4 0x200c1683 in ?? () #5 0x200c190a in ?? () #6 0x39766 in _XimProtoGetIMValues (xim=0x5a300, arg=0x58ab0) at imDefIm.c:1524 #7 0x5967 in XGetIMValues () #8 0x1842 in main () (gdb) up 6 #6 0x39766 in _XimProtoGetIMValues (xim=0x5a300, arg=0x58ab0) at imDefIm.c:1524 1524 Xfree(preply); (gdb) list 1519 } 1520 decode_name = _XimDecodeIMATTRIBUTE(im, im->core.im_resources, 1521 im->core.im_num_resources, data, data_len, 1522 arg, XIM_GETIMVALUES); 1523 if (reply != preply) 1524 Xfree(preply); 1525 1526 if (decode_name) 1527 return decode_name; 1528 else (gdb) - 確認できるリリース R6.3p3 (XFree86-3.3.x) R6.4p3 R6.5.1 R6.6 - 修正されているリリース XFree86-4.2.0 (しかしメモリリークは直っていない) - 回避策 XGetIMValues()を使わない。 - 修正方法 R6.6に次のパッチを適用する。 diff -c -r -d xc.orig/lib/X11/imDefIm.c xc/lib/X11/imDefIm.c *** xc.orig/lib/X11/imDefIm.c Sun Jan 5 07:01:29 2003 --- xc/lib/X11/imDefIm.c Sun Jan 5 07:17:39 2003 *************** *** 1429,1435 **** INT16 len; CARD32 reply32[BUFSIZE/4]; char *reply = (char *)reply32; ! XPointer preply; int buf_size; int ret_code; char *makeid_name; --- 1429,1435 ---- INT16 len; CARD32 reply32[BUFSIZE/4]; char *reply = (char *)reply32; ! XPointer preply = NULL; int buf_size; int ret_code; char *makeid_name; *************** *** 1516,1525 **** data = &buf_s[2]; data_len = buf_s[1]; } decode_name = _XimDecodeIMATTRIBUTE(im, im->core.im_resources, im->core.im_num_resources, data, data_len, arg, XIM_GETIMVALUES); ! if (reply != preply) Xfree(preply); if (decode_name) --- 1516,1528 ---- data = &buf_s[2]; data_len = buf_s[1]; } + else { + Xfree(buf); + } decode_name = _XimDecodeIMATTRIBUTE(im, im->core.im_resources, im->core.im_num_resources, data, data_len, arg, XIM_GETIMVALUES); ! if (preply != NULL && reply != preply) Xfree(preply); if (decode_name)