e$BF|K%3%s%H%m!<%k%7%9%F%`e(B(e$B3te(B)e$B$N6a1J$H?=$7$^$9!#e(B
e$B$h$m$7$/$*$M$,$$$7$^$9!#e(B
e$B$h$&$d$/:F8=$5$;$k%9%/%j%W%H$r:n$l$^$7$?!#e(B
e$B>/$J$/$H$b<j85$N4D6-$G$O3N<B$K:F8=$G$-$F$$$k$h$&$G$9!#e(B
e$B860x$bGD0.$G$-$?$H;W$$$^$9!#e(B
e$B$?$@$7:F8=$5$;$k$3$H$,$G$-$k$N$O!Ve(Bfree()e$B$7$?%a%b%jFbMF$r;2>H$9$k!W$3$H$^$G$G!"e(B
2e$B=Ee(B free()
e$B$,5/$-$k$+$I$&$+$O!“e(Bfree()e$B$7$?%a%b%j$r;2>H$7$?7k2L$K0MB8$7$F$$$k0Ye(B
e$B3N<B$K%”%!<%H$5$;$k$3$H$O$G$-$^$;$s!#e(B
e$B0J2<%l%]!<%H$G$9!#e(B
e$B$^$::F8=$5$;$k%9%/%j%W%H$rE=$j$^$9!#e(B
=========== e$B:F8=%9%/%j%W%He(B(duplicate_free.rb) ===========
require “thread”
(A) for tuning sweep order.
$gcflag = false
def gc_once
unless $gcflag
GC.start
$gcflag = true
end
end
def m1
q = Queue.new
dummy = Array.new(100) do [] end
(class << q; self; end).module_eval do
define_method(:push) do |item|
puts “push(#{item.inspect})”
super(item)
end
end
dummy = nil
gc_once
m2(q)
end
def m2(q)
thr = Thread.new do
2.times do
q.push :tok
sleep 0.1
end
end
q.pop
q.pop
thr.join
nil
end
call twice for sweep original SCOPE…
m1()
m1()
GC.start
=========== duplicate_free.rb e$B$3$3$^$Ge(B ===========
valgrind e$B$G5/F0$9$k$H!"e(Bfree()
e$B$7$?%a%b%j$rFI$b$&$H$7$F$$$k$3$H$,3NG’$G$-$^$9!#e(B
e$B>/$7%9%/%j%W%H$rJQ$($?$@$1$G5/$-$J$+$C$?$j$9$k$N$G!"e(B
e$BB>$N4D6-$G$b:F8=$9$k$+IT0B$G$9$,e(B…
$ valgrind ruby-1.8.6-preview2 duplicate_free.rb
--------------- snip -----------------
==17496== Invalid read of size 4
==17496== at 0x8073D1B: obj_free (gc.c:1256)
==17496== by 0x80736F0: gc_sweep (gc.c:1085)
==17496== by 0x8073FBF: garbage_collect (gc.c:1416)
==17496== by 0x8073FCC: rb_gc (gc.c:1422)
==17496== by 0x8073FDE: rb_gc_start (gc.c:1439)
==17496== by 0x805F5D6: call_cfunc (eval.c:5653)
==17496== by 0x805EB2A: rb_call0 (eval.c:5806)
==17496== by 0x80600DC: rb_call (eval.c:6053)
==17496== by 0x8058F1B: rb_eval (eval.c:3438)
==17496== by 0x80543CA: eval_node (eval.c:1423)
==17496== by 0x805491F: ruby_exec_internal (eval.c:1599)
==17496== by 0x8054963: ruby_exec (eval.c:1619)
==17496== Address 0x40D9FC0 is 0 bytes inside a block of size 20 free’d
==17496== at 0x400501A: free (vg_replace_malloc.c:233)
==17496== by 0x8073D72: obj_free (gc.c:1259)
==17496== by 0x80736F0: gc_sweep (gc.c:1085)
==17496== by 0x8073FBF: garbage_collect (gc.c:1416)
==17496== by 0x8073FCC: rb_gc (gc.c:1422)
==17496== by 0x8073FDE: rb_gc_start (gc.c:1439)
==17496== by 0x805F5D6: call_cfunc (eval.c:5653)
==17496== by 0x805EB2A: rb_call0 (eval.c:5806)
==17496== by 0x80600DC: rb_call (eval.c:6053)
==17496== by 0x8058F1B: rb_eval (eval.c:3438)
==17496== by 0x80543CA: eval_node (eval.c:1423)
==17496== by 0x805491F: ruby_exec_internal (eval.c:1599)
e$B$3$l$,H/@8$9$k>r7o$O$+$J$j9~$_$$$C$F$^$7$Fe(B
- define_method e$B$G%a%=%C%I$rDj5Ae(B
-
-
e$B$GDj5A$7$?%a%=%C%I$r8F$S=P$7Cf$K!"%9%l%C%I$N%3%s%F%-%9%H%9%$%C%AH/@8e(B
3) 1) e$B$NDj5A;~$Ne(B struct SCOPE
e$B$H!"e(B2)e$B$G%a%=%C%I8F$S=P$7$7$?;~$K!“e(B
eval.c:8551(1.8.6-preview2) e$B$”$?$j$G@8@.$5$l$ke(B struct SCOPE
e$B$,F1;~$Ke(B
GC e$BBP>]$H$J$k!#e(B
4) e$B$7$+$b%*%j%8%J%k$NJ}$Ne(B struct SCOPE e$B$,@h$Ke(B obj_free()
e$B$,8F$P$l$k!#e(B
e$B$H$$$&$H$3$m$@$H;W$$$^$9!#e(B
e$B:F8=%9%/%j%W%H$Ne(B gc_once e$B$NB8:_$H$+!"e(Bm1
e$B$re(B2e$BEY8F$s$G$$$k$N$O!"e(B3),4) e$B$N>r7o$re(B
e$BK~$?$9$?$aI,MW$J$h$&$@$C$?$+$i$G$9!#e(B
e$B%3%T!<$5$l$?e(B struct SCOPE e$B$Ne(B flags e$B$,e(B 2) e$B$K$h$je(B
SCOPE_DONT_RECYCLE(4)e$B$,e(B
e$BIU$1$i$l$?8e$Ge(B scope_dup() e$B$5$l$J$$$^$^e(B obj_free()
e$B$KMh$k$H!“e(B
e$B%%j%8%J%k$HF1$8e(B local_vars[-1] e$B$r8+$F$7$^$$$^$9!#e(B
e$BF1$82s$Ne(B GC e$B$G%%j%8%J%k$Ne(B SCOPE e$B$be(B GC
e$BBP>]$G!”$+$D@h$Ke(B sweep e$B$5$l$Fe(B
e$B$$$?>l9g!"4{$K$=$NNN0h$Oe(B free() e$B$5$l$F$7$^$C$F$$$^$9!#e(B
e$B$5$i$K$3$3$Ge(B free() e$B$5$l$?%a%b%jNN0h$N@hF,e(B4e$B%P%$%H$,e(B 0
e$B$K$J$C$Fe(B
e$B$$$k;~$K$+$.$j!"e(Blocal_tbl(e$B$3$l$b%*%j%8%J%k$Ne(B SCOPE e$B$Ne(B
sweep e$B;~$Ke(B free()e$B:Q$_e(B)e$B$re(B
free() e$B$7$F$7$^$C$Fe(B 2e$B=Ee(B free() e$B$H$J$j$^$9!#e(B
e$B0l1~@[:n$N%Q%C%A$bE=$j$^$9!#e(B
valgrind e$B$N<B9T$G!Ve(BAddress *** is 0 bytes inside a block of size
20 free’de$B!We(B
e$B$N%a%C%;!<%8$,=P$J$/$J$k$3$H$H!"e(Bmake check
e$B$,DL$k$3$@$1$O3NG’CW$7$^$7$?!#e(B
e$B$b$&$9$0e(B 1.8.6
e$B$,%j%j!<%9$5$l$k$3$H$H;W$$$^$9$,!"$G$-$l$P$3$N7o$X$NBP:v$be(B
e$BF~$C$F$$$?$i4r$7$$$G$9!#e(B
e$B$H$$$&$N$b!":#2s$N%5!<%P$O>-Mh$*5R$5$s$K$bDs6!$9$k$+$b$7$l$:!"e(B
e$B5R@h4D6-$G$O$?$$$F$$3F<o%G%#%9%H%j%S%e!<%7%g%s$N%Q%C%1!<%8$re(B
e$B;H$&$3$H$K$J$k$H;W$$$^$9$N$G!“e(Bruby-1.8.6 e$B0J9_!”$H$$$&$h$&$Je(B
e$B;XDj$,$G$-$k$[$&$,3Z$G$9$N$G!#e(B
e$B$h$m$7$/$48!F$$/$@$5$$!#e(B
e$B0J2<e(B ruby-1.8.6-preview2 e$B$KBP$9$k%Q%C%A$G$9!#e(B
— src/ruby-1.8.6-preview2/env.h 2007-02-13 08:01:19.000000000
+0900
+++ src/ruby-1.8.6-preview2-modify/env.h 2007-03-01
11:19:50.000000000 +0900
@@ -43,6 +43,7 @@
#define SCOPE_MALLOC 1
#define SCOPE_NOSTACK 2
#define SCOPE_DONT_RECYCLE 4
+#define SCOPE_CLONE 8
extern int ruby_in_eval;
— src/ruby-1.8.6-preview2/parse.y 2007-02-20 15:53:16.000000000
+0900
+++ src/ruby-1.8.6-preview2-modify/parse.y 2007-03-01
11:26:35.000000000 +0900
@@ -5725,7 +5725,8 @@
rb_mem_clear(ruby_scope->local_vars+i, len-i);
}
if (ruby_scope->local_tbl && ruby_scope->local_vars[-1] ==
0) {
— src/ruby-1.8.6-preview2/eval.c 2007-02-19 18:28:43.000000000
+0900
+++ src/ruby-1.8.6-preview2-modify/eval.c 2007-03-01
10:39:08.000000000 +0900
@@ -8547,11 +8547,12 @@
if (klass) _block.frame.last_class = klass;
_block.frame.argc = RARRAY(tmp)->len;
_block.frame.flags = ruby_frame->flags;
- if (_block.frame.argc && (ruby_frame->flags & FRAME_DMETH)) {
— src/ruby-1.8.6-preview2/gc.c 2007-02-13 08:01:19.000000000
+0900
+++ src/ruby-1.8.6-preview2-modify/gc.c 2007-03-01 11:23:48.000000000
+0900
@@ -1253,7 +1253,7 @@
if (RANY(obj)->as.scope.local_vars &&
RANY(obj)->as.scope.flags != SCOPE_ALLOCA) {
VALUE *vars = RANY(obj)->as.scope.local_vars-1;
-
RUBY_CRITICAL(free(RANY(obj)->as.scope.local_tbl));
if (RANY(obj)->as.scope.flags & SCOPE_MALLOC)
RUBY_CRITICAL(free(vars));