ソフトウェアエンジニア現役続行

雑多なことを綴ります

DBD::SQLite-1.14に関数が戻ってこない不具合がある

Unix環境でperlのDBD::SQLite-1.14の関数を使ってsqlite3につなぐと、関数から戻ってこない不具合が起こることがあります。DBD::SQLite 1.14はCent OS 5.1に標準で入っているバージョンです。

再現プログラムは↓


use DBI;
DBI->connect('dbi:SQLite:dbname=/tmp/foo.sqlite', "", "");

このプログラムをulimit -vで仮想メモリを制限しながら実行します。すると、ある仮想メモリの大きさで実行すると、DBI->connect()から戻ってこないことがあります。その仮想メモリの大きさは、実行する環境によって変わります。

straceでシステムコールを追ったり、DBD::SQLite-1.14のソースコードを読み進めていって、DBD::SQLite-1.14のos_unix.cの中でpthread_create()に失敗したときのエラーハンドリングをしていないことに問題があることが分かりました。

os_unix.cの520行目のあたり↓


pthread_create(&t[0], 0, threadLockingTest, &d[0]);
pthread_create(&t[1], 0, threadLockingTest, &d[1]);
pthread_join(t[0], 0);
pthread_join(t[1], 0);

pthread_create()に失敗してもpthread_join()が呼ばれるため、t[0]のメモリの値によっては、ここでfutexロックがかかったまま固まってしまいます。

修正patchを提供しようと思いましたが、2011年01月15日の時点でのDBD::SQLiteの最新バージョンは1.31であり、このバージョンでは実装が大きく変更されていて、pthread_create()も呼ばれていないため、本家にpatchを提供するわけにもいかず。。。

簡単にこの不具合を解消するには、例えば以下のようにします。これでpthread_create()に失敗したときに固まらずにエラー終了してくれます。


int rc;
rc = pthread_create(&t[0], 0, threadLockingTest, &d[0]); assert(rc == 0);
rc = pthread_create(&t[1], 0, threadLockingTest, &d[1]); assert(rc == 0);
pthread_join(t[0], 0);
pthread_join(t[1], 0);