[Gauche-devel-jp] [Mac OS X] Gauche.frameworkでsyslibdir/sysarchdirなどが正しく取得できない場合がある不具合の修正パッチ

Back to archive index

naoya_t naoya****@gmail*****
2008年 8月 22日 (金) 15:01:13 JST


naoya_tです。

来たる9月20日にアルクから出版される「英辞郎 第四版」にMac OS
X用検索ソフトとして拙作「DiDi」のカスタマイズ版が同梱されるのですが、Cocoa(Objective-C)にGauche.frameworkをバンドルして使わせて頂いております。
(特に検索条件文をパースして、マッチ判定関数にコンパイルする辺りでGaucheが活躍しています)

開発中に以下のような不具合を発見しましたので、修正のためのパッチを送らせて頂きます。
・sitelibdir は正しくフルパスに展開されるのに、syslibdir は ./share/gauche/0.8.13/lib
のように展開され、結果としてライブラリファイルが読み込めない
・sysarchdir も同様に ./lib/gauche/0.8.13/i386-apple-darwin8 のように展開されてしまうため
dynamic-load に失敗し、can't find dlopen-able module "srfi-1-lib"
のようなエラーが出まくる
・なぜか Intel Mac, OS X 10.4.x に限って発生し、PowerPC ないし Leopard上では再現しない

原因箇所は src/getdir_darwin.c の
get_install_dir()関数なのですが、CFBundleGetBundleWithIdentifier()で取得したbundleオブジェクトをCFRetain()していないのにCFRelease()しているため二重解放になっていて、その結果初回(sitelibdirの展開時)にはバンドルが取得できるものの次のsyslibdir展開時にはNULLが返り、暫定出力の
"." が返されていました。

本来どのCPU、どのOSバージョンで出てもおかしくないのですが、不思議なことに Mac OS X 10.4.x で Intel Mac
の場合に限ってこの問題が発生していました。

;; この問題の原因究明にあたり、REPLが使える便利さを実感しました。

以下のコードでは error: 以下にエラー時の対応をまとめたりしていますが、ここでどうしてもやるべきなのは
 CFRetain(bundle);
の1点です。あとはshiroさんの判断におまかせします。

--- src/getdir_darwin.c.orig    2005-10-24 10:37:21.000000000 +0900
+++ src/getdir_darwin.c 2008-08-22 13:45:57.000000000 +0900
@@ -22,36 +22,57 @@
 static int get_install_dir(char *buf, int buflen,
                            void (*errfn)(const char *, ...))
 {
-    CFBundleRef bundle;
-    CFURLRef bundleURL;
-    CFStringRef bundlePath;
+    CFBundleRef bundle     = NULL;
+    CFURLRef    bundleURL  = NULL;
+    CFStringRef bundlePath = NULL;

     bundle = CFBundleGetBundleWithIdentifier(CFSTR(LIBGAUCHE_ID));
     if (bundle == NULL) {
         /* This call fails when gosh is called during the build process
            (thus, the framework hasn't been created).  For the time
            being, we just return a dummy directory. */
-        strcpy(buf, ".");
-        return 1;
+        goto error;
     }
+    /* Ownership of bundle follows the Get Rule of Core Foundation.
+       ie. we must claim ownership (with the CFRetain function).
+       We are then responsible for relinquishing ownership when we
have finished with it. */
+    CFRetain(bundle);
+
     bundleURL = CFBundleCopyBundleURL(bundle);
     if (bundleURL == NULL) {
         errfn("CFBundleCopyBundleURL failed");
+        goto error;
     }
+    /* Ownership of bundleURL follows the Create Rule of Core Foundation.
+       ie. it is our responsibility to relinquish ownership (using
CFRelease) when we have finished with it. */
+
     bundlePath = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
     if (bundlePath == NULL) {
         errfn("CFURLCopyFileSystemPath failed");
+        goto error;
     }
+    /* Ownership follows the Create Rule. */
+
     if (!CFStringGetCString(bundlePath, buf, buflen, kCFStringEncodingUTF8)) {
         errfn("CFStringGetCString failed");
+        goto error;
     }
     if (strlen(buf) + strlen(SUBDIR) + 1 >= buflen) {
         errfn("pathname too long");
+        goto error;
     }
+
     strcat(buf, SUBDIR);
     CFRelease(bundlePath);
     CFRelease(bundleURL);
     CFRelease(bundle);
     return strlen(buf);
+error:
+    /* For the time being, we just return a dummy directory. */
+    strcpy(buf, ".");
+    if (bundlePath) CFRelease(bundlePath);
+    if (bundleURL) CFRelease(bundleURL);
+    if (bundle) CFRelease(bundle);
+    return 1;
 }


--------
naoya_t / Naoya Tozuka
E-mail: naoya****@gmail*****




Gauche-devel-jp メーリングリストの案内
Back to archive index