JRuby

using activerecord 'to_xml' method crashes JRuby (and debugger)

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Critical Critical
  • Resolution: Fixed
  • Affects Version/s: JRuby 1.2
  • Fix Version/s: JRuby 1.2
  • Component/s: Core Classes/Modules
  • Labels:
    None
  • Environment:
    MacOS 10.5.6, JRuby trunk r8497, activerecord 2.2.2 and trunk
  • Testcase included:
    yes
  • Number of attachments :
    1

Description

Using an activerecord 'to_xml' method on an AR instance crashes JRuby (and debugger).

The JRuby regression happened in a large commit about callbacks on Dec 18:

svn rev:8398

"Grr...I suppose I should have checked this before, but Mongrel still uses CallbackFactory. We need to get them off it so we can delete it some day. Damn you, crufty old dependencies!"

My tests are being run with these gems:

activerecord (2.2.2)
activerecord-jdbc-adapter (0.9)
activerecord-jdbcmysql-adapter (0.9)

Here's the test code:

filename: ar_to_xml.rb

Unable to find source-code formatter for language: name. Available languages are: javascript, sql, xhtml, actionscript, none, html, xml, java
require 'rubygems'
require 'activerecord'

# create a db named 'my_active_record_test'
# GRANT ALL PRIVILEGES ON my_activerecord_test.* to 'rails'@'localhost';

@logger = Logger.new $stderr
ActiveRecord::Base.logger = @logger
ActiveRecord::Base.colorize_logging = false

pool = ActiveRecord::Base.establish_connection(
  :adapter  => RUBY_PLATFORM =~ /java/ ? 'jdbcmysql' : 'mysql',
  :username => 'rails',
  :encoding => 'utf8',
  :database => 'my_activerecord_test'
)

ActiveRecord::Schema.define do
  drop_table :posts if pool.connection.table_exists?(:posts)
  create_table :posts do |t|
    t.string :subject
    t.text :body
  end
end

class Post < ActiveRecord::Base; end

p = Post.create(:subject => 'first post', :body => 'this is the body')
puts p.to_xml

This works fine in MRI. Here's the result in jruby svn r8497

$ jruby ar_to_xml.rb
SQL (1.4ms)  SET SQL_AUTO_IS_NULL=0
-- drop_table(:posts)
SQL (1.6ms)  DROP TABLE `posts`
   -> 0.0025s
   -> 0 rows
-- create_table(:posts)
SQL (25.9ms)  CREATE TABLE `posts` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `subject` varchar(255), `body` text) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_bin
   -> 0.0314s
   -> 0 rows
SQL (2.1ms)  INSERT INTO `posts` (`subject`, `body`) VALUES('first post', 'this is the body')
Entities$PrimitiveEntityMap:471:in `<init>': java.lang.NoClassDefFoundError: org/jruby/util/collections/IntHashMap
	from Entities$LookupEntityMap:552:in `<init>'
	from Entities:754:in `<init>'
	from Entities:402:in `<clinit>'
	from FastXsService:28:in `fast_xs'
	from FastXsServiceCallback$fast_xs_FS0:-1:in `call'
	from org.jruby.runtime.callback.FastInvocationCallback:55:in `execute'
	from org.jruby.internal.runtime.methods.FullFunctionCallbackMethod:69:in `call'
	from org.jruby.internal.runtime.methods.DynamicMethod:226:in `call'
	from org.jruby.internal.runtime.methods.DynamicMethod:203:in `call'
	from org.jruby.internal.runtime.methods.AliasMethod:60:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:253:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:72:in `call'
	from org.jruby.ast.CallNoArgNode:61:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:246:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:273:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:112:in `call'
	from org.jruby.ast.FCallOneArgNode:36:in `interpret'
	from org.jruby.ast.CallTwoArgNode:59:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:246:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:273:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:112:in `call'
	from org.jruby.ast.FCallOneArgNode:36:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.CaseNode:108:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:246:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:273:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:112:in `call'
	from org.jruby.ast.FCallOneArgNode:36:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.EvStrNode:82:in `interpret'
	from org.jruby.ast.DStrNode:82:in `appendToString'
	from org.jruby.ast.DStrNode:72:in `buildDynamicString'
	from org.jruby.ast.DStrNode:64:in `interpret'
	from org.jruby.ast.CallOneArgNode:57:in `interpret'
	from org.jruby.ast.IfNode:108:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.runtime.InterpretedBlock:202:in `evalBlockBody'
	from org.jruby.runtime.InterpretedBlock:153:in `yield'
	from org.jruby.runtime.Block:120:in `yield'
	from org.jruby.RubyArray:1533:in `each'
	from org.jruby.RubyArray$i_method_0_0$RUBYFRAMEDINVOKER$each:-1:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:263:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:81:in `callBlock'
	from org.jruby.runtime.callsite.CachingCallSite:86:in `call'
	from org.jruby.ast.CallNoArgBlockNode:63:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:288:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:293:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:152:in `call'
	from org.jruby.ast.FCallTwoArgNode:38:in `interpret'
	from org.jruby.ast.IfNode:108:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:183:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:243:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:32:in `call'
	from org.jruby.ast.FCallManyArgsNode:60:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:204:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:253:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:72:in `call'
	from org.jruby.ast.CallNoArgNode:61:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.ast.IfNode:110:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.ast.BeginNode:79:in `interpret'
	from org.jruby.ast.InstAsgnNode:87:in `interpret'
	from org.jruby.ast.OpAsgnOrNode:101:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:204:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:253:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:72:in `call'
	from org.jruby.ast.VCallNode:81:in `interpret'
	from org.jruby.ast.CallSpecialArgBlockNode:52:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:225:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:263:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:81:in `callBlock'
	from org.jruby.runtime.callsite.CachingCallSite:86:in `call'
	from org.jruby.ast.FCallNoArgBlockPassNode:26:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:204:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:253:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:72:in `call'
	from org.jruby.ast.CallNoArgNode:61:in `interpret'
	from org.jruby.ast.IfNode:110:in `interpret'
	from org.jruby.ast.NewlineNode:100:in `interpret'
	from org.jruby.ast.BlockNode:67:in `interpret'
	from org.jruby.internal.runtime.methods.DefaultMethod:156:in `interpretedCall'
	from org.jruby.internal.runtime.methods.DefaultMethod:133:in `call'
	from org.jruby.internal.runtime.methods.DefaultMethod:204:in `call'
	from org.jruby.runtime.callsite.CachingCallSite:253:in `cacheAndCall'
	from org.jruby.runtime.callsite.CachingCallSite:72:in `call'
	from ar_to_xml:31:in `__file__'
	from ar_to_xml:-1:in `load'
	from org.jruby.Ruby:573:in `runScript'
	from org.jruby.Ruby:476:in `runNormally'
	from org.jruby.Ruby:350:in `runFromMain'
	from org.jruby.Main:214:in `run'
	from org.jruby.Main:100:in `run'
	from org.jruby.Main:84:in `main'

The crash happens in when executing line 154 of activerecord's xml_serializer.rb

starting at line 153

def to_xml(options = {}, &block)
  serializer = XmlSerializer.new(self, options)
  block_given? ? serializer.to_s(&block) : serializer.to_s
end

The debugger actually ends up displaying line 7 of activerecord's serialization.rb

def initialize(record, options = {})
  @record, @options = record, options.dup
end

If you have the latest ruby-debug gems you can run this test from the shell and attach a remote debugger from a version 7 instance of NetBeans.

see: http://blogs.sun.com/martink/entry/remote_debugging_debug_whatever_ruby

jruby --debug -S rdebug-ide -p 7000 --stop -- ar_to_xml.rb

The debugger exits with this statement on the console:
Exception in DebugThread loop: undefined method `[]' for nil:NilClass

I have these versions of ruby-debugger installed:

ruby-debug (0.10.3)
ruby-debug-base (0.10.3.1)
ruby-debug-ide (0.4.3)

Activity

Hide
Charles Oliver Nutter added a comment -

Well I suppose I should have expected this...it looks like something outside of JRuby is using IntHashMap. I can reinstate the class, but it's been deprecated for quite a while. It's a serious nuisance that it's being used outside of JRuby, but I don't want to break AR. So I will file a separate bug to get AR to stop using it (or to annex it).

Patch attached to reinstate IntHashMap.

Show
Charles Oliver Nutter added a comment - Well I suppose I should have expected this...it looks like something outside of JRuby is using IntHashMap. I can reinstate the class, but it's been deprecated for quite a while. It's a serious nuisance that it's being used outside of JRuby, but I don't want to break AR. So I will file a separate bug to get AR to stop using it (or to annex it). Patch attached to reinstate IntHashMap.
Hide
Charles Oliver Nutter added a comment -

Fix applied in r8499. Also filed JRUBY-3272 to have AR stop using IntHashMap.

Show
Charles Oliver Nutter added a comment - Fix applied in r8499. Also filed JRUBY-3272 to have AR stop using IntHashMap.

People

Vote (0)
Watch (0)

Dates

  • Created:
    Updated:
    Resolved: