Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GC delete referenced object.(maybe write barrier bug.) #2525

Closed
dycoon opened this issue Aug 11, 2014 · 4 comments
Closed

GC delete referenced object.(maybe write barrier bug.) #2525

dycoon opened this issue Aug 11, 2014 · 4 comments

Comments

@dycoon
Copy link
Contributor

dycoon commented Aug 11, 2014

This code crash mruby.

proc_gc.rb

def delay_call(&block)

  p = Proc.new do
    yield
  end
  p

end

class C

  attr_accessor :v
  attr_accessor :t

  def initialize iv
    self.v = iv
  end

end

n = 3000
m = (n / 10)

a = []

n.times do |j|
  p = delay_call do
    if j % m == 0
      puts "test m #{i} #{j}"
    end
  end
  c = C.new(
    delay_call do
      p.call
    end
  )
  a[j] = c
end

n.times do |i|
  n.times do |j|
    if (i + j) % m == 0
      p = delay_call do
        if j % m == 0
          puts "test m #{i} #{j}"
        end
      end
      c = C.new(
        delay_call do
          p.call
        end
      )
      a[j] = c
    end
    a[j].t = nil
  end

  a.each do |c|
    c.t = nil
    p = c.v.call
  end

end

I guess as follows cause.

  1. c.t = nil set write barrier
  2. run gc and mark c and add to mrb->atomic_gray_list
  3. but mrb->atomic_gray_list is not used finally
  4. mark incompletely

I encountered on windows and linux.

follows is build code on windows.

VCVAR_PATH = 'C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat'
MINIRAKE = '.\minirake'

puts `git clone https://github.com/mruby/mruby.git build_tmp/mruby`
Dir.chdir 'build_tmp/mruby'
puts `ruby #{MINIRAKE}`
#puts `cmd /c "call \"#{VCVAR_PATH.gsub("\\", "\\\\")}\" x86 & ruby #{MINIRAKE.gsub("\\", "\\\\")} -v"`
Dir.chdir '../..'

puts "proc gc"
puts `build_tmp/mruby/build/host/bin/mruby proc_gc.rb`

dycoon added a commit to dycoon/mruby_dycoon that referenced this issue Aug 12, 2014
dycoon added a commit to dycoon/mruby_dycoon that referenced this issue Aug 13, 2014
This reverts commit a9d19c8.
@matz matz closed this as completed in 6c1dfc9 Aug 13, 2014
ghost pushed a commit to iij/mruby that referenced this issue Aug 14, 2014
dycoon added a commit to dycoon/mruby_dycoon that referenced this issue Aug 14, 2014
dycoon added a commit to dycoon/mruby_dycoon that referenced this issue Aug 14, 2014
This reverts commit a9d19c8.
@dycoon
Copy link
Contributor Author

dycoon commented Aug 14, 2014

I think that this problem is not resolved radically.

now reproduction codes are as follows.

def delay_call(&block)

  p = Proc.new do
    yield
  end
  p

end

class C

  attr_accessor :v
  attr_accessor :t

  def initialize iv
    self.v = iv
  end

end

n = 7187
m = (n / 121).floor

a = []

n.times do |j|
  p = delay_call do
    if j % m == 0
      puts "test init #{j}"
    end
  end
  c = C.new(
    delay_call do
      p.call
    end
  )
  a[j] = c
end

n.times do |i|
  n.times do |j|
    if (i + j) % m == 0
      p = delay_call do
        if j % m == 0
          puts "test m #{i} #{j}"
        end
      end
      c = C.new(
        delay_call do
          p.call
        end
      )
      a[j] = c
    end
    a[j].t = nil
  end

  a.each do |c|
    c.t = nil
    p = c.v.call
  end


end

change loop count(n) and overwriting interval(m).

I wish to make more efficient reproduction codes...

@dycoon
Copy link
Contributor Author

dycoon commented Aug 14, 2014

I think that following is better reproduction code.

proc_gc_ef.rb

def delay_call(&block)

  p = Proc.new do
    yield
  end
  p

end

class C

  attr_accessor :v
  attr_accessor :t

  def initialize iv
    self.v = iv
  end

end


oi = 1000

10.times do |i|
  n = i * 100 + 17

  [93, 121, 127].each do |j|
    m = j + 1

    a = []

    n.times do |j|
      p = delay_call do
        if j % oi == 0
          puts "test init #{j}"
        end
      end
      c = C.new(
        delay_call do
          p.call
        end
      )
      a[j] = c
    end

    n.times do |i|
      n.times do |j|
        if (i + j) % m == 0
          p = delay_call do
            if j % oi == 0
              puts "test m #{i} #{j}"
            end
          end
          c = C.new(
            delay_call do
              p.call
            end
          )
          a[j] = c
        end
        a[j].t = nil
      end

      a.each do |c|
        c.t = nil
        p = c.v.call
      end

    end

  end

end

puts "succeeded!"

build and test script for mingw and linux.

VCVAR_PATH = 'C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat'
MINIRAKE = '.\minirake'

puts `git clone https://github.com/mruby/mruby.git build_tmp/mruby`
puts `sh -c \"cd build_tmp/mruby; git reset --hard HEAD\"`
#puts `sh -c \"cd build_tmp/mruby; ruby minirake clean\"`
puts `sh -c \"cd build_tmp/mruby; ruby minirake\"`

puts "proc gc ef"
ret = `build_tmp/mruby/build/host/bin/mruby proc_gc_ef.rb`
succeeded ||= ret.match(/succeeded!/)
puts "#{ret}"

# before correction
puts `sh -c \"cd build_tmp/mruby; git reset --hard 2b9e5e751b4d6d1a86eb25b2a4e40f9c8d19c06c\"`
#puts `sh -c \"cd build_tmp/mruby; ruby minirake clean\"`
puts `sh -c \"cd build_tmp/mruby; ruby minirake\"`

puts "proc gc ef before correction"
ret = `build_tmp/mruby/build/host/bin/mruby proc_gc_ef.rb`
succeeded ||= ret.match(/succeeded!/)
puts "#{ret}"

if succeeded
  puts "all success."
else
  puts "some failed."
end

Bon vacation, now.
I'm not harrying.
thanks.

@dycoon
Copy link
Contributor Author

dycoon commented Aug 28, 2014

I think this problem is solved at 77b2ec3.
I sended pull request.

I think this problem happend as follows.

  1. paint env black.
  2. write white object to stack.
  3. pop call info.
  4. added white object is removed from stack.
  5. added white object is never painted gray or black.

another test pattern.
(previouse test pattern does not crash on a9d19c8)

proc_gc_ef_2.rb

def delay_call(&block)

  p = Proc.new do
    yield
  end
  p

end

class C

  attr_accessor :v
  attr_accessor :t

  def initialize iv
    self.v = iv
  end

end


oi = 1000

10.times do |i|
  n = i * 100 + 17

  [93, 121, 127].each do |j|
    m = j + 1

    a = []

    n.times do |j|
      p = nil

      c = C.new(
        delay_call do
          p.call
        end
      )
      p = delay_call do
        if j % oi == 0
          puts "test init #{j}"
        end
      end
      a[j] = c
    end

    n.times do |i|
      n.times do |j|
        if (i + j) % m == 0
          p = delay_call do
            if j % oi == 0
              puts "test m #{i} #{j}"
            end
          end
          c = C.new(
            delay_call do
              p.call
            end
          )
          a[j] = c
        end
        a[j].t = nil
      end

      a.each do |c|
        c.t = nil
        p = c.v.call
      end

    end

  end

end

if false
  [3989, 7129].each do |n|

    [93, 121, 127, 1061, 131, 2647, 431].each do |j|
      m = j

      a = []

      n.times do |j|
        p = delay_call do
          if j % oi == 0
            puts "test init #{j}"
          end
        end
        c = C.new(
          delay_call do
            p.call
          end
        )
        a[j] = c
      end

      n.times do |i|
        n.times do |j|
          if (i + j) % m == 0
            p = delay_call do
              if j % oi == 0
                puts "test m #{i} #{j}"
              end
            end
            c = C.new(
              delay_call do
                p.call
              end
            )
            a[j] = c
          end
          a[j].t = nil
        end

        a.each do |c|
          c.t = nil
          p = c.v.call
        end

      end

    end

  end
end

puts "succeeded!"

matz added a commit that referenced this issue Aug 28, 2014
add write barrier to env on pop call info poped. #2525
@matz
Copy link
Member

matz commented Aug 28, 2014

#2569 fixed this.

@matz matz closed this as completed Aug 28, 2014
matz added a commit that referenced this issue Aug 28, 2014
matz added a commit that referenced this issue Aug 28, 2014
ghost pushed a commit to iij/mruby that referenced this issue Sep 1, 2014
ghost pushed a commit to iij/mruby that referenced this issue Sep 1, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants