Ruby Issue Tracking System: Issues
https://redmine.ruby-lang.org/
https://redmine.ruby-lang.org/favicon.ico?1711330511
2012-08-27T08:12:45Z
Ruby Issue Tracking System
Redmine
Ruby master - Feature #6936 (Closed): Forbid singleton class and instance variabls for float
https://redmine.ruby-lang.org/issues/6936
2012-08-27T08:12:45Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>[Feature <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Introduce Flonum technique to speedup floating computation on th 64bit environment (Closed)" href="https://redmine.ruby-lang.org/issues/6763">#6763</a>] などで議論されていた flonum が r36798 でが入ったわけですが、</p>
<ol>
<li>Float のオブジェクトID の仕様が変更</li>
<li>flonum な float に特異メソッドが追加不可</li>
<li>flonum な float に特異クラスが作成不可</li>
<li>flonum な float は同じ値同士でインスタンス変数が共有される</li>
</ol>
<p>といった非互換が存在します。<br>
もっとも、1. は通常意識するはずのないところですし、2. は元から禁止されています。<br>
気になるのは 3. と 4. で、これは 1.9.3 と挙動が異なるだけでなく、<br>
32bit 環境での 2.0 や、64bit環境の flonum でない float オブジェクトとも挙動が異なります。</p>
<p>実際問題として実害はないような気もしますが、このような違いが極めて実装上の問題で、<br>
Ruby 上から見えないところに存在するのは気持ち悪く感じます。</p>
<p>よって、以下のようにするとよいのではないでしょうか。</p>
<ul>
<li>flonum でない float でも特異クラスの作成を禁止</li>
<li>float へのインスタンス変数作成を禁止</li>
</ul>
<p>後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。</p>
<p>話を発散させると、この話は true, false, nil, Fixnum, Symbol のような即値から、<br>
Bignum や Time のような immutable っぽいオブジェクトにも当てはまる気がしています。</p>
Ruby master - Feature #6910 (Rejected): Loading syck's broken yaml with psych
https://redmine.ruby-lang.org/issues/6910
2012-08-23T11:04:21Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>You know, syck outputs wrong yaml.<br>
For example, syck works as following:</p>
<p>ruby-1.9.2 > ["\u3042",Time.at(0).to_s].to_yaml<br>
=> "--- \n- "\xE3\x81\x82"\n- 1970-01-01 09:00:00 +09:00\n"</p>
<p>It should be</p>
<p>ruby-1.9.3 > ["\u3042",Time.at(0).to_s].to_yaml<br>
=> "---\n- あ\n- '1970-01-01 09:00:00 +0900'\n"</p>
<p>syck's dump of Unicode string is interpreted as "\u00E3\u0081\u0082".<br>
syck's dump of Time like string is interpreted as Time.<br>
It is hard to migrate old data to new and correct data, so it is useful if psych has a such compatibility option.</p>
Ruby master - Feature #6767 (Closed): Utility method to get a duplicated string whose encoding is...
https://redmine.ruby-lang.org/issues/6767
2012-07-22T03:20:31Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>ある String を ASCII-8BIT にしたいことはしばしばあります。<br>
それだけならばまだ force_encoding しろよという話なのですが、<br>
<a class="issue tracker-2 status-6 priority-4 priority-default closed" title="Feature: Bitwise string operations (Rejected)" href="https://redmine.ruby-lang.org/issues/6361">#6361</a> の例のように、バイナリ文字列にさらにバイナリ文字列を結合していく場合、<br>
毎行毎行 force_encoding を書いていくのにはつらいものがあります。</p>
<p>解決案としては、<br>
(1) バイナリリテラルの導入<br>
(2) dup.force_encoding(Encoding::ASCII_8BIT) する短いメソッドを追加<br>
(3) ASCII-8BIT に他のエンコーディングの文字列を結合した場合は暗黙に force_encoding<br>
が考えられます。</p>
<p>しかし、(1) は文法拡張なのでハードルが高く、(3) は方々で議論になっている通りです。<br>
よって、(2) が妥当ではないかと思います。</p>
<p>名前をまつもとさん提案の String#b としたパッチを以下の通り添付します。</p>
<p>diff --git a/string.c b/string.c<br>
index d038835..76cbc36 100644<br>
--- a/string.c<br>
+++ b/string.c<br>
@@ -601,7 +601,7 @@ rb_str_export_to_enc(VALUE str, rb_encoding *enc)<br>
}</p>
<p>static VALUE<br>
-str_replace_shared(VALUE str2, VALUE str)<br>
+str_replace_shared_without_enc(VALUE str2, VALUE str)<br>
{<br>
if (RSTRING_LEN(str) <= RSTRING_EMBED_LEN_MAX) {<br>
STR_SET_EMBED(str2);<br>
@@ -616,8 +616,14 @@ str_replace_shared(VALUE str2, VALUE str)<br>
RSTRING(str2)->as.heap.aux.shared = str;<br>
FL_SET(str2, ELTS_SHARED);<br>
}</p>
<ul>
<li>rb_enc_cr_str_exact_copy(str2, str);</li>
</ul>
<ul>
<li>return str2;<br>
+}</li>
</ul>
<p>+static VALUE<br>
+str_replace_shared(VALUE str2, VALUE str)<br>
+{</p>
<ul>
<li>str_replace_shared_without_enc(str2, str);</li>
<li>rb_enc_cr_str_exact_copy(str2, str);<br>
return str2;<br>
}</li>
</ul>
<p>@@ -7340,6 +7346,23 @@ rb_str_force_encoding(VALUE str, VALUE enc)</p>
<p>/*</p>
<ul>
<li>call-seq:</li>
</ul>
<ul>
<li>
<ul>
<li>
<pre><code>str.b -> str
</code></pre>
</li>
</ul>
</li>
<li>
<ul>
<li>
</ul>
</li>
<li>
<ul>
<li>Returns a copied string whose encoding is ASCII-8BIT.</li>
</ul>
</li>
<li>*/</li>
<li>
</ul>
<p>+static VALUE<br>
+rb_str_b(VALUE str)<br>
+{</p>
<ul>
<li>VALUE str2 = str_alloc(rb_cString);</li>
<li>str_replace_shared_without_enc(str2, str);</li>
<li>OBJ_INFECT(str2, str);</li>
<li>ENC_CODERANGE_SET(str2, ENC_CODERANGE_VALID);</li>
<li>return str2;<br>
+}</li>
<li>
</ul>
<p>+/*</p>
<ul>
<li>
<ul>
<li>
<p>call-seq:</p>
</li>
<li>
<pre><code>str.valid_encoding? -> true or false
</code></pre>
</li>
<li>
<li>
<p>Returns true for a string which encoded correctly.<br>
@@ -7969,6 +7992,7 @@ Init_String(void)</p>
<p>rb_define_method(rb_cString, "encoding", rb_obj_encoding, 0); /* in encoding.c */<br>
rb_define_method(rb_cString, "force_encoding", rb_str_force_encoding, 1);</p>
</li>
</ul>
</li>
<li>rb_define_method(rb_cString, "b", rb_str_b, 0);<br>
rb_define_method(rb_cString, "valid_encoding?", rb_str_valid_encoding_p, 0);<br>
rb_define_method(rb_cString, "ascii_only?", rb_str_is_ascii_only_p, 0);</li>
</ul>
<p>diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb<br>
index dfcaa94..3a4bca7 100644<br>
--- a/test/ruby/test_m17n.rb<br>
+++ b/test/ruby/test_m17n.rb<br>
@@ -1469,4 +1469,14 @@ class TestM17N < Test::Unit::TestCase<br>
yield(*strs)<br>
end<br>
end<br>
+</p>
<ul>
<li>def test_str_b</li>
<li>s = "\u3042"</li>
<li>assert_equal(a("\xE3\x81\x82"), s.b)</li>
<li>assert_equal(Encoding::ASCII_8BIT, s.b.encoding)</li>
<li>s.taint</li>
<li>assert_equal(true, s.b.tainted?)</li>
<li>s.untrust</li>
<li>assert_equal(true, s.b.untrusted?)</li>
<li>end<br>
end</li>
</ul>
Ruby master - Feature #6752 (Closed): Replacing ill-formed subsequencce
https://redmine.ruby-lang.org/issues/6752
2012-07-19T11:42:58Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
== 概要<br>
Stringになんらかの理由で不正なバイト列が含まれている時に、それを置換文字で置き換えたい。</p>
<p>== ユースケース<br>
実際に確認されているユースケースは以下の通りです。</p>
<ul>
<li>
<p>twitterのtitle</p>
</li>
<li>
<p>IRCのログ</p>
</li>
<li>
<p>ニコニコ動画の API</p>
</li>
<li>
<p>Webクローリング<br>
これらの不正なバイト列の生成過程は、おそらく、バイト単位で文字列を切り詰めた時に末尾が切れて、<br>
末尾がおかしい不正な文字列が作られます。(前二者)<br>
これをコンテナに入れたり結合することによって、途中にも混ざった文字列が作られます。(後二者)</p>
</li>
<li>
<p><a href="https://twitter.com/takahashim/status/18974040397" class="external">https://twitter.com/takahashim/status/18974040397</a></p>
</li>
<li>
<p><a href="https://twitter.com/n0kada/status/215674740705210368" class="external">https://twitter.com/n0kada/status/215674740705210368</a></p>
</li>
<li>
<p><a href="https://twitter.com/n0kada/status/215686490070585346" class="external">https://twitter.com/n0kada/status/215686490070585346</a></p>
</li>
<li>
<p><a href="https://twitter.com/hajimehoshi/status/215671146769682432" class="external">https://twitter.com/hajimehoshi/status/215671146769682432</a></p>
</li>
<li>
<p><a href="http://po-ru.com/diary/fixing-invalid-utf-8-in-ruby-revisited/" class="external">http://po-ru.com/diary/fixing-invalid-utf-8-in-ruby-revisited/</a></p>
</li>
<li>
<p><a href="http://stackoverflow.com/questions/2982677/ruby-1-9-invalid-byte-sequence-in-utf-8" class="external">http://stackoverflow.com/questions/2982677/ruby-1-9-invalid-byte-sequence-in-utf-8</a></p>
</li>
</ul>
<p>== 必要な引数: 置換文字<br>
省略可能、String。<br>
デフォルトは、Unicode系ならU+FFFD、それ以外では「?」。<br>
デフォルトが空文字でない理由は、削除してしまうことで、従来は存在しなかったトークンを作れてしまい、<br>
上位のレイヤーの脆弱性に繋がるからです。<br>
<a href="http://unicode.org/reports/tr36/#UTF-8_Exploit" class="external">http://unicode.org/reports/tr36/#UTF-8_Exploit</a></p>
<p>== API<br>
--- str.encode(str.encoding, invalid: replace, [replace: "〓"])</p>
<ul>
<li>CSI的じゃなくて気持ち悪い</li>
<li>iconv でできるのは glibc iconv か GNU libiconv に //IGNORE つけた時で他はできない</li>
<li>実装上のメリットは後述の通り、直感に反してあまりない(と思う)</li>
</ul>
<p>== 別メソッド</p>
<ul>
<li>新しいメソッドである</li>
<li>fix/repair invalid/illegal bytes/sequence あたりの名前か</li>
</ul>
<p>== 実装<br>
=== 鬼車ベース<br>
int ret = rb_enc_precise_mbclen(p, e, enc); して、<br>
MBCLEN_INVALID_P(ret) が真な時、何バイト目が不正なのかわからないのが微妙。<br>
ONIGENC_CONSTRUCT_MBCLEN_INVALID() がバイト数を取らないのが原因なので、<br>
鬼車のエンコーディングモジュール全てに影響してしまうため、修正困難。<br>
不正なバイトはほとんど存在しないと仮定して、効率を犠牲にすれば回避は可能。</p>
<p>=== transcodeベース<br>
UCS正規化なglibc iconv, GNU libiconv, Perl Encodeなどと違って、<br>
CSIなtranscodeでは、自分自身に変換する場合、<br>
エンコーディングごとに「何もしない」変換モジュールを用意しないといけない。</p>
<p>とりあえず鬼車ベースのコンセプト実装とテストを添付しておきます。</p>
<p>diff --git a/string.c b/string.c<br>
index d038835..4808f15 100644<br>
--- a/string.c<br>
+++ b/string.c<br>
@@ -7426,6 +7426,199 @@ rb_str_ellipsize(VALUE str, long len)<br>
return ret;<br>
}</p>
<p>+/*</p>
<ul>
<li>
<ul>
<li>call-seq:</li>
</ul>
</li>
<li>
<ul>
<li>str.fix_invalid -> new_str</li>
</ul>
</li>
<li>
<ul>
<li>
</ul>
</li>
<li>
<ul>
<li>If the string is well-formed, it returns self.</li>
</ul>
</li>
<li>
<ul>
<li>If the string has invalid byte sequence, repair it with given replacement</li>
</ul>
</li>
<li>
<ul>
<li>character.</li>
</ul>
</li>
<li>*/<br>
+VALUE<br>
+rb_str_fix_invalid(VALUE str)<br>
+{</li>
<li>int cr = ENC_CODERANGE(str);</li>
<li>rb_encoding *enc;</li>
<li>if (cr == ENC_CODERANGE_7BIT || cr == ENC_CODERANGE_VALID)</li>
<li>return rb_str_dup(str);</li>
<li>
<li>enc = STR_ENC_GET(str);</li>
<li>if (rb_enc_asciicompat(enc)) {</li>
<li>const char *p = RSTRING_PTR(str);</li>
<li>const char *e = RSTRING_END(str);</li>
<li>const char *p1 = p;</li>
<li>/* 10 should be enough for the usual use case,</li>
<li>
<ul>
<li>fixing a wrongly chopped character at the end of the string</li>
</ul>
</li>
<li>*/</li>
<li>long room = 10;</li>
<li>VALUE buf = rb_str_buf_new(RSTRING_LEN(str) + room);</li>
<li>const char *rep;</li>
<li>if (enc == rb_utf8_encoding())</li>
<li>
<pre><code> rep = "\xEF\xBF\xBD";
</code></pre>
</li>
<li>else</li>
<li>
<pre><code> rep = "?";
</code></pre>
</li>
<li>cr = ENC_CODERANGE_7BIT;</li>
<li>
<li>p = search_nonascii(p, e);</li>
<li>if (!p) {</li>
<li>
<pre><code> p = e;
</code></pre>
</li>
<li>}</li>
<li>while (p < e) {</li>
<li>
<pre><code> int ret = rb_enc_precise_mbclen(p, e, enc);
</code></pre>
</li>
<li>
<pre><code> if (MBCLEN_CHARFOUND_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> if ((unsigned char)*p > 127) cr = ENC_CODERANGE_VALID;
</code></pre>
</li>
<li>
<pre><code> p += MBCLEN_CHARFOUND_LEN(ret);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_INVALID_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> const char *q;
</code></pre>
</li>
<li>
<pre><code> long clen = rb_enc_mbmaxlen(enc);
</code></pre>
</li>
<li>
<pre><code> if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
</code></pre>
</li>
<li>
<pre><code> q = RSTRING_END(buf);
</code></pre>
</li>
<li>
<li>
<pre><code> if (e - p < clen) clen = e - p;
</code></pre>
</li>
<li>
<pre><code> if (clen < 3) {
</code></pre>
</li>
<li>
<pre><code> clen = 1;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> long len = RSTRING_LEN(buf);
</code></pre>
</li>
<li>
<pre><code> clen--;
</code></pre>
</li>
<li>
<pre><code> rb_str_buf_cat(buf, p, clen);
</code></pre>
</li>
<li>
<pre><code> for (; clen > 1; clen--) {
</code></pre>
</li>
<li>
<pre><code> ret = rb_enc_precise_mbclen(q, q + clen, enc);
</code></pre>
</li>
<li>
<pre><code> if (MBCLEN_NEEDMORE_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_INVALID_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> continue;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> rb_bug("shouldn't reach here '%s'", q);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> rb_str_set_len(buf, len);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> p += clen;
</code></pre>
</li>
<li>
<pre><code> p1 = p;
</code></pre>
</li>
<li>
<pre><code> rb_str_buf_cat2(buf, rep);
</code></pre>
</li>
<li>
<pre><code> p = search_nonascii(p, e);
</code></pre>
</li>
<li>
<pre><code> if (!p) {
</code></pre>
</li>
<li>
<pre><code> p = e;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_NEEDMORE_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> rb_bug("shouldn't reach here");
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>}</li>
<li>if (p1 < p) {</li>
<li>
<pre><code> rb_str_buf_cat(buf, p1, p - p1);
</code></pre>
</li>
<li>}</li>
<li>if (p < e) {</li>
<li>
<pre><code> rb_str_buf_cat2(buf, rep);
</code></pre>
</li>
<li>
<pre><code> cr = ENC_CODERANGE_VALID;
</code></pre>
</li>
<li>}</li>
<li>ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), cr);</li>
<li>return buf;</li>
<li>}</li>
<li>else if (rb_enc_dummy_p(enc)) {</li>
<li>return rb_str_dup(str);</li>
<li>}</li>
<li>else {</li>
<li>/* ASCII incompatible */</li>
<li>const char *p = RSTRING_PTR(str);</li>
<li>const char *e = RSTRING_END(str);</li>
<li>const char *p1 = p;</li>
<li>/* 10 should be enough for the usual use case,</li>
<li>
<ul>
<li>fixing a wrongly chopped character at the end of the string</li>
</ul>
</li>
<li>*/</li>
<li>long room = 10;</li>
<li>VALUE buf = rb_str_buf_new(RSTRING_LEN(str) + room);</li>
<li>const char *rep;</li>
<li>long mbminlen = rb_enc_mbminlen(enc);</li>
<li>static rb_encoding *utf16be;</li>
<li>static rb_encoding *utf16le;</li>
<li>static rb_encoding *utf32be;</li>
<li>static rb_encoding *utf32le;</li>
<li>if (!utf16be) {</li>
<li>
<pre><code> utf16be = rb_enc_find("UTF-16BE");
</code></pre>
</li>
<li>
<pre><code> utf16le = rb_enc_find("UTF-16LE");
</code></pre>
</li>
<li>
<pre><code> utf32be = rb_enc_find("UTF-32BE");
</code></pre>
</li>
<li>
<pre><code> utf32le = rb_enc_find("UTF-32LE");
</code></pre>
</li>
<li>}</li>
<li>if (enc == utf16be) {</li>
<li>
<pre><code> rep = "\xFF\xFD";
</code></pre>
</li>
<li>}</li>
<li>else if (enc == utf16le) {</li>
<li>
<pre><code> rep = "\xFD\xFF";
</code></pre>
</li>
<li>}</li>
<li>else if (enc == utf32be) {</li>
<li>
<pre><code> rep = "\x00\x00\xFF\xFD";
</code></pre>
</li>
<li>}</li>
<li>else if (enc == utf32le) {</li>
<li>
<pre><code> rep = "\xFD\xFF\x00\x00";
</code></pre>
</li>
<li>}</li>
<li>else {</li>
<li>
<pre><code> rep = "?";
</code></pre>
</li>
<li>}</li>
<li>
<li>while (p < e) {</li>
<li>
<pre><code> int ret = rb_enc_precise_mbclen(p, e, enc);
</code></pre>
</li>
<li>
<pre><code> if (MBCLEN_CHARFOUND_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> p += MBCLEN_CHARFOUND_LEN(ret);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_INVALID_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> const char *q;
</code></pre>
</li>
<li>
<pre><code> long clen = rb_enc_mbmaxlen(enc);
</code></pre>
</li>
<li>
<pre><code> if (p > p1) rb_str_buf_cat(buf, p1, p - p1);
</code></pre>
</li>
<li>
<pre><code> q = RSTRING_END(buf);
</code></pre>
</li>
<li>
<li>
<pre><code> if (e - p < clen) clen = e - p;
</code></pre>
</li>
<li>
<pre><code> if (clen < mbminlen * 3) {
</code></pre>
</li>
<li>
<pre><code> clen = mbminlen;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> long len = RSTRING_LEN(buf);
</code></pre>
</li>
<li>
<pre><code> clen -= mbminlen;
</code></pre>
</li>
<li>
<pre><code> rb_str_buf_cat(buf, p, clen);
</code></pre>
</li>
<li>
<pre><code> for (; clen > mbminlen; clen-=mbminlen) {
</code></pre>
</li>
<li>
<pre><code> ret = rb_enc_precise_mbclen(q, q + clen, enc);
</code></pre>
</li>
<li>
<pre><code> if (MBCLEN_NEEDMORE_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_INVALID_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> continue;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> rb_bug("shouldn't reach here '%s'", q);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> rb_str_set_len(buf, len);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> p += clen;
</code></pre>
</li>
<li>
<pre><code> p1 = p;
</code></pre>
</li>
<li>
<pre><code> rb_str_buf_cat2(buf, rep);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (MBCLEN_NEEDMORE_P(ret)) {
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> rb_bug("shouldn't reach here");
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>}</li>
<li>if (p1 < p) {</li>
<li>
<pre><code> rb_str_buf_cat(buf, p1, p - p1);
</code></pre>
</li>
<li>}</li>
<li>if (p < e) {</li>
<li>
<pre><code> rb_str_buf_cat2(buf, rep);
</code></pre>
</li>
<li>}</li>
<li>ENCODING_CODERANGE_SET(buf, rb_enc_to_index(enc), ENC_CODERANGE_VALID);</li>
<li>return buf;</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>/**********************************************************************</p>
<ul>
<li>Document-class: Symbol</li>
<li>
</ul>
<p>@@ -7882,6 +8075,7 @@ Init_String(void)<br>
rb_define_method(rb_cString, "getbyte", rb_str_getbyte, 1);<br>
rb_define_method(rb_cString, "setbyte", rb_str_setbyte, 2);<br>
rb_define_method(rb_cString, "byteslice", rb_str_byteslice, -1);</p>
<ul>
<li>
<p>rb_define_method(rb_cString, "fix_invalid", rb_str_fix_invalid, 0);</p>
<p>rb_define_method(rb_cString, "to_i", rb_str_to_i, -1);<br>
rb_define_method(rb_cString, "to_f", rb_str_to_f, 0);<br>
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb<br>
index 47f349c..2b0cfeb 100644<br>
--- a/test/ruby/test_string.rb<br>
+++ b/test/ruby/test_string.rb<br>
@@ -2031,6 +2031,29 @@ class TestString < Test::Unit::TestCase</p>
<p>assert_equal(u("\x82")+("\u3042"*9), ("\u3042"*10).byteslice(2, 28))<br>
end</p>
</li>
<li>
<li>
<p>def test_fix_invalid</p>
</li>
<li>
<p>assert_equal("\uFFFD\uFFFD\uFFFD", "\x80\x80\x80".fix_invalid)</p>
</li>
<li>
<p>assert_equal("\uFFFDA", "\xF4\x80\x80A".fix_invalid)</p>
</li>
<li>
<li>
<a name="exapmles-in-Unicode-610-D93b"></a>
<h1 >exapmles in Unicode 6.1.0 D93b<a href="#exapmles-in-Unicode-610-D93b" class="wiki-anchor">¶</a></h1>
</li>
<li>
<p>assert_equal("\x41\uFFFD\uFFFD\x41\uFFFD\x41",</p>
</li>
<li>
<pre><code> "\x41\xC0\xAF\x41\xF4\x80\x80\x41".fix_invalid)
</code></pre>
</li>
<li>
<p>assert_equal("\x41\uFFFD\uFFFD\uFFFD\x41",</p>
</li>
<li>
<pre><code> "\x41\xE0\x9F\x80\x41".fix_invalid)
</code></pre>
</li>
<li>
<p>assert_equal("\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064",</p>
</li>
<li>
<pre><code> "\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64".fix_invalid)
</code></pre>
</li>
<li>
<li>
<p>assert_equal("abcdefghijklmnopqrstuvwxyz\u0061\uFFFD\uFFFD\uFFFD\u0062\uFFFD\u0063\uFFFD\uFFFD\u0064",</p>
</li>
<li>
<pre><code> "abcdefghijklmnopqrstuvwxyz\x61\xF1\x80\x80\xE1\x80\xC2\x62\x80\x63\x80\xBF\x64".fix_invalid)
</code></pre>
</li>
<li>
<li>
<p>assert_equal("\uFFFD\u3042".encode("UTF-16BE"),</p>
</li>
<li>
<pre><code> "\xD8\x00\x30\x42".force_encoding(Encoding::UTF_16BE).
</code></pre>
</li>
<li>
<pre><code> fix_invalid)
</code></pre>
</li>
<li>
<p>assert_equal("\uFFFD\u3042".encode("UTF-16LE"),</p>
</li>
<li>
<pre><code> "\x00\xD8\x42\x30".force_encoding(Encoding::UTF_16LE).
</code></pre>
</li>
<li>
<pre><code> fix_invalid)
</code></pre>
</li>
<li>
<p>end<br>
end</p>
</li>
</ul>
<p>class TestString2 < TestString<br>
=end</p>
Ruby master - Bug #6577 (Closed): GC中にstack overflowが発生するとSEGVする
https://redmine.ruby-lang.org/issues/6577
2012-06-12T02:18:44Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>GC中にstack overflowが発生すると、例外作成時にrb_new_objするので[BUG]ります。</p>
<p>原因<br>
(1) caller のテストで Fiber を利用するようにした<br>
(2) caller 実行中に GC が発生<br>
(3) GC 中にマシンスタックオーバーフロー(SEGV)が発生<br>
(4) スタックオーバーフローエラーを作成<br>
(5) スタックオーバーフローエラーを作るときに object allocation している<br>
(6) -> [BUG]</p>
<p>対処法:<br>
スタックオーバーフローエラーを投げるときはオブジェクト作らないようにする<br>
対症療法:<br>
caller のテストで Fiber を使わないようにする<br>
対症療法その2:<br>
callerのテストで GC.disable</p>
<p>nariさんがGC で再帰しないようにするなんて構想も先日語っておられましたが。</p>
Ruby master - Bug #6556 (Closed): ネストした配列の inspect で segv
https://redmine.ruby-lang.org/issues/6556
2012-06-08T00:36:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>./miniruby -e'10000.times.inject(x=[]){|a,|a<<(b=[]);b};x.inspect'<br>
で segv します。</p>
<p>% ./miniruby -e'10000.times.inject(x=[]){|a,|a<<(b=[]);b};x.inspect'|&less<br>
-e:1: [BUG] Segmentation fault<br>
ruby 2.0.0dev (2012-06-06 trunk 35950) [x86_64-freebsd9.0]</p>
<p>-- Control frame information -----------------------------------------------<br>
c:3116 p:---- s:6234 b:6234 l:006233 d:006233 CFUNC :inspect<br>
c:3115 p:---- s:6232 b:6232 l:006231 d:006231 CFUNC :inspect<br>
c:3114 p:---- s:6230 b:6230 l:006229 d:006229 CFUNC :inspect<br>
(中略)<br>
c:0005 p:---- s:0012 b:0012 l:000011 d:000011 CFUNC :inspect<br>
c:0004 p:---- s:0010 b:0010 l:000009 d:000009 CFUNC :inspect<br>
c:0003 p:0041 s:0007 b:0007 l:001458 d:002430 EVAL -e:1<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:0000 s:0002 b:0002 l:001458 d:001458 TOP</p>
<p>-e:1:in <code><main>' -e:1:in </code>inspect'<br>
-e:1:in <code>inspect' (中略) -e:1:in </code>inspect'<br>
-e:1:in `inspect'</p>
<p>-- C level backtrace information -------------------------------------------<br>
0x44c8bd <rb_warning+734> at /home/naruse/obj/ruby/miniruby ../../ruby/error.c:269<br>
0x44c9d8 <rb_bug+228> at /home/naruse/obj/ruby/miniruby ../../ruby/error.c:288<br>
0x518181 <ruby_posix_signal+352> at /home/naruse/obj/ruby/miniruby ../../ruby/signal.c:577<br>
0x800ca7723 <_pthread_sigmask+707> at /lib/libthr.so.3<br>
0x800ca7897 <_pthread_sigmask+1079> at /lib/libthr.so.3<br>
0x7ffffffff003</p>
<p>-- Other runtime information -----------------------------------------------</p>
<ul>
<li>
<p>Loaded script: -e</p>
</li>
<li>
<p>Loaded features:</p>
<p>0 enumerator.so</p>
</li>
</ul>
<p>[NOTE]<br>
You may have encountered a bug in the Ruby interpreter or extension libraries.<br>
Bug reports are welcome.<br>
For details: <a href="http://www.ruby-lang.org/bugreport.html" class="external">http://www.ruby-lang.org/bugreport.html</a></p>
<p>zsh: abort (core dumped) ./miniruby -e'p 10000.times.inject(x=[]){|a,|a<<(b=[]);b};x.inspect'</p>
Ruby master - Bug #6441 (Rejected): IO.pipe on ENFILE
https://redmine.ruby-lang.org/issues/6441
2012-05-16T12:59:05Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>今の Ruby は open(2) などで、errno=ENFILE が発生した場合、<br>
すなわち fd を使いきっている場合には、rb_gc() を呼び、IO オブジェクトを GC して、<br>
fd が解放されないか試み、それでもダメだったら諦めるとしています。</p>
<p>しかし、IO.pipe の場合はこれに失敗することがあります。<br>
これは、lazy sweep が上記の目的のため T_FILE の場合は直ちに sweep することにしている所、<br>
pipe の場合はその例外にあたらないからです。</p>
Ruby master - Bug #6405 (Closed): Re: [ruby-cvs:42717] ryan:r35541 (trunk): Imported minitest 2....
https://redmine.ruby-lang.org/issues/6405
2012-05-05T17:27:47Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>After r35541, test-all fails as following:</p>
<ol start="2">
<li>
<p>Error:<br>
test_equals_tilde(TestGemPlatform):<br>
TypeError: can't convert Gem::Platform to String<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/test/rubygems/test_gem_platform.rb:210:in <code>test_equals_tilde' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:633:in </code>block in _run_suites'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:631:in <code>each' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:631:in </code>_run_suites'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:21:in <code>run' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:682:in </code>run'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:714:in <code>run' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:718:in </code>run'<br>
./test/runner.rb:15:in `'</p>
</li>
<li>
<p>Error:<br>
test_dir(TestGemInstaller):<br>
TypeError: can't convert Regexp to String<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/test/rubygems/test_gem_installer.rb:1220:in <code>test_dir' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:633:in </code>block in _run_suites'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:631:in <code>each' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:631:in </code>_run_suites'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:21:in <code>run' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:682:in </code>run'<br>
/home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:714:in <code>run' /home/chkbuild/build/ruby-trunk/20120504T230101Z/ruby/lib/test/unit.rb:718:in </code>run'<br>
./test/runner.rb:15:in `'</p>
</li>
</ol>
<p>Why don't you run tests before commit.</p>
<p>(2012/05/05 6:46), <a href="mailto:ryan@ruby-lang.org" class="email">ryan@ruby-lang.org</a> wrote:</p>
<blockquote>
<p>ryan 2012-05-05 06:46:01 +0900 (Sat, 05 May 2012)</p>
<p>New Revision: 35541</p>
<p><a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35541" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=35541</a></p>
<p>Log:<br>
Imported minitest 2.12.1 (r7323)</p>
<p>Added files:<br>
trunk/test/minitest/metametameta.rb<br>
Modified files:<br>
trunk/ChangeLog<br>
trunk/lib/minitest/README.txt<br>
trunk/lib/minitest/autorun.rb<br>
trunk/lib/minitest/benchmark.rb<br>
trunk/lib/minitest/mock.rb<br>
trunk/lib/minitest/pride.rb<br>
trunk/lib/minitest/spec.rb<br>
trunk/lib/minitest/unit.rb<br>
trunk/test/minitest/test_minitest_benchmark.rb<br>
trunk/test/minitest/test_minitest_mock.rb<br>
trunk/test/minitest/test_minitest_spec.rb<br>
trunk/test/minitest/test_minitest_unit.rb</p>
</blockquote>
<p>--<br>
NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a></p>
Ruby master - Bug #6400 (Closed): dl/callback with fiddle occurs SEGV on NetBSD amd64
https://redmine.ruby-lang.org/issues/6400
2012-05-04T21:33:37Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>On NetBSD amd64, libffi with callback occurs SEGV as following.</p>
<p>kelvena% cat p<br>
require 'dl/callback'<br>
require 'dl/func'<br>
include DL<br>
Called_with = nil<br>
addr = set_callback(TYPE_VOID, 1) do |str|<br>
called_with = dlunwrap(str)<br>
end<br>
func = CFunc.new(addr, TYPE_VOID, 'test')<br>
f = Function.new(func, [TYPE_VOIDP])<br>
arg = 'foo'<br>
f.call(dlwrap(arg))<br>
kelvena% ./ruby p<br>
/home/naruse/local/ruby/lib/ruby/2.0.0/dl/func.rb:55: [BUG] Segmentation fault<br>
ruby 2.0.0dev (2012-04-30 trunk 35500) [x86_64-netbsd6.99.5]</p>
<p>-- Control frame information -----------------------------------------------<br>
c:0005 p:---- s:0022 b:0022 l:000021 d:000021 CFUNC :call<br>
c:0004 p:0059 s:0018 b:0018 l:000017 d:000017 METHOD /home/naruse/local/ruby/lib/ruby/2.0.0/dl/func.<br>
rb:55<br>
c:0003 p:0157 s:0010 b:0010 l:001db8 d:0021a8 EVAL p:11<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:0000 s:0002 b:0002 l:001db8 d:001db8 TOP</p>
<p>-- Ruby level backtrace information ----------------------------------------<br>
p:11:in <code><main>' /home/naruse/local/ruby/lib/ruby/2.0.0/dl/func.rb:55:in </code>call'<br>
/home/naruse/local/ruby/lib/ruby/2.0.0/dl/func.rb:55:in `call'</p>
<p>-- Other runtime information -----------------------------------------------</p>
<ul>
<li>
<p>Loaded script: p</p>
</li>
<li>
<p>Loaded features:</p>
<p>0 enumerator.so<br>
1 /home/naruse/local/ruby/lib/ruby/2.0.0/x86_64-netbsd6.99.5/enc/encdb.so<br>
2 /home/naruse/local/ruby/lib/ruby/2.0.0/x86_64-netbsd6.99.5/enc/trans/transdb.so<br>
3 /home/naruse/local/ruby/lib/ruby/2.0.0/rubygems/defaults.rb<br>
4 /home/naruse/local/ruby/lib/ruby/2.0.0/x86_64-netbsd6.99.5/rbconfig.rb<br>
5 /home/naruse/local/ruby/lib/ruby/2.0.0/rubygems/deprecate.rb<br>
6 /home/naruse/local/ruby/lib/ruby/2.0.0/rubygems/exceptions.rb<br>
7 /home/naruse/local/ruby/lib/ruby/2.0.0/rubygems/custom_require.rb<br>
8 /home/naruse/local/ruby/lib/ruby/2.0.0/rubygems.rb<br>
9 /home/naruse/local/ruby/lib/ruby/2.0.0/x86_64-netbsd6.99.5/dl.so<br>
10 /home/naruse/local/ruby/lib/ruby/2.0.0/x86_64-netbsd6.99.5/fiddle.so<br>
11 /home/naruse/local/ruby/lib/ruby/2.0.0/fiddle/function.rb<br>
12 /home/naruse/local/ruby/lib/ruby/2.0.0/fiddle/closure.rb<br>
13 /home/naruse/local/ruby/lib/ruby/2.0.0/fiddle.rb<br>
14 /home/naruse/local/ruby/lib/ruby/2.0.0/dl.rb<br>
15 /home/naruse/local/ruby/lib/ruby/2.0.0/thread.rb<br>
16 /home/naruse/local/ruby/lib/ruby/2.0.0/dl/callback.rb<br>
17 /home/naruse/local/ruby/lib/ruby/2.0.0/dl/stack.rb<br>
18 /home/naruse/local/ruby/lib/ruby/2.0.0/dl/value.rb<br>
19 /home/naruse/local/ruby/lib/ruby/2.0.0/dl/func.rb</p>
</li>
</ul>
<p>[NOTE]<br>
You may have encountered a bug in the Ruby interpreter or extension libraries.<br>
Bug reports are welcome.<br>
For details: <a href="http://www.ruby-lang.org/bugreport.html" class="external">http://www.ruby-lang.org/bugreport.html</a></p>
<p>zsh: abort (core dumped) ./ruby p</p>
Ruby master - Bug #6272 (Closed): Rinda sticks on some tests
https://redmine.ruby-lang.org/issues/6272
2012-04-08T22:27:08Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Rindaが例えば以下のようにすると刺さります。</p>
<p>while [ yes ];do;make test-all TESTS='-v -n test_ruby_talk_264062 rinda/test_rinda.rb' RUBYOPT=-w;done</p>
<p>しばらく追ってみたところ、Rinda は Monitor#synchronize をすることで同期を守っているのですが、<br>
そのテストでは時刻を Rinda::MockClock で扱い、その中で Rinda::MockClock::MyTS を用いて時刻を配信しているのですが、<br>
この TupleSpace は複数のスレッドから触られるため、同一のスレッドからなら何度入ってもロックしない<br>
Monitor#synchronize でも、デッドロックしてしまうからっぽい気がします。</p>
Ruby master - Bug #6140 (Rejected): test
https://redmine.ruby-lang.org/issues/6140
2012-03-14T17:28:04Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Redmineを1.3.2にしたのでテスト</p>
Ruby master - Feature #6118 (Feedback): Hash#keys_of(values), returns related keys of given values
https://redmine.ruby-lang.org/issues/6118
2012-03-06T17:55:07Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Hash#key(value) の複数版がほしいです。</p>
<p>{a: 1, b: 2, c: 3, d: 1}.key(1)<br>
=> :a<br>
というメソッドはあるのですが、<br>
{a: 1, b: 2, c: 3, d: 1}.keys_of(1)<br>
=> [:a, :d]<br>
というメソッドは現状ありません。</p>
<p>Ruby での実装例は以下のような感じになります。<br>
どうでしょうか。</p>
<p>class Hash<br>
def keys_of(*a)<br>
each_with_object([]) {|(k, v), r| r << k if a.include? v}<br>
end<br>
end</p>
Ruby master - Feature #5959 (Rejected): Addrinfo#inspectname
https://redmine.ruby-lang.org/issues/5959
2012-02-02T17:16:51Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Addrinfo の導入によって、Socket.getaddrinfo での正引き結果がオブジェクト化され、<br>
元のホスト名を inspect で見れるようになってとても便利になったわけですが、<br>
現在この元のホスト名をとりだす API がありません。</p>
<p>ホスト名とIP アドレスをセットで扱うのに、つまり解決済みの名前とアドレスの組を扱うのに Addrinfo って便利なので、<br>
ホスト名を取り出す API が欲しいです。<br>
現在の C での名前、inspectname か hostname あたりでどうでしょう。</p>
Ruby master - Bug #5868 (Closed): make failed on i686-linux from Bitmap Marking GC
https://redmine.ruby-lang.org/issues/5868
2012-01-09T10:54:12Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>i686-linux に置いて、r34225 以降 make に失敗します。</p>
<p><a href="http://c5632.rubyci.org/~chkbuild/ruby-trunk/log/20120109T010103Z.log.html.gz" class="external">http://c5632.rubyci.org/~chkbuild/ruby-trunk/log/20120109T010103Z.log.html.gz</a><br>
<a href="http://u32.rubyci.org/~chkbuild/ruby-trunk/log/20120108T230102Z.log.html.gz" class="external">http://u32.rubyci.org/~chkbuild/ruby-trunk/log/20120108T230102Z.log.html.gz</a><br>
<a href="http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20120109T000400Z.log.html.gz" class="external">http://www.rubyist.net/~akr/chkbuild/debian/ruby-trunk/log/20120109T000400Z.log.html.gz</a></p>
Ruby master - Feature #5861 (Rejected): String#version_compare
https://redmine.ruby-lang.org/issues/5861
2012-01-08T07:54:53Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>バージョン番号っぽい文字列を比較するメソッド、String#version_compare を追加しませんか。<br>
"2.6.18".version_compare("2.6.3") #=> 1<br>
などと使います。</p>
<p>詳細な仕様は Gauche の gauche.version モジュールの version-compare 関数の仕様を丸パクリするのが良いと思います。<br>
提案している名前も Gauche そのままです。<br>
<a href="http://practical-scheme.net/gauche/man/gauche-refj_103.html" class="external">http://practical-scheme.net/gauche/man/gauche-refj_103.html</a></p>
<p>それなりにユースケースはある…というか今まさにテストを書いていて、<br>
Linux カーネルのバージョン番号を欲しくなったのですが、いかがでしょうか。</p>
Ruby master - Feature #5820 (Closed): Merge Onigmo to Ruby 2.0
https://redmine.ruby-lang.org/issues/5820
2011-12-29T02:42:18Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Ruby 1.9 では正規表現エンジンや M17N の基盤として Oniguruma を用いています。<br>
これを 2.0 では Oniguruma の改造版である、k-takata さんの Onigmo に置き換えようという話です。<br>
<a href="https://github.com/k-takata/Onigmo/tree/tmp/ruby-2.0.x" class="external">https://github.com/k-takata/Onigmo/tree/tmp/ruby-2.0.x</a></p>
<p>この取り込みによる影響は以下の通りです。</p>
<ul>
<li>100%互換 (既存のテストが全て無修正で通る)</li>
<li>いくつかの新機能 <a href="/issues/5208">[ruby-dev:44410]</a>
<ul>
<li>正規表現<br>
* \K, \R, \X, (?(cond)yes|no), \g<0>, \g<+n>, (?au)<br>
* Perl 5.10互換の名前参照(←Rubyには不要でしょう。)
<ul>
<li>Shift_JIS, EUC-JPで、全角アルファベットなどの大文字小文字同一視検索に対応。</li>
<li>Shift_JIS, EUC-JPで、\p{Han}, \p{Latin}, \p{Greek}, \p{Cyrillic} に対応。</li>
<li>最適化
<ul>
<li>暗黙のアンカーによる最適化を実装。</li>
<li>
<a href="http://redmine.ruby-lang.org/issues/3568" class="external">http://redmine.ruby-lang.org/issues/3568</a> で無効化された最適化を再度有効化。</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>現状は POSIX 文字クラスに非互換があり、それが解決されればマージ可能と認識しています。</p>
Ruby master - Bug #5813 (Closed): net/http's EOFError and Keep-Alive
https://redmine.ruby-lang.org/issues/5813
2011-12-27T14:56:52Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p><a href="https://blade.ruby-lang.org/ruby-dev/39421">[ruby-dev:39421]</a> describes exceptions thrown by open-uri, and raise a question why net/http raises EOFError.</p>
<p>net/http sometimes raises EOFError.<br>
I recently find it is because of Keep-Alive.<br>
On HTTP/1.1, connections are Keep-Alive and a Keep-Alive connection has a timeout.<br>
If a client of such connection doesn't send anything after some communication,<br>
server closes the connection because of Keep-Alive timeout,<br>
and the client's connection shall raise EOFError (sometimes it may be ECONNRESET).</p>
<p>HTTP/1.1 says a client should retry a request if the request is idempotent.<br>
<a href="http://tools.ietf.org/html/rfc2616#section-8.1.4" class="external">http://tools.ietf.org/html/rfc2616#section-8.1.4</a><br>
<a href="http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-17#section-6.1.5" class="external">http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-17#section-6.1.5</a><br>
<a href="http://www.studyinghttp.net/connections" class="external">http://www.studyinghttp.net/connections</a><br>
So I attached a patch to such retry to net/http.</p>
<p>FYI, this timeout of Keep-Alive, KeepAliveTimeout, is:<br>
Apache in FreeBSD ports or pkgsrc is 5 seconds,<br>
the on in Debian Packages or RPM is 15 seconds.</p>
<p>diff --git a/lib/net/http.rb b/lib/net/http.rb<br>
index 879cfe0..13bd1a7 100644<br>
--- a/lib/net/http.rb<br>
+++ b/lib/net/http.rb<br>
@@ -1332,7 +1332,10 @@ module Net #:nodoc:<br>
res<br>
end</p>
<ul>
<li>IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:</li>
<li>def transport_request(req)</li>
<li>
<pre><code> count = 0
begin_transport req
res = catch(:response) {
req.exec @socket, @curr_http_version, edit_path(req.path)
</code></pre>
</li>
</ul>
<p>@@ -1346,6 +1349,16 @@ module Net #:nodoc:<br>
}<br>
end_transport req, res<br>
res</p>
<ul>
<li>rescue EOFError, Errno::ECONNRESET => exception</li>
<li>
<pre><code> if count == 0 && IDEMPOTENT_METHODS_.include?(req.method)
</code></pre>
</li>
<li>
<pre><code> count += 1
</code></pre>
</li>
<li>
<pre><code> @socket.close if @socket and not @socket.closed?
</code></pre>
</li>
<li>
<pre><code> D "Conn close because of error #{exception}, and retry"
</code></pre>
</li>
<li>
<pre><code> retry
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<pre><code> D "Conn close because of error #{exception}"
</code></pre>
</li>
<li>
<pre><code> @socket.close if @socket and not @socket.closed?
</code></pre>
</li>
<li>
<pre><code> raise
</code></pre>
rescue => exception<br>
D "Conn close because of error #{exception}"<br>
@socket.close if @socket and not @socket.closed?<br>
diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb<br>
index 1515854..2e7ab4e 100644<br>
--- a/test/net/http/test_http.rb<br>
+++ b/test/net/http/test_http.rb<br>
@@ -564,3 +564,29 @@ class TestNetHTTPContinue < Test::Unit::TestCase<br>
assert_not_match(/HTTP/1.1 100 continue/, @debug.string)<br>
end<br>
end</li>
<li>
</ul>
<p>+class TestNetHTTPKeepAlive < Test::Unit::TestCase</p>
<ul>
<li>CONFIG = {</li>
<li>'host' => '127.0.0.1',</li>
<li>'port' => 10081,</li>
<li>'proxy_host' => nil,</li>
<li>'proxy_port' => nil,</li>
<li>'RequestTimeout' => 0.1,</li>
<li>}</li>
<li>
<li>include TestNetHTTPUtils</li>
<li>
<li>def test_keep_alive_get</li>
<li>start {|http|</li>
<li>
<pre><code> res = http.get('/')
</code></pre>
</li>
<li>
<pre><code> assert_kind_of Net::HTTPResponse, res
</code></pre>
</li>
<li>
<pre><code> assert_kind_of String, res.body
</code></pre>
</li>
<li>
<pre><code> sleep 1
</code></pre>
</li>
<li>
<pre><code> assert_nothing_raised {
</code></pre>
</li>
<li>
<pre><code> res = http.get('/')
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> assert_kind_of Net::HTTPResponse, res
</code></pre>
</li>
<li>
<pre><code> assert_kind_of String, res.body
</code></pre>
</li>
<li>}</li>
<li>end<br>
+end<br>
diff --git a/test/net/http/utils.rb b/test/net/http/utils.rb<br>
index 50f616f..07e0b9f 100644<br>
--- a/test/net/http/utils.rb<br>
+++ b/test/net/http/utils.rb<br>
@@ -51,6 +51,7 @@ module TestNetHTTPUtils<br>
:ServerType => Thread,<br>
}<br>
server_config[:OutputBufferSize] = 4 if config('chunked')</li>
<li>server_config[:RequestTimeout] = config('RequestTimeout') if config('RequestTimeout')<br>
if defined?(OpenSSL) and config('ssl_enable')<br>
server_config.update({<br>
:SSLEnable => true,</li>
</ul>
Ruby master - Bug #5790 (Closed): net/http の EOFError と Keep-Alive
https://redmine.ruby-lang.org/issues/5790
2011-12-22T18:49:13Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p><a href="https://blade.ruby-lang.org/ruby-dev/39421">[ruby-dev:39421]</a> がずっと心に残っていたので、思い立って調べてみたので、<br>
(正確には自分が高頻度で踏むようになったので調べてみた)<br>
その調査結果と対策案を提案します。</p>
<p>まず、投げられる原因ですが、根本的な原因は Keep-Alive のタイムアウトです。<br>
HTTP/1.1 ではデフォルトで持続的接続を行うので、複数回のリクエストに渡って<br>
一つの socket が使い回されます。</p>
<p>しかし、リクエスト同士で時間が開いていると、サーバー側でタイムアウトする<br>
可能性があります。この時にクライアント側の read(2) が 0 を返す、<br>
つまり EOFError となることがあります。</p>
<p>HTTP/1.1 は、冪等なメソッドの場合には確認なしにリトライすべきと言っているので、<br>
そのようにするパッチを添付します。<br>
冪等でないメソッドの場合にどうするべきかは悩ましいところです。<br>
<a href="http://tools.ietf.org/html/rfc2616#section-8.1.4" class="external">http://tools.ietf.org/html/rfc2616#section-8.1.4</a><br>
<a href="http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-17#section-6.1.5" class="external">http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-17#section-6.1.5</a><br>
<a href="http://www.studyinghttp.net/connections" class="external">http://www.studyinghttp.net/connections</a></p>
<p>なお、この Keep-Alive における Timeout は、<br>
Apache の場合、FreeBSD ports や pkgsrc では 5 秒、<br>
Debian Packages や RPM では 15 秒でした。</p>
<p>diff --git a/lib/net/http.rb b/lib/net/http.rb<br>
index 879cfe0..13bd1a7 100644<br>
--- a/lib/net/http.rb<br>
+++ b/lib/net/http.rb<br>
@@ -1332,7 +1332,10 @@ module Net #:nodoc:<br>
res<br>
end</p>
<ul>
<li>IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:</li>
<li>def transport_request(req)</li>
<li>
<pre><code> count = 0
begin_transport req
res = catch(:response) {
req.exec @socket, @curr_http_version, edit_path(req.path)
</code></pre>
</li>
</ul>
<p>@@ -1346,6 +1349,16 @@ module Net #:nodoc:<br>
}<br>
end_transport req, res<br>
res</p>
<ul>
<li>rescue EOFError, Errno::ECONNRESET => exception</li>
<li>
<pre><code> if count == 0 && IDEMPOTENT_METHODS_.include?(req.method)
</code></pre>
</li>
<li>
<pre><code> count += 1
</code></pre>
</li>
<li>
<pre><code> @socket.close if @socket and not @socket.closed?
</code></pre>
</li>
<li>
<pre><code> D "Conn close because of error #{exception}, and retry"
</code></pre>
</li>
<li>
<pre><code> retry
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<pre><code> D "Conn close because of error #{exception}"
</code></pre>
</li>
<li>
<pre><code> @socket.close if @socket and not @socket.closed?
</code></pre>
</li>
<li>
<pre><code> raise
</code></pre>
rescue => exception<br>
D "Conn close because of error #{exception}"<br>
@socket.close if @socket and not @socket.closed?<br>
diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb<br>
index 1515854..2e7ab4e 100644<br>
--- a/test/net/http/test_http.rb<br>
+++ b/test/net/http/test_http.rb<br>
@@ -564,3 +564,29 @@ class TestNetHTTPContinue < Test::Unit::TestCase<br>
assert_not_match(/HTTP/1.1 100 continue/, @debug.string)<br>
end<br>
end</li>
<li>
</ul>
<p>+class TestNetHTTPKeepAlive < Test::Unit::TestCase</p>
<ul>
<li>CONFIG = {</li>
<li>'host' => '127.0.0.1',</li>
<li>'port' => 10081,</li>
<li>'proxy_host' => nil,</li>
<li>'proxy_port' => nil,</li>
<li>'RequestTimeout' => 0.1,</li>
<li>}</li>
<li>
<li>include TestNetHTTPUtils</li>
<li>
<li>def test_keep_alive_get</li>
<li>start {|http|</li>
<li>
<pre><code> res = http.get('/')
</code></pre>
</li>
<li>
<pre><code> assert_kind_of Net::HTTPResponse, res
</code></pre>
</li>
<li>
<pre><code> assert_kind_of String, res.body
</code></pre>
</li>
<li>
<pre><code> sleep 1
</code></pre>
</li>
<li>
<pre><code> assert_nothing_raised {
</code></pre>
</li>
<li>
<pre><code> res = http.get('/')
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> assert_kind_of Net::HTTPResponse, res
</code></pre>
</li>
<li>
<pre><code> assert_kind_of String, res.body
</code></pre>
</li>
<li>}</li>
<li>end<br>
+end<br>
diff --git a/test/net/http/utils.rb b/test/net/http/utils.rb<br>
index 50f616f..07e0b9f 100644<br>
--- a/test/net/http/utils.rb<br>
+++ b/test/net/http/utils.rb<br>
@@ -51,6 +51,7 @@ module TestNetHTTPUtils<br>
:ServerType => Thread,<br>
}<br>
server_config[:OutputBufferSize] = 4 if config('chunked')</li>
<li>server_config[:RequestTimeout] = config('RequestTimeout') if config('RequestTimeout')<br>
if defined?(OpenSSL) and config('ssl_enable')<br>
server_config.update({<br>
:SSLEnable => true,</li>
</ul>
Ruby master - Bug #5768 (Closed): TestRequire#test_race_exceptionで競合するケースがまだある
https://redmine.ruby-lang.org/issues/5768
2011-12-17T10:48:22Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>まだrequireで競合するケースが残っています。<br>
現在のテストだと確率的にしか起きませんが、以下の通り変更すると確実に起きるようになります。</p>
<p>diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb<br>
index 9186a6f..262a5ef 100644<br>
--- a/test/ruby/test_require.rb<br>
+++ b/test/ruby/test_require.rb<br>
@@ -352,7 +352,7 @@ class TestRequire < Test::Unit::TestCase<br>
TestRequire.scratch << :pre<br>
Thread.pass until t2 = TestRequire.scratch[1]<br>
Thread.pass until t2.stop?<br>
-open(<strong>FILE</strong>, "w") {|f| f.puts "TestRequire.scratch << :post"}<br>
+open(<strong>FILE</strong>, "w") {|f| f.puts "TestRequire.scratch << :post"; f.puts "t1,t2=TestRequire.scratch[1, 2];if Thread.current == t2; Thread.pass until t1.stopped?; end"}<br>
raise "con1"<br>
EOS<br>
tmp.close<br>
@@ -364,6 +364,7 @@ raise "con1"<br>
t2_res = nil</p>
<pre><code> t1 = Thread.new do
</code></pre>
<ul>
<li>
<pre><code> scratch << t1
begin
require(path)
rescue RuntimeError
</code></pre>
</li>
</ul>
<p>@@ -389,8 +390,8 @@ raise "con1"<br>
assert_nothing_raised(ThreadError, bug5754) {t1.join}<br>
assert_nothing_raised(ThreadError, bug5754) {t2.join}</p>
<ul>
<li>assert_equal(true, (t1_res ^ t2_res), bug5754)</li>
<li>assert_equal([:pre, t2, :post, :t2, :t1], scratch, bug5754)</li>
</ul>
<ul>
<li>assert_equal(true, (t1_res ^ t2_res), bug5754 + " t1:#{t1_res} t2:#{t2_res}")</li>
<li>assert_equal([:pre, t1, t2, :post, :t2, :t1], scratch, bug5754)<br>
ensure<br>
tmp.close(true) if tmp<br>
end</li>
</ul>
Backport193 - Backport #5757 (Closed): main threadがreadやselectで待っていると、^C でなかなか死なない
https://redmine.ruby-lang.org/issues/5757
2011-12-13T16:35:41Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>FreeBSD 9 にて、 ./ruby と起動して ^C を投げてもなかなか死にません。<br>
./miniruby でも -e'$stdin.read' でも同じです。</p>
<p>仕組みとしては、main thread が read や select で待つ場合、最近は blocking region で<br>
unblock.func に ubf_select を設定するわけですが、この時にシグナルが来ると、</p>
<ol>
<li>どこかのスレッドの sighandler が呼ばれて、rb_thread_wakeup_timer_thread() が呼ばれる</li>
<li>タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる</li>
<li>タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる</li>
<li>タイマースレッドが起きて、thread_timer() -> timer_thread_function() -> rb_threadptr_check_signal() -> rb_threadptr_interrupt() -> (th->unblock.func)(th->unblock.arg) -> ubf_select() -> rb_thread_wakeup_timer_thread() が呼ばれる<br>
...</li>
</ol>
<p>対策はいくつかあり得ると思うのですが、例えば、ubf_select() から rb_thread_wakeup_timer_thread() を呼ばないようにするとか</p>
Ruby master - Bug #5691 (Closed): rb_path2class raises a NameError if a constant in the path exis...
https://redmine.ruby-lang.org/issues/5691
2011-11-30T22:21:39Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>An exception from rb_path2class differs on strange context.</p>
<p>% ./ruby -r./spec/rubyspec/optional/capi/ext/class_spec.so -e'CApiClassSpecs.new.rb_path2class("CApiClassSpecs::X")'<br>
-e:1:in <code>rb_path2class': undefined class/module CApiClassSpecs::X (ArgumentError) % ./ruby -r./spec/rubyspec/optional/capi/ext/class_spec.so -e'X=1;CApiClassSpecs.new.rb_path2class("CApiClassSpecs::X")' -e:1:in </code>rb_path2class': uninitialized constant CApiClassSpecs::X (NameError)</p>
Ruby master - Bug #5548 (Closed): OpenSSL::Engine can't load some old engines/new engines
https://redmine.ruby-lang.org/issues/5548
2011-11-02T11:20:11Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Current ext/openssl is missing a check for ENGINE_load_dynamic(),<br>
and doesn't have checks/functions for new engines.</p>
<p>diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb<br>
index 8d8cee3..8f13121 100644<br>
--- a/ext/openssl/extconf.rb<br>
+++ b/ext/openssl/extconf.rb<br>
@@ -118,6 +118,8 @@ if have_header("openssl/engine.h")<br>
have_func("ENGINE_get_digest")<br>
have_func("ENGINE_get_cipher")<br>
have_func("ENGINE_cleanup")<br>
+</p>
<ul>
<li>have_func("ENGINE_load_dynamic")<br>
have_func("ENGINE_load_4758cca")<br>
have_func("ENGINE_load_aep")<br>
have_func("ENGINE_load_atalla")<br>
@@ -126,6 +128,12 @@ if have_header("openssl/engine.h")<br>
have_func("ENGINE_load_nuron")<br>
have_func("ENGINE_load_sureware")<br>
have_func("ENGINE_load_ubsec")</li>
<li>have_func("ENGINE_load_padlock")</li>
<li>have_func("ENGINE_load_capi")</li>
<li>have_func("ENGINE_load_gmp")</li>
<li>have_func("ENGINE_load_gost")</li>
<li>have_func("ENGINE_load_cryptodev")</li>
<li>have_func("ENGINE_load_aesni")<br>
end<br>
have_func("DH_generate_parameters_ex")<br>
have_func("DSA_generate_parameters_ex")<br>
diff --git a/ext/openssl/ossl_engine.c b/ext/openssl/ossl_engine.c<br>
index 79f51b8..829680c 100644<br>
--- a/ext/openssl/ossl_engine.c<br>
+++ b/ext/openssl/ossl_engine.c<br>
@@ -64,29 +64,47 @@ ossl_engine_s_load(int argc, VALUE *argv, VALUE klass)<br>
#if HAVE_ENGINE_LOAD_DYNAMIC<br>
OSSL_ENGINE_LOAD_IF_MATCH(dynamic);<br>
#endif<br>
-#if HAVE_ENGINE_LOAD_CSWIFT</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(cswift);<br>
+#if HAVE_ENGINE_LOAD_4758CCA</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(4758cca);<br>
#endif<br>
-#if HAVE_ENGINE_LOAD_CHIL</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(chil);<br>
+#if HAVE_ENGINE_LOAD_AEP</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(aep);<br>
#endif<br>
#if HAVE_ENGINE_LOAD_ATALLA<br>
OSSL_ENGINE_LOAD_IF_MATCH(atalla);<br>
#endif<br>
+#if HAVE_ENGINE_LOAD_CHIL</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(chil);<br>
+#endif<br>
+#if HAVE_ENGINE_LOAD_CSWIFT</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(cswift);<br>
+#endif<br>
#if HAVE_ENGINE_LOAD_NURON<br>
OSSL_ENGINE_LOAD_IF_MATCH(nuron);<br>
#endif<br>
+#if HAVE_ENGINE_LOAD_SUREWARE</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(sureware);<br>
+#endif<br>
#if HAVE_ENGINE_LOAD_UBSEC<br>
OSSL_ENGINE_LOAD_IF_MATCH(ubsec);<br>
#endif<br>
-#if HAVE_ENGINE_LOAD_AEP</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(aep);<br>
+#if HAVE_ENGINE_LOAD_PADLOCK</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(padlock);<br>
#endif<br>
-#if HAVE_ENGINE_LOAD_SUREWARE</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(sureware);<br>
+#if HAVE_ENGINE_LOAD_CAPI</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(capi);<br>
#endif<br>
-#if HAVE_ENGINE_LOAD_4758CCA</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(4758cca);<br>
+#if HAVE_ENGINE_LOAD_GMP</li>
</ul>
<ul>
<li>OSSL_ENGINE_LOAD_IF_MATCH(gmp);<br>
+#endif<br>
+#if HAVE_ENGINE_LOAD_GOST</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(gost);<br>
+#endif<br>
+#if HAVE_ENGINE_LOAD_CRYPTODEV</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(cryptodev);<br>
+#endif<br>
+#if HAVE_ENGINE_LOAD_AESNI</li>
<li>OSSL_ENGINE_LOAD_IF_MATCH(aesni);<br>
#endif<br>
#endif<br>
#ifdef HAVE_ENGINE_LOAD_OPENBSD_DEV_CRYPTO</li>
</ul>
Ruby master - Bug #5547 (Closed): Cleanup engine after a test
https://redmine.ruby-lang.org/issues/5547
2011-11-02T11:16:21Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>OpenSSL::Engine.load() loads engines and register them, and it may change the behavior of some existing methods.</p>
<p>For example on NetBSD 6 with cryptodev, it effects DH as folloing:<br>
./ruby -ropenssl -e'p OpenSSL::PKey::DH.new(256).public_key.private?;p OpenSSL::Engine.load;p OpenSSL::PKey::DH.new(256).public_key.private?'<br>
false<br>
true<br>
true</p>
<p>After loads cryptodev and register it (yes, it needs register. current ext/openssl can't register a engine),<br>
OpenSSL::PKey::DH#private?'s behavior seems to be changed.</p>
<p>Whether it is a bug or not, test/openssl/test_engine.rb should be fixed.</p>
<a name="Index-testopenssltest_enginerb"></a>
<h1 >Index: test/openssl/test_engine.rb<a href="#Index-testopenssltest_enginerb" class="wiki-anchor">¶</a></h1>
<p>--- test/openssl/test_engine.rb (revision 33605)<br>
+++ test/openssl/test_engine.rb (working copy)<br>
@@ -8,6 +8,7 @@<br>
OpenSSL::Engine.load<br>
OpenSSL::Engine.engines<br>
OpenSSL::Engine.engines</p>
<ul>
<li>OpenSSL::Engine.cleanup<br>
end</li>
</ul>
<p>end</p>
Ruby master - Bug #5526 (Closed): SEGV: ./ruby -rfiber -ve'f=Fiber.new{f.resume};f.transfer'
https://redmine.ruby-lang.org/issues/5526
2011-11-01T00:02:47Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>FreeBSD 9 にて、./ruby -rfiber -ve'f=Fiber.new{f.resume};f.transfer' で SEGV します。<br>
他のプラットフォームでも dead fiber call 例外なのはおかしくて、<br>
double resume 例外になるべきでしょう。</p>
Ruby master - Bug #5524 (Closed): IO.wait_for_single_fd(closed fd) sticks on other than Linux
https://redmine.ruby-lang.org/issues/5524
2011-10-31T21:31:41Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>r31428 で、test_wait_for_invalid_fd ってテストを追加しており、<br>
IO.wait_for_single_fd(close 済みの fd) が EBADF になることを確認しているのですが、<br>
これ単体で動かすと FreeBSD で戻ってきません。</p>
<p>思うに、このテストって本来ポータブルに刺さる物なんじゃないでしょうか。<br>
test-allだと何かの弾みで通ってしまうだけで。</p>
<p>% cat poll.c<br>
#include <stdio.h><br>
#include <stdlib.h><br>
#include <poll.h><br>
#include <errno.h><br>
int<br>
main(void) {<br>
int pipes[2];<br>
int res = pipe(pipes);<br>
if (res != 0) abort();<br>
int r = pipes[0];<br>
int w = pipes[1];<br>
res = close(w);<br>
if (res != 0) abort();</p>
<pre><code>struct pollfd fds;
fds.fd = w;
fds.events = POLLOUT;
errno = 0;
res = poll(&fds, 1, 1000);
fprintf(stderr, "%d %d %d\n", res, errno, fds.revents);
return 0;
</code></pre>
<p>}</p>
<p>というプログラムではポータブルに POLLVAL が返り、</p>
<p>#include <stdio.h><br>
#include <stdlib.h><br>
#include <sys/select.h><br>
int<br>
main(void) {<br>
int pipes[2];<br>
int res = pipe(pipes);<br>
if (res != 0) abort();<br>
int r = pipes[0];<br>
int w = pipes[1];<br>
res = close(w);<br>
if (res != 0) abort();<br>
fd_set readfds; FD_ZERO(&readfds);<br>
fd_set writefds; FD_ZERO(&writefds);<br>
fd_set exceptfds; FD_ZERO(&exceptfds);<br>
//struct timeval *timeout = NULL;<br>
//FD_SET(r, &readfds);<br>
FD_SET(w, &writefds);<br>
res = select(1, &readfds, &writefds, &exceptfds, NULL);<br>
return 0;<br>
}</p>
<p>はポータブルにブロックされるあたり、このテストってLinux依存なんじゃ無いかという疑惑を持っているんですがどうでしょう。</p>
Ruby master - Feature #5282 (Closed): test-all 結果の順序
https://redmine.ruby-lang.org/issues/5282
2011-09-06T20:21:56Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>現在 Failure と Error と Skip が混ざって結果が出てくるので、ソートして欲しい。</p>
<p>具体的な順番は、一瞬 Skip を最後にしたくなるのだが、通常 EF は数個でかつ末尾から見る訳なので、<br>
Skip Failure Error の順がよいのではなかろうか。</p>
<p>ついでに、一番最後に ruby -v を出力してくれるとうれしいです。</p>
Backport193 - Backport #5276 (Closed): 4294967295.8.round is 4294967295 on 32bit
https://redmine.ruby-lang.org/issues/5276
2011-09-05T18:01:46Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>ruby -e'p 4294967295.8.round' must be 4294967296 but 4294967295 on 32bit environment.</p>
Ruby master - Feature #5180 (Closed): net/http の接続時に用いる IP アドレスの指定
https://redmine.ruby-lang.org/issues/5180
2011-08-10T11:45:57Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>通常 net/http を使う時は、Net::HTTP.start("ruby-lang.org") などとホスト名を使います。<br>
で、Socket がホスト名から IP アドレスを引いて、コネクションが張られます。<br>
普通の人はこれで足りるわけですが、ふつうな人はしばしば DNS で引けない IP アドレスに接続したくなります。<br>
例えば、ホスト名は "ruby-lang.org" としたいが、IP アドレスは 127.0.0.1 とか。</p>
<p>以下のパッチをあてると、<br>
Net::HTTP.start("ruby-lang.org", ipaddr: '127.0.0.1')<br>
などとできるようになります。</p>
<pre><code class="diff syntaxhl" data-language="diff"><span class="gh">diff --git a/lib/net/http.rb b/lib/net/http.rb
index 7b9ec4f..6d034e0 100644
</span><span class="gd">--- a/lib/net/http.rb
</span><span class="gi">+++ b/lib/net/http.rb
</span><span class="p">@@ -524,7 +524,7 @@</span> module Net #:nodoc:
# _opt_ :: optional hash
#
# _opt_ sets following values by its accessor.
<span class="gd">- # The keys are ca_file, ca_path, cert, cert_store, ciphers,
</span><span class="gi">+ # The keys are ipaddr, ca_file, ca_path, cert, cert_store, ciphers,
</span> # close_on_empty_response, key, open_timeout, read_timeout, ssl_timeout,
# ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
# If you set :use_ssl as true, you can use https and default value of
<span class="p">@@ -542,6 +542,7 @@</span> module Net #:nodoc:
port, p_addr, p_port, p_user, p_pass = *arg
port = https_default_port if !port && opt && opt[:use_ssl]
http = new(address, port, p_addr, p_port, p_user, p_pass)
<span class="gi">+ http.ipaddr = opt[:ipaddr] if opt[:ipaddr]
</span>
if opt
if opt[:use_ssl]
<span class="p">@@ -575,6 +576,7 @@</span> module Net #:nodoc:
def initialize(address, port = nil)
@address = address
@port = (port || HTTP.default_port)
<span class="gi">+ @ipaddr = nil
</span> @curr_http_version = HTTPVersion
@no_keepalive_server = false
@close_on_empty_response = false
<span class="p">@@ -620,6 +622,17 @@</span> module Net #:nodoc:
# The port number to connect to.
attr_reader :port
<span class="gi">+ # The IP address to connect to/used to connect to
+ def ipaddr
+ started? ? @socket.io.peeraddr[3] : @ipaddr
+ end
+
+ # Set the IP address to connect to
+ def ipaddr=(addr)
+ raise IOError, "ipaddr value changed, but session already started" if started?
+ @ipaddr = addr
+ end
+
</span> # Number of seconds to wait for the connection to open. Any number
# may be used, including Floats for fractional seconds. If the HTTP
# object cannot open a connection in this many seconds, it raises a
<span class="p">@@ -945,7 +958,7 @@</span> module Net #:nodoc:
# without proxy
def conn_address
<span class="gd">- address()
</span><span class="gi">+ @ipaddr || address()
</span> end
def conn_port
</code></pre>
Ruby master - Feature #5153 (Closed): Remove rb_add_suffix
https://redmine.ruby-lang.org/issues/5153
2011-08-03T12:11:46Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>rb_add_suffix in util.c is GPL and obsoleted code, so I want to remove it.</p>
<p>rb_add_suffix is drived from Perl's win32.c file and GPL/Artistic License.<br>
The code is used when ruby runs with -i (inplace option).<br>
Practically it works only when the renamed file can't create.<br>
(the validation is also a function of the code, but it is not essential)</p>
<p>But this behavior is Windows specific.<br>
On other environment, ruby simply skip the file with a warning "Can't rename %s to %s: %s, skipping file".<br>
I think Windows should follow this.</p>
Ruby master - Feature #5142 (Rejected): Remove ruby-mode.el from ruby's repo
https://redmine.ruby-lang.org/issues/5142
2011-08-02T10:46:33Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>ruby-mode.el は Emacs に添付されるようになりましたが、<br>
今も Ruby のリポジトリ内に misc/ruby-mode.el として存在し続けています。<br>
マスタが Ruby と Emacs の2つあるのも良くないですし、放置されているチケットも多いので、<br>
Ruby のリポジトリからは削除してしまいませんか。</p>
<p>なお、ruby-mode.el 以外の *.el についてはこのチケットの管轄外とします。</p>
Backport193 - Backport #5130 (Closed): Thread.pass sticks on OpenBSD
https://redmine.ruby-lang.org/issues/5130
2011-08-01T15:51:28Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
On OpenBSD 4.9, following script will stick.</p>
<p>./miniruby -ve'Thread.new{Thread.pass}'<br>
=end</p>
Ruby master - Bug #5114 (Closed): rake's tests imply the binary name of ruby
https://redmine.ruby-lang.org/issues/5114
2011-07-29T16:21:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>As Jeremy reported on <a href="/issues/5097">[ruby-core:38530]</a>, current rake tests imply the binary name of ruby as "ruby".<br>
They should use /#{Regexp.quote(RUBY)} -e/ as znz says on <a href="https://blade.ruby-lang.org/ruby-core/38579">[ruby-core:38579]</a>.</p>
Ruby master - Feature #5097 (Closed): Supported platforms of Ruby 1.9.3
https://redmine.ruby-lang.org/issues/5097
2011-07-26T11:52:57Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Let's decide the supported platforms.</p>
<p>== Background</p>
<p><a href="http://redmine.ruby-lang.org/projects/ruby-19/wiki/SupportedPlatforms" class="external">http://redmine.ruby-lang.org/projects/ruby-19/wiki/SupportedPlatforms</a></p>
<p>== Process</p>
<p>If you want to support a platform, please declare.<br>
But when a platform dependent bug is reported, it will be assigned to you.</p>
<p>== Current Maintainer</p>
<p>mswin32, mswin64 (Microsoft Windows):<br>
NAKAMURA Usaku (usa)<br>
mingw32 (Minimalist GNU for Windows):<br>
Nobuyoshi Nakada (nobu)<br>
IA-64 (Debian GNU/Linux):<br>
TAKANO Mitsuhiro (takano32)<br>
Symbian OS:<br>
Alexander Zavorine (azov)<br>
AIX:<br>
Yutaka Kanemoto (kanemoto)<br>
FreeBSD:<br>
Akinori MUSHA (knu)<br>
Solaris:<br>
Naohisa Goto<br>
RHEL, CentOS<br>
KOSAKI Motohiro</p>
<p>Platforms which doesn't have a maintainer are following:</p>
<ul>
<li>Debian</li>
<li>Ubuntu</li>
<li>Mac OS X (LLVM related issues)</li>
<li>cygwin (don't work)</li>
<li>NetBSD (works)</li>
<li>OpenBSD (it may not work)</li>
<li>DragonFlyBSD (don't work)</li>
</ul>
Ruby master - Bug #5094 (Closed): Supported platforms of Ruby 1.9.3
https://redmine.ruby-lang.org/issues/5094
2011-07-26T00:15:52Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>はい、リリース前恒例! サポートプラットフォーム決めのお時間がやって参りました。</p>
<p>前回は 1.9.1 リリース時だったわけですが、あれからずいぶんと経ったので、<br>
改めてサポートするプラットフォームを決めましょう。</p>
<p>== これまでのあらすじ</p>
<p><a href="http://redmine.ruby-lang.org/projects/ruby-19/wiki/SupportedPlatformsJa" class="external">http://redmine.ruby-lang.org/projects/ruby-19/wiki/SupportedPlatformsJa</a></p>
<p>== 決め方</p>
<p>サポートしたいプラットフォームがある方は宣言してください。<br>
ただし、当該プラットフォーム固有っぽいバグがあった場合、そのチケットをアサインする事があるので、<br>
覚悟を決めてから宣言してください。</p>
<p>いつでも「サポート終了!」は宣言できるので [要出典] お気軽にご応募くださいませ。</p>
<p>なお、1.9.3 のリリースのちょっと前あたりで一度締めとする予定です。</p>
<p>== 成瀬の提案</p>
<p>さて、前回のサポートプラットフォーム決めでいくつか反省があるので、ここに一つ提案を行います。</p>
<blockquote>
<p>なお、「メンテナがいる」とは明確なプラットフォームメンテナがいるもの(mswin32など)のほかに、「日々その環境でRubyを開発しているコミッタがいるもの」を含む。</p>
</blockquote>
<p>この後半を削ることを提案します。<br>
例として、Debian はいまだに lenny 32bit が対象になってしまっています。<br>
ようするに切るタイミングが決まらなかったという話で、<br>
こういうのはえいやで決める人がいるべきだろうと思うわけです。</p>
<p>== 現在のメンテナ</p>
<p>ちなみに現在のメンテナは以下の通りです。</p>
<p>mswin32, mswin64 (Microsoft Windows):<br>
NAKAMURA Usaku (usa)<br>
mingw32 (Minimalist GNU for Windows):<br>
Nobuyoshi Nakada (nobu)<br>
IA-64 (Debian GNU/Linux):<br>
TAKANO Mitsuhiro (takano32)<br>
Symbian OS:<br>
Alexander Zavorine (azov)<br>
AIX:<br>
Yutaka Kanemoto (kanemoto)<br>
FreeBSD:<br>
Akinori MUSHA (knu)<br>
Solaris:<br>
Naohisa Goto</p>
<p>逆にメンテナがいない主なプラットフォーム(と備考)は以下の通りです。</p>
<ul>
<li>Debian</li>
<li>Ubuntu</li>
<li>CentOS</li>
<li>Mac OS X (LLVM絡みが微妙)</li>
<li>cygwin (動かない)</li>
<li>NetBSD (動く)</li>
<li>OpenBSD (動かない気がする)</li>
<li>DragonFlyBSD (動かない)</li>
</ul>
Ruby master - Bug #5076 (Closed): Mac OS X Lion Support
https://redmine.ruby-lang.org/issues/5076
2011-07-22T20:20:03Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Ruby doesn't work on Lion.</p>
Backport192 - Backport #5075 (Rejected): invalid *fdp in Mac OS X and FreeBSD over recvmsg with S...
https://redmine.ruby-lang.org/issues/5075
2011-07-22T17:51:06Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Mac OS X と FreeBSD にて、存在しない fd を close してしまう問題について、<br>
現在 r32598 で応急処置が施されていますが、根本的な原因について、<br>
sys/kern/uipc_socket.c を見るに、<br>
<a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_socket.c?rev=1.340.2.6.2.1;content-type=text%2Fplain;only_with_tag=RELENG_8_2_0_RELEASE" class="external">http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_socket.c?rev=1.340.2.6.2.1;content-type=text%2Fplain;only_with_tag=RELENG_8_2_0_RELEASE</a></p>
<pre><code> * Process one or more MT_CONTROL mbufs present before any data mbufs
* in the first mbuf chain on the socket buffer. If MSG_PEEK, we
* just copy the data; if !MSG_PEEK, we call into the protocol to
* perform externalization (or freeing if controlp == NULL).
</code></pre>
<p>とあるので、recvmsg に MSG_PEEK を与えた場合は invalid なものが返ってくると思うのですが。</p>
<p>ちなみに、以下のような printf パッチをあてて走らせると、discard_cmsg() に来たものは全て invalid になっています。</p>
<p>diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c<br>
index 61e0576..ad44fb4 100644<br>
--- a/ext/socket/ancdata.c<br>
+++ b/ext/socket/ancdata.c<br>
@@ -1379,6 +1379,7 @@ rb_recvmsg(int fd, struct msghdr *msg, int flags)<br>
static void<br>
discard_cmsg(struct cmsghdr *cmh, char *msg_end)<br>
{</p>
<ul>
<li>fprintf(stderr, "discard_cmsg-begin\n");<br>
if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {<br>
int *fdp = (int *)CMSG_DATA(cmh);<br>
int *end = (int *)((char *)cmh + cmh->cmsg_len);<br>
@@ -1391,12 +1392,18 @@ discard_cmsg(struct cmsghdr *cmh, char *msg_end)<br>
*/<br>
struct stat buf;<br>
if (fstat(*fdp, &buf) == 0) {</li>
<li>
<pre><code> fprintf(stderr, "fdp: %d is valid (%p %p %p)\n", *fdp,fdp,end,msg_end);
rb_update_max_fd(*fdp);
close(*fdp);
}
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "fdp: %d is invalid (%p %p %p)\n", *fdp,fdp,end,msg_end);
</code></pre>
</li>
<li>
<pre><code> rb_backtrace();
</code></pre>
</li>
<li>
<pre><code> }
fdp++;
}
</code></pre>
}</li>
<li>fprintf(stderr, "discard_cmsg-end\n");<br>
}<br>
#endif</li>
</ul>
<p>@@ -1432,6 +1439,7 @@ make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)<br>
(char *)fdp + sizeof(int) <= msg_end) {<br>
int fd = *fdp;<br>
struct stat stbuf;</p>
<ul>
<li>fprintf(stderr,"makeiounixr: %d (%p %p %p)\n", *fdp,fdp,end,msg_end);<br>
VALUE io;<br>
if (fstat(fd, &stbuf) == -1)<br>
rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");</li>
</ul>
Ruby master - Bug #5026 (Closed): 1.9.3 allows URI(uri, parser)
https://redmine.ruby-lang.org/issues/5026
2011-07-14T07:28:08Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>r28699 introduces a new API: the second argument of URI(uri [, parser]).<br>
But I object this because such parser argument should be obsolete.</p>
Ruby master - Feature #4921 (Rejected): Remove intern.h
https://redmine.ruby-lang.org/issues/4921
2011-06-23T08:15:07Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>まず、intern.h って何者なんでしょう。<br>
推測としては internal の意だと思うんですが、その場合 include/ruby にいるのは<br>
よろしくないですし、一方で公開 API っぽいのが名実ともに多い気がします。</p>
<p>思うに 1.9 において、intern.h の中身は include/ruby/ruby.h か、<br>
最近新設された internal.h のどちらかにあるべきで、include/ruby/intern.h は<br>
もう必要ないのではないでしょうか。</p>
Ruby master - Bug #4886 (Closed): autoload in instance_eval doesn't work
https://redmine.ruby-lang.org/issues/4886
2011-06-15T09:53:15Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>autoload を instance_eval の中で使うとうまく動きません。</p>
<p>% ./ruby -e'instance_eval{autoload :R,"a";p R}'<br>
-e:1:in <code>block in <main>': uninitialized constant R (NameError) from -e:1:in </code>instance_eval'<br>
from -e:1:in `'</p>
Ruby master - Bug #4826 (Closed): Date fails RubySpec
https://redmine.ruby-lang.org/issues/4826
2011-06-04T21:44:01Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>最近の Date の変更で、以下のように RubySpec が失敗しています。<br>
RubySpec 側を直した方がいい物もあるような気がしますが、Date 側の問題もあるようなので確認頂けますか。<br>
spec 側を直すべきものについてはあるべき挙動を教えて頂ければそう直します。</p>
<p>なお、RubySpec は <a href="http://rubyspec.org/" class="external">http://rubyspec.org/</a> です。<br>
RubySpec を実行するには、git をインストールした上で、<br>
make update-rubyspec<br>
すると、spec/rubyspec 下に rubyspec のコードが持ってこられるので、<br>
make test-rubyspec MSPECOPT='-V -j -f s /library/date/civil_spec.rb'<br>
などとすれば該当のテストだけを走らせることができます。</p>
<ol start="6">
<li>
</ol>
<p>Date#civil creats a Date for different calendar reform dates FAILED<br>
Expected 2<br>
to equal 20</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:61:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/civil_spec.rb:5:in </code><top (required)>'</p>
<ol start="7">
<li>
</ol>
<p>Date#civil doesn't blow up (illegal instruction and segfault, respectively) when fed huge numbers FAILED<br>
Expected FloatDomainError but got RangeError (float Inf out of range of integer)<br>
/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:72:in <code>block (4 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:71:in </code>each'<br>
/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:71:in <code>block (3 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/civil_spec.rb:5:in </code><top (required)>'</p>
<ol start="8">
<li>
</ol>
<p>Date#gregorian? marks a day before the calendar reform as Julian FAILED<br>
Expected true<br>
to equal false</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/gregorian_spec.rb:8:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/gregorian_spec.rb:4:in </code><top (required)>'</p>
<ol start="9">
<li>
</ol>
<p>Date#gregorian? marks a day after the calendar reform as Julian FAILED<br>
Expected false<br>
to equal true</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/gregorian_spec.rb:13:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/gregorian_spec.rb:4:in </code><top (required)>'</p>
<ol start="10">
<li>
</ol>
<p>Date#julian? should mark a day before the calendar reform as Julian FAILED<br>
Expected false<br>
to equal true</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/julian_spec.rb:20:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/julian_spec.rb:16:in </code><top (required)>'</p>
<ol start="11">
<li>
</ol>
<p>Date#julian? should mark a day after the calendar reform as Julian FAILED<br>
Expected true<br>
to equal false</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/julian_spec.rb:25:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/julian_spec.rb:16:in </code><top (required)>'</p>
<ol start="12">
<li>
</ol>
<p>Date#new creats a Date for different calendar reform dates FAILED<br>
Expected 2<br>
to equal 20</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:61:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/new_spec.rb:5:in </code><top (required)>'</p>
<ol start="13">
<li>
</ol>
<p>Date#new doesn't blow up (illegal instruction and segfault, respectively) when fed huge numbers FAILED<br>
Expected FloatDomainError but got RangeError (float Inf out of range of integer)<br>
/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:72:in <code>block (4 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:71:in </code>each'<br>
/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/shared/civil.rb:71:in <code>block (3 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/date/new_spec.rb:5:in </code><top (required)>'</p>
Ruby master - Bug #4825 (Closed): BigDecimal#new is broken
https://redmine.ruby-lang.org/issues/4825
2011-06-04T21:32:58Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>RubySpec にて以下のテストが失敗しています。</p>
<p>BigDecimal.new creates a new object of class BigDecimal FAILED<br>
Expected #<a href="BigDecimal:445ef968,'0.1E0',9(18)" class="external">BigDecimal:445ef968,'0.1E0',9(18)</a><br>
to equal (1/10)</p>
<p>/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/bigdecimal/new_spec.rb:12:in <code>block (3 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/bigdecimal/new_spec.rb:8:in </code>each'<br>
/usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/bigdecimal/new_spec.rb:8:in <code>block (2 levels) in <top (required)>' /usr/home/chkbuild/build/ruby-trunk/20110604T110102Z/rubyspec/library/bigdecimal/new_spec.rb:4:in </code><top (required)>'</p>
Ruby master - Bug #4815 (Closed): RubyGems test failed
https://redmine.ruby-lang.org/issues/4815
2011-06-02T12:04:59Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>Following tests are failed.<br>
This is because $LOAD_PATH includes the current directory which test-all is running,<br>
and top source directory of ruby has the directory named "missing".<br>
So test_execute_one_missing and test_execute_missing, they check the absence of "missing" directory, are failed.</p>
<ol start="29">
<li>
<p>Failure:<br>
test_execute_one_missing(TestGemCommandsWhichCommand) [/usr/home/chkbuild/build/ruby-trunk/20110602T010101Z/ruby/test/rubygems/test_gem_commands_which_command.rb:42]:<br>
--- expected<br>
+++ actual<br>
@@ -1,2 +1,3 @@<br>
"/usr/home/chkbuild/build/ruby-trunk/20110602T010101Z/tmp/test_rubygems_93491/gemhome/gems/foo_bar-2/lib/foo_bar.rb<br>
+/usr/home/chkbuild/build/ruby-trunk/20110602T010101Z/ruby/missing<br>
"</p>
</li>
<li>
<p>Failure:<br>
test_execute_missing(TestGemCommandsWhichCommand) [/usr/home/chkbuild/build/ruby-trunk/20110602T010101Z/ruby/test/rubygems/test_gem_commands_which_command.rb:51]:<br>
Gem::MockGemUi::TermError expected but nothing was raised.</p>
</li>
</ol>
Ruby master - Feature #4595 (Closed): TkPhotoImage documentation
https://redmine.ruby-lang.org/issues/4595
2011-04-22T12:12:22Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
以下のような pull request が来ています。</p>
<p>I have documented some method from TkPhotoImage, based on the original Tcl/Tk docs.</p>
<p><a href="https://github.com/ruby/ruby/pull/9" class="external">https://github.com/ruby/ruby/pull/9</a><br>
=end</p>
Ruby master - Feature #4529 (Rejected): date_core と long 型
https://redmine.ruby-lang.org/issues/4529
2011-03-26T06:13:43Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
おそらく既にご存じの通り、最近 date_core も含めて ext 中の shorten-64-to-32 を直しています。<br>
それに際して date_core をいじっていて気づいたのですが、ユリウス日や年を long で保持したり int で保持したりしています。</p>
<p>int と long が混在していると、long から int へのキャスト時にオーバーフローが起こりえますし、<br>
そもそも long は</p>
<ul>
<li>環境によってサイズが違う (int も 理屈の上では違うはずだが、CRuby では 32bit しか確認してない)</li>
<li>long は mswin64 でだけポインタとサイズが違うので、Unix な人には気づきづらいバグの温床になる<br>
というような懸念があるので、特に理由が無いのであれば、int にするか、int64_t にするかした方がよいかと思います。<br>
(CRuby は C90 だが、int64_t を configure で定義している)</li>
</ul>
<p>例えば int に統一する場合のパッチは以下の通りです</p>
<p>=end</p>
Ruby master - Bug #4455 (Closed): rubygem's test fails when source directory and build directory ...
https://redmine.ruby-lang.org/issues/4455
2011-03-01T23:12:35Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
In lib/rubygems/test_case.rb, it sets @project_dir as Dir.pwd.<br>
But the use cases of @project_dir are both top of source and build directory.<br>
It breaks when they differ.</p>
<p>This happens when:</p>
<p>cd $HOME<br>
mkdir bin-ruby<br>
svn co <a href="http://svn.ruby-lang.org/repos/ruby/trunk" class="external">http://svn.ruby-lang.org/repos/ruby/trunk</a> src-ruby<br>
cd ruby<br>
autoconf<br>
mkdir ../build-ruby<br>
cd ../build-ruby<br>
../ruby/configure --prefix=$HOME/bin-ruby<br>
make<br>
make install<br>
make test-all</p>
<p>The error messages are following:<br>
2) Failure:<br>
test_self_prefix(TestGem) [/home/naruse/ruby/test/rubygems/test_gem.rb:779]:<br>
Expected "/home/naruse/obj/ruby", not "/home/naruse/ruby".</p>
<ol start="3">
<li>
<p>Failure:<br>
test_self_prefix_libdir(TestGem) [/home/naruse/ruby/test/rubygems/test_gem.rb:786]:<br>
Expected "/home/naruse/ruby" to be nil.</p>
</li>
<li>
<p>Failure:<br>
test_self_find_files(TestGem) [/home/naruse/ruby/test/rubygems/test_gem.rb:655]:<br>
Expected ["/home/naruse/obj/ruby/test/rubygems/sff/discover.rb",<br>
"/tmp/test-all/test_rubygems_56936/gemhome/gems/sff-2/lib/sff/discover.rb",<br>
"/tmp/test-all/test_rubygems_56936/gemhome/gems/sff-1/lib/sff/discover.rb"], not ["/home/naruse/ruby/test/rubygems/sff/discover.rb",<br>
"/tmp/test-all/test_rubygems_56936/gemhome/gems/sff-2/lib/sff/discover.rb",<br>
"/tmp/test-all/test_rubygems_56936/gemhome/gems/sff-1/lib/sff/discover.rb"].</p>
</li>
<li>
<p>Failure:<br>
test_self_prefix_sitelibdir(TestGem) [/home/naruse/ruby/test/rubygems/test_gem.rb:795]:<br>
Expected "/home/naruse/ruby" to be nil.</p>
</li>
<li>
<p>Error:<br>
test_execute_removes_executable(TestGemCommandsUninstallCommand):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2 for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:32:in `block (2 levels) in test_execute_removes_executable'
/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:31:in `block in test_execute_removes_executable'
/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:30:in `test_execute_removes_executable'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="7">
<li>
<p>Error:<br>
test_execute_prerelease(TestGemCommandsUninstallCommand):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/pre-2.b/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/pre-2.b/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome/gems/pre-2.b for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome/gems/pre-2.b/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:100:in `block (2 levels) in test_execute_prerelease'
/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:99:in `block in test_execute_prerelease'
/home/naruse/ruby/test/rubygems/test_gem_commands_uninstall_command.rb:98:in `test_execute_prerelease'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="8">
<li>Error:<br>
test_class_build(TestGemExtRakeBuilder):<br>
Gem::InstallError: rake failed:</li>
</ol>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb</p>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/prefix RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/prefix<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_ext_rake_builder.rb:36:in `block (2 levels) in test_class_build'
/home/naruse/ruby/test/rubygems/test_gem_ext_rake_builder.rb:34:in `chdir'
/home/naruse/ruby/test/rubygems/test_gem_ext_rake_builder.rb:34:in `block in test_class_build'
/home/naruse/ruby/test/rubygems/test_gem_ext_rake_builder.rb:33:in `test_class_build'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="9">
<li>
<p>Error:<br>
test_install_ignore_dependencies(TestGemInstaller):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb --build_arg1 --build_arg2</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2 for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_installer.rb:698:in `block (2 levels) in test_install_ignore_dependencies'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:697:in `block in test_install_ignore_dependencies'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:696:in `test_install_ignore_dependencies'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="10">
<li>
<p>Error:<br>
test_install_with_no_prior_files(TestGemInstaller):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb --build_arg1 --build_arg2</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2 for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_installer.rb:594:in `block (2 levels) in test_install_with_no_prior_files'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:593:in `block in test_install_with_no_prior_files'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:592:in `test_install_with_no_prior_files'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="11">
<li>
<p>Error:<br>
test_install_check_dependencies_install_dir(TestGemInstaller):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb --build_arg1 --build_arg2</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome2/gems/a-2/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome2/gems/a-2/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome2/gems/a-2 for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome2/gems/a-2/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_installer.rb:673:in `block (2 levels) in test_install_check_dependencies_install_dir'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:672:in `block in test_install_check_dependencies_install_dir'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:671:in `test_install_check_dependencies_install_dir'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<ol start="12">
<li>
<p>Error:<br>
test_install(TestGemInstaller):<br>
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.</p>
<p>/home/naruse/obj/ruby/ruby mkrf_conf.rb --build_arg1 --build_arg2</p>
</li>
</ol>
<p>rake RUBYARCHDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib RUBYLIBDIR=/tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/lib<br>
/home/naruse/obj/ruby/rbconfig.rb:7: ruby lib version (1.9.3) doesn't match executable version (1.8.7) (RuntimeError)<br>
from /home/naruse/ruby/lib/rubygems.rb:36:in <code>require' from /home/naruse/ruby/lib/rubygems.rb:36 from /usr/local/bin/rake:9:in </code>require'<br>
from /usr/local/bin/rake:9</p>
<p>Gem files will remain installed in /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2 for inspection.<br>
Results logged to /tmp/test-all/test_rubygems_56936/gemhome/gems/a-2/ext/a/gem_make.out</p>
<pre><code>/home/naruse/ruby/test/rubygems/test_gem_installer.rb:560:in `block (2 levels) in test_install'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:559:in `block in test_install'
/home/naruse/ruby/test/rubygems/test_gem_installer.rb:558:in `test_install'
../../ruby/test/runner.rb:10:in `<main>'
</code></pre>
<p>=end</p>
Ruby master - Bug #4454 (Closed): Fails test by ext/date
https://redmine.ruby-lang.org/issues/4454
2011-03-01T13:34:19Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
ext/date 導入以降、以下の2テストが失敗します。</p>
<ol start="2">
<li>
<p>Failure:<br>
test_sub(TestDate) [/home/chkbuild/build/ruby-trunk/20110228T230101Z/ruby/test/date/test_date.rb:44]:<br>
<"#<DateSub: -4712-01-01 (-1/2,0,2299161)>"> expected but was<br>
<"#<DateSub[R]: -4712-01-01 (-1/2,0,2299161)>">.</p>
</li>
<li>
<p>Failure:<br>
test__attr(TestDateAttr) [/home/chkbuild/build/ruby-trunk/20110228T230101Z/ruby/test/date/test_date_attr.rb:12]:<br>
Expected /#<Date\d?: 1965-05-23 (4877807/2,0,2299161)>/ to match "#<Date[L]: 1965-05-23 (2438904j,0,2299161)>".<br>
=end</p>
</li>
</ol>
Ruby master - Bug #4426 (Closed): rubygems/test_gem_gemcutter_utilities.rb fails
https://redmine.ruby-lang.org/issues/4426
2011-02-22T20:57:18Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
When run make RUBYOPT=-w TESTS='-v rubygems/test_gem_gemcutter_utilities.rb' test-all, it fails as following:</p>
<ol>
<li>
<p>Error:<br>
test_sign_in(TestGemGemcutterUtilities):<br>
NameError: uninitialized constant Gem::Command<br>
/home/naruse/ruby/test/rubygems/test_gem_gemcutter_utilities.rb:19:in `setup'</p>
</li>
<li>
<p>Error:<br>
test_sign_in_skips_with_existing_credentials(TestGemGemcutterUtilities):<br>
NameError: uninitialized constant Gem::Command<br>
/home/naruse/ruby/test/rubygems/test_gem_gemcutter_utilities.rb:19:in `setup'</p>
</li>
<li>
<p>Error:<br>
test_sign_in_with_bad_credentials(TestGemGemcutterUtilities):<br>
NameError: uninitialized constant Gem::Command<br>
/home/naruse/ruby/test/rubygems/test_gem_gemcutter_utilities.rb:19:in `setup'</p>
</li>
<li>
<p>Error:<br>
test_sign_in_with_host(TestGemGemcutterUtilities):<br>
NameError: uninitialized constant Gem::Command<br>
/home/naruse/ruby/test/rubygems/test_gem_gemcutter_utilities.rb:19:in `setup'</p>
</li>
<li>
<p>Error:<br>
test_sign_in_with_other_credentials_doesnt_overwrite_other_keys(TestGemGemcutterUtilities):<br>
NameError: uninitialized constant Gem::Command<br>
/home/naruse/ruby/test/rubygems/test_gem_gemcutter_utilities.rb:19:in `setup'<br>
=end</p>
</li>
</ol>
Ruby master - Bug #4395 (Closed): Can't require test/rubygems/simple_gem when tests run in differ...
https://redmine.ruby-lang.org/issues/4395
2011-02-14T09:34:46Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
It fails as following:</p>
<ol>
<li>
<p>Skipped:<br>
test_require_failed(test/rubygems/simple_gem) [/home/naruse/ruby/test/rubygems/test_gem_format.rb:8]:<br>
cannot load such file -- test/rubygems/simple_gem</p>
</li>
<li>
<p>Skipped:<br>
test_require_failed(test/rubygems/simple_gem) [/home/naruse/ruby/test/rubygems/test_gem_validator.rb:8]:<br>
cannot load such file -- test/rubygems/simple_gem</p>
</li>
</ol>
<p>Line 8 of test/rubygems/test_gem_format.rb should use require_relative.<br>
=end</p>
Ruby master - Bug #4376 (Closed): rdoc can't handle correctly the return value when the file has ...
https://redmine.ruby-lang.org/issues/4376
2011-02-07T13:11:12Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
From r30806 to r30813, make rdoc raises error on LANG=C environment like:<br>
<a href="http://59.106.172.211/~chkbuild/ruby-trunk/log/20110207T010100Z.log.html.gz" class="external">http://59.106.172.211/~chkbuild/ruby-trunk/log/20110207T010100Z.log.html.gz</a></p>
<p>This is because the encoding of output is set to US-ASCII, failed character<br>
encoding conversion on doc/re.rdoc, and wrongly treated nil as String.</p>
<p>The main bug is set to US-ASCII, so I fixed it in r30813.<br>
But nil treatment should be rdoc's bug, so I report this.</p>
<p>Generating RDoc documentation<br>
Parsing sources...<br>
unable to convert U+6771 from UTF-8 to US-ASCII for ../../ruby/doc/re.rdoc, skipping<br>
Before reporting this, could you check that the file you're documenting<br>
has proper syntax:</p>
<p>/home/naruse/local/ruby/bin/ruby -c ../../ruby/re.c</p>
<p>RDoc is not a full Ruby parser and will fail when fed invalid ruby programs.</p>
<p>The internal error was:</p>
<pre><code> (NoMethodError) undefined method `sub' for nil:NilClass
</code></pre>
<p>/home/naruse/ruby/lib/rdoc/markup/pre_process.rb:126:in <code>include_file' /home/naruse/ruby/lib/rdoc/markup/pre_process.rb:76:in </code>block in handle'<br>
/home/naruse/ruby/lib/rdoc/markup/pre_process.rb:61:in <code>gsub!' /home/naruse/ruby/lib/rdoc/markup/pre_process.rb:61:in </code>handle'<br>
/home/naruse/ruby/lib/rdoc/parser/c.rb:867:in <code>look_for_directives_in' /home/naruse/ruby/lib/rdoc/parser/c.rb:516:in </code>find_class_comment'<br>
/home/naruse/ruby/lib/rdoc/parser/c.rb:687:in <code>handle_class_module' /home/naruse/ruby/lib/rdoc/parser/c.rb:204:in </code>block in do_classes'<br>
/home/naruse/ruby/lib/rdoc/parser/c.rb:199:in <code>scan' /home/naruse/ruby/lib/rdoc/parser/c.rb:199:in </code>do_classes'<br>
/home/naruse/ruby/lib/rdoc/parser/c.rb:987:in <code>scan' /home/naruse/ruby/lib/rdoc/rdoc.rb:322:in </code>parse_file'<br>
/home/naruse/ruby/lib/rdoc/rdoc.rb:367:in <code>block in parse_files' /home/naruse/ruby/lib/rdoc/rdoc.rb:365:in </code>map'<br>
/home/naruse/ruby/lib/rdoc/rdoc.rb:365:in <code>parse_files' /home/naruse/ruby/lib/rdoc/rdoc.rb:423:in </code>document'<br>
../../ruby/bin/rdoc:15:in <code><main>' uh-oh! RDoc had a problem: undefined method </code>sub' for nil:NilClass</p>
<p>run with --debug for full backtrace<br>
*** Error code 1</p>
<p>Stop in /home/naruse/obj/ruby.<br>
=end</p>
Ruby master - Feature #4180 (Closed): Add Zlib.deflate / Zlib.inflate
https://redmine.ruby-lang.org/issues/4180
2010-12-21T10:34:56Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Zlib::Deflate.deflate ってムダに長いと思いんです。<br>
Rails 的な言葉で言うと、DRY じゃないと言いますか。<br>
Zlib.deflate でいいんじゃないかと。</p>
<p>同様に、Zlib::Inflate.inflate も Zlib.inflate でいいのではないでしょうか。<br>
=end</p>
Backport187 - Backport #4171 (Closed): Warn Array#choice
https://redmine.ruby-lang.org/issues/4171
2010-12-19T18:26:40Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Array#choice は Ruby 1.8.7 で入ったメソッドですが、1.9 ではなくなっているので、<br>
ruby_1_8 だけでなく、ruby_1_8_7 パッチリリースでも warning を出すようにしませんか。<br>
=end</p>
Ruby master - Bug #4163 (Closed): RubyGems uses deprecated API: YAML.quick_emit.
https://redmine.ruby-lang.org/issues/4163
2010-12-16T04:46:28Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
RubyGems::Specification#to_yaml uses depcrecated API: YAML.quick_emit,<br>
and it show many warnings on make test-all.<br>
/usr/home/chkbuild/build/ruby-trunk//ruby/lib/rubygems/specification.rb:706:in `to_yaml': YAML.quick_emit is deprecated<br>
=end</p>
Ruby master - Feature #4142 (Closed): multipart/form-data for net/http
https://redmine.ruby-lang.org/issues/4142
2010-12-10T09:17:39Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
multipart/form-data 対応を net/http に入れませんか。<br>
追加される API は Net::HTTPRequest#set_form になります。</p>
<p>akr さんからは multipart/form-data 用のデータを出力する API 案も示唆されたのですが、<br>
chunked encoding を考慮に入れるとうまくまとまらなかったので見送っています。</p>
<p>diff --git a/lib/net/http.rb b/lib/net/http.rb<br>
index 4d475b1..2751f77 100644<br>
--- a/lib/net/http.rb<br>
+++ b/lib/net/http.rb<br>
@@ -22,6 +22,7 @@<br>
require 'net/protocol'<br>
autoload :OpenSSL, 'openssl'<br>
require 'uri'<br>
+autoload :SecureRandom, 'securerandom'</p>
<p>module Net #:nodoc:</p>
<p>@@ -1772,7 +1773,8 @@ module Net #:nodoc:<br>
alias content_type= set_content_type</p>
<pre><code> # Set header fields and a body from HTML form data.
</code></pre>
<ul>
<li>
<a name="params-should-be-a-Hash-containing-HTML-form-data"></a>
<h1 >+params+ should be a Hash containing HTML form data.<a href="#params-should-be-a-Hash-containing-HTML-form-data" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<ul>
<li>
<a name="params-should-be-an-Array-of-Arrays-or"></a>
<h1 >+params+ should be an Array of Arrays or<a href="#params-should-be-an-Array-of-Arrays-or" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="a-Hash-containing-HTML-form-data"></a>
<h1 >a Hash containing HTML form data.<a href="#a-Hash-containing-HTML-form-data" class="wiki-anchor">¶</a></h1>
<a name="Optional-argument-sep-means-data-record-separator"></a>
<h1 >Optional argument +sep+ means data record separator.<a href="#Optional-argument-sep-means-data-record-separator" class="wiki-anchor">¶</a></h1>
<h1></h1>
<a name="Values-are-URL-encoded-as-necessary-and-the-content-type-is-set-to"></a>
<h1 >Values are URL encoded as necessary and the content-type is set to<a href="#Values-are-URL-encoded-as-necessary-and-the-content-type-is-set-to" class="wiki-anchor">¶</a></h1>
</li>
</ul>
<p>@@ -1792,6 +1794,48 @@ module Net #:nodoc:</p>
<pre><code> alias form_data= set_form_data
</code></pre>
<ul>
<li>
<a name="Set-a-HTML-form-data-set"></a>
<h1 >Set a HTML form data set.<a href="#Set-a-HTML-form-data-set" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="params-is-the-form-data-set-it-is-an-Array-of-Arrays-or-a-Hash"></a>
<h1 >+params+ is the form data set; it is an Array of Arrays or a Hash<a href="#params-is-the-form-data-set-it-is-an-Array-of-Arrays-or-a-Hash" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="enctype-is-the-type-to-encode-the-form-data-set"></a>
<h1 >+enctype is the type to encode the form data set.<a href="#enctype-is-the-type-to-encode-the-form-data-set" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="It-is-applicationx-www-form-urlencoded-or-multipartform-data"></a>
<h1 >It is application/x-www-form-urlencoded or multipart/form-data.<a href="#It-is-applicationx-www-form-urlencoded-or-multipartform-data" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="formpot-is-an-optional-hash-to-specify-the-detail"></a>
<h1 >+formpot+ is an optional hash to specify the detail.<a href="#formpot-is-an-optional-hash-to-specify-the-detail" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="boundary-the-boundary-of-the-multipart-message"></a>
<h1 >boundary:: the boundary of the multipart message<a href="#boundary-the-boundary-of-the-multipart-message" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="charset-the-charset-of-the-message-All-names-and-the-values-of"></a>
<h1 >charset:: the charset of the message. All names and the values of<a href="#charset-the-charset-of-the-message-All-names-and-the-values-of" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="non-file-fields-are-encoded-as-the-charset"></a>
<h1 >non-file fields are encoded as the charset.<a href="#non-file-fields-are-encoded-as-the-charset" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="Each-item-of-params-is-an-array-and-contains-following-items"></a>
<h1 >Each item of params is an array and contains following items:<a href="#Each-item-of-params-is-an-array-and-contains-following-items" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="name-the-name-of-the-field"></a>
<h1 >+name+:: the name of the field<a href="#name-the-name-of-the-field" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="value-the-value-of-the-field-it-should-be-a-String-or-a-File"></a>
<h1 >+value+:: the value of the field, it should be a String or a File<a href="#value-the-value-of-the-field-it-should-be-a-String-or-a-File" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="opt-an-optional-hash-to-specify-additional-information"></a>
<h1 >+opt+:: an optional hash to specify additional information<a href="#opt-an-optional-hash-to-specify-additional-information" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="Each-item-is-a-file-field-or-a-normal-field"></a>
<h1 >Each item is a file field or a normal field.<a href="#Each-item-is-a-file-field-or-a-normal-field" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="If-value-is-a-File-object-or-the-opt-have-a-filename-key"></a>
<h1 >If +value+ is a File object or the +opt+ have a filename key,<a href="#If-value-is-a-File-object-or-the-opt-have-a-filename-key" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="the-item-is-treated-as-a-file-field"></a>
<h1 >the item is treated as a file field.<a href="#the-item-is-treated-as-a-file-field" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="If-Transfer-Encoding-is-set-as-chunked-this-send-the-request-in"></a>
<h1 >If Transfer-Encoding is set as chunked, this send the request in<a href="#If-Transfer-Encoding-is-set-as-chunked-this-send-the-request-in" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="chunked-encoding-Because-chunked-encoding-is-HTTP11-feature"></a>
<h1 >chunked encoding. Because chunked encoding is HTTP/1.1 feature,<a href="#chunked-encoding-Because-chunked-encoding-is-HTTP11-feature" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="you-must-confirm-the-server-to-support-HTTP11-before-sending-it"></a>
<h1 >you must confirm the server to support HTTP/1.1 before sending it.<a href="#you-must-confirm-the-server-to-support-HTTP11-before-sending-it" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="Example"></a>
<h1 >Example:<a href="#Example" class="wiki-anchor">¶</a></h1>
</li>
<li>
<a name="httpset_formq-ruby-lang-en"></a>
<h1 >http.set_form([["q", "ruby"], ["lang", "en"]])<a href="#httpset_formq-ruby-lang-en" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<a name="See-also-RFC-2388-RFC-2616-HTML-401-and-HTML5"></a>
<h1 >See also RFC 2388, RFC 2616, HTML 4.01, and HTML5<a href="#See-also-RFC-2388-RFC-2616-HTML-401-and-HTML5" class="wiki-anchor">¶</a></h1>
</li>
<li>
<h1></h1>
</li>
<li>
<p>def set_form(params, enctype='application/x-www-form-urlencoded', formopt={})</p>
</li>
<li>
<pre><code> @body_data = params
</code></pre>
</li>
<li>
<pre><code> @body = nil
</code></pre>
</li>
<li>
<pre><code> @body_stream = nil
</code></pre>
</li>
<li>
<pre><code> @form_option = formopt
</code></pre>
</li>
<li>
<pre><code> case enctype
</code></pre>
</li>
<li>
<pre><code> when /\Aapplication\/x-www-form-urlencoded\z/i,
</code></pre>
</li>
<li>
<pre><code> /\Amultipart\/form-data\z/i
</code></pre>
</li>
<li>
<pre><code> self.content_type = enctype
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> raise ArgumentError, "invalid enctype: #{enctype}"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<p>end</p>
</li>
<li>
<a name="Set-the-Authorization-header-for-Basic-authorization"></a>
<h1 >Set the Authorization: header for "Basic" authorization.<a href="#Set-the-Authorization-header-for-Basic-authorization" class="wiki-anchor">¶</a></h1>
<p>def basic_auth(account, password)<br>
@header['authorization'] = [basic_encode(account, password)]<br>
@@ -1849,6 +1893,7 @@ module Net #:nodoc:<br>
self['User-Agent'] ||= 'Ruby'<br>
@body = nil<br>
@body_stream = nil</p>
</li>
<li>
<pre><code> @body_data = nil
</code></pre>
<p>end</p>
<p>attr_reader :method<br>
@@ -1876,6 +1921,7 @@ module Net #:nodoc:<br>
def body=(str)<br>
@body = str<br>
@body_stream = nil</p>
</li>
<li>
<pre><code> @body_data = nil
str
</code></pre>
<p>end</p>
</li>
</ul>
<p>@@ -1884,6 +1930,7 @@ module Net #:nodoc:<br>
def body_stream=(input)<br>
@body = nil<br>
@body_stream = input</p>
<ul>
<li>
<pre><code> @body_data = nil
input
</code></pre>
end</li>
</ul>
<p>@@ -1901,6 +1948,8 @@ module Net #:nodoc:<br>
send_request_with_body sock, ver, path, @body<br>
elsif @body_stream<br>
send_request_with_body_stream sock, ver, path, @body_stream</p>
<ul>
<li>
<pre><code> elsif @body_data
</code></pre>
</li>
<li>
<pre><code> send_request_with_body_data sock, ver, path, @body_data
else
write_header sock, ver, path
end
</code></pre>
</li>
</ul>
<p>@@ -1935,6 +1984,92 @@ module Net #:nodoc:<br>
end<br>
end</p>
<ul>
<li>
<p>def send_request_with_body_data(sock, ver, path, params)</p>
</li>
<li>
<pre><code> if /\Amultipart\/form-data\z/i !~ self.content_type
</code></pre>
</li>
<li>
<pre><code> self.content_type = 'application/x-www-form-urlencoded'
</code></pre>
</li>
<li>
<pre><code> return send_request_with_body(sock, ver, path, URI.encode_www_form(params))
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<li>
<pre><code> opt = @form_option.dup
</code></pre>
</li>
<li>
<pre><code> opt[:boundary] ||= SecureRandom.urlsafe_base64(40)
</code></pre>
</li>
<li>
<pre><code> self.set_content_type(self.content_type, boundary: opt[:boundary])
</code></pre>
</li>
<li>
<pre><code> if chunked?
</code></pre>
</li>
<li>
<pre><code> write_header sock, ver, path
</code></pre>
</li>
<li>
<pre><code> encode_multipart_form_data(sock, params, opt)
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> require 'tempfile'
</code></pre>
</li>
<li>
<pre><code> file = Tempfile.new('multipart')
</code></pre>
</li>
<li>
<pre><code> encode_multipart_form_data(file, params, opt)
</code></pre>
</li>
<li>
<pre><code> file.rewind
</code></pre>
</li>
<li>
<pre><code> self.content_length = file.size
</code></pre>
</li>
<li>
<pre><code> write_header sock, ver, path
</code></pre>
</li>
<li>
<pre><code> IO.copy_stream(file, sock)
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<p>end</p>
</li>
<li>
<li>
<p>def encode_multipart_form_data(out, params, opt)</p>
</li>
<li>
<pre><code> charset = opt[:charset]
</code></pre>
</li>
<li>
<pre><code> boundary = opt[:boundary]
</code></pre>
</li>
<li>
<pre><code> boundary ||= SecureRandom.urlsafe_base64(40)
</code></pre>
</li>
<li>
<pre><code> chunked_p = chunked?
</code></pre>
</li>
<li>
<li>
<pre><code> buf = ''
</code></pre>
</li>
<li>
<pre><code> params.each do |key, value, h={}|
</code></pre>
</li>
<li>
<pre><code> key = quote_string(key, charset)
</code></pre>
</li>
<li>
<pre><code> filename =
</code></pre>
</li>
<li>
<pre><code> h.key?(:filename) ? h[:filename] :
</code></pre>
</li>
<li>
<pre><code> value.respond_to?(:to_path) ? File.basename(value.to_path) :
</code></pre>
</li>
<li>
<pre><code> nil
</code></pre>
</li>
<li>
<li>
<pre><code> buf << "--#{boundary}\r\n"
</code></pre>
</li>
<li>
<pre><code> if filename
</code></pre>
</li>
<li>
<pre><code> filename = quote_string(filename, charset)
</code></pre>
</li>
<li>
<pre><code> type = h[:content_type] || 'application/octet-stream'
</code></pre>
</li>
<li>
<pre><code> buf << "Content-Disposition: form-data; " \
</code></pre>
</li>
<li>
<pre><code> "name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
</code></pre>
</li>
<li>
<pre><code> "Content-Type: #{type}\r\n\r\n"
</code></pre>
</li>
<li>
<pre><code> if !out.respond_to?(:write) || !value.respond_to?(:read)
</code></pre>
</li>
<li>
<pre><code> # if +out+ is not an IO or +value+ is not an IO
</code></pre>
</li>
<li>
<pre><code> buf << (value.respond_to?(:read) ? value.read : value)
</code></pre>
</li>
<li>
<pre><code> elsif value.respond_to?(:size) && chunked_p
</code></pre>
</li>
<li>
<pre><code> # if +out+ is an IO and +value+ is a File, use IO.copy_stream
</code></pre>
</li>
<li>
<pre><code> flush_buffer(out, buf, chunked_p)
</code></pre>
</li>
<li>
<pre><code> out << "%x\r\n" % value.size if chunked_p
</code></pre>
</li>
<li>
<pre><code> IO.copy_stream(value, out)
</code></pre>
</li>
<li>
<pre><code> out << "\r\n" if chunked_p
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> # +out+ is an IO, and +value+ is not a File but an IO
</code></pre>
</li>
<li>
<pre><code> flush_buffer(out, buf, chunked_p)
</code></pre>
</li>
<li>
<pre><code> 1 while flush_buffer(out, value.read(4096), chunked_p)
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<pre><code> else
</code></pre>
</li>
<li>
<pre><code> # non-file field:
</code></pre>
</li>
<li>
<pre><code> # HTML5 says, "The parts of the generated multipart/form-data
</code></pre>
</li>
<li>
<pre><code> # resource that correspond to non-file fields must not have a
</code></pre>
</li>
<li>
<pre><code> # Content-Type header specified."
</code></pre>
</li>
<li>
<pre><code> buf << "Content-Disposition: form-data; name=\"#{key}\"\r\n\r\n"
</code></pre>
</li>
<li>
<pre><code> buf << (value.respond_to?(:read) ? value.read : value)
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<pre><code> buf << "\r\n"
</code></pre>
</li>
<li>
<pre><code> end
</code></pre>
</li>
<li>
<pre><code> buf << "--#{boundary}--\r\n"
</code></pre>
</li>
<li>
<pre><code> flush_buffer(out, buf, chunked_p)
</code></pre>
</li>
<li>
<pre><code> out << "0\r\n\r\n" if chunked_p
</code></pre>
</li>
<li>
<p>end</p>
</li>
<li>
<li>
<p>def quote_string(str, charset)</p>
</li>
<li>
<pre><code> str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
</code></pre>
</li>
<li>
<pre><code> str = str.gsub(/[\\"]/, '\\\\\&')
</code></pre>
</li>
<li>
<p>end</p>
</li>
<li>
<li>
<p>def flush_buffer(out, buf, chunked_p)</p>
</li>
<li>
<pre><code> return unless buf
</code></pre>
</li>
<li>
<pre><code> out << "%x\r\n"%buf.bytesize if chunked_p
</code></pre>
</li>
<li>
<pre><code> out << buf
</code></pre>
</li>
<li>
<pre><code> out << "\r\n" if chunked_p
</code></pre>
</li>
<li>
<pre><code> buf.clear
</code></pre>
</li>
<li>
<p>end</p>
</li>
<li>
<p>def supply_default_content_type<br>
return if content_type()<br>
warn 'net/http: warning: Content-Type did not set; using application/x-www-form-urlencoded' if $VERBOSE<br>
diff --git a/lib/net/protocol.rb b/lib/net/protocol.rb<br>
index 2a6cfb4..a3ffa71 100644<br>
--- a/lib/net/protocol.rb<br>
+++ b/lib/net/protocol.rb<br>
@@ -168,6 +168,8 @@ module Net # :nodoc:<br>
}<br>
end</p>
</li>
<li>
<p>alias << write</p>
</li>
<li>
<p>def writeline(str)<br>
writing {<br>
write0 str + "\r\n"<br>
diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb<br>
index 76280ad..12c03a4 100644<br>
--- a/test/net/http/test_http.rb<br>
+++ b/test/net/http/test_http.rb<br>
@@ -303,6 +303,102 @@ module TestNetHTTP_version_1_2_methods<br>
assert_equal data.size, res.body.size<br>
assert_equal data, res.body<br>
end</p>
</li>
<li>
<li>
<p>def test_set_form</p>
</li>
<li>
<p>require 'tempfile'</p>
</li>
<li>
<p>file = Tempfile.new('ruby-test')</p>
</li>
<li>
<p>file << "\u{30c7}\u{30fc}\u{30bf}"</p>
</li>
<li>
<p>data = [</p>
</li>
<li>
<pre><code> ['name', 'Gonbei Nanashi'],
</code></pre>
</li>
<li>
<pre><code> ['name', "\u{540d}\u{7121}\u{3057}\u{306e}\u{6a29}\u{5175}\u{885b}"],
</code></pre>
</li>
<li>
<pre><code> ['s"i\o', StringIO.new("\u{3042 3044 4e9c 925b}")],
</code></pre>
</li>
<li>
<pre><code> ["file", file, filename: "ruby-test"]
</code></pre>
</li>
<li>
<p>]</p>
</li>
<li>
<p>expected = <<"<strong>EOM</strong>".gsub(/\n/, "\r\n")<br>
+--<br>
+Content-Disposition: form-data; name="name"</p>
</li>
<li>
</ul>
<p>+Gonbei Nanashi<br>
+--<br>
+Content-Disposition: form-data; name="name"<br>
+<br>
+\xE5\x90\x8D\xE7\x84\xA1\xE3\x81\x97\xE3\x81\xAE\xE6\xA8\xA9\xE5\x85\xB5\xE8\xA1\x9B<br>
+--<br>
+Content-Disposition: form-data; name="s\"i\\o"<br>
+<br>
+\xE3\x81\x82\xE3\x81\x84\xE4\xBA\x9C\xE9\x89\x9B<br>
+--<br>
+Content-Disposition: form-data; name="file"; filename="ruby-test"<br>
+Content-Type: application/octet-stream<br>
+<br>
+\xE3\x83\x87\xE3\x83\xBC\xE3\x82\xBF<br>
+----<br>
+<strong>EOM</strong></p>
<ul>
<li>start {|http|</li>
<li>
<pre><code> _test_set_form_urlencoded(http, data.reject{|k,v|!v.is_a?(String)})
</code></pre>
</li>
<li>
<pre><code> _test_set_form_multipart(http, false, data, expected)
</code></pre>
</li>
<li>
<pre><code> _test_set_form_multipart(http, true, data, expected)
</code></pre>
</li>
<li>}</li>
<li>end</li>
<li>
<li>def _test_set_form_urlencoded(http, data)</li>
<li>req = Net::HTTP::Post.new('/')</li>
<li>req.set_form(data)</li>
<li>res = http.request req</li>
<li>assert_equal "name=Gonbei+Nanashi&name=%E5%90%8D%E7%84%A1%E3%81%97%E3%81%AE%E6%A8%A9%E5%85%B5%E8%A1%9B", res.body</li>
<li>end</li>
<li>
<li>def _test_set_form_multipart(http, chunked_p, data, expected)</li>
<li>data.each{|k,v|v.rewind rescue nil}</li>
<li>req = Net::HTTP::Post.new('/')</li>
<li>req.set_form(data, 'multipart/form-data')</li>
<li>req['Transfer-Encoding'] = 'chunked' if chunked_p</li>
<li>res = http.request req</li>
<li>body = res.body</li>
<li>assert_match(/\A--(?\S+)/, body)</li>
<li>/\A--(?\S+)/ =~ body</li>
<li>expected = expected.gsub(//, boundary)</li>
<li>assert_equal(expected, body)</li>
<li>end</li>
<li>
<li>def test_set_form_with_file</li>
<li>require 'tempfile'</li>
<li>file = Tempfile.new('ruby-test')</li>
<li>file << $test_net_http_data</li>
<li>filename = File.basename(file.to_path)</li>
<li>data = [['file', file]]</li>
<li>expected = <<"<strong>EOM</strong>".gsub(/\n/, "\r\n")<br>
+--<br>
+Content-Disposition: form-data; name="file"; filename=""<br>
+Content-Type: application/octet-stream</li>
<li>
</ul>
<p>+<br>
+----<br>
+<strong>EOM</strong></p>
<ul>
<li>expected.sub!(//, filename)</li>
<li>expected.sub!(//, $test_net_http_data)</li>
<li>start {|http|</li>
<li>
<pre><code> data.each{|k,v|v.rewind rescue nil}
</code></pre>
</li>
<li>
<pre><code> req = Net::HTTP::Post.new('/')
</code></pre>
</li>
<li>
<pre><code> req.set_form(data, 'multipart/form-data')
</code></pre>
</li>
<li>
<pre><code> res = http.request req
</code></pre>
</li>
<li>
<pre><code> body = res.body
</code></pre>
</li>
<li>
<pre><code> header, _ = body.split(/\r\n\r\n/, 2)
</code></pre>
</li>
<li>
<pre><code> assert_match(/\A--(?<boundary>\S+)/, body)
</code></pre>
</li>
<li>
<pre><code> /\A--(?<boundary>\S+)/ =~ body
</code></pre>
</li>
<li>
<pre><code> expected = expected.gsub(/<boundary>/, boundary)
</code></pre>
</li>
<li>
<pre><code> assert_match(/^--(?<boundary>\S+)\r\n/, header)
</code></pre>
</li>
<li>
<pre><code> assert_match(
</code></pre>
</li>
<li>
<pre><code> /^Content-Disposition: form-data; name="file"; filename="#{filename}"\r\n/,
</code></pre>
</li>
<li>
<pre><code> header)
</code></pre>
</li>
<li>
<pre><code> assert_equal(expected, body)
</code></pre>
</li>
<li>
<li>
<pre><code> data.each{|k,v|v.rewind rescue nil}
</code></pre>
</li>
<li>
<pre><code> req['Transfer-Encoding'] = 'chunked'
</code></pre>
</li>
<li>
<pre><code> res = http.request req
</code></pre>
</li>
<li>
<pre><code> #assert_equal(expected, res.body)
</code></pre>
</li>
<li>}</li>
<li>end<br>
end</li>
</ul>
<p>class TestNetHTTP_version_1_1 < Test::Unit::TestCase<br>
=end</p>
Ruby master - Bug #4138 (Closed): Test Failure because of method redefined: test/irb/test_option.rb
https://redmine.ruby-lang.org/issues/4138
2010-12-09T03:51:04Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
test-all が以下のように失敗します。</p>
<ol start="2">
<li>Failure:<br>
test_end_of_option(TestIRB::TestOption) [/home/naruse/ruby/test/irb/test_option.rb:8]:<br>
<a href="/issues/4117">[ruby-core:33574]</a>.<br>
<[]> expected but was<br>
<["/home/naruse/ruby/lib/irb/ext/save-history.rb:29: warning: method redefined; discarding old save_history=",<br>
"/home/naruse/ruby/lib/irb/extend-command.rb:211: warning: previous definition of save_history= was here"]>.<br>
=end</li>
</ol>
Ruby master - Bug #4137 (Closed): Test Failure because of assigned but unused variable: ruby/test...
https://redmine.ruby-lang.org/issues/4137
2010-12-09T03:50:01Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
test-all が以下のように失敗します</p>
<ol start="3">
<li>Failure:<br>
test_shadowing_variable(TestRubyOptions) [/home/naruse/ruby/test/ruby/test_rubyoptions.rb:462]:<br>
<a href="/issues/4130">[ruby-dev:42718]</a>.<br>
<["-e:3: warning: shadowing outer local variable - a"]> expected but was<br>
<["-e:3: warning: shadowing outer local variable - a",<br>
"-e:3: warning: assigned but unused variable - a"]>.<br>
=end</li>
</ol>
Ruby master - Feature #4089 (Closed): Add addr2line for C level backtrace
https://redmine.ruby-lang.org/issues/4089
2010-11-26T09:22:36Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
最近の Ruby は SEGV や BUG 時に Ruby level backtrace を出したり、<br>
取れるときは C level backtrace を出したりしています。</p>
<p>ところが、C level backtrace だけ見ても実のところあまり助けにならないことが多いので、<br>
ソースコードのファイルや行数も可能ならば出したいところです。</p>
<p>などと言っていたら浜地さんがパッチを作ってくれたので、これを取り込みませんか。<br>
glibc 環境 (つまり Linux) や、libexecinfo を導入している FreeBSD や NetBSD など (のELFなバイナリ) で動きます。</p>
<p>diff --git a/addr2line.c b/addr2line.c<br>
new file mode 100644<br>
index 0000000..da85f4d<br>
--- /dev/null<br>
+++ b/addr2line.c<br>
@@ -0,0 +1,534 @@<br>
+/**********************************************************************<br>
+</p>
<ul>
<li>addr2line.h -</li>
<li>
<li>$Author$</li>
<li>
<li>Copyright (C) 2010 Shinichiro Hamaji</li>
<li>
</ul>
<p>+*********************************************************************<em>/<br>
+<br>
+#include "addr2line.h"<br>
+<br>
+#include <stdio.h><br>
+<br>
+#ifdef <strong>ELF</strong><br>
+<br>
+#include <elf.h><br>
+#include <fcntl.h><br>
+#include <limits.h><br>
+#include <stdio.h><br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <sys/mman.h><br>
+#include <sys/types.h><br>
+#include <sys/stat.h><br>
+#include <unistd.h><br>
+<br>
+#ifdef HAVE_DL_ITERATE_PHDR<br>
+# ifndef _GNU_SOURCE<br>
+# define _GNU_SOURCE<br>
+# endif<br>
+# include <link.h><br>
+#endif<br>
+<br>
+#define DW_LNS_copy 0x01<br>
+#define DW_LNS_advance_pc 0x02<br>
+#define DW_LNS_advance_line 0x03<br>
+#define DW_LNS_set_file 0x04<br>
+#define DW_LNS_set_column 0x05<br>
+#define DW_LNS_negate_stmt 0x06<br>
+#define DW_LNS_set_basic_block 0x07<br>
+#define DW_LNS_const_add_pc 0x08<br>
+#define DW_LNS_fixed_advance_pc 0x09<br>
+#define DW_LNS_set_prologue_end 0x0a /</em> DWARF3 <em>/<br>
+#define DW_LNS_set_epilogue_begin 0x0b /</em> DWARF3 <em>/<br>
+#define DW_LNS_set_isa 0x0c /</em> DWARF3 <em>/<br>
+<br>
+/</em> Line number extended opcode name. <em>/<br>
+#define DW_LNE_end_sequence 0x01<br>
+#define DW_LNE_set_address 0x02<br>
+#define DW_LNE_define_file 0x03<br>
+#define DW_LNE_set_discriminator 0x04 /</em> DWARF4 */<br>
+<br>
+# if SIZEOF_VOIDP == 8<br>
+# define ElfW(x) Elf64##<em>##x<br>
+# else<br>
+# define ElfW(x) Elf32##</em>##x<br>
+# endif<br>
+<br>
+typedef struct {</p>
<ul>
<li>const char *dirname;</li>
<li>const char *filename;</li>
<li>int line;</li>
<li>
<li>int fd;</li>
<li>void *mapped;</li>
<li>size_t mapped_size;</li>
<li>unsigned long base_addr;<br>
+} line_info_t;</li>
<li>
</ul>
<p>+/* Avoid consuming stack as this module may be used from signal handler */<br>
+static char binary_filename[PATH_MAX];<br>
+<br>
+static unsigned long<br>
+uleb128(char **p) {</p>
<ul>
<li>unsigned long r = 0;</li>
<li>int s = 0;</li>
<li>for (;;) {</li>
<li>unsigned char b = *(unsigned char *)(*p)++;</li>
<li>if (b < 0x80) {</li>
<li>
<pre><code> r += b << s;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>}</li>
<li>r += (b & 0x7f) << s;</li>
<li>s += 7;</li>
<li>}</li>
<li>return r;<br>
+}</li>
<li>
</ul>
<p>+static long<br>
+sleb128(char **p) {</p>
<ul>
<li>long r = 0;</li>
<li>int s = 0;</li>
<li>for (;;) {</li>
<li>unsigned char b = *(unsigned char *)(*p)++;</li>
<li>if (b < 0x80) {</li>
<li>
<pre><code> if (b & 0x40) {
</code></pre>
</li>
<li>
<pre><code> r -= (0x80 - b) << s;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else {
</code></pre>
</li>
<li>
<pre><code> r += (b & 0x3f) << s;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>}</li>
<li>r += (b & 0x7f) << s;</li>
<li>s += 7;</li>
<li>}</li>
<li>return r;<br>
+}</li>
<li>
</ul>
<p>+static const char *<br>
+get_nth_dirname(int dir, char *p)<br>
+{</p>
<ul>
<li>if (!dir--) {</li>
<li>return "";</li>
<li>}</li>
<li>while (dir) {</li>
<li>while (*p) p++;</li>
<li>p++;</li>
<li>if (!*p) {</li>
<li>
<pre><code> fprintf(stderr, "Unexpected directory number %d in %s\n",
</code></pre>
</li>
<li>
<pre><code> dir, binary_filename);
</code></pre>
</li>
<li>
<pre><code> return "";
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>return p;<br>
+}</li>
<li>
</ul>
<p>+static void<br>
+fill_filename(int file, char *include_directories, char *filenames,</p>
<ul>
<li>
<pre><code> line_info_t *line)
</code></pre>
</li>
</ul>
<p>+{</p>
<ul>
<li>int i;</li>
<li>char *p = filenames;</li>
<li>char *filename;</li>
<li>unsigned long dir;</li>
<li>for (i = 1; i <= file; i++) {</li>
<li>filename = p;</li>
<li>if (!*p) {</li>
<li>
<pre><code> /* Need to output binary file name? */
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "Unexpected file number %d in %s\n",
</code></pre>
</li>
<li>
<pre><code> file, binary_filename);
</code></pre>
</li>
<li>
<pre><code> return;
</code></pre>
</li>
<li>}</li>
<li>while (*p) p++;</li>
<li>p++;</li>
<li>dir = uleb128(&p);</li>
<li>/* last modified. */</li>
<li>uleb128(&p);</li>
<li>/* size of the file. */</li>
<li>uleb128(&p);</li>
<li>
<li>if (i == file) {</li>
<li>
<pre><code> line->filename = filename;
</code></pre>
</li>
<li>
<pre><code> line->dirname = get_nth_dirname(dir, include_directories);
</code></pre>
</li>
<li>}</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>+static int<br>
+get_path_from_symbol(const char *symbol, const char **p, size_t *len)<br>
+{</p>
<ul>
<li>if (symbol[0] == '0') {</li>
<li>/* libexecinfo */</li>
<li>*p = strchr(symbol, '/');</li>
<li>if (*p == NULL) return 0;</li>
<li>*len = strlen(*p);</li>
<li>}</li>
<li>else {</li>
<li>/* glibc */</li>
<li>const char *q;</li>
<li>*p = symbol;</li>
<li>q = strchr(symbol, '(');</li>
<li>if (q == NULL) return 0;</li>
<li>*len = q - symbol;</li>
<li>}</li>
<li>return 1;<br>
+}</li>
<li>
</ul>
<p>+static void<br>
+fill_line(int num_traces, void **traces,</p>
<ul>
<li>unsigned long addr, int file, int line,</li>
<li>char *include_directories, char *filenames, line_info_t *lines)<br>
+{</li>
<li>int i;</li>
<li>for (i = 0; i < num_traces; i++) {</li>
<li>unsigned long a = (unsigned long)traces[i] - lines[i].base_addr;</li>
<li>/* We assume one line code doesn't result >100 bytes of native code.</li>
<li>
<pre><code> We may want more reliable way eventually... */
</code></pre>
</li>
<li>if (addr < a && a < addr + 100) {</li>
<li>
<pre><code> fill_filename(file, include_directories, filenames, &lines[i]);
</code></pre>
</li>
<li>
<pre><code> lines[i].line = line;
</code></pre>
</li>
<li>}</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>+static void<br>
+parse_debug_line_cu(int num_traces, void **traces,</p>
<ul>
<li>
<pre><code> char **debug_line, line_info_t *lines)
</code></pre>
</li>
</ul>
<p>+{</p>
<ul>
<li>char *p, *cu_end, *cu_start, *include_directories, *filenames;</li>
<li>unsigned long unit_length;</li>
<li>int default_is_stmt, line_base;</li>
<li>unsigned int header_length, minimum_instruction_length, line_range,</li>
<li>
<pre><code> opcode_base;
</code></pre>
</li>
<li>unsigned char *standard_opcode_lengths;</li>
<li>
<li>/* The registers. */</li>
<li>unsigned long addr = 0;</li>
<li>unsigned int file = 1;</li>
<li>unsigned int line = 1;</li>
<li>unsigned int column = 0;</li>
<li>int is_stmt = default_is_stmt;</li>
<li>int basic_block = 0;</li>
<li>int end_sequence = 0;</li>
<li>int prologue_end = 0;</li>
<li>int epilogue_begin = 0;</li>
<li>unsigned int isa = 0;</li>
<li>
<li>p = *debug_line;</li>
<li>
<li>unit_length = *(unsigned int *)p;</li>
<li>p += sizeof(unsigned int);</li>
<li>if (unit_length == 0xffffffff) {</li>
<li>unit_length = *(unsigned long *)p;</li>
<li>p += sizeof(unsigned long);</li>
<li>}</li>
<li>
<li>cu_end = p + unit_length;</li>
<li>
<li>/*dwarf_version = *(unsigned short <em>)p;</em>/</li>
<li>p += 2;</li>
<li>
<li>header_length = *(unsigned int *)p;</li>
<li>p += sizeof(unsigned int);</li>
<li>
<li>cu_start = p + header_length;</li>
<li>
<li>minimum_instruction_length = *(unsigned char *)p;</li>
<li>p++;</li>
<li>
<li>default_is_stmt = *(unsigned char *)p;</li>
<li>p++;</li>
<li>
<li>line_base = *(char *)p;</li>
<li>p++;</li>
<li>
<li>line_range = *(unsigned char *)p;</li>
<li>p++;</li>
<li>
<li>opcode_base = *(unsigned char *)p;</li>
<li>p++;</li>
<li>
<li>standard_opcode_lengths = (unsigned char *)p - 1;</li>
<li>p += opcode_base - 1;</li>
<li>
<li>include_directories = p;</li>
<li>
<li>/* skip include directories */</li>
<li>while (*p) {</li>
<li>while (*p) p++;</li>
<li>p++;</li>
<li>}</li>
<li>p++;</li>
<li>
<li>filenames = p;</li>
<li>
<li>p = cu_start;</li>
<li>
</ul>
<p>+#define FILL_LINE() \</p>
<ul>
<li>do { \</li>
<li>fill_line(num_traces, traces, addr, file, line, \</li>
<li>
<pre><code> include_directories, filenames, lines); \
</code></pre>
</li>
<li>basic_block = prologue_end = epilogue_begin = 0; \</li>
<li>} while (0)</li>
<li>
<li>while (p < cu_end) {</li>
<li>unsigned long a;</li>
<li>unsigned char op = *p++;</li>
<li>switch (op) {</li>
<li>case DW_LNS_copy:</li>
<li>
<pre><code> FILL_LINE();
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_advance_pc:</li>
<li>
<pre><code> a = uleb128(&p);
</code></pre>
</li>
<li>
<pre><code> addr += a;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_advance_line: {</li>
<li>
<pre><code> long a = sleb128(&p);
</code></pre>
</li>
<li>
<pre><code> line += a;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>}</li>
<li>case DW_LNS_set_file:</li>
<li>
<pre><code> file = uleb128(&p);
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_set_column:</li>
<li>
<pre><code> column = uleb128(&p);
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_negate_stmt:</li>
<li>
<pre><code> is_stmt = !is_stmt;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_set_basic_block:</li>
<li>
<pre><code> basic_block = 1;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_const_add_pc:</li>
<li>
<pre><code> a = ((255 - opcode_base) / line_range) *
</code></pre>
</li>
<li>
<pre><code> minimum_instruction_length;
</code></pre>
</li>
<li>
<pre><code> addr += a;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_fixed_advance_pc:</li>
<li>
<pre><code> a = *(unsigned char *)p++;
</code></pre>
</li>
<li>
<pre><code> addr += a;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_set_prologue_end:</li>
<li>
<pre><code> prologue_end = 1;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_set_epilogue_begin:</li>
<li>
<pre><code> epilogue_begin = 1;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case DW_LNS_set_isa:</li>
<li>
<pre><code> isa = uleb128(&p);
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>case 0:</li>
<li>
<pre><code> a = *(unsigned char *)p++;
</code></pre>
</li>
<li>
<pre><code> op = *p++;
</code></pre>
</li>
<li>
<pre><code> switch (op) {
</code></pre>
</li>
<li>
<pre><code> case DW_LNE_end_sequence:
</code></pre>
</li>
<li>
<pre><code> end_sequence = 1;
</code></pre>
</li>
<li>
<pre><code> FILL_LINE();
</code></pre>
</li>
<li>
<pre><code> addr = 0;
</code></pre>
</li>
<li>
<pre><code> file = 1;
</code></pre>
</li>
<li>
<pre><code> line = 1;
</code></pre>
</li>
<li>
<pre><code> column = 0;
</code></pre>
</li>
<li>
<pre><code> is_stmt = default_is_stmt;
</code></pre>
</li>
<li>
<pre><code> end_sequence = 0;
</code></pre>
</li>
<li>
<pre><code> isa = 0;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> case DW_LNE_set_address:
</code></pre>
</li>
<li>
<pre><code> addr = *(unsigned long *)p;
</code></pre>
</li>
<li>
<pre><code> p += sizeof(unsigned long);
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> case DW_LNE_define_file:
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "Unsupported operation in %s\n",
</code></pre>
</li>
<li>
<pre><code> binary_filename);
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>
<pre><code> default:
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "Unknown extended opcode: %d in %s\n",
</code></pre>
</li>
<li>
<pre><code> op, binary_filename);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>default: {</li>
<li>
<pre><code> unsigned int addr_incr;
</code></pre>
</li>
<li>
<pre><code> int line_incr;
</code></pre>
</li>
<li>
<pre><code> a = op - opcode_base;
</code></pre>
</li>
<li>
<pre><code> addr_incr = (a / line_range) * minimum_instruction_length;
</code></pre>
</li>
<li>
<pre><code> line_incr = line_base + (a % line_range);
</code></pre>
</li>
<li>
<pre><code> addr += addr_incr;
</code></pre>
</li>
<li>
<pre><code> line += line_incr;
</code></pre>
</li>
<li>
<pre><code> FILL_LINE();
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>}</li>
<li>*debug_line = p;<br>
+}</li>
<li>
</ul>
<p>+static void<br>
+parse_debug_line(int num_traces, void **traces,</p>
<ul>
<li>
<pre><code> char *debug_line, unsigned long size, line_info_t *lines)
</code></pre>
</li>
</ul>
<p>+{</p>
<ul>
<li>char *debug_line_end = debug_line + size;</li>
<li>while (debug_line < debug_line_end) {</li>
<li>parse_debug_line_cu(num_traces, traces, &debug_line, lines);</li>
<li>}</li>
<li>if (debug_line != debug_line_end) {</li>
<li>fprintf(stderr, "Unexpected size of .debug_line in %s\n",</li>
<li>
<pre><code> binary_filename);
</code></pre>
</li>
<li>}<br>
+}</li>
<li>
</ul>
<p>+/* read file and fill lines */<br>
+static void<br>
+fill_lines(int num_traces, void **traces, char **syms,</p>
<ul>
<li>
<pre><code>char *file, line_info_t *lines)
</code></pre>
</li>
</ul>
<p>+{</p>
<ul>
<li>int i;</li>
<li>char *shstr;</li>
<li>char *section_name;</li>
<li>ElfW(Ehdr) *ehdr;</li>
<li>ElfW(Shdr) *shdr, *shstr_shdr, *debug_line_shdr = NULL;</li>
<li>
<li>for (i = 0; i < num_traces; i++) {</li>
<li>const char *path;</li>
<li>size_t len;</li>
<li>if (get_path_from_symbol(syms[i], &path, &len) &&</li>
<li>
<pre><code> !strncmp(path, binary_filename, len)) {
</code></pre>
</li>
<li>
<pre><code> lines[i].line = -1;
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>
<li>ehdr = (ElfW(Ehdr) *)file;</li>
<li>shdr = (ElfW(Shdr) *)(file + ehdr->e_shoff);</li>
<li>
<li>shstr_shdr = shdr + ehdr->e_shstrndx;</li>
<li>shstr = file + shstr_shdr->sh_offset;</li>
<li>
<li>for (i = 0; i < ehdr->e_shnum; i++) {</li>
<li>section_name = shstr + shdr[i].sh_name;</li>
<li>if (!strcmp(section_name, ".debug_line")) {</li>
<li>
<pre><code> debug_line_shdr = shdr + i;
</code></pre>
</li>
<li>
<pre><code> break;
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>
<li>if (!debug_line_shdr) {</li>
<li>/* this file doesn't have .debug_line section */</li>
<li>return;</li>
<li>}</li>
<li>
<li>parse_debug_line(num_traces, traces,</li>
<li>
<pre><code> file + debug_line_shdr->sh_offset,
</code></pre>
</li>
<li>
<pre><code> debug_line_shdr->sh_size,
</code></pre>
</li>
<li>
<pre><code> lines);
</code></pre>
</li>
</ul>
<p>+}<br>
+<br>
+#ifdef HAVE_DL_ITERATE_PHDR<br>
+<br>
+typedef struct {</p>
<ul>
<li>int num_traces;</li>
<li>char **syms;</li>
<li>line_info_t *lines;<br>
+} fill_base_addr_state_t;</li>
<li>
</ul>
<p>+static int<br>
+fill_base_addr(struct dl_phdr_info *info, size_t size, void *data)<br>
+{</p>
<ul>
<li>int i;</li>
<li>fill_base_addr_state_t *st = (fill_base_addr_state_t *)data;</li>
<li>for (i = 0; i < st->num_traces; i++) {</li>
<li>const char *path;</li>
<li>size_t len;</li>
<li>size_t name_len = strlen(info->dlpi_name);</li>
<li>
<li>if (get_path_from_symbol(st->syms[i], &path, &len) &&</li>
<li>
<pre><code> (len == name_len || (len > name_len && path[len-name_len-1] == '/')) &&
</code></pre>
</li>
<li>
<pre><code> !strncmp(path+len-name_len, info->dlpi_name, name_len)) {
</code></pre>
</li>
<li>
<pre><code> st->lines[i].base_addr = info->dlpi_addr;
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>return 0;<br>
+}</li>
<li>
</ul>
<p>+#endif /* HAVE_DL_ITERATE_PHDR */<br>
+<br>
+void<br>
+rb_dump_backtrace_with_lines(int num_traces, void **trace, char **syms)<br>
+{</p>
<ul>
<li>int i;</li>
<li>int fd;</li>
<li>/* async-signal unsafe */</li>
<li>line_info_t *lines = (line_info_t *)calloc(num_traces,</li>
<li>
<pre><code> sizeof(line_info_t));
</code></pre>
</li>
<li>off_t filesize;</li>
<li>char *file;</li>
<li>
<li>/* Note that line info of shared objects might not be shown</li>
<li>
<pre><code> if we don't have dl_iterate_phdr */
</code></pre>
</li>
</ul>
<p>+#ifdef HAVE_DL_ITERATE_PHDR</p>
<ul>
<li>fill_base_addr_state_t fill_base_addr_state;</li>
<li>
<li>fill_base_addr_state.num_traces = num_traces;</li>
<li>fill_base_addr_state.syms = syms;</li>
<li>fill_base_addr_state.lines = lines;</li>
<li>/* maybe async-signal unsafe */</li>
<li>dl_iterate_phdr(fill_base_addr, &fill_base_addr_state);<br>
+#endif /* HAVE_DL_ITERATE_PHDR */</li>
<li>
<li>for (i = 0; i < num_traces; i++) {</li>
<li>const char *path;</li>
<li>size_t len;</li>
<li>if (lines[i].line) {</li>
<li>
<pre><code> continue;
</code></pre>
</li>
<li>}</li>
<li>
<li>if (!get_path_from_symbol(syms[i], &path, &len)) {</li>
<li>
<pre><code> continue;
</code></pre>
</li>
<li>}</li>
<li>
<li>strncpy(binary_filename, path, len);</li>
<li>binary_filename[len] = '\0';</li>
<li>
<li>fd = open(binary_filename, O_RDONLY);</li>
<li>filesize = lseek(fd, 0, SEEK_END);</li>
<li>lseek(fd, 0, SEEK_SET);</li>
<li>/* async-signal unsafe */</li>
<li>file = (char *)mmap(NULL, filesize, PROT_READ, MAP_SHARED, fd, 0);</li>
<li>
<li>lines[i].fd = fd;</li>
<li>lines[i].mapped = file;</li>
<li>lines[i].mapped_size = filesize;</li>
<li>
<li>fill_lines(num_traces, trace, syms, file, lines);</li>
<li>}</li>
<li>
<li>/* fprintf may not be async-signal safe */</li>
<li>for (i = 0; i < num_traces; i++) {</li>
<li>line_info_t *line = &lines[i];</li>
<li>
<li>if (line->line > 0) {</li>
<li>
<pre><code> fprintf(stderr, "%s ", syms[i]);
</code></pre>
</li>
<li>
<pre><code> if (line->filename) {
</code></pre>
</li>
<li>
<pre><code> if (line->dirname && line->dirname[0]) {
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "%s/", line->dirname);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "%s", line->filename);
</code></pre>
</li>
<li>
<pre><code> } else {
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, "???");
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> fprintf(stderr, ":%d\n", line->line);
</code></pre>
</li>
<li>} else {</li>
<li>
<pre><code> fprintf(stderr, "%s\n", syms[i]);
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>
<li>for (i = 0; i < num_traces; i++) {</li>
<li>line_info_t *line = &lines[i];</li>
<li>if (line->fd) {</li>
<li>
<pre><code> munmap(line->mapped, line->mapped_size);
</code></pre>
</li>
<li>
<pre><code> close(line->fd);
</code></pre>
</li>
<li>}</li>
<li>}</li>
<li>free(lines);<br>
+}</li>
<li>
</ul>
<p>+#endif /* defined(<strong>ELF</strong>) <em>/<br>
diff --git a/addr2line.h b/addr2line.h<br>
new file mode 100644<br>
index 0000000..cbb18e5<br>
--- /dev/null<br>
+++ b/addr2line.h<br>
@@ -0,0 +1,21 @@<br>
+/</em>*********************************************************************<br>
+</p>
<ul>
<li>addr2line.h -</li>
<li>
<li>$Author$</li>
<li>
<li>Copyright (C) 2010 Shinichiro Hamaji</li>
<li>
</ul>
<p>+**********************************************************************/<br>
+<br>
+#ifndef RUBY_ADDR2LINE_H<br>
+#define RUBY_ADDR2LINE_H<br>
+<br>
+#ifdef <strong>ELF</strong><br>
+<br>
+void<br>
+rb_dump_backtrace_with_lines(int num_traces, void **traces, char *<em>syms);<br>
+<br>
+#endif /</em> <strong>ELF</strong> <em>/<br>
+<br>
+#endif /</em> RUBY_ADDR2LINE_H */<br>
diff --git a/common.mk b/common.mk<br>
index c45c3e1..cf66e42 100644<br>
--- a/common.mk<br>
+++ b/common.mk<br>
@@ -91,6 +91,7 @@ COMMONOBJS = array.$(OBJEXT) <br>
vm_dump.$(OBJEXT) <br>
thread.$(OBJEXT) <br>
cont.$(OBJEXT) \</p>
<ul>
<li>
<pre><code> addr2line.$(OBJEXT) \
$(BUILTIN_ENCOBJS) \
$(BUILTIN_TRANSOBJS) \
$(MISSING)
</code></pre>
</li>
</ul>
<p>diff --git a/configure.in b/configure.in<br>
index 36a58d4..ef2ee2d 100644<br>
--- a/configure.in<br>
+++ b/configure.in<br>
@@ -1300,7 +1300,7 @@ AC_CHECK_FUNCS(fmod killpg wait4 waitpid fork spawnv syscall chroot getcwd eacce<br>
setsid telldir seekdir fchmod cosh sinh tanh log2 round<br>
setuid setgid daemon select_large_fdset setenv unsetenv<br>
mktime timegm gmtime_r clock_gettime gettimeofday\</p>
<ul>
<li>
<pre><code> pread sendfile shutdown sigaltstack)
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> pread sendfile shutdown sigaltstack dl_iterate_phdr)
</code></pre>
</li>
</ul>
<p>AC_CACHE_CHECK(for unsetenv returns a value, rb_cv_unsetenv_return_value,<br>
[AC_TRY_COMPILE([<br>
diff --git a/vm_dump.c b/vm_dump.c<br>
index 2975001..b22c041 100644<br>
--- a/vm_dump.c<br>
+++ b/vm_dump.c<br>
@@ -10,6 +10,7 @@</p>
<p>#include "ruby/ruby.h"<br>
+#include "addr2line.h"<br>
#include "vm_core.h"</p>
<p>#define MAX_POSBUF 128<br>
@@ -785,9 +786,13 @@ rb_vm_bugreport(void)<br>
int i;</p>
<pre><code>if (syms) {
</code></pre>
<p>+#ifdef <strong>ELF</strong></p>
<ul>
<li>
<pre><code> rb_dump_backtrace_with_lines(n, trace, syms);
</code></pre>
</li>
</ul>
<p>+#else<br>
for (i=0; i<n; i++) {<br>
fprintf(stderr, "%s\n", syms[i]);<br>
}<br>
+#endif<br>
free(syms);<br>
}<br>
#elif defined(_WIN32)<br>
=end</p>
Ruby master - Feature #3961 (Rejected): printfと精度指定と負の値と
https://redmine.ruby-lang.org/issues/3961
2010-10-18T18:01:01Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
printf が、フォーマットに精度指定しつつ負の値を与えた時の挙動が、<br>
Perl と必然性無く異なっていて不便です。</p>
<p>% ./ruby -e'printf("%#.8x", -1)'<br>
0x..ffffff</p>
<p>そもそもこの挙動は C 言語由来で、C の場合例えば以下の通りになります。</p>
<p>% cat test.c<br>
#include <stdio.h><br>
int main(void)<br>
{<br>
printf("%#x\n", -1);<br>
return 0;<br>
}<br>
% cc t.c && ./a.out<br>
0xffffffff</p>
<p>また、おそらく直接参考にしたであろう Perl では以下の通りです、<br>
% perl -e'printf("%#x",-1)'<br>
0xffffffffffffffff<br>
% perl -e'printf("%#.30x",-1)'<br>
0x00000000000000ffffffffffffffff<br>
つまり、Perl (の 64bit int 版) では、64bitで補数を取っています。</p>
<p>さて、Ruby の場合多倍長整数が組み込みなため、補数を取ると無限に続いてしまうから、<br>
% ./ruby -e'printf("%#x",-1)'<br>
0x..f<br>
と .. で略すのは理にかなっていると思います。</p>
<p>しかし、現在の Ruby は精度を指定した際にも..がついてしまうので、<br>
Perl のような動きを実現させる事ができません。<br>
% ./ruby -e'printf("%#.8x",-1)'<br>
0x..ffffff<br>
で、この .. っていらないと思うんです。</p>
<p>例えば浮動小数点数の場合には以下のように .. とか付けずにぶった切る訳で、<br>
無限大方向と無限小方向という違いはあれど、<br>
「Perlとかと同じ挙動にできない」というデメリットの方が大きいのではないでしょうか。<br>
% ./ruby -e'printf("%#.8f",10.0/3)'<br>
3.33333333</p>
<p>わたしの場合、CRuby 側の inspect が printf("%x", negative_value) などとしている部分の動作を<br>
RubySpec で Ruby で書く時に頭を抱えてしまいました。</p>
<p>というわけでパッチは例えば以下の通りです。</p>
<p>diff --git a/sprintf.c b/sprintf.c<br>
index 21509ea..0e97955 100644<br>
--- a/sprintf.c<br>
+++ b/sprintf.c<br>
@@ -844,7 +844,7 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)<br>
}<br>
else {<br>
s = nbuf;</p>
<ul>
<li>
<pre><code> if (v < 0) {
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (v < 0 && !(flags & FPREC0)) {
dots = 1;
}
snprintf(fbuf, sizeof(fbuf), "%%l%c", *p == 'X' ? 'x' : *p);
</code></pre>
</li>
</ul>
<p>@@ -892,7 +892,8 @@ rb_str_format(int argc, const VALUE *argv, VALUE fmt)<br>
tmp1 = tmp = rb_big2str0(val, base, RBIGNUM_SIGN(val));<br>
s = RSTRING_PTR(tmp);<br>
if (*s == '-') {</p>
<ul>
<li>
<pre><code> dots = 1;
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (!(flags & FPREC0))
</code></pre>
</li>
<li>
<pre><code> dots = 1;
if (base == 10) {
rb_warning("negative number for %%u specifier");
}
</code></pre>
</li>
</ul>
<p>@@ -925,14 +926,11 @@ rb_str_format(int argc, const VALUE <em>argv, VALUE fmt)<br>
}<br>
}<br>
if (prefix && !prefix[1]) { /</em> octal */</p>
<ul>
<li>
<pre><code> if (dots) {
</code></pre>
</li>
<li>
<pre><code> prefix = 0;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> else if (len == 1 && *s == '0') {
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (len == 1 && *s == '0') {
len = 0;
if (flags & FPREC) prec--;
}
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> else if ((flags & FPREC) && (prec > len)) {
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> else if ((flags & FPREC) && (prec > len) && v >= 0) {
prefix = 0;
}
}
</code></pre>
</li>
</ul>
<p>diff --git a/test/ruby/test_sprintf.rb b/test/ruby/test_sprintf.rb<br>
index 96a1b62..24b6a34 100644<br>
--- a/test/ruby/test_sprintf.rb<br>
+++ b/test/ruby/test_sprintf.rb<br>
@@ -24,12 +24,12 @@ class TestSprintf < Test::Unit::TestCase<br>
assert_equal("0000", sprintf("%.4b", 0))<br>
assert_equal("0001", sprintf("%.4b", 1))<br>
assert_equal("0010", sprintf("%.4b", 2))</p>
<ul>
<li>assert_equal("..11", sprintf("%.4b", -1))</li>
</ul>
<ul>
<li>
<p>assert_equal("1111", sprintf("%.4b", -1))</p>
<p>assert_equal(" 0000", sprintf("%6.4b", 0))<br>
assert_equal(" 0001", sprintf("%6.4b", 1))<br>
assert_equal(" 0010", sprintf("%6.4b", 2))</p>
</li>
</ul>
<ul>
<li>assert_equal(" ..11", sprintf("%6.4b", -1))</li>
</ul>
<ul>
<li>
<p>assert_equal(" 1111", sprintf("%6.4b", -1))</p>
<p>assert_equal(" 0", sprintf("%#4b", 0))<br>
assert_equal(" 0b1", sprintf("%#4b", 1))<br>
@@ -44,12 +44,12 @@ class TestSprintf < Test::Unit::TestCase<br>
assert_equal("0000", sprintf("%#.4b", 0))<br>
assert_equal("0b0001", sprintf("%#.4b", 1))<br>
assert_equal("0b0010", sprintf("%#.4b", 2))</p>
</li>
</ul>
<ul>
<li>assert_equal("0b..11", sprintf("%#.4b", -1))</li>
</ul>
<ul>
<li>
<p>assert_equal("0b1111", sprintf("%#.4b", -1))</p>
<p>assert_equal(" 0000", sprintf("%#6.4b", 0))<br>
assert_equal("0b0001", sprintf("%#6.4b", 1))<br>
assert_equal("0b0010", sprintf("%#6.4b", 2))</p>
</li>
</ul>
<ul>
<li>assert_equal("0b..11", sprintf("%#6.4b", -1))</li>
</ul>
<ul>
<li>
<p>assert_equal("0b1111", sprintf("%#6.4b", -1))</p>
<p>assert_equal("+0", sprintf("%+b", 0))<br>
assert_equal("+1", sprintf("%+b", 1))<br>
@@ -288,6 +288,8 @@ class TestSprintf < Test::Unit::TestCase<br>
b1 = (/../ =~ s1) != nil<br>
b2 = (/../ =~ s2) != nil<br>
assert(b1 == b2, "<a href="https://blade.ruby-lang.org/ruby-dev/33224">[ruby-dev:33224]</a>")</p>
</li>
<li>
<li>
<p>assert_equal("ffffffff", sprintf("%.8x", -1))<br>
end</p>
</li>
</ul>
<pre><code>def test_named
</code></pre>
<p>diff --git a/test/ruby/test_sprintf_comb.rb b/test/ruby/test_sprintf_comb.rb<br>
index 261732b..3105127 100644<br>
--- a/test/ruby/test_sprintf_comb.rb<br>
+++ b/test/ruby/test_sprintf_comb.rb<br>
@@ -190,7 +190,7 @@ class TestSprintfComb < Test::Unit::TestCase<br>
if digits.last != radix-1<br>
digits << (radix-1)<br>
end</p>
<ul>
<li>
<pre><code> sign = '..'
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> sign = '..' unless precision
else
sign = '-'
end
</code></pre>
</li>
</ul>
<p>@@ -222,8 +222,8 @@ class TestSprintfComb < Test::Unit::TestCase<br>
end<br>
end<br>
if type == 'o' && hs</p>
<ul>
<li>
<pre><code> if digits.empty? || digits.last != d
</code></pre>
</li>
<li>
<pre><code> digits << d
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if digits.empty? || digits.last != 0
</code></pre>
</li>
<li>
<pre><code> prefix = '0'
end
</code></pre>
end<br>
=end</li>
</ul>
Ruby master - Feature #3947 (Closed): Array#packのにエンディアン指定修飾子</>を追加
https://redmine.ruby-lang.org/issues/3947
2010-10-14T15:46:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Ruby の伏魔殿 Array#pack ですが、機種依存な部分をいじる際にはしばしば強力かつ唯一の手段になる事があります。<br>
具体的には RubySpec 書く時とか。</p>
<p>さて、pack のようにバイト列を扱う場合、しばしば問題になるのがエンディアンです。<br>
ここで、Ruby の Array#pack は 16bit/32bit 固定の整数に対してはエンディアン固定の<br>
n/N/v/V 指定子を用意していますが、short/int/long/long long のように、<br>
マシン依存の型をエンディアン固定で pack する手段を提供していません。<br>
というわけで、これが欲しいです。</p>
<p>ここで問題になるのがどのように指定するかなのですが、pack のネタ元である Perl さんでは既に </> 修飾子を<br>
この目的のために提供しています。<br>
<a href="http://perldoc.perl.org/functions/pack.html" class="external">http://perldoc.perl.org/functions/pack.html</a><br>
というわけで、これに追従するのがよろしいと思います。</p>
<pre><code> > sSiIlLqQ Force big-endian byte-order on the type.
jJfFdDpP (The "big end" touches the construct.)
< sSiIlLqQ Force little-endian byte-order on the type.
jJfFdDpP (The "little end" touches the construct.)
</code></pre>
<p>なお、「</> とかきもい」という意見もあるかとは思いますが、pack は機種依存とかに触るきもいメソッドなので、<br>
そこを気にするよりは長い物に巻かれておいた方が無難ではないかなと思うため、</> 修飾子がベストかと思います。<br>
=end</p>
Ruby master - Feature #3946 (Closed): Array#packのqQ指定子に機種依存サイズフラグ!を追加
https://redmine.ruby-lang.org/issues/3946
2010-10-14T15:36:56Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Ruby の伏魔殿 Array#pack ですが、機種依存な部分をいじる際にはしばしば強力かつ唯一の手段になる事があります。<br>
具体的には RubySpec 書く時とか。</p>
<p>さて、q/Q は 64bit signed/unsigned int なのですが、機種依存の long long (厳密には LONG_LONG) のサイズが必要な場合、<br>
現状 Ruby レベルから取る手段が一切ありません。<br>
すでに s/S/i/I/l/L (16bit/32bit/32bit) は、! をつけることでその機種の short/int/long のサイズになるため、<br>
これを q/Q に拡張すると唯一の手段が提供される事になります。</p>
<p>というわけで、Array#packのqQ指定子に機種依存サイズフラグ!を追加したいです。<br>
=end</p>
Ruby master - Bug #3945 (Closed): Numeric#step with infinity unit
https://redmine.ruby-lang.org/issues/3945
2010-10-14T04:15:58Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Numeric#step with infinity unit doesn't works well:</p>
<blockquote>
<p>1.step(0, Float::INFINITY) {|x| p x }<br>
1.0<br>
=> 1<br>
1.step(0, -Float::INFINITY) {|x| p x }<br>
=> 1</p>
</blockquote>
<p>Expected result is:</p>
<blockquote>
<p>1.step(0, Float::INFINITY) {|x| p x }<br>
=> 1<br>
1.step(0, -Float::INFINITY) {|x| p x }<br>
1.0<br>
=> 1<br>
=end</p>
</blockquote>
Ruby master - Bug #3816 (Closed): OpenSSL::BN#prime?の引数の取り扱いがおかしい
https://redmine.ruby-lang.org/issues/3816
2010-09-10T16:20:29Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
OpenSSL::BN#prime?を引数なしで呼ぶと以下の通り例外が出ます。</p>
<p>irb(main):001:0> require'openssl'=> trueirb(main):002:0> OpenSSL::BN.new("461166461445805738999").prime?<br>
TypeError: no implicit conversion from nil to integer<br>
from (irb):2:in <code>prime?' from (irb):2 from /home/naruse/local/ruby_1_9_2/bin/irb:12:in </code>'</p>
<p>コードを見るに、rb_scan_args の引数との比較が誤っているように見えるので、引数ありでもおかしいでしょう。<br>
以下の変更で直ります。</p>
<p>diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c<br>
index bec5135..6adc59f 100644<br>
--- a/ext/openssl/ossl_bn.c<br>
+++ b/ext/openssl/ossl_bn.c<br>
@@ -669,7 +669,7 @@ ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)<br>
VALUE vchecks;<br>
int checks = BN_prime_checks;</p>
<ul>
<li>if (rb_scan_args(argc, argv, "01", &vchecks) == 0) {</li>
</ul>
<ul>
<li>if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {<br>
checks = NUM2INT(vchecks);<br>
}<br>
GetBN(self, bn);<br>
=end</li>
</ul>
Ruby master - Bug #3673 (Closed): PTY.getpty with IO.pipe doesn't finish on FreeBSD
https://redmine.ruby-lang.org/issues/3673
2010-08-10T10:53:16Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
以下のプログラムが FreeBSD で終了しません。<br>
(test/ruby/test_rubyoptions.rb の test_script_from_stdin より)<br>
Ubuntu 8.04 や Mac OS X 10.6 では終わることを確認しています。</p>
<p>require 'pty'<br>
#require 'timeout'<br>
s, w = IO.pipe<br>
PTY.getpty('./ruby', out: w) do |r, m|<br>
w.close<br>
#m.print("print 'abc'\n")<br>
m.print("\C-d")<br>
p s.read</p>
<a name="result-Timeouttimeout3-sread"></a>
<h1 >result = Timeout.timeout(3) {s.read}<a href="#result-Timeouttimeout3-sread" class="wiki-anchor">¶</a></h1>
<p>end<br>
puts :fin<br>
=end</p>
Ruby master - Bug #3672 (Closed): PTY.getpty with non exist program
https://redmine.ruby-lang.org/issues/3672
2010-08-10T10:48:52Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
存在しないプログラムを指定して PTY.getpty を呼ぶと [BUG] になります。<br>
PTY.getpty 側での対処と rb_fork_err 側での対処がありえますが、<br>
とりあえず後者側でも対処が必要でしょう。</p>
<p>% ./ruby -rpty -e'PTY.getpty"a"'<br>
-e:1: [BUG] rb_sys_fail(fork failed) - errno == 0<br>
ruby 1.9.3dev (2010-08-09 trunk 28938) [x86_64-freebsd8.1]</p>
<h2>-- control frame ----------<br>
c:0004 p:---- s:0010 b:0010 l:000009 d:000009 CFUNC :getpty<br>
c:0003 p:0017 s:0006 b:0006 l:0024b8 d:0010e8 EVAL -e:1<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:0000 s:0002 b:0002 l:0024b8 d:0024b8 TOP</h2>
<p>-- Ruby level backtrace information ----------------------------------------<br>
-e:1:in <code><main>' -e:1:in </code>getpty'</p>
<p>[NOTE]<br>
You may have encountered a bug in the Ruby interpreter or extension libraries.<br>
Bug reports are welcome.<br>
For details: <a href="http://www.ruby-lang.org/bugreport.html" class="external">http://www.ruby-lang.org/bugreport.html</a></p>
<p>zsh: abort (core dumped) ./ruby -rpty -e'PTY.getpty"a"'<br>
=end</p>
Ruby master - Bug #3593 (Closed): cont.cで"PAGE_SIZE" redefined
https://redmine.ruby-lang.org/issues/3593
2010-07-21T17:20:27Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
cont.cで以下のようなwarningがでます。<br>
ifndefを使うべきか、RB_PAGE_SIZEなどと別の名前を使うべきか迷ったので、対処お願いします。<br>
../../ruby/cont.c:45:1: warning: "PAGE_SIZE" redefined<br>
In file included from /usr/include/sys/param.h:110,<br>
from /usr/include/pthread_np.h:34,<br>
from ../../ruby/thread_pthread.h:16,<br>
from ../../ruby/vm_core.h:29,<br>
from ../../ruby/cont.c:13:<br>
/usr/include/machine/param.h:100:1: warning: this is the location of the previous definition<br>
../../ruby/cont.c:46:1: warning: "PAGE_MASK" redefined<br>
/usr/include/machine/param.h:101:1: warning: this is the location of the previous definition<br>
../../ruby/cont.c:45:1: warning: "PAGE_SIZE" redefined<br>
In file included from /usr/include/sys/param.h:111,<br>
from /usr/include/pthread_np.h:35,<br>
from ../../ruby/thread_pthread.h:17,<br>
from ../../ruby/vm_core.h:30,<br>
from ../../ruby/cont.c:14:<br>
/usr/include/machine/param.h:100:1: warning: this is the location of the previous definition<br>
../../ruby/cont.c:46:1: warning: "PAGE_MASK" redefined<br>
/usr/include/machine/param.h:101:1: warning: this is the location of the previous definition<br>
../../ruby/cont.c: In function 'fiber_initialize_machine_stack_context':<br>
../../ruby/cont.c:567: warning: assignment from incompatible pointer type<br>
=end</p>
Ruby master - Bug #3568 (Closed): /(?<=a).*b/ =~ "aab" doesn't match
https://redmine.ruby-lang.org/issues/3568
2010-07-14T12:09:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
「1.9.1で /(?<=a).*b/ =~ "aab" がマッチしないのはなぜ? 」<br>
<a href="http://pc12.2ch.net/test/read.cgi/tech/1272248179/735" class="external">http://pc12.2ch.net/test/read.cgi/tech/1272248179/735</a><br>
=end</p>
Ruby master - Bug #3515 (Closed): FreeBSD wrongly raises ECONNRESET on close(2)
https://redmine.ruby-lang.org/issues/3515
2010-07-02T12:20:40Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
FreeBSD 8 では現在以下のようなテストに失敗しています。</p>
<ol>
<li>
<p>Error:<br>
test_idle(IMAPTest):<br>
Errno::ECONNRESET: Connection reset by peer<br>
/home/naruse/ruby/test/net/imap/test_imap.rb:189:in `test_idle'</p>
</li>
<li>
<p>Failure:<br>
test_03(TestDRbSSLCore) [/home/naruse/ruby/test/drb/drbtest.rb:138]:<br>
[DRb::DRbConnError] exception expected, not<br>
Class: <a href="Errno::ECONNRESET" class="external">Errno::ECONNRESET</a><br>
Message: <"Connection reset by peer"><br>
---Backtrace---<br>
/home/naruse/ruby/test/drb/drbtest.rb:139:in <code>block in test_03' /home/naruse/ruby/test/drb/drbtest.rb:138:in </code>test_03'</p>
</li>
</ol>
<hr>
<ol start="3">
<li>Failure:<br>
test_07_public_private_protected_missing(TestDRbSSLCore) [/home/naruse/ruby/test/drb/drbtest.rb:182]:<br>
Exception raised:<br>
<#<Errno::ECONNRESET: Connection reset by peer>>.</li>
</ol>
<p>これらに共通するのは「Errno::ECONNRESET: Connection reset by peer」という例外が発生している点です。<br>
この例外は socket の close(2) を呼んだ際に errno に ECONNRESET がセットされたときに発生します。<br>
しかし、この挙動は POSIX 仕様外であり、FreeBSD 独自のものです。</p>
<p><a href="http://www.freebsd.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+8.0-RELEASE&format=html" class="external">http://www.freebsd.org/cgi/man.cgi?query=close&apropos=0&sektion=0&manpath=FreeBSD+8.0-RELEASE&format=html</a><br>
<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/close.html" class="external">http://www.opengroup.org/onlinepubs/9699919799/functions/close.html</a><br>
<a href="http://netbsd.gw.com/cgi-bin/man-cgi?close++NetBSD-current" class="external">http://netbsd.gw.com/cgi-bin/man-cgi?close++NetBSD-current</a><br>
<a href="http://www.openbsd.org/cgi-bin/man.cgi?query=close&apropos=0&sektion=0&manpath=OpenBSD+Current&arch=i386&format=html" class="external">http://www.openbsd.org/cgi-bin/man.cgi?query=close&apropos=0&sektion=0&manpath=OpenBSD+Current&arch=i386&format=html</a><br>
<a href="http://leaf.dragonflybsd.org/cgi/web-man?command=close&section=ANY" class="external">http://leaf.dragonflybsd.org/cgi/web-man?command=close&section=ANY</a><br>
<a href="http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html" class="external">http://www.kernel.org/doc/man-pages/online/pages/man2/close.2.html</a><br>
<a href="http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man2/close.2.html" class="external">http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man2/close.2.html</a></p>
<p>これが結果的に、他の OS では例外が投げられない状況で例外が発生するという現象を生み出しています。<br>
以下は関連する議論です。<br>
<a href="http://old.nabble.com/close()-failing-with-ECONNRESET-td28817716.html" class="external">http://old.nabble.com/close()-failing-with-ECONNRESET-td28817716.html</a><br>
<a href="http://old.nabble.com/Re:-kern-146845:--libc--close(2)-returns-error-54-(connection-reset-by-peer)-wrongly-td28649525.html" class="external">http://old.nabble.com/Re:-kern-146845:--libc--close(2)-returns-error-54-(connection-reset-by-peer)-wrongly-td28649525.html</a></p>
<p>で、Ruby における対策ですが、close(2) で errno に ECONNRESET がセットされた場合、<br>
それを無視するべきだと思います。<br>
いかがそのパッチなのですがいかがでしょうか。</p>
<p>diff --git a/io.c b/io.c<br>
index 05b2d45..a1b49d2 100644<br>
--- a/io.c<br>
+++ b/io.c<br>
@@ -3436,7 +3436,7 @@ fptr_finalize(rb_io_t <em>fptr, int noraise)<br>
/</em> fptr->fd may be closed even if close fails.<br>
* POSIX doesn't specify it.<br>
* We assumes it is closed. */</p>
<ul>
<li>
<pre><code> if (close(fptr->fd) < 0 && NIL_P(err))
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> if (close(fptr->fd) < 0 && NIL_P(err) && errno != ECONNRESET)
err = noraise ? Qtrue : INT2NUM(errno);
</code></pre>
}<br>
skip_fd_close:<br>
=end</li>
</ul>
Backport186 - Backport #3403 (Closed): A bug related to ruby's regular expression!!!!!!
https://redmine.ruby-lang.org/issues/3403
2010-06-07T16:01:37Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Backport r28192</p>
<p>I found a bug related to ruby's regular expression!<br>
puts(/wo{0,3}?/.match("woo"))<br>
This line of code should show a "w" on the screen, but my ruby shows "wo" on then screen.<br>
According to the principles of regular expression, this is a non-greedy match, so it should match 0 "o", but it matches at least 1 "o". I think this is a bug!<br>
I also tried this in the javascript language, it works well!("w" is shown)</p>
<p>My ruby version is v1.8.7-p249.<br>
=end</p>
Backport187 - Backport #3402 (Closed): A bug related to ruby's regular expression!!!!!!
https://redmine.ruby-lang.org/issues/3402
2010-06-07T16:00:55Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Backport r28192</p>
<p>I found a bug related to ruby's regular expression!<br>
puts(/wo{0,3}?/.match("woo"))<br>
This line of code should show a "w" on the screen, but my ruby shows "wo" on then screen.<br>
According to the principles of regular expression, this is a non-greedy match, so it should match 0 "o", but it matches at least 1 "o". I think this is a bug!<br>
I also tried this in the javascript language, it works well!("w" is shown)</p>
<p>My ruby version is v1.8.7-p249.<br>
=end</p>
Ruby master - Feature #3036 (Closed): String#encode(to, from, opt) の opt[:replace] に Hash
https://redmine.ruby-lang.org/issues/3036
2010-03-29T16:11:29Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
<a href="https://blade.ruby-lang.org/ruby-dev/40540">[ruby-dev:40540]</a> の String#encode(to, from, opt) の opt[:replace] に Hash の話を、<br>
別にチケットとして起こしておきます</p>
<p>String#encode(to, from, opt) の opt[:replace] に Hash を与えられるようにして、<br>
そこに、変換元 encoding の文字 => 変換先の文字、という未定義文字の fallback 変換表を与えられるようにする、<br>
というものを今考えています。<br>
これだと例えば、<br>
fallbacks = {<br>
?¥uE6AD => "[ふくろ]",<br>
?¥u{1F4BA} => "[いす]"<br>
}<br>
"¥u{3042 E6AD 1F4BA}".encode("UTF8-KDDI", replace: fallbacks) #=> "あ[ふくろ][いす]"<br>
=end</p>
Ruby master - Feature #2969 (Closed): String#to_f が -h.hhh±pd を解釈できるように
https://redmine.ruby-lang.org/issues/2969
2010-03-16T04:01:03Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
C99 の printf には a という指定子があります。</p>
<pre><code> aA The argument is printed in style ‘[-h.hhh±pd]’ where there is
one digit before the hexadecimal point and the number after
is equal to the precision specification for the argument;
when the precision is missing, enough digits are produced to
convey the argument's exact double-precision floating-point
representation. The values ∞ and NaN are printed as ‘inf’
and ‘nan’, respectively.
</code></pre>
<p>これを使うと、以下のような形で整形されます。<br>
-0.0 #=> "-0x0p+0"<br>
729.0/10 #=> "0x1.239999999999ap+6"<br>
Math.log(3) #=> "0x1.193ea7aad030ap+0"<br>
Math.exp(100) #=> "0x1.3494a9b171bf5p+144"</p>
<p>この形式の利点は、複雑な浮動小数点数を比較的少ない文字数で正確に表せることと、<br>
仮数部が16進であるため丸めが起きていることを説明する際に便利な点が挙げられます。</p>
<p>で、この形式を使っているのですが、RubyのString#to_f で解釈してくれず悲しくなるので、<br>
解釈できるようにしませんか。<br>
パッチは以下の通りです。</p>
<p>diff --git a/util.c b/util.c<br>
index 5ebc5f3..e361d51 100644<br>
--- a/util.c<br>
+++ b/util.c<br>
@@ -2106,6 +2106,44 @@ ruby_strtod(const char *s00, char **se)<br>
}<br>
break2:<br>
if (*s == '0') {</p>
<ul>
<li>
<pre><code> if (s[1] == 'x') {
</code></pre>
</li>
<li>
<pre><code> static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF";
</code></pre>
</li>
<li>
<pre><code> s0 = ++s;
</code></pre>
</li>
<li>
<pre><code> adj = 0;
</code></pre>
</li>
<li>
<li>
<pre><code> while (*++s && (s1 = strchr(hexdigit, *s))) {
</code></pre>
</li>
<li>
<pre><code> adj *= 16;
</code></pre>
</li>
<li>
<pre><code> adj += (s1 - hexdigit) & 15;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<li>
<pre><code> if (*s == '.') {
</code></pre>
</li>
<li>
<pre><code> aadj = 1.;
</code></pre>
</li>
<li>
<pre><code> while (*++s && (s1 = strchr(hexdigit, *s))) {
</code></pre>
</li>
<li>
<pre><code> aadj /= 16;
</code></pre>
</li>
<li>
<pre><code> adj += aadj * ((s1 - hexdigit) & 15);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<li>
<pre><code> if (*s != 'p') {
</code></pre>
</li>
<li>
<pre><code> s = s0;
</code></pre>
</li>
<li>
<pre><code> goto ret;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<li>
<pre><code> dsign = 0x2C - *++s; /* +: 2B, -: 2D */
</code></pre>
</li>
<li>
<pre><code> if (abs(dsign) != 1) {
</code></pre>
</li>
<li>
<pre><code> s = s0;
</code></pre>
</li>
<li>
<pre><code> goto ret;
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<li>
<pre><code> for (nd = 0, s++; (c = *s) >= '0' && c <= '9'; s++) {
</code></pre>
</li>
<li>
<pre><code> nd *= 10;
</code></pre>
</li>
<li>
<pre><code> nd += c;
</code></pre>
</li>
<li>
<pre><code> nd -= '0';
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<li>
<pre><code> dval(rv) = ldexp(adj, nd * dsign);
</code></pre>
</li>
<li>
<pre><code> goto ret;
</code></pre>
</li>
<li>
<pre><code> }
nz0 = 1;
while (*++s == '0') ;
if (!*s)
</code></pre>
</li>
</ul>
<p>diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb<br>
index 64205f6..72d3242 100644<br>
--- a/test/ruby/test_string.rb<br>
+++ b/test/ruby/test_string.rb<br>
@@ -1381,10 +1381,24 @@ class TestString < Test::Unit::TestCase<br>
end</p>
<pre><code>def test_to_f
</code></pre>
<ul>
<li>assert_equal(0.0, S("0.0").to_f)</li>
<li>assert_equal(?0, S("0.0").to_f.to_s[0])</li>
<li>assert_equal(-0.0, S("-0.0").to_f)</li>
<li>assert_equal(?-, S("-0.0").to_f.to_s[0])<br>
assert_equal(344.3, S("344.3").to_f)<br>
assert_equal(5.9742e24, S("5.9742e24").to_f)<br>
assert_equal(98.6, S("98.6 degrees").to_f)<br>
assert_equal(0.0, S("degrees 100.0").to_f)</li>
<li>assert_equal(0.0, S("0x0p+0").to_f)</li>
<li>assert_equal(?0, S("0x0p+0").to_f.to_s[0])</li>
<li>assert_equal(-0.0, S("-0x0p+0").to_f)</li>
<li>assert_equal(?-, S("-0x0p+0").to_f.to_s[0])</li>
<li>assert_equal(1.0, S("0x1p+0").to_f)</li>
<li>assert_equal(?1, S("0x1p+0").to_f.to_s[0])</li>
<li>assert_equal(1024.0, S("0x1p+10").to_f)</li>
<li>assert_equal(0.0009765625, S("0x1p-10").to_f)</li>
<li>assert_equal(2.6881171418161356e+43, S("0x1.3494a9b171bf5p+144").to_f)</li>
<li>assert_equal(-3.720075976020836e-44, S("-0x1.a8c1f14e2af5dp-145").to_f)<br>
end</li>
</ul>
<pre><code>def test_to_i
</code></pre>
<p>=end</p>
Ruby master - Feature #2968 (Rejected): 数値の正負を返すメソッド
https://redmine.ruby-lang.org/issues/2968
2010-03-16T03:38:54Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
数値の正負を返すメソッドが欲しいです。<br>
主たる想定用途は 0.0 と -0.0 を区別したいときです。<br>
これは、0.0 > -0.0 や 0.0 == -0.0 では知ることができません。<br>
とりあえず flo.to_s[0] == ?- で知ることができますが、これではあんまりです。</p>
<p>悩みどころはいつもの通りメソッド名ですが、</p>
<ul>
<li>Numeric#positive? と Numeric#negative?</li>
<li>Numeric#sign -> 負で -1、正で 1</li>
<li>Numeric#sign? -> 負で true, 正で false (signbit(3) に習う)<br>
あたりでしょうか。</li>
</ul>
<p>いかがでしょう。<br>
=end</p>
Ruby master - Feature #2835 (Closed): String#encodeに置換文字列のみを与えたら未定義向けとみなす
https://redmine.ruby-lang.org/issues/2835
2010-03-03T21:53:11Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Ruby 1.9 もおおむね完成してからそろそろ 3 年が経つのですが、<br>
気付いた事として、String#encode(to, from, opt) の opt に :replace を指定した時は、<br>
ほとんどの場合 :undef => :replace も指定するという事があります。</p>
<p>よくよく考えれば、不正なバイト列を続行したいという事は少ないし、推奨されず、<br>
ゆえに置換文字列を指定する場合はたいてい未定義文字を置き換えたい場合な訳です。</p>
<p>以下のパッチは、:invalid => :replace がしているされている場合以外に、<br>
(つまり、不正なバイト列向けに置換文字列が指定されている可能性がある場合以外)<br>
置換文字列を指定している場合、:undef => :replace とみなします。</p>
<p>想定ケースでは :undef => :replace と書かなくてすむので楽な上に、<br>
楽な方法に誘導する事で、よく考えずに {:invalid => :replace, :undef => :replace}<br>
と書いてしまう人を減らせるので一石二鳥だと思うのですが、いかがでしょう。</p>
<p>diff --git a/transcode.c b/transcode.c<br>
index d511547..9d6a886 100644<br>
--- a/transcode.c<br>
+++ b/transcode.c<br>
@@ -2394,6 +2394,11 @@ econv_opts(VALUE opt)<br>
rb_raise(rb_eArgError, "unknown value for undefined character option");<br>
}</p>
<ul>
<li>v = rb_hash_aref(opt, sym_replace);</li>
<li>if (!NIL_P(v) && !(ecflags & ECONV_INVALID_REPLACE)) {</li>
<li>
<pre><code> ecflags |= ECONV_UNDEF_REPLACE;
</code></pre>
</li>
<li>}</li>
<li>v = rb_hash_aref(opt, sym_xml);<br>
if (!NIL_P(v)) {<br>
if (v==sym_text) {<br>
=end</li>
</ul>
Ruby 1.8 - Bug #2761 (Closed): weird behaviour of readline on OSX 10.6
https://redmine.ruby-lang.org/issues/2761
2010-02-19T05:36:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Hi,</p>
<p>You seems to use Ruby 1.8.x.<br>
So can you try following?</p>
<a name="Index-extreadlinereadlinec"></a>
<h1 >Index: ext/readline/readline.c<a href="#Index-extreadlinereadlinec" class="wiki-anchor">¶</a></h1>
<p>--- ext/readline/readline.c (revision 26664)<br>
+++ ext/readline/readline.c (working copy)<br>
@@ -833,6 +833,12 @@<br>
#ifdef HAVE_RL_EVENT_HOOK<br>
rl_event_hook = readline_event;<br>
#endif<br>
+#ifdef HAVE_RL_CATCH_SIGNALS</p>
<ul>
<li>rl_catch_signals = 0;<br>
+#endif<br>
+#ifdef HAVE_RL_CATCH_SIGWINCH</li>
<li>rl_catch_sigwinch = 0;<br>
+#endif<br>
#ifdef HAVE_RL_CLEAR_SIGNALS<br>
rl_clear_signals();<br>
#endif<br>
Index: ext/readline/extconf.rb<br>
===================================================================<br>
--- ext/readline/extconf.rb (revision 26664)<br>
+++ ext/readline/extconf.rb (working copy)<br>
@@ -59,6 +59,9 @@<br>
have_readline_var("rl_attempted_completion_over")<br>
have_readline_var("rl_library_version")<br>
have_readline_var("rl_event_hook")<br>
+# workaround for native windows.<br>
+/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_catch_sigwinch")<br>
+/mswin|bccwin|mingw/ !~ RUBY_PLATFORM && have_readline_var("rl_catch_signals")<br>
have_readline_func("rl_cleanup_after_signal")<br>
have_readline_func("rl_clear_signals")<br>
have_readline_func("rl_vi_editing_mode")</li>
</ul>
<p>(2010/02/19 4:59), Andrew Eberbach wrote:</p>
<blockquote>
<p>Hi</p>
<p>I've been noticing that irb (and as a result script/console in rails)<br>
don't behave correctly with Control C. Nothing would happen when I hit<br>
control C until I hit enter or a few more keys and then it would clear<br>
the line and show a ^C and reset to the prompt. This doesn't happen on<br>
Linux and it didn't happen on 10.5</p>
<p>If there's a long running process in irb hitting control c works as<br>
expected but not if it's just sitting at a prompt.</p>
<p>I played around with the ext/readline.c and found that if I put a</p>
<p>rl_catch_signals = 0;</p>
<p>(see <a href="http://tiswww.case.edu/php/chet/readline/readline.html" class="external">http://tiswww.case.edu/php/chet/readline/readline.html</a>)</p>
<p>in Init_readline()</p>
<p>Then everything works as normal. Should this be added as a patch?<br>
Reading the readline docs it seems to me that what's happening is the<br>
internal readline handler gets stuck sending SIGINT back to the ruby<br>
process even though there's a trap("SIGINT") defined. Any ideas?</p>
<p>Andrew</p>
</blockquote>
<p>--<br>
NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a><br>
=end</p>
Ruby master - Bug #2748 (Closed): fix for READ_CHECK causes failures on FreeBSD 8.0
https://redmine.ruby-lang.org/issues/2748
2010-02-16T03:41:08Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
間を置いてからの報告で申し訳ないのですが、例の READ_CHECK の修正 (r26625) が、<br>
FreeBSD での test-all の失敗を増やします。<br>
r26625 を revert するとこれらのテストは成功するようになります。</p>
<ol>
<li>
<p>Failure:<br>
test_read_error(TestIO) [/home/naruse/ruby/test/ruby/test_io.rb:869]:<br>
RuntimeError expected but nothing was raised.</p>
</li>
<li>
<p>Failure:<br>
test_readpartial_error(TestIO) [/home/naruse/ruby/test/ruby/test_io.rb:834]:<br>
RuntimeError expected but nothing was raised.<br>
=end</p>
</li>
</ol>
Ruby master - Bug #2724 (Third Party's Issue): fork from other than the main thread causes wrong ...
https://redmine.ruby-lang.org/issues/2724
2010-02-09T03:04:20Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>NetBSD 5.0.[01] において、main thread 以外の pthread から fork すると、<br>
pthread とカーネルスレッド (lwp) との関連が壊れるという現象が確認されています。</p>
<p>後述のパッチがあまりにアレなのでこの問題は Third Party's Issue とし、<br>
Ruby 側では修正を入れない事としますが、情報の共有と記録のために<br>
ここにチケットを切っておきます。</p>
<p>なお、この workaround の作成には @_enamiさんの助けがありました。</p>
<p>追記:<br>
NetBSD 側では kern/42772 として報告、修正されています。<br>
<a href="http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=42772" class="external">http://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=42772</a></p>
<a name="Index-thread_pthreadc"></a>
<h1 >Index: thread_pthread.c<a href="#Index-thread_pthreadc" class="wiki-anchor">¶</a></h1>
<p>--- thread_pthread.c (revision 26615)<br>
+++ thread_pthread.c (working copy)<br>
@@ -17,6 +17,93 @@<br>
#include <sys/resource.h><br>
#endif</p>
<p>+#if defined(<strong>NetBSD_Version</strong>) && <strong>NetBSD_Version</strong> >= 500000000<br>
+/* Hack for NetBSD 5.0.x's broken pthread->pt_lid <em>/<br>
+/</em> Copied from /src/lib/libpthread/pthread_int.h <em>/<br>
+#define BROKEN_PTHREAD_T_PT_LID<br>
+#include <lwp.h><br>
+#include <pthread_queue.h><br>
+#include <sys/tree.h><br>
+<br>
+#define PTHREAD_KEYS_MAX 256<br>
+#define PTHREAD__UNPARK_MAX 32<br>
+<br>
+/</em></p>
<ul>
<li>
<ul>
<li>The size of this structure needs to be no larger than struct</li>
</ul>
</li>
<li>
<ul>
<li>__pthread_cleanup_store, defined in pthread.h.</li>
</ul>
</li>
<li>*/<br>
+struct pt_clean_t {</li>
<li>
<pre><code> PTQ_ENTRY(pt_clean_t) ptc_next;
</code></pre>
</li>
<li>
<pre><code> void (*ptc_cleanup)(void *);
</code></pre>
</li>
<li>
<pre><code> void *ptc_arg;
</code></pre>
</li>
</ul>
<p>+};<br>
+<br>
+struct pthread_lock_ops {</p>
<ul>
<li>
<pre><code> void (*plo_init)(__cpu_simple_lock_t *);
</code></pre>
</li>
<li>
<pre><code> int (*plo_try)(__cpu_simple_lock_t *);
</code></pre>
</li>
<li>
<pre><code> void (*plo_unlock)(__cpu_simple_lock_t *);
</code></pre>
</li>
<li>
<pre><code> void (*plo_lock)(__cpu_simple_lock_t *);
</code></pre>
</li>
</ul>
<p>+};<br>
+<br>
+struct __pthread_st {</p>
<ul>
<li>
<pre><code> pthread_t pt_self; /* Must be first. */
</code></pre>
</li>
<li>
<pre><code> unsigned int pt_magic; /* Magic number */
</code></pre>
</li>
<li>
<pre><code> int pt_state; /* running, blocked, etc. */
</code></pre>
</li>
<li>
<pre><code> pthread_mutex_t pt_lock; /* lock on state */
</code></pre>
</li>
<li>
<pre><code> int pt_flags; /* see PT_FLAG_* below */
</code></pre>
</li>
<li>
<pre><code> int pt_cancel; /* Deferred cancellation */
</code></pre>
</li>
<li>
<pre><code> int pt_errno; /* Thread-specific errno. */
</code></pre>
</li>
<li>
<pre><code> stack_t pt_stack; /* Our stack */
</code></pre>
</li>
<li>
<pre><code> void *pt_exitval; /* Read by pthread_join() */
</code></pre>
</li>
<li>
<pre><code> char *pt_name; /* Thread's name, set by the app. */
</code></pre>
</li>
<li>
<pre><code> int pt_willpark; /* About to park */
</code></pre>
</li>
<li>
<pre><code> lwpid_t pt_unpark; /* Unpark this when parking */
</code></pre>
</li>
<li>
<pre><code> struct pthread_lock_ops pt_lockops;/* Cached to avoid PIC overhead */
</code></pre>
</li>
<li>
<pre><code> pthread_mutex_t *pt_droplock; /* Drop this lock if cancelled */
</code></pre>
</li>
<li>
<pre><code> pthread_cond_t pt_joiners; /* Threads waiting to join. */
</code></pre>
</li>
<li>
<li>
<pre><code> /* Threads to defer waking, usually until pthread_mutex_unlock(). */
</code></pre>
</li>
<li>
<pre><code> lwpid_t pt_waiters[PTHREAD__UNPARK_MAX];
</code></pre>
</li>
<li>
<pre><code> size_t pt_nwaiters;
</code></pre>
</li>
<li>
<li>
<pre><code> /* Stack of cancellation cleanup handlers and their arguments */
</code></pre>
</li>
<li>
<pre><code> PTQ_HEAD(, pt_clean_t) pt_cleanup_stack;
</code></pre>
</li>
<li>
<li>
<pre><code> /* LWP ID and entry on the list of all threads. */
</code></pre>
</li>
<li>
<pre><code> lwpid_t pt_lid;
</code></pre>
</li>
<li>
<pre><code> RB_ENTRY(__pthread_st) pt_alltree;
</code></pre>
</li>
<li>
<pre><code> PTQ_ENTRY(__pthread_st) pt_allq;
</code></pre>
</li>
<li>
<pre><code> PTQ_ENTRY(__pthread_st) pt_deadq;
</code></pre>
</li>
<li>
<li>
<pre><code> /*
</code></pre>
</li>
<li>
<pre><code> * General synchronization data. We try to align, as threads
</code></pre>
</li>
<li>
<pre><code> * on other CPUs will access this data frequently.
</code></pre>
</li>
<li>
<pre><code> */
</code></pre>
</li>
<li>
<pre><code> int pt_dummy1 __aligned(128);
</code></pre>
</li>
<li>
<pre><code> struct lwpctl *pt_lwpctl; /* Kernel/user comms area */
</code></pre>
</li>
<li>
<pre><code> volatile int pt_blocking; /* Blocking in userspace */
</code></pre>
</li>
<li>
<pre><code> volatile int pt_rwlocked; /* Handed rwlock successfully */
</code></pre>
</li>
<li>
<pre><code> volatile int pt_signalled; /* Received pthread_cond_signal() */
</code></pre>
</li>
<li>
<pre><code> volatile int pt_mutexwait; /* Waiting to acquire mutex */
</code></pre>
</li>
<li>
<pre><code> void * volatile pt_mutexnext; /* Next thread in chain */
</code></pre>
</li>
<li>
<pre><code> void * volatile pt_sleepobj; /* Object slept on */
</code></pre>
</li>
<li>
<pre><code> PTQ_ENTRY(__pthread_st) pt_sleep;
</code></pre>
</li>
<li>
<pre><code> void (*pt_early)(void *);
</code></pre>
</li>
<li>
<pre><code> int pt_dummy2 __aligned(128);
</code></pre>
</li>
<li>
<li>
<pre><code> /* Thread-specific data. Large so it sits close to the end. */
</code></pre>
</li>
<li>
<pre><code> int pt_havespecific;
</code></pre>
</li>
<li>
<pre><code> void *pt_specific[PTHREAD_KEYS_MAX];
</code></pre>
</li>
<li>
<li>
<pre><code> /*
</code></pre>
</li>
<li>
<pre><code> * Context for thread creation. At the end as it's cached
</code></pre>
</li>
<li>
<pre><code> * and then only ever passed to _lwp_create().
</code></pre>
</li>
<li>
<pre><code> */
</code></pre>
</li>
<li>
<pre><code> ucontext_t pt_uc;
</code></pre>
</li>
</ul>
<p>+};<br>
+#endif /* <strong>NetBSD</strong> */<br>
+<br>
+<br>
static void native_mutex_lock(pthread_mutex_t *lock);<br>
static void native_mutex_unlock(pthread_mutex_t *lock);<br>
static int native_mutex_trylock(pthread_mutex_t *lock);<br>
@@ -833,6 +920,9 @@<br>
native_reset_timer_thread(void)<br>
{<br>
timer_thread_id = 0;<br>
+#ifdef BROKEN_PTHREAD_T_PT_LID</p>
<ul>
<li>((struct __pthread_st *)pthread_self())->pt_lid = _lwp_self();<br>
+#endif<br>
}</li>
</ul>
<p>#ifdef HAVE_SIGALTSTACK</p>
Ruby master - Feature #2635 (Rejected): Unbundle rdoc
https://redmine.ruby-lang.org/issues/2635
2010-01-23T23:20:56Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
The rdoc in trunk is outdated and not maintained,<br>
and latest rdoc is in gen.</p>
<p>I think Ruby 1.9 shouldn't bundle such old rdoc.<br>
People who needs rdoc should install from gem.<br>
=end</p>
Ruby master - Feature #2586 (Rejected): openssl: Load root certificates on Windows
https://redmine.ruby-lang.org/issues/2586
2010-01-10T15:27:08Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
On Unix, ext/openssl can use the system's root certificates.<br>
But on Windows root certificates are not provided as files.</p>
<p>By this patch, OpenSSL::X509::Store#set_default_paths can load<br>
root certificates bundled with Windows.<br>
=end</p>
Ruby master - Feature #2579 (Closed): Net::HTTP.start("www.ruby-lang.org", use_ssl: true) で SSL 利...
https://redmine.ruby-lang.org/issues/2579
2010-01-09T20:34:21Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
従来、Net::HTTP で https アクセスをするためには</p>
<p>http = Net::HTTP.new("www.ruby-lang.org", 443) # port を指定<br>
http.use_ssl = true # use_ssl を true に<br>
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # デフォルトだと検証してくれないので変更<br>
http.start{|h| } # やっと本題<br>
http.finish # 破棄</p>
<p>などとする必要がありました。</p>
<p>この提案では、Net::HTTP(addr, opt){..} という呼び出し方を追加します。<br>
opt はハッシュで、アクセサのある項目を設定する事が出来ます。</p>
<p>なお、折角の新 API なので、この API を使った場合、verify_mode のデフォルトが VERIFY_PEER になっています。<br>
つまり、この API を用いた場合デフォルトで SSL 署名の有効性を検査するため、<br>
期限切れやオレオレ証明書の場合例外が出ます。</p>
<p>これにより、さっきのは以下のように書けます。<br>
Net::HTTP.start("www.ruby-lang.org", use_ssl: true){|h| }</p>
<p>P.S.<br>
なお、以上の例で用いている <a href="http://www.ruby-lang.org" class="external">www.ruby-lang.org</a> は、現在 SSL 証明書が期限切れのため、<br>
この例を今実行すると検証に失敗して例外が出ます。<br>
今は StartCom とかだと無料で 主要環境でルート証明書が入っている Web サーバ用の SSL 証明書が取得できますから、<br>
そういうのに入れ替えた方がいいのではないでしょうか。<br>
=end</p>
Ruby master - Feature #2574 (Closed): merging net/https
https://redmine.ruby-lang.org/issues/2574
2010-01-08T09:40:06Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
現在 net/https はほとんど抜け殻で、ほぼ require 'openssl' するためだけに存在するのですが、<br>
残っているロジックも net/http に移してしまって、net/http だけで https も扱えるようにしませんか。<br>
autoload を使って https に実際にアクセスしたときに openssl ライブラリをロードするようにしたので、<br>
無駄に読み込むこともありません。</p>
<p>なお、net/https は require を使うままにしているので、こちらだともし openssl ライブラリがない場合、<br>
net/https ロード時にエラーが出るという現在の挙動をそのまま利用できます。<br>
=end</p>
Backport191 - Backport #2477 (Closed): String#split should be ASCII sensitive
https://redmine.ruby-lang.org/issues/2477
2009-12-14T15:51:40Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
If r24544 is backported, r24934 is also worth backported.</p>
<p>Author: naruse <a href="mailto:naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e" class="email">naruse@b2dd03c8-39d4-4d8f-98ff-823fe69b080e</a><br>
Date: Tue Sep 15 05:27:29 2009 +0000</p>
<pre><code> Use rb_isspace for ASCII-incompatible strings.
* string.c (rb_str_split_m): use rb_isspace when the string
may be ASCII-incompatible.
(rb_str_lstrip_bang): ditto.
(rb_str_rstrip_bang): ditto.
</code></pre>
<p>=end</p>
Ruby master - Feature #2470 (Closed): Encoding#new doesn't undef_method-ed
https://redmine.ruby-lang.org/issues/2470
2009-12-10T08:03:34Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
Fixnum や Encoding のような、rb_undef_alloc_func されているクラスでは、<br>
Hoge.new がエラーになりますが、<br>
Fixnum などでは Fixnum.new が undef されているのに、<br>
Encoding ではなされていないため、呼んだ際の挙動が異なります。</p>
<p>irb(main):001:0> Fixnum.new<br>
NoMethodError: undefined method <code>new' for Fixnum:Class from (irb):1 from /usr/local/bin/irb_1_9_1:12:in </code>'<br>
irb(main):002:0> Encoding.new<br>
TypeError: allocator undefined for Encoding<br>
from (irb):2:in <code>new' from (irb):2 from /usr/local/bin/irb_1_9_1:12:in </code>'</p>
<p>以下がパッチです。</p>
<p>diff --git a/encoding.c b/encoding.c<br>
index 38d81b8..f9d2f20 100644<br>
--- a/encoding.c<br>
+++ b/encoding.c<br>
@@ -1484,6 +1484,7 @@ Init_Encoding(void)</p>
<pre><code> rb_cEncoding = rb_define_class("Encoding", rb_cObject);
rb_undef_alloc_func(rb_cEncoding);
</code></pre>
<ul>
<li>
<p>rb_undef_method(CLASS_OF(rb_cEncoding), "new");<br>
rb_define_method(rb_cEncoding, "to_s", enc_name, 0);<br>
rb_define_method(rb_cEncoding, "inspect", enc_inspect, 0);<br>
rb_define_method(rb_cEncoding, "name", enc_name, 0);<br>
diff --git a/object.c b/object.c<br>
index 10eb983..704cb2a 100644<br>
--- a/object.c<br>
+++ b/object.c<br>
@@ -2680,6 +2680,7 @@ Init_Object(void)</p>
<p>rb_cData = rb_define_class("Data", rb_cObject);<br>
rb_undef_alloc_func(rb_cData);</p>
</li>
<li>
<p>rb_undef_method(CLASS_OF(rb_cData), "new");</p>
<p>rb_cTrueClass = rb_define_class("TrueClass", rb_cObject);<br>
rb_define_method(rb_cTrueClass, "to_s", true_to_s, 0);<br>
diff --git a/vm.c b/vm.c<br>
index fa028fd..e522c9f 100644<br>
--- a/vm.c<br>
+++ b/vm.c<br>
@@ -1944,6 +1944,7 @@ Init_VM(void)<br>
/* ::VM */<br>
rb_cRubyVM = rb_define_class("RubyVM", rb_cObject);<br>
rb_undef_alloc_func(rb_cRubyVM);</p>
</li>
<li>
<p>rb_undef_method(CLASS_OF(rb_cRubyVM), "new");</p>
<p>/* ::VM::FrozenCore <em>/<br>
fcore = rb_class_new(rb_cBasicObject);<br>
@@ -1962,6 +1963,7 @@ Init_VM(void)<br>
/</em> ::VM::Env */<br>
rb_cEnv = rb_define_class_under(rb_cRubyVM, "Env", rb_cObject);<br>
rb_undef_alloc_func(rb_cEnv);</p>
</li>
<li>
<p>rb_undef_method(CLASS_OF(rb_cEnv), "new");</p>
<p>/* ::Thread */<br>
rb_cThread = rb_define_class("Thread", rb_cObject);<br>
=end</p>
</li>
</ul>
Ruby master - Feature #2454 (Rejected): OpenSSL has no maintainer
https://redmine.ruby-lang.org/issues/2454
2009-12-08T00:54:31Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
OpenSSL is famous security library and Ruby has a wrapper for it.<br>
But it has no maintainer now.<br>
We, aren't familiar with this security related library, don't want maintain this.<br>
This situation prevent merging path for OpenSSL 1.0 and other requests.</p>
<p>So anyone can maintain ext/openssl or review patches for ext/openssl?<br>
=end</p>
Ruby master - Bug #2386 (Closed): r25230 causes SEGV arround Marshal
https://redmine.ruby-lang.org/issues/2386
2009-11-20T07:54:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
以下のコミット以降、後述の現象が発生するそうです。</p>
<p>Author: nobu <a href="mailto:nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e" class="email">nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e</a><br>
Date: Sun Oct 4 10:30:56 2009 +0000</p>
<pre><code>* marshal.c (struct {dump,load}_arg): manage with dfree, instead
of using local variable which may be moved by context switch.
<a href="https://blade.ruby-lang.org/ruby-dev/39425">[ruby-dev:39425]</a>
</code></pre>
<p><a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=25230" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=25230</a></p>
<hr>
<p>けいじゅ@いしつかです.</p>
<p>最新版のrubyで以下のメッセージが出るようになってしまったのですが, これ<br>
はどのような意味でしょうか?</p>
<p>% ruby -v<br>
ruby 1.9.2dev (2009-11-19 trunk 25848) [i686-linux]</p>
<p>each: method `to_s' called on hidden object (0x9438e48)</p>
<p>また, これを調べていたら: 以下のようなSEGVも発生するようになってしまい<br>
ました... なんか, 関係あるでしょうか?</p>
<a name="rubyのバージョンは微妙に違います"></a>
<h1 >rubyのバージョンは微妙に違います.<a href="#rubyのバージョンは微妙に違います" class="wiki-anchor">¶</a></h1>
<p>/usr/local/apps/rubyware/ruby-1.9.2-20091118/lib/ruby/1.9.1/delegate.rb:265: [BUG] Segmentation fault<br>
ruby 1.9.2dev (2009-11-18 trunk 25846) [i686-linux]</p>
<h2>-- control frame ----------<br>
c:0037 p:---- s:0130 b:0130 l:000129 d:000129 CFUNC :write<br>
c:0036 p:0026 s:0126 b:0126 l:000768 d:000125 LAMBDA /usr/local/apps/rubyware/ruby-1.9.2-20091118/lib/ruby/1.9.1/delegate.rb:265<br>
c:0035 p:---- s:0121 b:0121 l:000120 d:000120 FINISH<br>
c:0034 p:---- s:0119 b:0119 l:000118 d:000118 CFUNC :dump<br>
c:0033 p:0062 s:0114 b:0114 l:000ba8 d:000113 BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:863<br>
c:0032 p:0050 s:0110 b:0110 l:000109 d:000109 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:849<br>
c:0031 p:0011 s:0105 b:0105 l:000ba8 d:000ba8 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:859<br>
c:0030 p:0079 s:0101 b:0101 l:000095 d:000100 BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:787<br>
c:0029 p:0019 s:0099 b:0099 l:000098 d:000098 METHOD <a href="internal:prelude" class="external">internal:prelude</a>:8<br>
c:0028 p:0013 s:0096 b:0096 l:000095 d:000095 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:780<br>
c:0027 p:0015 s:0092 b:0092 l:000091 d:000091 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:303<br>
c:0026 p:0118 s:0088 b:0088 l:001e8c d:000087 BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-group-by.rb:56<br>
c:0025 p:---- s:0083 b:0083 l:000082 d:000082 FINISH<br>
c:0024 p:---- s:0081 b:0081 l:000080 d:000080 CFUNC :call<br>
c:0023 p:0014 s:0077 b:0077 l:0011ec d:000076 BLOCK test/testc.rb:3196<br>
c:0022 p:---- s:0074 b:0074 l:000073 d:000073 FINISH<br>
c:0021 p:---- s:0072 b:0072 l:000071 d:000071 CFUNC :each<br>
c:0020 p:0032 s:0069 b:0069 l:0011ec d:00263c BLOCK test/testc.rb:3195<br>
c:0019 p:---- s:0065 b:0065 l:000064 d:000064 FINISH<br>
c:0018 p:---- s:0063 b:0063 l:000062 d:000062 CFUNC :each<br>
c:0017 p:0017 s:0060 b:0060 l:000059 d:000059 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/nfile.rb:78<br>
c:0016 p:0073 s:0056 b:0056 l:000055 d:000055 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:156<br>
c:0015 p:0011 s:0051 b:0051 l:0011ec d:00074c BLOCK test/testc.rb:3188<br>
c:0014 p:---- s:0047 b:0047 l:000046 d:000046 FINISH<br>
c:0013 p:---- s:0045 b:0045 l:000044 d:000044 CFUNC :yield<br>
c:0012 p:0014 s:0040 b:0040 l:0000dc d:000039 BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/block-source.rb:81<br>
c:0011 p:0021 s:0038 b:0038 l:000037 d:000037 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/stdout.rb:35<br>
c:0010 p:0014 s:0034 b:0034 l:0000dc d:0000dc METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/block-source.rb:80<br>
c:0009 p:0043 s:0029 b:0029 l:000028 d:000028 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-each-substream-mapper.rb:26<br>
c:0008 p:0073 s:0025 b:0025 l:000024 d:000024 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:156<br>
c:0007 p:0137 s:0020 b:0020 l:001e8c d:001f2c BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-group-by.rb:47<br>
c:0006 p:---- s:0016 b:0016 l:000015 d:000015 FINISH<br>
c:0005 p:---- s:0014 b:0014 l:000013 d:000013 CFUNC :call<br>
c:0004 p:0012 s:0011 b:0011 l:000010 d:000010 METHOD /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:143<br>
c:0003 p:0077 s:0007 b:0007 l:0020f8 d:000006 BLOCK /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:125<br>
c:0002 p:---- s:0004 b:0004 l:000003 d:000003 FINISH<br>
c:0001 p:---- s:0002 b:0002 l:000001 d:000001 TOP</h2>
<p>/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:125:in <code>block in start' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:143:in </code>basic_start'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:143:in <code>call' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-group-by.rb:47:in </code>block in start_export'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:156:in <code>each' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-each-substream-mapper.rb:26:in </code>basic_each'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/block-source.rb:80:in <code>yield19' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/stdout.rb:35:in </code>replace_stdout'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/block-source.rb:81:in <code>block in yield19' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/share/block-source.rb:81:in </code>yield'<br>
test/testc.rb:3188:in <code>block in context' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/njob.rb:156:in </code>each'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/nfile.rb:78:in <code>basic_each' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/nfile.rb:78:in </code>each'<br>
test/testc.rb:3195:in <code>block (2 levels) in context' test/testc.rb:3195:in </code>each'<br>
test/testc.rb:3196:in <code>block (3 levels) in context' test/testc.rb:3196:in </code>call'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/n-group-by.rb:56:in <code>block (2 levels) in start_export' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:303:in </code>push'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:780:in <code>push' <internal:prelude>:8:in </code>synchronize'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:787:in <code>block in push' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:859:in </code>store_2ndmemory'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:849:in <code>open_2ndmemory' /home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:863:in </code>block in store_2ndmemory'<br>
/home/keiju/public/a.research/fairy/git/fairy/lib/fairy/node/port.rb:863:in <code>dump' /usr/local/apps/rubyware/ruby-1.9.2-20091118/lib/ruby/1.9.1/delegate.rb:265:in </code>block in delegating_block'<br>
/usr/local/apps/rubyware/ruby-1.9.2-20091118/lib/ruby/1.9.1/delegate.rb:265:in `write'</p>
<p>-- C level backtrace information -------------------------------------------<br>
fairy processor --node 45566 --id 0(rb_vm_bugreport+0xb5) [0x81621a5]<br>
fairy processor --node 45566 --id 0 [0x819f3ce]<br>
fairy processor --node 45566 --id 0(rb_bug+0x28) [0x819f468]<br>
fairy processor --node 45566 --id 0 [0x80f71e5]<br>
[0xb801c40c]<br>
fairy processor --node 45566 --id 0(rb_funcall+0xe1) [0x815ee81]<br>
fairy processor --node 45566 --id 0(rb_obj_as_string+0x81) [0x8103811]<br>
fairy processor --node 45566 --id 0 [0x8079378]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_vm_invoke_proc+0x81) [0x8159b61]<br>
fairy processor --node 45566 --id 0 [0x815aab5]<br>
fairy processor --node 45566 --id 0(rb_funcall+0x18e) [0x815ef2e]<br>
fairy processor --node 45566 --id 0(rb_io_write+0x29) [0x80712a9]<br>
fairy processor --node 45566 --id 0 [0x8089f38]<br>
fairy processor --node 45566 --id 0 [0x814d71d]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_vm_invoke_proc+0x81) [0x8159b61]<br>
fairy processor --node 45566 --id 0 [0x8062ec4]<br>
fairy processor --node 45566 --id 0 [0x814d71d]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_yield+0x4f) [0x816103f]<br>
fairy processor --node 45566 --id 0(rb_ary_each+0x41) [0x81716a1]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_yield+0x4f) [0x816103f]<br>
fairy processor --node 45566 --id 0 [0x8082bf8]<br>
fairy processor --node 45566 --id 0 [0x814d71d]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_vm_invoke_proc+0x81) [0x8159b61]<br>
fairy processor --node 45566 --id 0 [0x8062ec4]<br>
fairy processor --node 45566 --id 0 [0x814d71d]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_vm_invoke_proc+0x81) [0x8159b61]<br>
fairy processor --node 45566 --id 0 [0x8062ec4]<br>
fairy processor --node 45566 --id 0 [0x814d71d]<br>
fairy processor --node 45566 --id 0 [0x8151689]<br>
fairy processor --node 45566 --id 0 [0x8152bbd]<br>
fairy processor --node 45566 --id 0 [0x815511d]<br>
fairy processor --node 45566 --id 0 [0x8159399]<br>
fairy processor --node 45566 --id 0(rb_vm_invoke_proc+0x81) [0x8159b61]<br>
fairy processor --node 45566 --id 0 [0x81682ed]<br>
fairy processor --node 45566 --id 0 [0x81683a1]<br>
/lib/i686/cmov/libpthread.so.0 [0xb7fe84b5]<br>
/lib/i686/cmov/libc.so.6(clone+0x5e) [0xb7efea5e]</p>
<p>--<br>
NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a><br>
=end</p>
Ruby master - Feature #2340 (Rejected): Removing YAML/Syck
https://redmine.ruby-lang.org/issues/2340
2009-11-06T17:16:10Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
YAML and Syck is a _why's product and widely used bundled library of Ruby.<br>
But they are not maintained for 2 years and no more by _why.<br>
And they support only YAML 1.0, not 1.1 and 1.2.<br>
So YAML/Syck considered harmful.<br>
=end</p>
Ruby master - Bug #2327 (Closed): String#upto で beg が非英数の時破壊的変更がその後に影響する
https://redmine.ruby-lang.org/issues/2327
2009-11-04T00:02:15Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
String の場合、upto のブロックパラメータを破壊的に変更することが出来ますが、<br>
非英数の際にこれがその後の挙動に影響を与えることがあります。</p>
<p>irb(main):001:0> "1".upto("9"){|x|print x;x.replace("9")}<br>
123456789=> "1"<br>
irb(main):002:0> "a".upto("z"){|x|print x;x.replace("z")}<br>
abcdefghijklmnopqrstuvwxyz=> "a"<br>
irb(main):003:0> "\u3041".upto("\u3093"){|x|print x;x.replace("\u3093")}<br>
ぁ=> "ん"<br>
irb(main):004:0> s="\u3041";s.upto("\u3093"){|x|print x;x.replace("\u3093")}<br>
ぁ=> "ん"</p>
<p>以上のように、"ぁ"のみで終わってしまったり、戻り値が変わってしまったりします。<br>
=end</p>
Ruby master - Bug #2208 (Rejected): Exception#inspect の message 部が inspect されていない
https://redmine.ruby-lang.org/issues/2208
2009-10-14T17:38:54Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
通常 Object#inspect の結果にでてくる文字列は inspect されています。<br>
しかし、Exception#inspect はそのままになっています。<br>
<a href="http://shinh.skr.jp/m/?date=20091014#c02" class="external">http://shinh.skr.jp/m/?date=20091014#c02</a></p>
<p>class Foo;def initialize;@a="\t";end;end<br>
Foo.new.inspect #=> #<Foo:0x000008012dffd8 <a class="user active user-mention" href="https://redmine.ruby-lang.org/users/52980">@A (A A)</a>="\t"></p>
<p>Exception.new("\t") #=> #<Exception: " "></p>
<p>単なるかけ忘れな気がするのですがどうでしょう。</p>
<p>diff --git a/error.c b/error.c<br>
index a7342de..3a5580a 100644<br>
--- a/error.c<br>
+++ b/error.c<br>
@@ -458,7 +458,7 @@ exc_exception(int argc, VALUE *argv, VALUE self)<br>
static VALUE<br>
exc_to_s(VALUE exc)<br>
{</p>
<ul>
<li>VALUE mesg = rb_attr_get(exc, rb_intern("mesg"));</li>
</ul>
<ul>
<li>
<p>VALUE mesg = rb_inspect(rb_attr_get(exc, rb_intern("mesg")));</p>
<p>if (NIL_P(mesg)) return rb_class_name(CLASS_OF(exc));<br>
if (OBJ_TAINTED(exc)) OBJ_TAINT(mesg);<br>
=end</p>
</li>
</ul>
Ruby master - Feature #2166 (Rejected): Add CreationError
https://redmine.ruby-lang.org/issues/2166
2009-10-01T00:33:34Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin</p>
<blockquote>
<p>Here is a patch which implements the CreationError exception class,<br>
as documented in the Tempfile API documentation. However,<br>
I could not write a unit test for it because there seems<br>
to be no mocking/stubbing framework that I could use.</p>
</blockquote>
<p>Originally <a href="/issues/1999">[ruby-core:25131]</a> and patch is there.<br>
=end</p>
Ruby master - Feature #2102 (Closed): String#inspect as default_internal encoding
https://redmine.ruby-lang.org/issues/2102
2009-09-16T01:11:37Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
String#inspect の結果は特定のエンコーディングに揃えるようにしませんか。</p>
<p>現在の inspect は異なるエンコーディングを持つ文字列でも何も考えず結合を試み、<br>
結果 EncodingCompatibilityError が上がったとしても気にしない、<br>
というものになっています。</p>
<p>しかし、inspect は irb や p など、とりあえずオブジェクトの中身を概観したい、<br>
という時に使われるものなのに、異なるエンコーディングがあるくらいで、<br>
例外になってしまうは正直不便です。</p>
<p>添付のパッチでは、</p>
<ul>
<li>default_internal が設定されていればそれを、設定されていなければ default_external を用いる。<br>
ただし、そのエンコーディングが ASCII compatible でない場合は US-ASCII を用いる。<br>
(以下 inspect のエンコーディングと呼ぶ)</li>
<li>String#inspect の結果は、その String のエンコーディングが、<br>
inspect のエンコーディングと同じ場合はこれまでと同様。</li>
<li>異なる場合、String 内の非 US-ASCII 文字は \xXX 形式でエスケープする。</li>
<li>String 以外の inspect はこれまでと同様。<br>
としています。<br>
これにより、inspect 結果のエンコーディングが一定になるので例外が上がることがなくなります。</li>
</ul>
<p>動作の例を示すと、inspect のエンコーディングが UTF-8 の場合、<br>
"あ".encode("UTF-16BE").inspect</p>
<a name="before-gt-0B"></a>
<h1 >before => "0B"<a href="#before-gt-0B" class="wiki-anchor">¶</a></h1>
<a name="after-gt-x30x42"></a>
<h1 >after => "\x30\x42"<a href="#after-gt-x30x42" class="wiki-anchor">¶</a></h1>
<p>"い".encode("UTF-8").inspect</p>
<a name="before-gt-い"></a>
<h1 >before => "い"<a href="#before-gt-い" class="wiki-anchor">¶</a></h1>
<a name="after-gt-い"></a>
<h1 >after => "い"<a href="#after-gt-い" class="wiki-anchor">¶</a></h1>
<p>"う".encode("EUC-JP").inspect</p>
<a name="before-gt-注-EUC-JP-で生のう"></a>
<h1 >before => "��" (注: EUC-JP で生の「う」)<a href="#before-gt-注-EUC-JP-で生のう" class="wiki-anchor">¶</a></h1>
<a name="after-gt-xA4xA6"></a>
<h1 >after => "\xA4\xA6"<a href="#after-gt-xA4xA6" class="wiki-anchor">¶</a></h1>
<p>["あ".encode("UTF-16BE"), "い".encode("UTF-8"), "う".encode("EUC-JP")].inspect</p>
<a name="beforegt-EncodingCompatibilityError"></a>
<h1 >before=> EncodingCompatibilityError<a href="#beforegt-EncodingCompatibilityError" class="wiki-anchor">¶</a></h1>
<a name="after-gt-x30x42-い-xA4xA6"></a>
<h1 >after => ["\x30\x42", "い", "\xA4\xA6"]<a href="#after-gt-x30x42-い-xA4xA6" class="wiki-anchor">¶</a></h1>
<p>どうでしょうか?</p>
<p>diff --git a/string.c b/string.c<br>
index aa36c37..b8d862c 100644<br>
--- a/string.c<br>
+++ b/string.c<br>
@@ -1739,6 +1739,12 @@ str_buf_cat(VALUE str, const char *ptr, long len)<br>
return str;<br>
}</p>
<p>+static VALUE<br>
+str_buf_cat2(VALUE str, const char *ptr)<br>
+{</p>
<ul>
<li>return str_buf_cat(str, ptr, strlen(ptr));<br>
+}</li>
<li>
</ul>
<p>VALUE<br>
rb_str_buf_cat(VALUE str, const char *ptr, long len)<br>
{<br>
@@ -4237,13 +4243,6 @@ str_cat_char(VALUE str, unsigned int c, rb_encoding *enc)<br>
rb_enc_str_buf_cat(str, s, n, enc);<br>
}</p>
<p>-static void<br>
-prefix_escape(VALUE str, unsigned int c, rb_encoding *enc)<br>
-{</p>
<ul>
<li>str_cat_char(str, '\', enc);</li>
<li>str_cat_char(str, c, enc);<br>
-}</li>
<li>
</ul>
<p>/*</p>
<ul>
<li>call-seq:</li>
<li>str.inspect => string<br>
@@ -4262,10 +4261,13 @@ rb_str_inspect(VALUE str)<br>
rb_encoding *enc = STR_ENC_GET(str);<br>
char *p, *pend;<br>
VALUE result = rb_str_buf_new(0);</li>
</ul>
<ul>
<li>rb_encoding *resenc = rb_default_internal_encoding();</li>
<li>
<li>if (resenc == NULL) resenc = rb_default_external_encoding();</li>
<li>if (!rb_enc_asciicompat(resenc)) resenc = rb_usascii_encoding();</li>
<li>rb_enc_associate(result, resenc);</li>
<li>str_buf_cat2(result, """);</li>
</ul>
<ul>
<li>if (!rb_enc_asciicompat(enc)) enc = rb_usascii_encoding();</li>
<li>rb_enc_associate(result, enc);</li>
<li>str_cat_char(result, '"', enc);<br>
p = RSTRING_PTR(str); pend = RSTRING_END(str);<br>
while (p < pend) {<br>
unsigned int c, cc;<br>
@@ -4278,8 +4280,7 @@ rb_str_inspect(VALUE str)<br>
goto escape_codepoint;<br>
}<br>
n = MBCLEN_CHARFOUND_LEN(n);</li>
<li>
<li>c = rb_enc_codepoint_len(p, pend, &n, enc);</li>
</ul>
<ul>
<li>c = rb_enc_mbc_to_codepoint(p, pend, enc);<br>
p += n;<br>
if (c == '"'|| c == '\' ||<br>
(c == '#' &&<br>
@@ -4287,51 +4288,49 @@ rb_str_inspect(VALUE str)<br>
MBCLEN_CHARFOUND_P(rb_enc_precise_mbclen(p,pend,enc)) &&<br>
(cc = rb_enc_codepoint(p,pend,enc),<br>
(cc == '$' || cc == '@' || cc == '{')))) {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, c, enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\");
</code></pre>
</li>
<li>
<pre><code> str_buf_cat(result, p - n, n);
</code></pre>
}<br>
else if (c == '\n') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'n', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\n");
</code></pre>
}<br>
else if (c == '\r') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'r', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\r");
</code></pre>
}<br>
else if (c == '\t') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 't', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\t");
</code></pre>
}<br>
else if (c == '\f') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'f', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\f");
</code></pre>
}<br>
else if (c == '\013') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'v', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\v");
</code></pre>
}<br>
else if (c == '\010') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'b', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\b");
</code></pre>
}<br>
else if (c == '\007') {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'a', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\a");
</code></pre>
}<br>
else if (c == 033) {</li>
</ul>
<ul>
<li>
<pre><code> prefix_escape(result, 'e', enc);
</code></pre>
</li>
</ul>
<ul>
<li>
<pre><code> str_buf_cat2(result, "\\e");
</code></pre>
}</li>
</ul>
<ul>
<li>else if (rb_enc_isprint(c, enc)) {</li>
<li>
<pre><code> rb_enc_str_buf_cat(result, p-n, n, enc);
</code></pre>
</li>
</ul>
<ul>
<li>else if ((enc == resenc && rb_enc_isprint(c, enc)) || rb_enc_isascii(c, enc)) {</li>
<li>
<pre><code> str_buf_cat(result, p-n, n);
</code></pre>
}<br>
else {</li>
</ul>
<ul>
<li>
<pre><code> char buf[5];
</code></pre>
</li>
<li>
<pre><code> char *s;
char *q;
</code></pre>
</li>
<li>escape_codepoint:<br>
for (q = p-n; q < p; q++) {</li>
<li>
<pre><code> s = buf;
</code></pre>
</li>
<li>
<pre><code> sprintf(buf, "\\x%02X", *q & 0377);
</code></pre>
</li>
<li>
<pre><code> while (*s) {
</code></pre>
</li>
<li>
<pre><code> str_cat_char(result, *s++, enc);
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
<li>
<pre><code> }
</code></pre>
</li>
</ul>
<p>+#define BACKESC_BUFSIZE 5</p>
<ul>
<li>
<pre><code> char buf[BACKESC_BUFSIZE];
</code></pre>
</li>
<li>
<pre><code> sprintf(buf, "\\x%02X", *q & 0377);
</code></pre>
</li>
<li>
<pre><code> str_buf_cat(result, buf, BACKESC_BUFSIZE - 1);
</code></pre>
</li>
</ul>
<p>+#undef BACKESC_BUFSIZE</p>
<ul>
<li>
<pre><code> }
</code></pre>
}<br>
}</li>
</ul>
<ul>
<li>str_cat_char(result, '"', enc);</li>
</ul>
<ul>
<li>
<p>str_buf_cat2(result, """);</p>
<p>OBJ_INFECT(result, str);<br>
return result;<br>
=end</p>
</li>
</ul>
Ruby master - Feature #2093 (Closed): String#stripの対象は\sか[:space:]か
https://redmine.ruby-lang.org/issues/2093
2009-09-13T02:24:49Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
現在、String#strip は rb_enc_isspace を使っています。<br>
つまり、[:space:] にマッチするものを落とすため、<br>
例えばいわゆる全角空白等も切り落とす対象になっています。</p>
<p>しかし、他の Ruby core API は ASCII を意識した動きをすることが多く、<br>
strip はちょっと予想を裏切る動作になっています。</p>
<p>なんとなくただの修正漏れのように感じるのですがどうでしょう?<br>
=end</p>
Ruby master - Feature #2032 (Closed): Change the license to "GPLv2+ or Ruby's original".
https://redmine.ruby-lang.org/issues/2032
2009-09-02T17:44:13Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
This is moved ticked from ruby-dev.<br>
Original post and ticket is <a class="issue tracker-2 status-5 priority-4 priority-default closed" title="Feature: Change the license to "GPLv2+ or Ruby's original". (Closed)" href="https://redmine.ruby-lang.org/issues/2000">#2000</a> in English.</p>
<p>----- Original Post -----</p>
<p>Hello.</p>
<p>Recently readline 6.0 was released and its license was changed from<br>
GPLv2+ (GPL version 2 and any later) to GPLv3+ [1][2]<br>
Unfortunately Ruby's license is still under GPLv2 and Ruby's original license [3],<br>
which is incompatible with GPLv3 [4]. So unless Ruby's license is changed<br>
to "GPLv2+ or Ruby's original license" or so , Ruby's readline module cannot be shipped<br>
any more. Note that "Ruby's original license" is regarded as incompatible with<br>
GPL [5].</p>
<p>So please change the Ruby's license to GPLv3 (and GPLv2) compat.</p>
<p>[1] <a href="http://tiswww.case.edu/php/chet/readline/rltop.html" class="external">http://tiswww.case.edu/php/chet/readline/rltop.html</a><br>
[2] <a href="https://www.redhat.com/archives/fedora-devel-list/2009-July/msg00192.html" class="external">https://www.redhat.com/archives/fedora-devel-list/2009-July/msg00192.html</a><br>
[3] <a href="http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/COPYING?view=co" class="external">http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/COPYING?view=co</a><br>
[4] <a href="https://fedoraproject.org/wiki/Licensing#GPL_Compatibility_Matrix" class="external">https://fedoraproject.org/wiki/Licensing#GPL_Compatibility_Matrix</a><br>
[5] <a href="https://fedoraproject.org/wiki/Licensing" class="external">https://fedoraproject.org/wiki/Licensing</a><br>
=end</p>
Ruby master - Feature #2017 (Rejected): String#/(sep)
https://redmine.ruby-lang.org/issues/2017
2009-08-31T02:35:22Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
String#/(separator) を String#join(separator) の alias として追加しませんか?</p>
<p>以前から、Array#*(sep) との対称性から String#/(sep) の採用は求められてきました。<br>
しかし、対称性だけでは根拠が弱く、入ることなく今に至っています。</p>
<p>今回は、String#split の出現頻度を調べてみました。<br>
Rubyのソースで調べてみると、<br>
% grep split **/<em>.rb|wc -l<br>
1096<br>
% grep gsub **/</em>.rb|wc -l<br>
617<br>
% grep push **/<em>.rb|wc -l<br>
732<br>
% grep to_i **/</em>.rb|wc -l<br>
1034<br>
% grep to_s **/<em>.rb|wc -l<br>
2414<br>
% grep each **/</em>.rb|wc -l<br>
4752<br>
という結果の通り、each や to_s には負けるものの、to_i に並び、<br>
高順位が予想された gsub をも越える使用頻度を誇っています。</p>
<p>これだけの頻度ならば / を割り当てるに足と思うのですが、いかがでしょうか。<br>
もし何かに String#/ をあてるならば、String#split 以外になる可能性は低いように思います。<br>
=end</p>
Ruby master - Feature #1951 (Closed): openのBOM指定拡張
https://redmine.ruby-lang.org/issues/1951
2009-08-18T23:47:15Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>#747と#802で議論された、openのBOM指定拡張ですが、現在の仕様は、</p>
<ul>
<li>BOMを捨てる</li>
<li>BOMを見てencodingを設定する<br>
という2つの機能が混在しています。</li>
</ul>
<p>このために、たとえば「<code>UTF-8-BOM</code>」という指定でも、<br>
BOMがUTF-16LEを示していた場合には実際に返ってくるStringはUTF-16LEになってしまいます。</p>
<p>この問題に対する解決案として、</p>
<ul>
<li>UTF-*-BOM はBOMを捨てるだけ。別のencodingだった場合は例外</li>
<li>
<code>BOM|UTF-*</code>を追加、これが現在の<code>UTF-*-BOM</code>相当の動作 (BOMを見る OR <code>UTF-*</code>と指定、というイメージ)<br>
というものを考えています。</li>
</ul>
<p>皆さんはどのように思われますか?</p>
Ruby master - Feature #1949 (Closed): Warn needless escaped characters
https://redmine.ruby-lang.org/issues/1949
2009-08-18T22:25:48Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
正規表現内での不必要なエスケープに警告を出しませんか。</p>
<p>動機としては、/\uXXXX/の非互換性の話があります。</p>
<p>これは、Ruby 1.8において、不必要なエスケープであった/\u/が、<br>
Ruby 1.9においては\uXXXXという構文が追加されたがために、<br>
エラーが出たり意味が変わってしまったりしたという話でした。</p>
<p>このような不幸な出来事は、/\u/と書いたら警告を出すようにしていたら、<br>
未然に防ぐことができたり、被害を減らすことができたかもしれません。</p>
<p>将来また別のエスケープ記法が追加される事は十分あり得る話だと思います。<br>
その際に同じ不幸を繰り返さないように、警告を出すようにしませんか。</p>
<p>具体的には、文字クラス外の<br>
g, i, j, k, l, m, o, p, q, y, E, F, H, I, J, K, L, N, O, P, Q, R, T, U, V, X, Y<br>
と、文字クラス内の<br>
g, i, j, k, l, m, o, p, q, y, z, A, B, E, F, G, H, I, J, K, L, N, O, P, Q, R, T, U, V, X, Y, Z<br>
あたりになるでしょうか。</p>
<p>なお、現状では警告が出ないが、すでにエスケープ記法として用いている、<br>
/\p/あたりは議論の余地のあるところかもしれません。<br>
=end</p>
Backport191 - Backport #1938 (Closed): FreeBSDでmakeに失敗する
https://redmine.ruby-lang.org/issues/1938
2009-08-14T16:56:45Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
common.mkに$(YACC) -d $(YFLAGS) -o y.tab.c $(<:=/)という行がありまして、<br>
これはLinuxとかWindowsでは動くんですが、BSD makeだとバックスラッシュがエスケープだと解釈され、<br>
「Unclosed substitution for < (= missing)」<br>
というエラーが出ます。</p>
<p>この問題はr22964で対処されています。<br>
=end</p>
Ruby master - Bug #1433 (Closed): test_sprintf_p fails
https://redmine.ruby-lang.org/issues/1433
2009-05-05T09:52:09Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
test_sprintf_p(TestM17N) [/home/naruse/git/ruby/test/ruby/test_m17n.rb:773]:<br>
<#<a href="Encoding:US-ASCII" class="external">Encoding:US-ASCII</a>> expected but was<br>
<#<a href="Encoding:ASCII-8BIT" class="external">Encoding:ASCII-8BIT</a>>.</p>
<p>1.9.1のパッチリリースのblocking bugである本件ですが、<br>
これはテスト側を動作に合わせるべきだと思っています。</p>
<p>この部分を最後に修正したのはうささんのようですが、どう思われますか。<br>
あと他の方も。<br>
=end</p>
Ruby master - Bug #941 (Closed): ignores SIGQUIT on FreeBSD 7.1
https://redmine.ruby-lang.org/issues/941
2008-12-29T11:14:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
FreeBSD 7.1-PRERELEASE amd64 にて、SIGQUIT を無視してしまうようです。</p>
<ol>
<li>Failure:<br>
test_status_kill(TestProcess) [test/ruby/test_process.rb:941]:<br>
Expected ["#<Process::Status: pid 53404 SIGQUIT (signal )>",<br>
"#<Process::Status: pid 53404 SIGQUIT (signal ) (core dumped)>"].include?(*["#<Process::Status: pid 53404 exit 0>"]) to return true.</li>
</ol>
<p>書き換えると以下の通り</p>
<p>% cat wait.rb<br>
sleep 10;<br>
print "finished\n";<br>
% ruby19 -e'pid=spawn("ruby19","wait.rb"); Thread.new{sleep 3; Process.kill(:SIGQUIT, pid) }; Process.wait(pid);;p $?'<br>
finished<br>
#<Process::Status: pid 53220 exit 0></p>
<p>なお、spawn("perl" に書き換えるとちゃんと殺せます<br>
=end</p>
Ruby master - Bug #624 (Closed): ArgumentError on "%c" % 0x80
https://redmine.ruby-lang.org/issues/624
2008-10-09T19:59:42Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
成瀬です。</p>
<p>Tanaka Akira wrote:</p>
<blockquote>
<p>In article <a href="mailto:874p3mqm1s.fsf@fsij.org" class="email">874p3mqm1s.fsf@fsij.org</a>,<br>
Tanaka Akira <a href="mailto:akr@fsij.org" class="email">akr@fsij.org</a> writes:</p>
<blockquote>
<p>"%c" % 0x80 が例外になります。</p>
</blockquote>
<p>うぅむ。ロケールに依存しているようですね。</p>
<p>EUC-JP ではおきます。</p>
<p>% LANG=ja_JP.EUC-JP ./ruby -ve '"%c" % 0x80'<br>
ruby 1.9.0 (2008-10-09 revision 19725) [i686-linux]<br>
-e:1: warning: useless use of % in void context<br>
-e:1:in <code>%': negative string size (or size too big) (ArgumentError) from -e:1:in </code>'<br>
zsh: exit 1 LANG=ja_JP.EUC-JP ./ruby -ve '"%c" % 0x80'</p>
<p>UTF-8 ではおきません。</p>
<p>% LANG=ja_JP.UTF-8 ./ruby -ve '"%c" % 0x80'<br>
ruby 1.9.0 (2008-10-09 revision 19725) [i686-linux]<br>
-e:1: warning: useless use of % in void context</p>
<p>7bit な文字列のエンコーディングを US-ASCII にしなくなったこ<br>
との影響ともいえるかなぁ。</p>
</blockquote>
<p>printf("%c", codepoint) という解釈になりますので、<br>
EUC-JP で例外というのは妥当な動作だと思います。</p>
<p>例外の内容が誤っている気はしますね。</p>
<p>--<br>
NARUSE, Yui <a href="mailto:naruse@airemix.jp" class="email">naruse@airemix.jp</a><br>
=end</p>
Ruby master - Bug #527 (Closed): test_execopts_pgroup(TestProcess) fails on NetBSD
https://redmine.ruby-lang.org/issues/527
2008-08-31T15:54:10Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
以下のテストが NetBSD 4.99.72 i386 にて失敗します。</p>
<p>test_execopts_pgroup(TestProcess) [/home/naruse/src/ruby-trunk/test/ruby/test_process.rb:141]:<br>
<a href="Errno::EPERM" class="external">Errno::EPERM</a> exception expected but none was thrown.<br>
=end</p>
Ruby master - Bug #525 (Closed): test_convert(TestBignum) on NETBSD
https://redmine.ruby-lang.org/issues/525
2008-08-31T14:42:12Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
NetBSD 4.99.72 i386 にて、test/ruby/test_bignum.rb が以下のとおり失敗します。</p>
<h2>test_convert(TestBignum) [/home/naruse/src/ruby-trunk/test/ruby/test_bignum.rb:199]:<br>
<a href="Errno::EINVAL" class="external">Errno::EINVAL</a> exception expected but was<br>
Class: <br>
Message: <"bignum too big to convert into <code>unsigned long'"> ---Backtrace--- /home/naruse/src/ruby-trunk/test/ruby/test_bignum.rb:201:in </code>wait'<br>
/home/naruse/src/ruby-trunk/test/ruby/test_bignum.rb:201:in <code>block in test_convert' /home/naruse/src/ruby-trunk/test/ruby/test_bignum.rb:199:in </code>test_convert'</h2>
<p>=end</p>
Ruby master - Bug #368 (Closed): 境界における Math.atanh 等の動作
https://redmine.ruby-lang.org/issues/368
2008-07-28T02:53:11Z
naruse (Yui NARUSE)
naruse@airemix.jp
<p>=begin<br>
現在の Ruby trunk では、FreeBSD 7 において、<br>
test/ruby/test_math.rb は以下のように失敗します。</p>
<p>y% ruby19 test/ruby/test_math.rb<br>
Loaded suite test/ruby/test_math<br>
Started<br>
......F...........FFF.....<br>
Finished in 0.036791548 seconds.</p>
<ol>
<li>
<p>Failure:<br>
test_atanh(TestMath) [test/ruby/test_math.rb:97]:<br>
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.</p>
</li>
<li>
<p>Failure:<br>
test_log(TestMath) [test/ruby/test_math.rb:113]:<br>
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.</p>
</li>
<li>
<p>Failure:<br>
test_log10(TestMath) [test/ruby/test_math.rb:129]:<br>
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.</p>
</li>
<li>
<p>Failure:<br>
test_log2(TestMath) [test/ruby/test_math.rb:121]:<br>
<[Errno::EDOM, Errno::ERANGE]> exception expected but none was thrown.</p>
</li>
</ol>
<p>26 tests, 126 assertions, 4 failures, 0 errors</p>
<p>これらの原因はいずれも境界における定義の違いに由来しているものと思わます。</p>
<p>例えば、NetBSD4 だと atanh のマニュアルには以下のようにあり、<br>
atanh(1) は NaN となります。</p>
<p>RETURN VALUES<br>
If |x|>=1, atanh(x) and atanhf(x) return +inf, -inf or NaN, and sets the<br>
global variable errno to EDOM.</p>
<p>しかし、FreeBSD7 では以下のようになっており、atanh(1) は infinity を返します。</p>
<p>RETURN VALUES<br>
The atanh() and the atanhf() functions return the inverse hyperbolic tan-<br>
gent of x if successful. If the argument has absolute value 1, a divide-<br>
by-zero exception is raised and an infinity is returned. If |x| > 1, an<br>
invalid exception is raised and an NaN is returned.</p>
<p>参考:<br>
<a href="http://www.hiroshima-cu.ac.jp/japanese/IPC/hunet99/sun/WorkShop/ja/html_docs/common-tools/numerical_comp_guide/standard.doc.html" class="external">http://www.hiroshima-cu.ac.jp/japanese/IPC/hunet99/sun/WorkShop/ja/html_docs/common-tools/numerical_comp_guide/standard.doc.html</a><br>
=end</p>