What appears to be a really sneaky bug related to loading assemblies (System::Action is temporarily

Intro: Using IronRuby 1.0 rc2; .NET 3.5SP1 on windows XP sp3
I have some code which is using DynamicMethod / GetILGenerator to create
statically typed methods at runtime, so I can call IUnknown-based COM
objects from IronRuby.

Here is a snippet

… piles of code which figures out what the method signature should

be
and generates it …
func_type_params = [System::Object] + someotherstuff

generate a .NET delegate to wrap the new DynamicMethod

puts “DEBUG: Action= #{System::Action.inspect}”
puts “DEBUG: Params= #{func_type_params.inspect}”
puts “DEBUG: F= #{System::Action.of(*func_type_params)}”
del_type = System::Action.of(*func_type_params).to_clr_type

This has been working reliably for some time, and still works with most
input. However, we’ve recently seen random failures. Here’s some of the
output from those Debug lines:

successful

DEBUG: Action= #<TypeGroup: System::Action, System::Action[T],
System::Action[T1, T2], System::Action[T1, T2, T3], System::Action[T1,
T2,
T3, T4]>
DEBUG: Params= [Object, Object, Object]
DEBUG: F= System::Action[Object, Object, Object]

and then the next one fails

DEBUG: Action= nil
DEBUG: Params= [Object, Fixnum, Interop::FieldID[], System::Object[]]
NoMethodError: undefined method `of’ for NilClass

As far as that tells me, System::Action has somehow been set to nil.
Note: The point at which System::Action gets nil’ed out is NOT always
the
same point.

If I run the code under iirb (copy/pasting my original script in), and
then
after the exception inspect System::Action, it reports this:

=> #<TypeGroup: System::Action, System::Action[T], System::Action[T1,
T2],
System::Action[T1, T2, T3], System::Action[T1, T2, T3, T4],
System::Action[T1, T2, T3, T4, T5], System::Action[T1, T2, T3, T4, T5,
T6],
System::Action[T1, T2, T3, T4, T5, T6,
T7], System::Action[T1, T2, T3, T4, T5, T6, T7, T8], System::Action[T1,
T2,
T3, T4, T5, T6, T7, T8, T9], System::Action[T1, T2, T3, T4, T5, T6, T7,
T8,
T9, T10], System::Action[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11],
System::Action[T1, T2, T3,
T4, T5, T6, T7, T8, T9, T10, T11, T12], System::Action[T1, T2, T3, T4,
T5,
T6, T7, T8, T9, T10, T11, T12, T13], System::Action[T1, T2, T3, T4, T5,
T6,
T7, T8, T9, T10, T11, T12, T13, T14], System::Action[T1, T2, T3, T4, T5,
T6,
T7, T8, T9, T10, T11,
T12, T13, T14, T15], System::Action[T1, T2, T3, T4, T5, T6, T7, T8, T9,
T10, T11, T12, T13, T14, T15, T16]>

As you can see, System::Action is no longer nil, but has now been given
a
bunch more overloads. These overloads come from System.CoreEx (part of
the
.NET reactive framework). Putting require ‘System.CoreEx’ at the top of
my
script to pre-load it makes this error go away.

From what I can tell, something causes the CLR to on-demand load
System.CoreEx.dll. This in turn adds more overloads to System::Action.
IronRuby appears to temporarily nil it out while loading, thus causing
the
crash.

Am I on the right track? As mentioned I think I can work around it by
preloading all the dll’s I know I’m going to need, but this doesn’t seem
to
be a reliable long-term solution.

Cheers, Orion

Could you try to write a simple repro in a .rb file that demonstrates
the issue?

Tomas

From: [email protected]
[mailto:[email protected]] On Behalf Of Orion E.
Sent: Wednesday, March 10, 2010 12:42 PM
To: [email protected]
Subject: [Ironruby-core] What appears to be a really sneaky bug related
to loading assemblies (System::Action is temporarily nil)

Intro: Using IronRuby 1.0 rc2; .NET 3.5SP1 on windows XP sp3
I have some code which is using DynamicMethod / GetILGenerator to create
statically typed methods at runtime, so I can call IUnknown-based COM
objects from IronRuby.

Here is a snippet

… piles of code which figures out what the method signature should

be and generates it …
func_type_params = [System::Object] + someotherstuff

generate a .NET delegate to wrap the new DynamicMethod

puts “DEBUG: Action= #{System::Action.inspect}”
puts “DEBUG: Params= #{func_type_params.inspect}”
puts “DEBUG: F= #{System::Action.of(*func_type_params)}”
del_type = System::Action.of(*func_type_params).to_clr_type

This has been working reliably for some time, and still works with most
input. However, we’ve recently seen random failures. Here’s some of the
output from those Debug lines:

successful

DEBUG: Action= #<TypeGroup: System::Action, System::Action[T],
System::Action[T1, T2], System::Action[T1, T2, T3], System::Action[T1,
T2, T3, T4]>
DEBUG: Params= [Object, Object, Object]
DEBUG: F= System::Action[Object, Object, Object]

and then the next one fails

DEBUG: Action= nil
DEBUG: Params= [Object, Fixnum, Interop::FieldID[], System::Object[]]
NoMethodError: undefined method `of’ for NilClass

As far as that tells me, System::Action has somehow been set to nil.
Note: The point at which System::Action gets nil’ed out is NOT always
the same point.

If I run the code under iirb (copy/pasting my original script in), and
then after the exception inspect System::Action, it reports this:

=> #<TypeGroup: System::Action, System::Action[T], System::Action[T1,
T2], System::Action[T1, T2, T3], System::Action[T1, T2, T3, T4],
System::Action[T1, T2, T3, T4, T5], System::Action[T1, T2, T3, T4, T5,
T6], System::Action[T1, T2, T3, T4, T5, T6,
T7], System::Action[T1, T2, T3, T4, T5, T6, T7, T8], System::Action[T1,
T2, T3, T4, T5, T6, T7, T8, T9], System::Action[T1, T2, T3, T4, T5, T6,
T7, T8, T9, T10], System::Action[T1, T2, T3, T4, T5, T6, T7, T8, T9,
T10, T11], System::Action[T1, T2, T3,
T4, T5, T6, T7, T8, T9, T10, T11, T12], System::Action[T1, T2, T3, T4,
T5, T6, T7, T8, T9, T10, T11, T12, T13], System::Action[T1, T2, T3, T4,
T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], System::Action[T1, T2, T3,
T4, T5, T6, T7, T8, T9, T10, T11,
T12, T13, T14, T15], System::Action[T1, T2, T3, T4, T5, T6, T7, T8, T9,
T10, T11, T12, T13, T14, T15, T16]>

As you can see, System::Action is no longer nil, but has now been given
a bunch more overloads. These overloads come from System.CoreEx (part of
the .NET reactive framework). Putting require ‘System.CoreEx’ at the top
of my script to pre-load it makes this error go away.

From what I can tell, something causes the CLR to on-demand load System.CoreEx.dll. This in turn adds more overloads to System::Action.
IronRuby appears to temporarily nil it out while loading, thus causing
the crash.

Am I on the right track? As mentioned I think I can work around it by
preloading all the dll’s I know I’m going to need, but this doesn’t seem
to be a reliable long-term solution.

Cheers, Orion