[#3479] Missing .document files for ext/ libraries — Brian Candler <B.Candler@...>

The ri documentation for zlib, strscan and iconv doesn't get built by 'make

12 messages 2004/10/06

[#3492] Re: ANN: Free-form-operators patch — Markus <markus@...>

> In message "Re: ANN: Free-form-operators patch"

15 messages 2004/10/11
[#3493] Re: ANN: Free-form-operators patch — Yukihiro Matsumoto <matz@...> 2004/10/11

Hi,

[#3495] Re: ANN: Free-form-operators patch — Markus <markus@...> 2004/10/12

On Mon, 2004-10-11 at 16:16, Yukihiro Matsumoto wrote:

[#3561] 1.8.2 - what can we do to help? — Dave Thomas <dave@...>

Folks:

23 messages 2004/10/26
[#3562] Re: 1.8.2 - what can we do to help? — Yukihiro Matsumoto <matz@...> 2004/10/27

Hi,

[BUG] segfault in ruby-1.8.2p2

From: Brian Candler <B.Candler@...>
Date: 2004-10-15 15:20:29 UTC
List: ruby-core #3523
I can reliably get ruby-1.8.2p2 to segfault on my system, which is:

$ uname -a
FreeBSD vaio.linnet.org 4.10-STABLE FreeBSD 4.10-STABLE #0: Sun Sep 26 17:08:21 BST 2004     root@localhost:/usr/obj/usr/src/sys/VAIO  i386
$ ruby -v
ruby 1.8.2 (2004-07-29) [i386-freebsd4]

The steps which I use to replicate this are as follows. Put the attached
four Ruby scripts into the current directory.

$ ruby test.rb &
[1] 72319
$ ruby breakpoint-client.rb
Executing break point "Person#initialize" at test.rb:7 in `initialize'
irb(#<DRb::DRbUnknown:0x811073c>):001:0> exit
Executing break point "Person#name" at test.rb:13 in `name'
irb(#<DRb::DRbUnknown:0x82e93fc>):001:0> name

At this point, the system hangs. Now press Ctrl-C

^CIRB::Abort: abort then interrupt!!
<< There is a 3-second delay>>
... long backtrace snipped ...
        from /usr/local/lib/ruby/1.8/drb/drb.rb:1324:in `run'
        from /usr/local/lib/ruby/1.8/drb/drb.rb:1249:in `initialize'
        from /usr/local/lib/ruby/1.8/drb/drb.rb:1505:in `new'
        from /usr/local/lib/ruby/1.8/drb/drb.rb:1505:in `start_service'
        from breakpoint-client.rb:16irb(#<DRb::DRbUnknown:0x82dc954>):002:0> 

Now type "exit" and hit Enter. I get:

Name: Random Person
./breakpoint.rb:148: [BUG] Segmentation fault
ruby 1.8.2 (2004-07-29) [i386-freebsd4]

No connection to breakpoint service at druby://localhost:42531:
  (connection closed)
  Reconnecting in 10 seconds...

At this point, I try to get out using Ctrl-C, but it doesn't work, so I use
Ctrl-Z to suspend, and then kill %2 to kill it.

^Z[1]   Abort trap              (core dumped) ruby test.rb

[2]+  Stopped                 ruby breakpoint-client.rb
$ kill %2
[2]+  Terminated              ruby breakpoint-client.rb
$ ls -l ruby.core
-rw-------  1 brian  brian  2744320 Oct 15 16:11 ruby.core
$ gdb -c ruby.core ruby
GNU gdb 4.18 (FreeBSD)
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-unknown-freebsd"...
(no debugging symbols found)...
Core was generated by `ruby'.
Program terminated with signal 6, Abort trap.
Reading symbols from /usr/local/lib/libruby18.so.18...
(no debugging symbols found)...done.
Reading symbols from /usr/lib/libcrypt.so.2...(no debugging symbols found)...
done.
Reading symbols from /usr/lib/libm.so.2...(no debugging symbols found)...done.
Reading symbols from /usr/lib/libc.so.4...(no debugging symbols found)...done.
Reading symbols from /usr/local/lib/ruby/1.8/i386-freebsd4/readline.so...
(no debugging symbols found)...done.
Reading symbols from /usr/lib/libreadline.so.4...
(no debugging symbols found)...done.
Reading symbols from /usr/lib/libncurses.so.5...(no debugging symbols found)...
done.
Reading symbols from /usr/local/lib/ruby/1.8/i386-freebsd4/socket.so...
(no debugging symbols found)...done.
Reading symbols from /usr/local/lib/ruby/1.8/i386-freebsd4/fcntl.so...
(no debugging symbols found)...done.
Reading symbols from /usr/libexec/ld-elf.so.1...(no debugging symbols found)...
done.
#0  0x28190084 in kill () from /usr/lib/libc.so.4
(gdb) bt
#0  0x28190084 in kill () from /usr/lib/libc.so.4
#1  0x281d197a in abort () from /usr/lib/libc.so.4
#2  0x280827d1 in rb_bug () from /usr/local/lib/libruby18.so.18
#3  0x280e6e82 in sigsegv () from /usr/local/lib/libruby18.so.18
#4  0xbfbfffac in ?? ()
#5  0x2809127f in eval () from /usr/local/lib/libruby18.so.18
#6  0x2809166e in rb_f_eval () from /usr/local/lib/libruby18.so.18
#7  0x2808fb22 in rb_call0 () from /usr/local/lib/libruby18.so.18
#8  0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#9  0x2808abd4 in rb_eval () from /usr/local/lib/libruby18.so.18
#10 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#11 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#12 0x2808abd4 in rb_eval () from /usr/local/lib/libruby18.so.18
#13 0x2808b54e in rb_eval () from /usr/local/lib/libruby18.so.18
#14 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#15 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#16 0x28090778 in rb_f_send () from /usr/local/lib/libruby18.so.18
#17 0x2808fb22 in rb_call0 () from /usr/local/lib/libruby18.so.18
#18 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#19 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#20 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#21 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#22 0x2808ac4c in rb_eval () from /usr/local/lib/libruby18.so.18
#23 0x2808b60e in rb_eval () from /usr/local/lib/libruby18.so.18
#24 0x28089fd6 in rb_eval () from /usr/local/lib/libruby18.so.18
#25 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#26 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#27 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#28 0x28089de1 in rb_eval () from /usr/local/lib/libruby18.so.18
---Type <return> to continue, or q <return> to quit---
#29 0x2808b504 in rb_eval () from /usr/local/lib/libruby18.so.18
#30 0x2808a11c in rb_eval () from /usr/local/lib/libruby18.so.18
#31 0x2808dceb in rb_yield_0 () from /usr/local/lib/libruby18.so.18
#32 0x2808e11e in rb_f_loop () from /usr/local/lib/libruby18.so.18
#33 0x2808fb51 in rb_call0 () from /usr/local/lib/libruby18.so.18
#34 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#35 0x2808abd4 in rb_eval () from /usr/local/lib/libruby18.so.18
#36 0x28089a8a in rb_eval () from /usr/local/lib/libruby18.so.18
#37 0x2808dceb in rb_yield_0 () from /usr/local/lib/libruby18.so.18
#38 0x2809a129 in rb_thread_yield () from /usr/local/lib/libruby18.so.18
#39 0x28099e47 in rb_thread_start_0 () from /usr/local/lib/libruby18.so.18
#40 0x2809a252 in rb_thread_start () from /usr/local/lib/libruby18.so.18
#41 0x2808fb22 in rb_call0 () from /usr/local/lib/libruby18.so.18
#42 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#43 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#44 0x28089a8a in rb_eval () from /usr/local/lib/libruby18.so.18
#45 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#46 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#47 0x2808ac4c in rb_eval () from /usr/local/lib/libruby18.so.18
#48 0x28089666 in rb_eval () from /usr/local/lib/libruby18.so.18
#49 0x2808a11c in rb_eval () from /usr/local/lib/libruby18.so.18
#50 0x2808dceb in rb_yield_0 () from /usr/local/lib/libruby18.so.18
#51 0x2809a129 in rb_thread_yield () from /usr/local/lib/libruby18.so.18
#52 0x28099e47 in rb_thread_start_0 () from /usr/local/lib/libruby18.so.18
#53 0x2809a252 in rb_thread_start () from /usr/local/lib/libruby18.so.18
#54 0x2808fb22 in rb_call0 () from /usr/local/lib/libruby18.so.18
#55 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#56 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#57 0x28089a8a in rb_eval () from /usr/local/lib/libruby18.so.18
---Type <return> to continue, or q <return> to quit---
#58 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#59 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#60 0x2808ac4c in rb_eval () from /usr/local/lib/libruby18.so.18
#61 0x2808b60e in rb_eval () from /usr/local/lib/libruby18.so.18
#62 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#63 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#64 0x280908d5 in rb_funcall2 () from /usr/local/lib/libruby18.so.18
#65 0x2809309c in rb_obj_call_init () from /usr/local/lib/libruby18.so.18
#66 0x280b850b in rb_class_new_instance () from /usr/local/lib/libruby18.so.18
#67 0x2808fb22 in rb_call0 () from /usr/local/lib/libruby18.so.18
#68 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#69 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#70 0x2808b60e in rb_eval () from /usr/local/lib/libruby18.so.18
#71 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#72 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#73 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#74 0x2809015a in rb_call0 () from /usr/local/lib/libruby18.so.18
#75 0x280905e4 in rb_call () from /usr/local/lib/libruby18.so.18
#76 0x2808a9af in rb_eval () from /usr/local/lib/libruby18.so.18
#77 0x28086168 in eval_node () from /usr/local/lib/libruby18.so.18
#78 0x280866fe in ruby_exec () from /usr/local/lib/libruby18.so.18
#79 0x28086771 in ruby_run () from /usr/local/lib/libruby18.so.18
#80 0x80485df in main ()
#81 0x8048516 in _start ()
(gdb) q

I hope you can dig something useful out of that!

Regards,

Brian.

Attachments (4)

binding_of_caller.rb (2.55 KB, text/x-ruby)
begin
  require 'simplecc'
rescue LoadError
  def Continuation.create(*args, &block)
    cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
    result ||= args
    return *[cc, *result]
  end
end

# This method returns the binding of the method that called your
# method. It will raise an Exception when you're not inside a method.
#
# It's used like this:
#   def inc_counter(amount = 1)
#     Binding.of_caller do |binding|
#       # Create a lambda that will increase the variable 'counter'
#       # in the caller of this method when called.
#       inc = eval("lambda { |arg| counter += arg }", binding)
#       # We can refer to amount from inside this block safely.
#       inc.call(amount)
#     end
#     # No other statements can go here. Put them inside the block.
#   end
#   counter = 0
#   2.times { inc_counter }
#   counter # => 2
#
# Binding.of_caller must be the last statement in the method.
# This means that you will have to put everything you want to
# do after the call to Binding.of_caller into the block of it.
# This should be no problem however, because Ruby has closures.
# If you don't do this an Exception will be raised. Because of
# the way that Binding.of_caller is implemented it has to be
# done this way.
def Binding.of_caller(&block)
  old_critical = Thread.critical
  Thread.critical = true
  count = 0
  cc, result, error, extra_data = Continuation.create(nil, nil)
  error.call if error

  tracer = lambda do |*args|
    type, context, extra_data = args[0], args[4], args
    if type == "return"
      count += 1
      # First this method and then calling one will return --
      # the trace event of the second event gets the context
      # of the method which called the method that called this
      # method.
      if count == 2
        # It would be nice if we could restore the trace_func
        # that was set before we swapped in our own one, but
        # this is impossible without overloading set_trace_func
        # in current Ruby.
        set_trace_func(nil)
        cc.call(eval("binding", context), nil, extra_data)
      end
    elsif type != "line"
      set_trace_func(nil)
      error_msg = "Binding.of_caller used in non-method context or " +
        "trailing statements of method using it aren't in the block."
      cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
    end
  end

  unless result
    set_trace_func(tracer)
    return nil
  else
    Thread.critical = old_critical
    case block.arity
      when 1 then yield(result)
      else yield(result, extra_data)        
    end
  end
end


breakpoint-client.rb (790 Bytes, text/x-ruby)
require 'breakpoint'

if ARGV[0] == "--help" then
  puts "This tool lets you connect to a breakpoint service ",
       "which was started via Breakpoint.activate_drb.",
       "",
       "Usage: ruby #{$0} [drb uri]",
       "",
       "The drb uri defaults to druby://localhost:42531"

  exit
end

uri = ARGV[0] || 'druby://localhost:42531'

DRb.start_service

begin
  service = DRbObject.new(nil, uri)
  loop do
    begin
      service.handle_breakpoint do |(workspace, message)|
        puts message
        IRB.start(nil, nil, workspace)
      end
    rescue Breakpoint::DRbService::FinishedException
    end
  end
rescue Exception => error
  puts "No connection to breakpoint service at #{uri}:",
       "  (#{error})",
       "  Reconnecting in 10 seconds..."
  sleep 10
  retry
end

breakpoint.rb (7.39 KB, text/x-ruby)
require 'irb'
require 'binding_of_caller'
require 'drb'

module Breakpoint
  extend self

  # This will pop up an interactive ruby session at a
  # pre-defined break point in a Ruby application. In
  # this session you can examine the environment of
  # the break point.
  #
  # You can get a list of variables in the context using
  # local_variables via +local_variables+. You can then
  # examine their values by typing their names.
  #
  # You can have a look at the call stack via +caller+.
  #
  # breakpoints can also return a value. They will execute
  # a supplied block for getting a default return value.
  # A custom value can be returned from the session by doing
  # +throw(:debug_return, value)+.
  #
  # You can also give names to break points which will be
  # used in the message that is displayed upon execution 
  # of them.
  #
  # Here's a sample of how breakpoints should be placed:
  #
  #   class Person
  #     def initialize(name, age)
  #       @name, @age = name, age
  #       breakpoint("Person#initialize")
  #     end
  #
  #     attr_reader :age
  #     def name
  #       breakpoint("Person#name") { @name }
  #     end
  #   end
  #
  #   person = Person.new("Random Person", 23)
  #   puts "Name: #{person.name}"
  #
  # And here is a sample debug session:
  #
  #   Executing break point "Person#initialize" at file.rb:4 in `initialize'
  #   irb(#<Person:0x292fbe8>):001:0> local_variables
  #   => ["name", "age", "_", "__"]
  #   irb(#<Person:0x292fbe8>):002:0> [name, age]
  #   => ["Random Person", 23]
  #   irb(#<Person:0x292fbe8>):003:0> [@name, @age]
  #   => ["Random Person", 23]
  #   irb(#<Person:0x292fbe8>):004:0> self
  #   => #<Person:0x292fbe8 @age=23, @name="Random Person">
  #   irb(#<Person:0x292fbe8>):005:0> @age += 1; self
  #   => #<Person:0x292fbe8 @age=24, @name="Random Person">
  #   irb(#<Person:0x292fbe8>):006:0> exit
  #   Executing break point "Person#name" at file.rb:9 in `name'
  #   irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
  #   Name: Overriden name
  def breakpoint(id = nil, context = nil, &block)
    callstack = caller
    callstack.slice!(0, 3) if callstack.first["breakpoint"]
    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures

    message = "Executing break point " + (id ? "#{id.inspect} " : "") +
              "at #{file}:#{line}" + (method ? " in `#{method}'" : "")

    if context then
      return handle_breakpoint(context, message, &block)
    end

    Binding.of_caller do |binding_context|
      handle_breakpoint(binding_context, message, &block)
    end
  end

  def handle_breakpoint(context, message, &block) # :nodoc:
    catch(:debug_return) do |value|
      if not use_drb? then
        puts message
        IRB.start(nil, IRB::WorkSpace.new(context))
      else
        @drb_service.add_breakpoint(context, message)
      end

      block.call if block
    end
  end
  private :handle_breakpoint

  # This asserts that the block evaluates to true.
  # If it doesn't evaluate to true a breakpoint will
  # automatically be created at that execution point.
  #
  # You can disable assert checking by setting 
  # Breakpoint.optimize_asserts to true before
  # loading the breakpoint.rb library. (It will still
  # be enabled when Ruby is run via the -d argument.)
  #
  # Example:
  #   person_name = "Foobar"
  #   assert { not person_name.nil? }
  def assert(context = nil, &condition)
    return if Breakpoint.optimize_asserts and not $DEBUG
    return if yield

    callstack = caller
    callstack.slice!(0, 3) if callstack.first["assert"]
    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures

    message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}. " +
              "Executing implicit breakpoint."

    if context then
      return handle_breakpoint(context, message)
    end

    Binding.of_caller do |context|
      handle_breakpoint(context, message)
    end
  end

  # Whether asserts should be ignored if not in debug mode.
  # Debug mode can be enabled by running ruby with the -d
  # switch or by setting $DEBUG to true.
  attr_accessor :optimize_asserts
  self.optimize_asserts = false

  class DRbService
    class FinishedException < Exception; end

    include DRbUndumped

    def initialize
      @breakpoint = @result = nil
      @has_breakpoint = @is_done = false
    end

    def add_breakpoint(context, message)
      workspace = IRB::WorkSpace.new(context)
      workspace.extend(DRbUndumped)

      @breakpoint = [workspace, message]
      @has_breakpoint = true

      until @is_done; end
      @is_done = false
    end

    def handle_breakpoint(&block)
      until @has_breakpoint; end
      @has_breakpoint = false

      #begin
      yield(@breakpoint)
      #rescue FinishedException
      #end

      @is_done = true
    end
  end

  # Will run Breakpoint in DRb mode. This will spawn a server
  # that can be attached to via the [ TODO: command ] command
  # whenever a breakpoint is executed. This is useful when you
  # are debugging CGI applications or other applications where
  # you can't access debug sessions via the standard input and
  # output of your application.
  #
  # You can specify an URI where the DRb server will run at.
  # This way you can specify the port the server runs on. The
  # default URI is druby://localhost:42531.
  #
  # Please note that breakpoints will be skipped silently in
  # case the DRb server can not spawned. (This can happen if
  # the port is already used by another instance of your
  # application on CGI or another application.)
  def activate_drb(uri = 'druby://localhost:42531')
    @use_drb = true
    @drb_service = DRbService.new
    DRb.start_service(uri, @drb_service)
  end

  def use_drb?
    @use_drb == true
  end
end

module IRB
  def IRB.start(ap_path = nil, main_context = nil, workspace = nil)
    $0 = File::basename(ap_path, ".rb") if ap_path

    # suppress some warnings about redefined constants
    old_verbose, $VERBOSE = $VERBOSE, nil
    IRB.setup(ap_path)
    $VERBOSE = old_verbose

    if @CONF[:SCRIPT] then
      irb = Irb.new(main_context, @CONF[:SCRIPT])
    else
      irb = Irb.new(main_context)
    end

    if workspace then
      irb.context.workspace = workspace
    end

    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
    @CONF[:MAIN_CONTEXT] = irb.context

    trap("SIGINT") do
      irb.signal_handle
    end
    
    catch(:IRB_EXIT) do
      irb.eval_input
    end
  end

  class << self; alias :old_CurrentContext :CurrentContext; end
  def IRB.CurrentContext
    if old_CurrentContext.nil? and Breakpoint.use_drb? then
      result = Object.new
      def result.last_value; end
      return result
    else
      old_CurrentContext
    end
  end

  class Context
    alias :old_evaluate :evaluate
    def evaluate(line, line_no)
      if line.chomp == "exit" then
        exit
      else
        old_evaluate(line, line_no)
      end
    end
  end

  class WorkSpace
    alias :old_evaluate :evaluate

    def evaluate(*args)
      if Breakpoint.use_drb? then
        result = old_evaluate(*args)
        result.extend(DRbUndumped) rescue nil
        return result
      else
        old_evaluate(*args)
      end
    end
  end
end

class DRb::DRbObject
  undef :inspect
end

def breakpoint(id = nil, &block)
  Binding.of_caller do |context|
    Breakpoint.breakpoint(id, context, &block)
  end
end

def assert(&block)
  Binding.of_caller do |context|
    Breakpoint.assert(context, &block)
  end
end
test.rb (319 Bytes, text/x-ruby)
require 'breakpoint'
Breakpoint.activate_drb

class Person
  def initialize(name, age)
    @name, @age = name, age
    breakpoint("Person#initialize")
  end

  attr_reader :age
  def name
    x = 8
    breakpoint("Person#name")
    @name
  end
end

person = Person.new("Random Person", 23)
puts "Name: #{person.name}"

In This Thread

Prev Next