here is my code, the .net vm maybe crashed. .net framework version is 4.6.1
var fastAllocate = typeof(string).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.First(x => x.Name == "FastAllocateString");
for (int i = 0; i < 100000; ++i)
{
Console.WriteLine("{0}", i);
var newString = (string)fastAllocate.Invoke(null, new object[] { 984 * 4 });
}
here is exception report:
Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'E:\Code\Bench\Bench\bin\Debug\Bench.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x740cbf2d, on thread 0xc50. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
how can fixed this problem?
var fastAllocate = typeof(string).GetMethod("FastAllocateString", BindingFlags.NonPublic | BindingFlags.Static);
Func<int, string> FastAllocateString = (Func<int, string>)fastAllocate.CreateDelegate(typeof(Func<int, string>));
i changed my code, this version runs well.
and this String.String(char, int) constructor is well too.
thanks a lot.
Out of interest, why are you trying to construct a string using the FastAllocateString() internal method, rather than construct it normally?
This crash is by design - the internal FastAllocateString method is not compatible with reflection.
In addition,
var str = new string('\0', length);
is going to be way faster/convenient than reflection. There is logic in place to return straight after allocating if the char to repeat is 0.
I was just taking a look at the behavior of this code and I noticed that in addition of having a different outcome in coreclr vs desktop, it also doesn't crash for the intended reason
The invocation itself is failing because it's exceeding the allocation limit, instead of failing to invoke by design as @jkotas mentioned.
Please correct me if I'm wrong, but for large strings it seems that it falls back to the SlowAllocateString method, which has its upper bound on string length. Also, a continued series of allocations as in the original example by @egmkang will eventually exhaust the TLS and trigger the exception (although I didn't verify that path)
The following code can reproduce this and also works differently according to the .NET version
var fastAlloc = typeof(string).GetMethods(BindingFlags.NonPublic | BindingFlags.Static)
.First(x => x.Name == "FastAllocateString");
// Small allocation
fastAlloc.Invoke(null, new object[] { 1024 });
Console.WriteLine("First call pass");
// Big allocation (upper limit)
fastAlloc.Invoke(null, new object[] { 0x3FFFFFDF });
Console.WriteLine("Second call pass");
// Throwing allocation (exceeding char boundary 0x3FFFFFDF)
fastAlloc.Invoke(null, new object[] { 0x3FFFFFE0 });
Console.WriteLine("Third call pass");
On .NET Core 1.0.0-preview2-003131:
First call pass
Second call pass
...
System.Reflection.TargetInvocationException was unhandled
HResult=-2146232828
Message=Exception has been thrown by the target of an invocation.
Source=System.Private.CoreLib
StackTrace:
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
at ConsoleApp1.Program.Main(String[] args)
InnerException:
HResult=-2147024882
Message=Exception of type 'System.OutOfMemoryException' was thrown.
InnerException:
On .NET desktop 4.6.1 - CLR 4.0.30319.42000:
First call passed
...
FatalExecutionEngineError occurred
Message: Managed Debugging Assistant 'FatalExecutionEngineError' has detected a problem in 'C:\Users\Merkava\Documents\Visual Studio 2015\Projects\ConsoleApplication2\ConsoleApplication2\bin\Debug\ConsoleApplication2.vshost.exe'.
Additional information: The runtime has encountered a fatal error. The address of the error was at 0x72e209bc, on thread 0x3210. The error code is 0xc0000005. This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code. Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.
Coreclr handles this in a more graceful way so that's already an improvement, but it still executes the method, Is this intentional despite that it should be forbidden by design?
Calling internal methods is forbidden and unsupported. When you break that rule, whatever bad happens is by design.
It is similar as if you call internal methods in a C++ library - you should never do that. If you get the calling convention wrong, you just mess up the stack and bad things will likely happen. Or the call is just not expected in that order and it may lead to incorrect internal data state, which leads to weird behavior later on. There's just plenty of things that could go wrong.
So basically making FCall invocations in user code via reflection is forbidden (although not enforced by the runtime), it can be considered unexpected behavior and no one in their right mind should do it. Makes sense
Thanks for the clarification
Most helpful comment
This crash is by design - the internal FastAllocateString method is not compatible with reflection.