Is this "unsafe" declaration unnecessary?
unsafe is purely a compile-time check. If it were needed the code wouldn’t compile. The runtime errors are caused by something else.

Furthermore, unsafe is needed if and only if you are using unmanaged pointers (e.g. inside a fixed block).