/ 最近 .rdf 追記 設定 本棚

脳log[Ruby: 2009-06-15~]



2009年06月15日 (月) 新はてブ。やっとヘッダの fixed/scroll状態を覚えるようになってスクロールが快適だけど。ピンの表示が間違ってる。

[Ruby] Dir.globと Dir.entries

globできない。どういうこと?

irb> Dir.glob("\\\\LS-WSGL420\\MediaLibrary\\*")
=> []
irb> Dir.entries("\\\\LS-WSGL420\\MediaLibrary")
=> [".", "..", "anime", "music"]

こういうことだった。

irb> Dir.entries("//LS-WSGL420/MediaLibrary/*")
=> ["//LS-WSGL420/MediaLibrary/anime", "//LS-WSGL420/MediaLibrary/music"]

DropHandlerから渡されたファイルパスは置換しなければいけない、と。


2009年06月14日 (日)

最終更新: 2009-09-06T20:33+0900

[Ruby] ruby-mp3info (version 0.6.13, 2009-05-26) を使ってみて。

 入手先とドキュメント

チキンなので日記に書きますよ。

 Mp3Info#renameがまるで使えない。

mp3info.rbの中でこのように File.writable? でチェックしているから、renameで @filenameを書きかえていてファイルが存在しないとエラーになる。

      raise(Mp3InfoError, "file is not writable") unless File.writable?(@filename)

ここを乗り越えても

          file.seek(-TAG1_SIZE, File::SEEK_END)

ファイル末尾から TAG1_SIZEバイト戻ることができなくてエラー。だってそれは新しく作ったサイズ 0 のファイルだから。

 yearと tracknumを 0 にされる。

I氏のつぼでタグを書き込んでいると、この二つのタグも他と同じく BOM付き UTF-16LE文字列になっているので、mp3info.rbのこの部分で BOMを数字にしようとして 0 になる。

            if %w{year tracknum}.include?(key)
              @tag[key] = tag_value.to_i
            end

 タイトルなど文字列の最後の一文字が消える。

おそらく mp3info/id3v2.rbのこの部分

        # remove padding zeros for textual tags
        out.sub!(/\0*$/, '')

この処理で outのサイズが奇数バイトになることがあって、さらに NKFが末尾の半端な 1バイトを無視するからではないかと。

あと、/\0*$/ というパターンは /\0+$/ でいいんじゃないかな(空文字列を空文字列に置換することもないし)。あとあと、$ でなく \z を使うとか。


(途中なので)メッセージだけ表示してタグの書き込みはしないでおこうと思っていたら、unless と書くべきところが if になっていて広範囲に mp3ファイルを書きかえてしまった。そしたらエクスプローラでジャンルやアルバム、アーティストなどの読み込みと書き込みができなくなってしまった。むむう。


2009年05月26日 (火) レンタルサーバーに /usr/local/bin/ruby18 というリンクがある。/usr/local/bin/rubyが 1.9になるのはいつになるだろう。

最終更新: 2009-09-02T23:17+0900

[Ruby] サクラのレンタルサーバーで OSのバージョンアップがあって、エラー。

/usr/local/lib/compat/libpthread.so.2: Undefined symbol "__malloc_lock" (RuntimeError)
/usr/local/lib/ruby/1.8/dl/import.rb:29:in `initialize'

Rubyは 1.8.6 p287だから新しくなってないのだけど。OSが今日の早くに FreeBSDの 6.1から 7.1へ。そしてエラー。

DLを使ってるのは sqlite3-rubyだろうなあ。


Undefined symbol "__malloc_lock"で検索したら Tracが動かなくなった人が見つかった。この人は万事解決といかなかったみたいだけど、自分は libsqlite.soをコンパイルし直したらうまくいった。Rubyや DLの問題ではなく sqliteライブラリの依存関係が原因だったよう。再コンパイルは UNIX系OSのバージョンアップにはつきものの作業なんだろうか。


2009年03月06日 (金)

[Ruby][tDiary] > tDiary: ニコ動プラグインが動いてない? - ただのにっき(2009-03-05)

試してみた。SecurityErrorが出た。リンク先の ruby-1.9.1とは違い、こちらは ruby-1.8.7-p72でのエラー内容。

>irb
irb(main):001:0> require 'open-uri'
=> true
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> open 'http://vvvvvv.sn25p.dip.jp/301.rb'
SecurityError: Insecure operation - []
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:577:in `[]'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:577:in `find_proxy'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:147:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:164:in `call'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:164:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:162:in `catch'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:162:in `open_loop'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:132:in `open_uri'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:518:in `open'
        from C:/Program Files (x86)/ruby/lib/ruby/1.8/open-uri.rb:30:in `open'
        from (irb):3
irb(main):004:0>

301.rbはこう。

#!ruby
require 'cgi'
cgi = CGI.new;
print cgi.header({
	'Status' => '301 Moved Permanently',
	'Location' => 'http://vvvvvv.sn25p.dip.jp/index.html'
});

ホストネームを指定しない場合は大丈夫だった。例えばこんな。

#!ruby
require 'cgi'
cgi = CGI.new;
print cgi.header({
	'Status' => '301 Moved Permanently',
	'Location' => '/index.html'
});

どこまで by designなんだろう。


2009年02月23日 (月)

[Ruby][tDiary] 続報・ruby-1.9.1で、不思議で困ったことが起こった

問題のコード(再掲)はこれ。あるハッシュのキーについて繰り返しているのに、ハッシュにそのキーが存在しない。(すべてのキーが見つからないわけではないが、見つからないキーはいつでも見つからない)

categorized.keys.each do |c|
	PStore.new(cache_file(c)).transaction do |db|
		categorized.fetch(c) #=> key not found (KeyError)
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

fetchをブロックの最初に持って行くと、そこではエラーにならない。

categorized.keys.each do |c|
		categorized.fetch(c) #=> O.K.
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

cache_file(c)の呼び出しが原因。その中でも includeしてある ERB::Utilの u()メソッドが核心。

categorized.keys.each do |c|
		::ERB::Util.u(c)
		categorized.fetch(c) #=> key not found (KeyError)
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

引数にした文字列のエンコーディングが変わってしまっている。

categorized.keys.each do |c|
		enc1 = c.encoding;
		::ERB::Util.u(c)
		enc2 = c.encoding
		categorized.fetch(c) { raise "#{enc1} #{enc2} #{::ERB.version}" } #=> UTF-8 ASCII-8BIT erb.rb [2.1.0 2009-01-11] (RuntimeError)
	PStore.new(cache_file(c)).transaction do |db|
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

ERB::Util.url_encodeの定義を見ると、引数の文字列を dupした後にエンコーディングを変更しているにも関わらず、呼び出し元に影響を与えてしまっている。

    def url_encode(s)
      s.to_s.dup.force_encoding("ASCII-8BIT").gsub(/[^a-zA-Z0-9_\-.]/n) {
        sprintf("%%%02X", $&.unpack("C")[0])
      }
    end
    alias u url_encode

そんなわけだから呼び出し側(category.rb)で

u( c.dup )

なんてやっても効果はなく、

u( ""+c )

あるいは

u( "#{c}" )

とやって初めて、今回の現象を回避することができた。

これは、文字列の複製を遅らせた結果、期せずしておこった現象にみえる

バグのはずなんだけど、irbで再現しようと思ってもできないんだこれが。


 追記@2009-08-13: 見る人が見れば修正はあっという間でした。

http://redmine.ruby-lang.org/issues/show/1929

(ここに、見るべき場所を見つけることもできなかった人間がひとり)

* 正しくは ruby-1.9.2dev(2009-02-03)


2009年02月15日 (日) 本文中の URL自動リンクがセミコロンで切れていたので、/shjs/lang/sh_ruby.jsと /shjs/lang/sh_javascript.jsを修正した。そこで使っていた正規表現は『詳説 正規表現 第3版』で、大抵の場合うまくいくと紹介されていたものでした。(CGIパラメータを ; で区切るのはいまだに異端でしたか)

[Ruby][tDiary] ruby-1.9.1*で、不思議で困ったことが起こった。

この断片で理解してもらえるだろうか。

categorized.keys.each do |c|
	PStore.new(cache_file(c)).transaction do |db|
		categorized.fetch(c) #=> key not found (KeyError)
		db['category'] = {} unless db.root?('category')
		db['category'].update(categorized[c])
	end
end

あるハッシュのキーについて繰り返しているのに、ハッシュにはそのキーが存在しないという、この不思議。

このとき、c は、

"\xE6\x9C\xAC\xE6\x97\xA5\xE3\x81\xAE\xE8\xB3\xBC\xE5\x85\xA5" ASCII-8BIT

ハッシュのキーリストとそのエンコーディングは、

"\xE6\x9C\xAC\xE6\x97\xA5\xE3\x81\xAE\xE8\xB3\xBC\xE5\x85\xA5" ASCII-8BIT
"本" UTF-8
"マンガ" UTF-8
"雑誌" UTF-8

存在しているだろうに……。

 追記@2009-02-20: 同じ目に遭っている人がいた。

さくらインターネット上で tDiary を ruby1.9.1-p0 で動かす - まちゅダイアリー(2009-02-19)(14:57現在、日別表示が不可能な状態。最新表示は可能)

* 正しくは ruby-1.9.2dev(2009-02-03)

最終更新: 2009-08-29T06:18+0900

[HTML][Ruby] 中途半端なメソッドは提供しないのもまた親切なのでは? > URI.escape

> URI.escape("http://exmaple.com/foo bar?a=b=c;d=e#hoge#fuga")
=> "http://exmaple.com/foo%20bar?a=b=c;d=e%23hoge%23fuga"

URLをパーツに分解せずに gsub一発でエスケープ(エンコード)するなんて不可能だと思うのです。仮にそうまでしても、上の例のように、「#」が CGIパラメータとして受け渡されるように、「%23」にエンコードするべきか、URLを構成する fragmentを示す記号として、「#」のまま残すべきか、判断できない(でしょう?)。

できないことをできるかのように見せかけるより、できない(のでメソッドを提供しない)という方が親切だと思う。

JavaScriptの提供する encodeURIComponent(「/」も「?」も「#」も「=」もエンコードするメソッド)相当のメソッドがあれば、それで十分だと思うんだけど。

 つぶやき

http://exmaple.com/foo bar/baz/

なんてのは不正な URLだから、どこにも存在しないのです。アドレスバーに表示するときに人間に読みやすいように、と上のようにデコードして表示することはあるかもしれないけれど、オリジナルの正しい URLは同時に保持しておくべきで、表示用の文字列からエンコードしようなんて思っちゃダメなのです。ブラウザのアドレスバーは表示と同時に編集も可能だから話は簡単ではないけど……これまでのところ、Firefoxは(自らの責任で)よきに計らってくれています。

RFC(古いのと新しいのと二種類?)も読んでいない放言なので、実は「できる」という可能性がなきにしもあらず。


[ruby-dev:39188] Re: URI.escape_component から、

 さておき、URI.escapeは独特の動きをするので、JavaScript/ECMAScript の
 escape とも encodeURI とも encodeURIComponent とも違います。

 そういえば、現在の仕様の意図をお聞きしたかったんだった
 [ruby-dev:38124]

 なお、面倒な話が出てきた時には、とりあえず akr さんが
 既に取り上げていないか調べるわけですが、やっぱり扱っているわけです。
 http://www.a-k-r.org/d/d2004_07.html
 https://www.codeblog.org/blog/akr/20070222.html

2009年02月02日 (月) [Vista] リソース モニタのキーボードインターフェイス: P(CPU項目を展開)、D(ディスク項目を展開)、N(ネットワーク項目を展開)、M(メモリ項目を展開)、L(全て展開)、Shift+P,D,N,M,L(それぞれの項目を展開、折り畳み切り替え)

[Ruby][tDiary] tDiaryは、1.9系の Rubyでは 1.9.2から動くようになるのか。

やっぱり nobuさんがやってくれました。

requireの処理の中で、セーフレベルを一時的に 0 に下げる部分があって、この範囲を広げることで、SecurityErrorが出ないようになっていた。(3日前)

画像は、tDiaryの amazon.rbが、リポジトリから持ってきただけの素の Ruby-1.9.2dev(2009-02-03)上で動いているところ。

既に正式版がリリースされて*しまって*いる Ruby-1.9.1との違いを、先月の日記に書いた例で見ていくと、

 $SAFE=1で、カレントディレクトリのスクリプトを requireしたとき

irb192> RUBY_DESCRIPTION
=> "ruby 1.9.2dev (2009-02-03) [i386-mswin32_90]"
irb192> $SAFE=1
=> 1
irb192> require "a"
SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192> require "a.rb"
SecurityError: cannot load from insecure path - Y:/.../Desktop/a.rb
        from (irb):4:in `require'
        from (irb):4
        from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192>

2009-02-03版の ruby-1.9.2devでは、$SAFE=1のとき、カレントディレクトリのスクリプトを requireできない。これは $:($LOAD_PATH)に汚染されていない "." が含まれていようと、require の引数の文字列が汚染されていなかろうと、requireできない。見つけた抜け道は、絶対パスで requireするか、$:($LOAD_PATH)にカレントディレクトリを絶対パスで追加すること("."が含まれる場合はそれより前に追加する必要もある)。

ruby-1.9.1の結果は Release Candidateのときと変わらず、

irb191> RUBY_DESCRIPTION
=> "ruby 1.9.1p0 (2009-01-30 revision 21907) [i386-mswin32]"
irb191> $SAFE=1
=> 1
irb191> require "a"
SecurityError: Insecure operation - require
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> require "a.rb"
a.rb required.
=> true
irb191>

ruby-1.9.1では、拡張子を付けてやるとカレントディレクトリのスクリプトも requireできる。拡張子を付けないときに requireできないのは ruby-1.9.2devも同じだが 、ruby-1.9.1には ruby-1.9.2devにない爆弾がある。$SAFE=1のときの拡張子を付けない requireは、添付ライブラリの requireであっても失敗したりする。

irb191> $SAFE=1
=> 1
irb191> require "stringio"
SecurityError: Insecure operation - require
        from (irb):2:in `require'
        from (irb):2
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> require "stringio.so"
=> true
irb191>

これが原因で、tDiaryを ruby-1.9.1で動かすのは絶望的だと思っている*。(ruby-1.9.1はリリースされちゃったし、スクリプトで対応できる範囲を超えているから)

この部分は SecurityErrorが出ない方向に修正されると思っていたから、ruby-1.9.2devで両方のパターンが SecurityErrorになったのは意外。

 $SAFE=1で、汚染されたパスが $:($LOAD_PATH)に含まれるとき

ruby-1.9.2devでは、汚染されたパスが $:($LOAD_PATH)のどの位置にあるかが重要。

irb192> $SAFE=1
=> 1
irb192> $:.unshift "!tainted!".taint
=> ["!tainted!", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", "."]
irb192> require "cgi"
SecurityError: cannot load from insecure path - Y:/.../Desktop/!tainted!/cgi.rb
       from (irb):3:in `require'
       from (irb):3
       from C:/Program Files (x86)/ruby/bin/irb192.bat:20:in `<main>'
irb192> $:.push $:.shift
=> ["C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby/1.9.2/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby192/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2", "C:/Program Files (x86)/ruby/lib/ruby192/1.9.2/i386-mswin32_90", ".", "!tainted!"]
irb192> require "cgi"
=> true
irb192>

ruby-1.9.2devでは、$SAFE=1で、汚染された LOAD_PATHからスクリプトを requireすることはできないが、汚染されていない LOAD_PATHからスクリプトを先に見つけた場合は、requireに成功する。ruby-1.9.1(とruby-1.8.7-p72)ではどうだったかというと、より厳しくて、

irb191> $SAFE=1
=> 1
irb191> $:.unshift "!tainted!".taint
=> ["!tainted!", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", "."]
irb191> require "cgi"
SecurityError: Insecure operation - require
        from (irb):3:in `require'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191> $:.push $:.shift
=> ["C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/site_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby/1.9.1/i386-msvcrt", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1", "C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/i386-mswin32", ".", "!tainted!"]
irb191> require "cgi"
SecurityError: Insecure operation - require
        from (irb):5:in `require'
        from (irb):5
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:20:in `<main>'
irb191>

ruby-1.9.1では、汚染されたパスが一つでも $:($LOAD_PATH)に含まれると、(相対パスでの) requireはできない。絶対パスならできるが、そんな書き方はしないので $:($LOAD_PATH)に追加するパスは常に untaintしなければならない。

 ruby-1.9.2dev(2009-02-03)は概ね期待通りの動作だが……

requireしたときのカレントディレクトリの扱いに、不満が残る。

多分、従来の Ruby、ruby-1.9.1や ruby-1.8.7は $:($LOAD_PATH)の要素の汚染状況なんて気にしていなかった。$:に含まれるか含まれないかだけが重要。2005年から現在まで変わっていない、リファレンスマニュアルのこの記述がそれを物語っていないか。

Level 1以上では起動時に以下の違いがある

  • 環境変数 RUBYLIB を $: に加えない
  • カレントディレクトリを $: に加えない
  • (以下略)

その方針に異議を唱えるものではないけれど、この方式には、セーフレベルによる分岐が起動時に限定されるという制限がある。コマンドラインオプション -T を指定したときにしか有効にならず、$SAFEを使ってセーフレベルをコントロールするシナリオでは機能しない。

ruby-1.9.2devは、$:($LOAD_PATH) の要素の汚染状況に注目することで、$SAFEを使ってセールレベルをコントロールする場合でも「環境変数 RUBYLIB を $: に加えない」「カレントディレクトリを $: に加えない」のと同等の制限を課せる可能性を持っている。つまり、「環境変数RUBYLIBとカレントディレクトリは常に $:($LOAD_PATH)に追加される。ただし汚染された状態で。」ということ。

それなのに現在の ruby-1.9.2devの、$SAFE=1の下での requireに対するカレントディレクトリの扱いは、ruby-1.8.7より、むしろ退化している。

ruby-1.8.7では $:($LOAD_PATH)に "." を追加したり取り除いたりすることでカレントディレクトリの扱いを、セーフレベルによらず、スクリプトがコントロールできた。

拡張子の有無で結果が変わる、動作に筋の通らない ruby-1.9.1の requireは論外として、

ruby-1.9.2devでは、カレントディレクトリのスクリプトの requireは $:($LOAD_PATH)によらず、SecurityErrorになる。カレントディレクトリを絶対パスで $:($LOAD_PATH)に追加することでコントロール可能だが、既に含まれているかもしれない "." が邪魔をする。ruby-1.9.2devは、$:($LOAD_PATH)に含まれる "." の汚染状況(あるいは "."が $:に含まれないこと)によってのみカレントディレクトリの扱いを変えるべきで、カレントディレクトリが特別に SecurityErrorになる、現在の ruby-1.9.2devには同意できない。

セールレベル1ではまだスクリプトを信用しているのだから、少なくとも ruby-1.8.7と同等のコントロールをスクリプトに渡して欲しい。

requireが利用する File.expand_pathの仕様によりカレントディレクトリからの相対パスが汚染されるのだろうが、File.expand_pathは requireが $:($LOAD_PATH)に依拠していることを知らないのだから requireが何とかすべき。

* その後の変更で、ruby-1.9.1らしき挙動の requireを検出したときはセーフレベルを 1から 0に下げてプラグインを実行することになっている。セーフレベル0なら今回のことは関係ないから。セーフレベルを下げるという発想は全く頭になかった。なんか、こう、負けた気がするからだろう。ruby-1.9.0だとセキュアモード(セーフレベル4)で動かないという話もあったけどどうなったんだろう。


2009年01月19日 (月) Wassrという Webサービスがあって、そこに tDiaryというチャンネルがあって、Firefoxにはライブブックマークとかいうものがあって、と、いろいろなものを発見。(コミットログの確認が svk sync + viewvcより簡単だ。古い記事がちょこちょこ投稿されると思ったら delicious..から tDiaryタグの付いた URLを拾っているとか。ほへー)

[Ruby][tDiary] requireと $SAFE=1と汚染された $LOAD_PATH

>irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]"
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> $:.unshift "hoge".taint
=> ["hoge", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8",..., "."]
irb(main):004:0> require 'cgi'
SecurityError: Insecure operation - require
        from (irb):4:in `require'
        from (irb):4
        from :0
irb(main):005:0>

1.8.7でもこうなのだから知らない俺が抜けているのだが、$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)と、一切の requireができなくなる。

期待したいのは、hoge/cgi.rbや hoge/cgi.soなどが存在するときには、このパスは汚染されているので SecurityError。存在しないときはファイルの探索を続けて C:/Program Files (x86)/ruby/lib/ruby/1.8/cgi.rb (このパスは汚染されていないはず)を読み込む、という動作なのだけど……。

実際はそうではないのだから tDiaryの

tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' )

というのは __FILE__ が汚染されているときに、わりと危険な操作ということになる。問題が起きないのは SAKURAのレンタルサーバの Rubyが 1.8.6だからなのか、__FILE__、File.dirname(__FILE__) が汚染されていることが稀だからなのか。(汚染されていることが実際にあるのは、20090117p01で書いたように、untaintすることで状況が改善したことから推測できる)


問題が起きないのは SAKURAのレンタルサーバの Rubyが 1.8.6だからなのか、__FILE__、File.dirname(__FILE__) が汚染されていることが稀だからなのか。

両方でした。__FILE__が汚染されているのは Ruby-1.9.1RC1だから(多分)。


$SAFE=1のときに汚染された文字列を $LOAD_PATHに追加する(pushでも unshiftでも)と、一切の requireができなくなる。

書きながら誇張だとは気付いていたのだけど(一切の、の部分が)、そうでない例を自分で見つけたので追記(2009-02-02)。

Windowsで、フルパスで、あるいは拡張子(.rb)なしのフルパスでなら requireできる。

Y:\...\Desktop\a>irb
irb(main):001:0> RUBY_DESCRIPTION
=> "ruby 1.8.7 (2008-05-31 patchlevel 0) [i386-mswin32_90]"
irb(main):002:0> $SAFE=1
=> 1
irb(main):003:0> $:.push "".taint
=> ["C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/site_ruby", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby/1.8/i386-msvcr90", "C:/Program Files (x86)/ruby/lib/ruby/vendor_ruby", "C:/Program Files (x86)/ruby/lib/ruby/1.8", "C:/Program Files (x86)/ruby/lib/ruby/1.8/i386-mswin32_90", ".", ""]
irb(main):004:0> require "a"
SecurityError: Insecure operation - require
        from (irb):4:in `require'
        from (irb):4
        from :0
irb(main):005:0> require "a.rb"
SecurityError: Insecure operation - require
        from (irb):5:in `require'
        from (irb):5
        from :0
irb(main):006:0> require "./a.rb"
SecurityError: Insecure operation - require
        from (irb):6:in `require'
        from (irb):6
        from :0
irb(main):007:0> require "Y:/.../Desktop/a/a"
=> true
irb(main):008:0> require "Y:/.../Desktop/a/a.rb"
=> false
irb(main):009:0> require "a"
SecurityError: Insecure operation - require
        from (irb):9:in `require'
        from (irb):9
        from :0
irb(main):010:0>

2009年01月17日 (土)

[Ruby][tDiary] 昨日(「引き続き rexml/source.rb:16の requireが SecurityErrorになる原因を探る」)の続き。

step1 load.c:147 (rb_feature_p)
   if (!load_path) load_path = rb_get_expanded_load_path();
step2 load.c:44 (rb_get_expanded_load_path)
   VALUE path = rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil);
step3
   Insecure Operation - require (SecurityError)

いました。Ruby1.9.1で SecurityErrorを量産する rb_get_expand_path()が。どうも、汚染された load_pathの一つを展開しようとして SecurityErrorになってる気がする。


$:($LOAD_PATH)の要素が汚染されてるのは、こちらの責任では?と思って確かめてみた。

SecurityErrorの直前で、$:の各要素が tainted?かどうかを TDiary::Config#debugを使って出力した結果。

D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : false Y:/server_root/www/ds14050/tdiary_on_ruby191
D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : true Y:/server_root/www/ds14050/tdiary_on_ruby191/misc/lib
D, [2009-01-17T23:36:46.289008 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby/1.9.1
D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby/1.9.1/i386-msvcr90
D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/site_ruby
D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby/1.9.1
D, [2009-01-17T23:36:46.289985 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby/1.9.1/i386-msvcr90
D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/vendor_ruby
D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/1.9.1
D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false C:/Program Files (x86)/ruby/lib/ruby19/1.9.1/i386-mswin32_90
D, [2009-01-17T23:36:46.290961 #1212] DEBUG -- : false .

ひとつ、ありましたね。tDiaryが該当パスを $LOAD_PATHに挿入する部分で、下のように untaintをつけるだけで理不尽な SecurityErrorが解決しました。(ただし、ASRでは依然 SecurityErrorになる。解決したのは、20090116p01で書いたように、load.cの 501行目をコメントアウトした Ruby-1.9.1RC1での話)

-tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ) + '/misc/lib' )
+tdiary.rb:12: $:.insert( 1, File::dirname( __FILE__ ).untaint + '/misc/lib' )

今回の一連の流れ(20090113p0120090114p0120090116p01)で、$SAFE=1が、SecurityErrorで使い物にならなくなる(>添付ライブラリの requireにも失敗する)、二つのルートが見つかった。それらは requireするライブラリの拡張子を明示したり、$LOAD_PATHの中身をすべて untaintすることで回避できたり、load.cの一行をコメントアウトしたりで回避できたが、スクリプトで対処すべきものではないと考える。file_expand_pathが $SAFE>0のとき、汚染された入力を一切受け付けないという前提のもと、(rb_)file_expand_pathを呼び出しているコードを見直すか、file_expand_pathが汚染された入力を受け入れて適切に処理するか、どちらかの変更が必要だと思う。「file_expand_path()の結果が汚染された入力や $LOAD_PATHの汚染された一要素に基づくとき、その展開されたパスも汚染されている。」「$SAFE=1のとき、最終的に requireするファイルのパスが、汚染された引数や、$LOAD_PATHの汚染された要素に基づくとき、SecurityError。」というのではいけないのだろうか。Ruby-1.8.7はそのへんうまくやっているのだが……。

改めてドキュメントを読んだら、汚染された文字列を引数にした Fileのクラスメソッド、インスタンスメソッドは禁止されていた。($SAFE=1のとき)

ドキュメントに従うなら rb_file_expand_pathが SecurityErrorを出すのは正しいのかも(Ruby-1.8.7がまちがっている)。それならば、$LOAD_PATHの汚染された要素を不用意に展開しようとして SecurityErrorを出したり(load.c:44:rb_get_expanded_load_path)、もともと汚染されていなかった文字列を複数回展開しようとして SecurityErrorを出したり(load.c:501:search_required)するほうを修正しなければ。

私見では、(最下層で実際の仕事を行う)file_expand_pathは汚染フラグを適切に伝播させるものの SecurityErrorは出さないでおき、(スクリプトから呼ばれる)File.expand_pathの実体である rb_file_s_expand_pathか、file_expand_pathに仕事を丸投げする rb_file_expand_pathでセーフレベルに基づくチェックを行うのが、呼び出し側にとって便利だと思う。

tDiaryのプラグインの recent_list.rbを書き換えたのは、今思えば不要だったみたいだ。(Rubyの方が変わるに違いないもの)


2009年01月16日 (金)

[Ruby][tDiary] Ruby1.9.1RC1で「Insecure Operation - require (SecurityError)」が頻発する原因。

20090113p0120090114p01で発生したエラーを起こす最小のスクリプトとそれを回避する方法。

>type a.rb
puts "a.rb required."

>ruby19 -v
ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32_90]

>ruby19 -e "$SAFE=1; require 'a'"
-e:1:in `require': Insecure operation - require (SecurityError)
        from -e:1:in `<main>'

>ruby19 -e "$SAFE=1; require 'a.rb'"
a.rb required.

二つの違いは requireするライブラリの拡張子(.rb)を明示しているかどうか。拡張子なしの場合に発生する SecurityErrorは間違いだと思う。そうでないと $SAFE = 1がまるで使い物にならない。添付ライブラリだってまともに動かなくなるんだから。

ところで、Ruby 1.9 - 1.9.1 RC2 issues - Ruby Issue Tracking Systemにはチケットを作成するためのフォームがない。ruby-dev MLはアーカイブをときどき閲覧しているが購読はしていない。是非ともこの SecurityErrorは消して欲しいのだが、報告を受け付ける間口が狭い。直通ルートがない。どうすべ。


どうすべ、と言ってる間に原因究明。

 load.c:500: type = rb_find_file_ext(&tmp, loadable_ext);
 load.c:501: tmp = rb_file_expand_path(tmp, Qnil);

501行目が不要に思える。そしてこれが SecurityErrorの原因。rb_find_file_extは内部で rb_file_expand_pathや file_expand_pathを呼び、その結果を tmpにコピーしてくれている。二度目を呼ぶ必要はないのでは? rb_file_expand_pathは適宜汚染されたStringオブジェクトを返し、また $SAFE>0のとき、汚染された引数を SecurityErrorで拒絶するので、複数回の (rb_)file_expand_path呼び出しは容易に SecurityErrorを引き起こす。これは Ruby1.9.1の、Ruby1.8.7とは異なっている動作。

>irb
irb(main):001:0> File.expand_path("a")
=> "Y:/a"
irb(main):002:0> File.expand_path("a").tainted?
=> true
irb(main):003:0> File.expand_path(File.expand_path("a"))
=> "Y:/a"
irb(main):004:0> $SAFE=1
=> 1
irb(main):005:0> File.expand_path(File.expand_path("a"))
=> "Y:/a" # $SAFE>0で、taintedな文字列でも展開する。(Ruby1.8.7)
irb(main):006:0> exit

>irb19
irb(main):001:0> File.expand_path("a")
=> "Y:/a"
irb(main):002:0> File.expand_path("a").tainted?
=> true
irb(main):003:0> File.expand_path(File.expand_path("a"))
=> "Y:/a"
irb(main):004:0> $SAFE=1
=> 1
irb(main):005:0> File.expand_path(File.expand_path("a"))
 # $SAFE>0で、taintedな文字列を引数にすると SecurityError (Ruby1.9.1RC1)
SecurityError: Insecure operation - expand_path
        from (irb):5:in `expand_path'
        from (irb):5
        from C:/Program Files (x86)/ruby/bin/irb19.bat:20:in `<main>'
irb(main):006:0>

問題設定が間違っていたのか? load.cの一行をコメントアウトしたことで、たしかに一つの SecurityErrorは消えたが tDiaryは動かない。20090114p01のエラーがまだ出る。

ただ、20090114のタイトルにちらっと書いた、open-uriの SecurityErrorはでなくなってる。

>irb19 (野良パッチ済み)
irb(main):001:0> $SAFE=1
=> 1
irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> open 'http://www.example.com'
=> #<StringIO:0x2b8e924>
irb(main):004:0>

比較として ASRでエラーが出るのを確認する。ただ、ASRでも二回目以降の openはエラーにならない。謎の挙動。この SecurityErrorも本来発生すべきものではないのだろう。

>"C:\Program Files (x86)\ActiveScriptRuby-1.9.1\bin\irb.bat"
irb(main):001:0> $SAFE=1
=> 1
irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> open 'http://www.example.com'
SecurityError: Insecure operation - write
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `write'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:375:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:322:in `block (3 levels) in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:373:in `call_block'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:364:in `<<'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/protocol.rb:88:in `read'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2333:in `read_body_0'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2288:in `read_body'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:321:in `block (2 levels) in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1120:in `block in transport_request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:2251:in `reading_body'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1119:in `transport_request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:1103:in `request'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:312:in `block in open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/net/http.rb:564:in `start'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:306:in `open_http'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:767:in `buffer_open'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:203:in `block in open_loop'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `catch'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:201:in `open_loop'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:146:in `open_uri'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:669:in `open'
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/open-uri.rb:33:in `open'
        from (irb):3
        from C:/Program Files (x86)/ActiveScriptRuby-1.9.1/bin/irb.bat:21:in `<main>'
irb(main):004:0> open 'http://www.example.com'
=> #<StringIO:0x2b611a4>
irb(main):005:0>

引き続き rexml/source.rb:16の requireが SecurityErrorになる原因を探る。(tDiaryを起動しないと再現させられないのが辛い)


2009年01月14日 (水) $SAFE=1だと添付ライブラリ(open-uri)が SecurityErrorを出しまくるんだけど……。260行目の require 'net/http' で出る。375行目の StringIOに書き込むところでも出る。破綻してる気がする。

[tDiary][Ruby] 昨日のつづき。recent_listを実際に修正。

方針は昨日書いたとおり、プラグインが自由に日記データを取得できる手段を提供した。

日記を一日書いたとたんにエラーということはなくなったみたい。


$SAFE=1で requireが失敗する(ファイル名の untaintもしているのに)のがそもそもおかしい。open-uriや rexmlで同様に requireで SecurityErrorエラーが生じていることからも、疑惑の目がウチの Rubyに向いてきた。「1.9.1RC1だから」ではなく「ウチでコンパイルしたから」、あるいは(開発者に)利用者が少なそうな 「Windows(それも Vista)だから」なのかもしれない。


ASRをインストールしてみたけどダメだった。同じ。tDiaryをセキュアモードで動かしているわけではないので Rubyのセーフレベルは最高でも 1。taintedな文字列を使った requireが失敗するならわかる。でも rexml/source.rbの 16行目は「require 'stringio'」だ。べったべたのリテラルだ。

500 Internal Server Error

Insecure operation - require (SecurityError)

C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/source.rb:16:in `require'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/source.rb:16:in `create_from'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:146:in `stream='
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/baseparser.rb:123:in `initialize'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `new'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/parsers/treeparser.rb:9:in `initialize'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:228:in `new'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:228:in `build'
C:/Program Files (x86)/ActiveScriptRuby-1.9.1/lib/ruby/1.9.1/rexml/document.rb:43:in `initialize'
(plugin/amazon.rb):231:in `new'
(plugin/amazon.rb):231:in `amazon_get'
(plugin/amazon.rb):322:in `isbn_image'
(TDiary::Plugin#eval_src):32:in `block in eval_src'
Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `eval'
Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src'
Y:/.../server_root/www/ds14050/tdiary_on_ruby191/tdiary.rb:112:in `block in safe'

2009年01月13日 (火) [Vista] >clipboard 'clipboard' は、内部コマンドまたは外部コマンド、操作可能なプログラムまたはバッチ ファイルとして認識されていません。 >clip 情報: "CLIP /?" と入力すると使用法が表示されます。 >clip /? コマンド ライン ツールの出力を Windows クリップボードにリダイレクトします。(やっぱりあるよねー。手コピしなくてすんでよかった。なお XPには……)

最終更新: 2015-07-09T23:54+0900

[tDiary][Ruby] Insecure operation - require (SecurityError)

tdiary/trunk (r3394) を ruby 1.9.1 (2008-12-30 patchlevel-0 revision 21203) [i386-mswin32_90] で動かしてみた。

dot.htaccessと tdiary.conf.beginnerを編集&リネームして、トップページの表示と一通りの設定変更を済ませて、記念すべき最初の書き込み。……トップページすら表示されなくなりました。

Insecure operation - require (SecurityError)

Y:/.../tdiary_on_ruby191/tdiary.rb:434:in `require'
Y:/.../tdiary_on_ruby191/tdiary.rb:434:in `block in load_styles'
Y:/.../tdiary_on_ruby191/tdiary.rb:433:in `glob'
Y:/.../tdiary_on_ruby191/tdiary.rb:433:in `load_styles'
Y:/.../tdiary_on_ruby191/tdiary/defaultio.rb:142:in `initialize'
Y:/.../tdiary_on_ruby191/tdiary.rb:1069:in `new'
Y:/.../tdiary_on_ruby191/tdiary.rb:1069:in `initialize'
Y:/.../tdiary_on_ruby191/tdiary.rb:1660:in `initialize'
Y:/.../tdiary_on_ruby191/tdiary.rb:1858:in `initialize'
(plugin/recent_list.rb):39:in `new'
(plugin/recent_list.rb):39:in `block (3 levels) in recent_list'
(plugin/recent_list.rb):37:in `reverse_each'
(plugin/recent_list.rb):37:in `block (2 levels) in recent_list'
(plugin/recent_list.rb):36:in `reverse_each'
(plugin/recent_list.rb):36:in `block in recent_list'
(plugin/recent_list.rb):35:in `catch'
(plugin/recent_list.rb):35:in `recent_list'
(TDiary::Plugin#eval_src):67:in `block in eval_src'
Y:/.../tdiary_on_ruby191/tdiary.rb:787:in `eval'
Y:/.../tdiary_on_ruby191/tdiary.rb:787:in `block in eval_src'
Y:/.../tdiary_on_ruby191/tdiary.rb:112:in `block in safe'

プラグイン:recent_listが原因。(外したら解決した)

$SAFE==1の状況で TDiaryMonth.new()するのがダメっぽい。

recent_list()を呼ばれたときに、そのたびに、TDiaryMonth.new()するんでなくて、読み込まれたときに必要なデータを準備しておけばいいんじゃないか、とか思ったけど、evalで TDiaryMonthクラスにアクセサを追加したりしているあたり*、反則。泥縄の対応では気が済まない。プラグインが日記データを要求できるようなインターフェイスが求められている(現在は TDiaryXXXX#initializeで読み込まれたもののみ、Plugin@diariesからアクセスできる)。然るべき手段を用意したのち、recent_list.rbはそれを利用するべき。

* 歴史的経緯>http://kitaj.no-ip.com/tdiary/20021106.html#p03


2008年05月15日 (木) 正規表現の存在を知り、その文法を知ったのは JScript5.5の HTMLヘルプだった。ほんとう、役に立つドキュメントだった。(>20080215p01) 「だった」といいつつ、今も持っていて参照もしているけれど。

[Ruby][正規表現] /n, /s, /e, /u, $KCODEのもやっとを解消

正規表現リテラルの /nseuフラグは正規表現のマッチ動作に影響を与える。(/nseuフラグのいずれも指定しなかった場合は実行時の $KCODEに従う)

/nが指定されていたり $KCODE='NONE'のとき、「.」は改行を除いたり改行を含んだりする 1バイトにマッチするメタ文字だが、/seuフラグが指定されていたり $KCODEが SsEeUuのいずれかで始まる文字列のとき、「.」は日本語を含む、Shift_JIS、EUC-JP、UTF-8の一文字(1-3?バイト)にマッチする。

/nseuフラグや $KCODEは正規表現のパターンの解釈にも影響を与える。

Shift_JISで保存したスクリプトファイルに /表w/ というパターンと '表w' という文字列リテラルがあり、マッチを行った場合。実行時に $KCODE='NONE'であればパターンは /\225\w/ と解釈され、"\225"の後にメタ文字 \wにマッチする文字を探し、失敗する。$KCODE='SJIS'であればパターンは /表w/ と解釈され、"表"のあとに "w"を探し、成功する。

irb(main)> /表w/n =~ '表w'
=> nil
irb(main)> /表w/s =~ '表w'
=> 0

正規表現パターンの中のマルチバイト文字は文字列の場合と同じく、あくまでバイト列であり、/nseuフラグや $KCODEがどうであれ EUC-JPで保存されたスクリプトの中の正規表現リテラル /あ/ は Shift_JISの「あ」を表すバイト列 "\202\240" にマッチすることはない。