From: "とみたまさひろ" Date: 2007-11-15T08:19:13+09:00 Subject: [ruby-dev:32296] CGI::Session::FileStore のデータが壊れる とみたです。 1.8.6 で CGI::Session::FileStore のデータが壊れることがあります。 * LOCK_EX を獲得できてないのにファイルの内容を消している。 412: f = File.open(@path, File::CREAT|File::TRUNC|File::RDWR, 0600) 413: f.flock File::LOCK_EX * finalizer から呼ばれる時、ファイルの内容が中途半端になることがある。 こっちの原因は良く分かりませんが、@hash の内容をファイルに出力している 時に何かが起きて途中までになってしまうようです。CGI が終了しないうちに ブラウザが別のリンクを押した等で、CGI が SIGPIPE になった場合に発生する みたいです。 ということで、次のようにしてみたらうまく動いているようです。 --- session.rb.orig 2007-02-13 08:01:19.000000000 +0900 +++ session.rb 2007-11-15 07:49:17.000000000 +0900 @@ -391,8 +391,9 @@ unless @hash @hash = {} begin + lockf = File.open(@path+".lock", "r") + lockf.flock File::LOCK_SH f = File.open(@path, 'r') - f.flock File::LOCK_SH for line in f line.chomp! k, v = line.split('=',2) @@ -400,6 +401,7 @@ end ensure f.close unless f.nil? + lockf.close if lockf end end @hash @@ -409,13 +411,17 @@ def update return unless @hash begin - f = File.open(@path, File::CREAT|File::TRUNC|File::RDWR, 0600) - f.flock File::LOCK_EX + lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600) + lockf.flock File::LOCK_EX + f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600) for k,v in @hash f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v)) end + f.close + File.rename @path+".new", @path ensure - f.close unless f.nil? + f.close if f and !f.closed? + lockf.close if lockf end end @@ -426,6 +432,8 @@ # Close and delete the session's FileStore file. def delete + File::unlink @path+".lock" rescue nil + File::unlink @path+".new" rescue nil File::unlink @path rescue Errno::ENOENT end -- とみたまさひろ 3469 42CC 4D32 F53C AD98 65A5 8C37 FF09 69C1 6040