[Bug:1.9] replacing array during sort may make assertion fail

e$B1sF#$G$9!#e(B

e$B0J2<$N$h$&$K$9$k$He(B assert e$B$,<:GT$7$^$9!#e(B

$ ./ruby -e ‘a = [4,3,2,1]; a.sort! {|x,y| a.replace([]); x <=> y }’
ruby: array.c:1755: rb_ary_sort_bang: Assertion `(((void)
((!((!(((VALUE)(tmp) & RUBY_IMMEDIATE_MASK) || !(((VALUE)(tmp) &
~((VALUE)RUBY_Qnil)) != 0)) && (((struct RBasic*)(tmp))->flags &
RUBY_T_MASK) != RUBY_T_NODE)?(((struct
RBasic*)(tmp))->flags&((((VALUE)1)<<(12+2)))):0) || !((!(((VALUE)(tmp)
& RUBY_IMMEDIATE_MASK) || !(((VALUE)(tmp) & ~((VALUE)RUBY_Qnil)) !=
0)) && (((struct RBasic*)(tmp))->flags & RUBY_T_MASK) !=
RUBY_T_NODE)?(((struct
RBasic*)(tmp))->flags&((((VALUE)1)<<(12+1)))):0)) ? 0 : (__assert_fail
("!((!(((VALUE)(tmp) & RUBY_IMMEDIATE_MASK) || !(((VALUE)(tmp) &
~((VALUE)RUBY_Qnil)) != 0)) && (((struct RBasic*)(tmp))->flags &
RUBY_T_MASK) != RUBY_T_NODE)?(((struct
RBasic*)(tmp))->flags&((((VALUE)1)<<(12+2)))):0) || !((!(((VALUE)(tmp)
& RUBY_IMMEDIATE_MASK) || !(((VALUE)(tmp) & ~((VALUE)RUBY_Qnil)) !=
0)) && (((struct RBasic*)(tmp))->flags & RUBY_T_MASK) !=
RUBY_T_NODE)?(((struct
RBasic*)(tmp))->flags&((((VALUE)1)<<(12+1)))):0)", “array.c”, 1755,
PRETTY_FUNCTION), 0))), ((!(((VALUE)(tmp) & RUBY_IMMEDIATE_MASK)
|| !(((VALUE)(tmp) & ~((VALUE)RUBY_Qnil)) != 0)) && (((struct
RBasic*)(tmp))->flags & RUBY_T_MASK) != RUBY_T_NODE)?(((struct
RBasic*)(tmp))->flags&((((VALUE)1)<<(12+1)))):0))’ failed.
e$B%"%!<%H$7$^$7$?e(B

e$B0J2<$N=$@5$G$$$$$G$7$g$&$+!#e(B

Index: array.c

— array.c (revision 20023)
+++ array.c (working copy)
@@ -1751,14 +1751,14 @@
ruby_qsort(RARRAY_PTR(tmp), RARRAY_LEN(tmp), sizeof(VALUE),
rb_block_given_p()?sort_1:sort_2, &data);

  •    if (ARY_EMBED_P(ary) || ARY_EMBED_P(tmp)) {
    
  •    if (ARY_EMBED_P(tmp)) {
           assert(ARY_EMBED_P(tmp));
           MEMCPY(RARRAY_PTR(ary), ARY_EMBED_PTR(tmp), VALUE,
    

ARY_EMBED_LEN(tmp));
ARY_SET_LEN(ary, ARY_EMBED_LEN(tmp));
}
else {

  •        assert(!ARY_EMBED_P(ary));
           assert(!ARY_EMBED_P(tmp));
    
  •        if (ARY_EMBED_P(ary)) FL_UNSET_EMBED(ary);
           if (RARRAY_PTR(ary) != RARRAY_PTR(tmp)) {
               assert(!ARY_SHARED_P(tmp));
               if (ARY_SHARED_P(ary)) {

e$B%A%1%C%He(B #697 e$B$,99?7$5$l$^$7$?!#e(B (by Yukihiro M.)

e$B%9%F!<%?%9e(B Opene$B$+$ie(BClosede$B$KJQ99e(B

fixed by r20026

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