The following IL code creates a Type instance named (fnptr)*
(token 0x2000000 - invalid, module mscorlib.dll).
ldtoken method void* ()*
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
What's the purpose of this type? Is it possible to create this type instance in C# without writing any IL code, maybe with reflection? Module.ResolveType on the token throws ArgumentOutOfRangeException.
Edit:
It's clear the (fnptr)
type is an internal CLR type representation of an IL method pointer type, though when removing the last *
, it simply returns IntPtr
.
Edit #2:
The (fnptr)
comes from a function that can be seen in the SSCLI typestring.cpp:
// ...or function pointer
else if (ty.IsFnPtrType())
{
// Don't attempt to format this currently, it may trigger GC due to fixups.
tnb.AddName(L"(fnptr)");
}
Why basic fnptr returns IntPtr can be seen in typehandle.cpp:
OBJECTREF TypeHandle::GetManagedClassObject() const
{
[...]
switch(GetInternalCorElementType()) {
case ELEMENT_TYPE_ARRAY:
case ELEMENT_TYPE_SZARRAY:
case ELEMENT_TYPE_BYREF:
case ELEMENT_TYPE_PTR:
return ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObject();
case ELEMENT_TYPE_VAR:
case ELEMENT_TYPE_MVAR:
return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject();
// for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release
case ELEMENT_TYPE_FNPTR:
return TheIntPtrClass()->GetManagedClassObject();
default:
_ASSERTE(!"Bad Element Type");
return NULL;
}
}
}
So it looks they've forgotten to fix it.
I have no real idea what you are asking and why you think there is anything wrong. (fnptr)* is the type name of a pointer to an unmanaged function pointer. That it gets special treatment in the CLR is indeed odd, I suspect it is an archeological artifact. Dating back to a time before .NET and before delegates were invented. The CLR started life as the "universal runtime" in Project 42, a failed project before .NET.
Maybe some C++/CLI code to demonstrate how to generate one is useful, shows you how to create it:
#include "stdafx.h"
using namespace System;
typedef void (*functionPointer)(int);
ref class Example {
public:
functionPointer* fp;
};
int main(array<System::String ^> ^args)
{
auto field = Example::typeid->GetField("fp");
auto name = field->FieldType->FullName;
Console::WriteLine(name);
return 0;
}
Output: (fnptr)*
Not sure where you're seeing the FNPTR being declared.
For this code:
.assembly extern mscorlib {}
.assembly Test
{
.ver 1:0:1:0
}
.module test.exe
.method static void main() cil managed
{
.maxstack 1
.entrypoint
ldtoken method void* ()*
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
ldtoken method void* ()
call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
ret
}
ILASM (4.5.22.0) outputs the following:
.method privatescope static void main$PST06000001() cil managed
{
.entrypoint
// Code size 21 (0x15)
.maxstack 1
IL_0000: ldtoken method void *()*
IL_0005: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000a: ldtoken method void *()
IL_000f: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0014: ret
} // end of method 'Global Functions'::main
Update #1:
Perhaps I am being dense here, but I am not seeing FNPTR being generated from this code:
typeof(StringBuilder).ToString();
The IL looks like this:
IL_0000: nop
IL_0001: ldtoken [mscorlib]System.Text.StringBuilder
IL_0006: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_000b: callvirt instance string [mscorlib]System.Object::ToString()
IL_0010: pop
IL_0011: ret
The Type.ToString()
call is a callvirt
operation since ToString() is a virtual method.
Virtual functions are usually manifested as structs of function pointers which would, I guess, result in a FNPTR being emitted. If you omit the *
in ()*
resulting in ()
, you're now describing a function, not a function pointer.
What version of .NET are you using when you see the FNPTR? What are you using to extract the IL?
It is possible to load the signature of a pointer to a function pointer:
public static unsafe Type GetTypeFromFieldSignature(byte[] signature, Type declaringType = null)
{
declaringType = declaringType ?? typeof(object);
Type sigtype = typeof(Type).Module.GetType("System.Signature");
Type rtype = typeof(Type).Module.GetType("System.RuntimeType");
var ctor = sigtype.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new[]{typeof(void*), typeof(int), rtype}, null);
fixed(byte* ptr = signature)
{
object sigobj = ctor.Invoke(new object[]{(IntPtr)ptr, signature.Length, declaringType});
return (Type)sigtype.InvokeMember("FieldType", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetProperty, null, sigobj, null);
}
}
var fnptrPtr = GetTypeFromFieldSignature(new byte[]{6, 15, 27, 0, 0, 1});
6 is field, 15 is pointer, 27 is function pointer and 0, 0, 1 is a method signature without return or parameters.