Skip to content

Static fields and static constructors aren't initialized/called when assembly is loaded in code #733

Closed
nanoframework/nf-interpreter
#1973
@MateuszKlatecki

Description

@MateuszKlatecki

Details about Problem

Target: any

Firmware image version: newest

Worked before? If so, with which nanoFramework image version: I checked the stable version and it also doesn't work

Device capabilities output:

Description

I have created a library that I am going to manually load during runtime with Assemby.Load. In the library I have classes that have static fields and static constructors. Fields are not automatically initialized and constructors are not called when assembly is loaded or before first use.

Detailed repro steps so we can see the same problem

  1. Create simple library with static fields and static constructor for example something like this
    public class MyClass
    {
        private static int[] storage = new int[8];  //this static field isn't initialized

        // this static constructor isn't called automatically
        static MyClass()
        {
            storage = new int[16];
        }
        public static void Store(int position, int value)
        {
            if (storage == null || position < 0 || position >= storage.Length)
                return;

            storage[position] = value;
        }

        public static int Load(int position)
        {
            if (storage == null || position < 0 || position >= storage.Length)
                return int.MinValue;
            return storage[position];
        }
    }
  1. Wrie program that load assembly and try to run methods:
using System.Device.Gpio;
using System.Diagnostics;
using System.Reflection;
using System.Threading;

namespace Program
{
    public class Program
    {
        private static GpioController s_GpioController;


        public static void Main()
        {
            s_GpioController = new GpioController();
            GpioPin led = s_GpioController.OpenPin(13, PinMode.Output);
            led.Write(PinValue.High);

            Debug.WriteLine("Hello from nanoFramework!");


            // array below is a pe file from this code:
            //public class MyClass
            //{
            //    private static int[] storage = new int[8];  //this static field isn't initialized

            //    // this static constructor isn't called automatically
            //    static MyClass()
            //    {
            //        storage = new int[16];
            //    }
            //    public static void Store(int position, int value)
            //    {
            //        if (storage == null || position < 0 || position >= storage.Length)
            //            return;

            //        storage[position] = value;
            //    }

            //    public static int Load(int position)
            //    {
            //        if (storage == null || position < 0 || position >= storage.Length)
            //            return int.MinValue;
            //        return storage[position];
            //    }
            //}

            byte[] myLib_pe = {
                0x4E, 0x46, 0x4D, 0x52, 0x4B, 0x31, 0x00, 0x00, 0x6C, 0x77, 0x97, 0xD8,
                0xA5, 0x2E, 0xBA, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x01, 0x00, 0x01, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
                0x98, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00,
                0xB8, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
                0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
                0x00, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00,
                0xA0, 0x01, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
                0x01, 0x02, 0x00, 0x00, 0xD2, 0xFC, 0x00, 0x00, 0x01, 0x00, 0x0A, 0x00,
                0x03, 0x00, 0x00, 0x00, 0xB1, 0xFE, 0x40, 0xFE, 0x00, 0x00, 0x00, 0x00,
                0xF7, 0xFE, 0x40, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF,
                0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x03, 0x11, 0x00, 0x00, 0x00, 0x00,
                0x01, 0x00, 0x01, 0x00, 0x15, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x11, 0x00,
                0xFE, 0xFF, 0x00, 0x00, 0x86, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
                0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x06, 0x00, 0x91, 0x24, 0x00, 0x00,
                0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x06, 0x00, 0x0F, 0x00, 0x17, 0x00,
                0x96, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01, 0x03, 0x0E, 0x00, 0x09, 0x00,
                0xDD, 0xFE, 0x3C, 0x00, 0x96, 0x00, 0x00, 0x00, 0x07, 0x01, 0x02, 0x02,
                0x10, 0x00, 0x0F, 0x00, 0x00, 0x4D, 0x79, 0x4C, 0x69, 0x62, 0x00, 0x4D,
                0x79, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x00, 0x53, 0x74, 0x6F, 0x72, 0x65,
                0x00, 0x73, 0x74, 0x6F, 0x72, 0x61, 0x67, 0x65, 0x00, 0x00, 0x00, 0x00,
                0x20, 0x00, 0x00, 0x06, 0x13, 0x07, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
                0x07, 0x07, 0x01, 0x00, 0x01, 0x07, 0x07, 0x00, 0x02, 0x28, 0x00, 0x80,
                0x00, 0x2A, 0x1E, 0x8D, 0x01, 0x40, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x10,
                0x8D, 0x01, 0x40, 0x80, 0x00, 0x00, 0x2A, 0x00, 0x7E, 0x00, 0x00, 0x2C,
                0x11, 0x02, 0x16, 0x32, 0x0D, 0x02, 0x7E, 0x00, 0x00, 0x8E, 0x69, 0xFE,
                0x04, 0x16, 0xFE, 0x01, 0x2B, 0x01, 0x17, 0x0A, 0x06, 0x2C, 0x02, 0x2B,
                0x06, 0x7E, 0x00, 0x00, 0x02, 0x03, 0x9E, 0x2A, 0x00, 0x7E, 0x00, 0x00,
                0x2C, 0x11, 0x02, 0x16, 0x32, 0x0D, 0x02, 0x7E, 0x00, 0x00, 0x8E, 0x69,
                0xFE, 0x04, 0x16, 0xFE, 0x01, 0x2B, 0x01, 0x17, 0x0A, 0x06, 0x2C, 0x08,
                0x20, 0x00, 0x00, 0x00, 0x80, 0x0B, 0x2B, 0x08, 0x7E, 0x00, 0x00, 0x02,
                0x94, 0x0B, 0x2B, 0x00, 0x07, 0x2A, 0x00, 0x00
            };


            var loadedAssembly = Assembly.Load(myLib_pe);

            if (loadedAssembly != null)
            {

                var type = loadedAssembly.GetTypes()[0];

                var storeMethod = type.GetMethod("Store");
                var loadMethod = type.GetMethod("Load");

                if (storeMethod != null)
                {
                    //store 5 at position 2
                    storeMethod.Invoke(null, new object[] { 2, 5 });

                    //load value form second position
                    int value = (int)loadMethod.Invoke(null, new object[] { 2 });

                    //if value is int.MinValue then infinite fast blinking
                    if (value == int.MinValue)
                    {
                        for (; ; )
                        {
                            led.Write(PinValue.Low);
                            Thread.Sleep(25);
                            led.Write(PinValue.High);
                            Thread.Sleep(25);
                        }
                    }

                    // if value is positive blink correct number times
                    while (value-- > 0)
                    {
                        led.Write(PinValue.Low);
                        Thread.Sleep(250);
                        led.Write(PinValue.High);
                        Thread.Sleep(250);
                    }
                }
            }

            Thread.Sleep(Timeout.Infinite);
        }
    }
}

...

Expected behaviour

Static constructor should be called and field initialized before first usage.

Additional context

If library is referenced (not loaded during runtime) then everything seems to work correctly.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions