IronLanguages / ironpython2

Implementation of the Python programming language for .NET Framework; built on top of the Dynamic Language Runtime (DLR).

Home Page:http://ironpython.net

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Static constructors not being called for loaded classes

Raijinili opened this issue · comments

IronPython 2.7.11

Assemblies are in: FFTPatcher_493_Beta_v6.zip

Reproduction code:

from __future__ import print_function
import sys, os
import clr

folder = r'path/to/folder'  #Path to the folder with FFTPatcher.exe and PatcherLib.dll.
sys.path.append(os.path.abspath(folder))

clr.AddReference('FFTPatcher.exe', 'PatcherLib.dll', 'PatcherLib.Resources.dll')

from FFTPatcher.Datatypes import FFTPatch
from PatcherLib.Datatypes import Context

psxPatch = FFTPatch()
try:
    psxPatch.BuildFromContext(Context.US_PSX)
except SystemError as e:
    print(e.clsException.ToString())

Result:

System.TypeInitializationException: The type initializer for 'FFTPatcher.Datatypes.FFTPatch' threw an exception. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at FFTPatcher.Datatypes.FFTPatch.GetAbilityEffects(IList`1 effectBytes, IList`1 itemEffectBytes, IList`1 reactionEffectBytes, Context context)
   at FFTPatcher.Datatypes.FFTPatch..cctor()
   --- End of inner exception stack trace ---
   at FFTPatcher.Datatypes.FFTPatch.GetStandardDefaults(Context context)
   at FFTPatcher.Datatypes.FFTPatch.BuildFromContext(Context context)
   at Microsoft.Scripting.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.LightLambda.Run4[T0,T1,T2,T3,TRet](T0 arg0, T1 arg1, T2 arg2, T3 arg3)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute3[T0,T1,T2,TRet](CallSite site, T0 arg0, T1 arg1, T2 arg2)
   at Microsoft.Scripting.Interpreter.DynamicInstruction`4.Run(InterpretedFrame frame)
   at Microsoft.Scripting.Interpreter.Interpreter.Run(InterpretedFrame frame)

This is being thrown during initialization of FFTPatch's static variables, such as at:
https://github.com/Glain/FFTPatcher/blob/bd5c402729572d8c90390e881144f868f3be0fe2/Datatypes/FFTPatch.cs#L110

It turns out that the PatcherLib.PSXResources.Binaries.AbilityEffects (and the others) referenced by this call is null. However, they were supposed to be initialized by the static constructor of PatcherLib.PSXResources:
https://github.com/Glain/FFTPatcher/blob/bd5c402729572d8c90390e881144f868f3be0fe2/PatcherLib.Resources/PSXResources.cs#L92


I also tried calling the static constructors manually, but this method doesn't show if there are errors in static initialization, so I can't tell why it doesn't work. I assume I'm not calling all of the prerequisite statics correctly.

# Requires Python code from above.

from System import Type
from System.Runtime.CompilerServices.RuntimeHelpers import RunClassConstructor
def runStaticConstructor(cls):
    typ = Type.GetType(cls)
    return RunClassConstructor(typ.TypeHandle)

from PatcherLib import ResourcesClass, PSXResources, PSPResources
runStaticConstructor(ResourcesClass)
assert ResourcesClass.ZipFileContents
runStaticConstructor(PSXResources)
runStaticConstructor(PSPResources)
runStaticConstructor(PSXResources.Binaries)
runStaticConstructor(PSPResources.Binaries)
print(PSXResources.Binaries.AbilityEffects)  #None
print(PSPResources.Binaries.AbilityEffects)  #None

I'm not sure it's an IronPython issue here, you can write the same program in C# and you also get the same error...

var psxPatch = new FFTPatch();
psxPatch.BuildFromContext(Context.US_PSX);

System.TypeInitializationException: 'The type initializer for 'FFTPatcher.Datatypes.FFTPatch' threw an exception.'
NullReferenceException: Object reference not set to an instance of an object.

I did that in C# Interactive, but didn't realize it also happened in an actual compiled program.

Do you think it's a problem with the FFTPatcher project?

(Forgot to update.)

Those are to force static initialization. I guess the issue also happens in the original program.

Since then, the static inits have been removed, or at least reduced to the point where I don't have the issue.