Discussion:
[Mono-list] Embedding Mono Trouble
Jeremy
2017-07-19 05:31:41 UTC
Permalink
I've compiled and linked a small test C++ project with mono to experiment
with embedding and invoking functionality in a c# assembly. I will paste
the full code at the bottom, but what is happened is that when I try
to mono_jit_exec, passing a valid domain and assembly, and the assemblypath
as argv, I get a crash inside mono in mono_stack_mark_pop, where old_top is
null

+ handles 0x0124dc88 {top=0x01235810 {size=1 prev=0x00000000 <NULL>
next=0x00000000 <NULL> ...} bottom=0x01235810 {...} ...} HandleStack *
+ info 0x0122e9c0 {node={next=0x0128f5c8 {next=0x00000000 <NULL> key=26972
} key=26564 } small_id=64 native_handle=...} MonoThreadInfo *
+ old_top 0x00000000 <NULL> _HandleChunk *
- stackmark 0x00d7f138 {size=0 interior_size=0 chunk=0x00000000 <NULL>
} HandleStackMark
*
size 0 int
interior_size 0 int
+ chunk 0x00000000 <NULL> _HandleChunk *



I am trying to invoke an empty Main function in my test assembly, as I have
read that it is necessary to properly initialize things by calling Main
before you call other functions. Other functions crash in this same
location btw. This is in Windows 10 using MSVC 2015. I have a "MonoTestLib"
also in the 2015 project as a C# console application. Mono can seemingly
find the functions within the assembly
with mono_method_desc_search_in_image calls, but any attempt to invoke them
with mono_runtime_invoke crashes with the above.

Here is the code

//TestClass.cs
using System;

public class TestClass
{
static public void StaticFunc()
{
Console.WriteLine("a TestClass!");
}
public void RunTest()
{
Console.WriteLine("TestClass!");
}
public void Test(int times)
{
for (var i = 0; i < times; ++i)
Console.WriteLine("Test!");
}

static int Main(string[] args)
{
Console.WriteLine("Main!");
return 0;
}
}


// main.cpp with mono embed

#include <iostream>

#include <mono/jit/jit.h>
#include <mono/metadata/mono-config.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>


/* The C# signature for this method is: string GetMessage () in class
Sample */
MonoString* getMessage()
{
return mono_string_new( mono_domain_get(), "Hello, world" );
}

void NotifyAssemblyLoaded( MonoAssembly *assembly, void* user_data )
{
std::cout << "Assembly Loaded " << std::endl;
}

int main( int argc, char** argv )
{
/*
* Load the default Mono configuration file, this is needed
* if you are planning on using the dllmaps defined on the
* system configuration
*/
//mono_config_parse( NULL );
mono_set_dirs("C:\\Program Files (x86)\\Mono\\lib", "C:\\Program Files
(x86)\\Mono\\etc");

/*
* mono_jit_init() creates a domain: each assembly is
* loaded and run in a MonoDomain.
*/
//MonoDomain *domain = mono_jit_init( "MonoTestLib.dll" );
MonoDomain *domain = mono_jit_init_version( "TestApp", "v4.0.30319" );

mono_install_assembly_load_hook( NotifyAssemblyLoaded, NULL );

/*
* Optionally, add an internal call that your startup.exe
* code can call, this will bridge startup.exe to Mono
*/
//mono_add_internal_call( "Sample::GetMessage", getMessage );

//Open a assembly in the domain
char* assemblyPath =
"D:\\git\\voxel_component_system\\VoxelComponentSystem\\MonoTestLib\\bin\\Debug\\MonoTestLib.exe";
MonoAssembly *assembly = mono_domain_assembly_open( domain, assemblyPath );
if ( !assembly )
{
std::cout << "mono_domain_assembly_open failed" << std::endl;
system( "pause" );
return 1;
}

MonoImage* image = mono_assembly_get_image( assembly );
if ( !image )
{
std::cout << "mono_assembly_get_image failed" << std::endl;
system( "pause" );
return 1;
}

// mono_jit_exec expects the assembly path
argv[ 0 ] = assemblyPath;
int resmain = mono_jit_exec( domain, assembly, argc, argv );
if(resmain != 0)
{
std::cout << "mono_jit_exec failed" << std::endl;
system( "pause" );
return 1;
}

#pragma region Run a static method
{
//Build a method description object
const char* TypeMethodDescStr = "TestClass:StaticFunc()";
MonoMethodDesc* TypeMethodDesc = mono_method_desc_new( TypeMethodDescStr,
NULL );
if ( !TypeMethodDesc )
{
std::cout << "mono_method_desc_new failed" << std::endl;
system( "pause" );
return 1;
}

//Search the method in the image
MonoMethod* method = mono_method_desc_search_in_image( TypeMethodDesc,
image );
if ( !method )
{
std::cout << "mono_method_desc_search_in_image failed" << std::endl;
system( "pause" );
return 1;
}

//run the method
std::cout << "Running the static method: " << TypeMethodDescStr <<
std::endl;
mono_runtime_invoke( method, nullptr, nullptr, nullptr ); // CRASH
}
#pragma endregion

#pragma region Run a normal method
{
//Get the class
MonoClass* testClass = mono_class_from_name_case( image, "", "TestClass" );
if ( !testClass )
{
std::cout << "mono_class_from_name failed" << std::endl;
system( "pause" );
return 1;
}

//Create a instance of the class
MonoObject* testObj = mono_object_new( domain, testClass );
if ( !testObj )
{
std::cout << "mono_object_new failed" << std::endl;
system( "pause" );
return 1;
}

//Call its default constructor
mono_runtime_object_init( testObj );

//Build a method description object
const char* BarkMethodDescStr = "TestClass:Test(int)";
MonoMethodDesc* BarkMethodDesc = mono_method_desc_new( BarkMethodDescStr,
NULL );
if ( !BarkMethodDesc )
{
std::cout << "mono_method_desc_new failed" << std::endl;
system( "pause" );
return 1;
}

//Search the method in the image
MonoMethod* method = mono_method_desc_search_in_image( BarkMethodDesc,
image );
if ( !method )
{
std::cout << "mono_method_desc_search_in_image failed" << std::endl;
system( "pause" );
return 1;
}

//Set the arguments for the method
void* args[ 1 ];
int barkTimes = 3;
args[ 0 ] = &barkTimes;

//Run the method
std::cout << "Running the method: " << BarkMethodDescStr << std::endl;
mono_runtime_invoke( method, testObj, args, nullptr ); // CRASH
}
#pragma endregion


return 0;
}





// callstack

mono-2.0-sgen.dll!mono_stack_mark_pop(MonoThreadInfo * info=0x00173600,
HandleStackMark * stackmark=0x0141ee78) Line 148 C
mono-2.0-sgen.dll!mono_icall_end(MonoThreadInfo * info=0x00173600,
HandleStackMark * stackmark=0x0141ee78, _MonoError * error=0x0141ee80) Line
12398 C
00f85394() Unknown
[Frames below may be incorrect and/or missing]
00f852d4() Unknown
00f85294() Unknown
00f84e90() Unknown
00ec1c04() Unknown
00ec13d8() Unknown
00ec0fc5() Unknown
mono-2.0-sgen.dll!mono_jit_runtime_invoke(_MonoMethod *
method=0x00230890, void * obj=0x00000000, void * * params=0x00000000,
_MonoObject * * exc=0x0141f1b8, _MonoError * error=0x0141f45c) Line 2794 C
mono-2.0-sgen.dll!do_runtime_invoke(_MonoMethod * method=0x00230890, void
* obj=0x00000000, void * * params=0x00000000, _MonoObject * *
exc=0x0141f1b8, _MonoError * error=0x0141f45c) Line 2827 C
mono-2.0-sgen.dll!mono_runtime_try_invoke(_MonoMethod *
method=0x00230890, void * obj=0x00000000, void * * params=0x00000000,
_MonoObject * * exc=0x0141f1b8, _MonoError * error=0x0141f45c) Line 2934 C
mono-2.0-sgen.dll!mono_runtime_class_init_full(MonoVTable *
vtable=0x0022b5c0, _MonoError * error=0x0141f45c) Line 471 C
mono-2.0-sgen.dll!mono_jit_compile_method_inner(_MonoMethod *
method=0x00230b08, _MonoDomain * target_domain=0x00170900, int
opt=378628607, _MonoError * error=0x0141f45c) Line 4331 C
mono-2.0-sgen.dll!mono_jit_compile_method_with_opt(_MonoMethod *
method=0x00230b08, unsigned int opt=378628607, int jit_only=0, _MonoError *
error=0x0141f45c) Line 2132 C
mono-2.0-sgen.dll!mono_jit_compile_method(_MonoMethod *
method=0x00230b08, _MonoError * error=0x0141f45c) Line 2178 C
mono-2.0-sgen.dll!common_call_trampoline(int * regs=0x0141f4d0, unsigned
char * code=0x00ec11e4, _MonoMethod * m=0x00230b08, MonoVTable *
vt=0x00000000, void * * vtable_slot=0x00000000, _MonoError *
error=0x0141f45c) Line 704 C
mono-2.0-sgen.dll!mono_magic_trampoline(int * regs=0x0141f4d0, unsigned
char * code=0x00ec11e4, void * arg=0x00230b08, unsigned char *
tramp=0x00000000) Line 834 C
00eb0188() Unknown
00230b08() Unknown
00ec12bc() Unknown
mono-2.0-sgen.dll!mono_jit_runtime_invoke(_MonoMethod *
method=0x00219710, void * obj=0x00000000, void * * params=0x0141f640,
_MonoObject * * exc=0x00000000, _MonoError * error=0x0141f6b8) Line 2794 C
mono-2.0-sgen.dll!do_runtime_invoke(_MonoMethod * method=0x00219710, void
* obj=0x00000000, void * * params=0x0141f640, _MonoObject * *
exc=0x00000000, _MonoError * error=0x0141f6b8) Line 2827 C
mono-2.0-sgen.dll!mono_runtime_invoke_checked(_MonoMethod *
method=0x00219710, void * obj=0x00000000, void * * params=0x0141f640,
_MonoError * error=0x0141f6b8) Line 2980 C
mono-2.0-sgen.dll!do_exec_main_checked(_MonoMethod * method=0x00219710,
_MonoArray * args=0x02c00290, _MonoError * error=0x0141f6b8) Line 4697 C
mono-2.0-sgen.dll!mono_runtime_exec_main_checked(_MonoMethod *
method=0x00219710, _MonoArray * args=0x02c00290, _MonoError *
error=0x0141f6b8) Line 4798 C
mono-2.0-sgen.dll!mono_runtime_run_main_checked(_MonoMethod *
method=0x00219710, int argc=1, char * * argv=0x00171538, _MonoError *
error=0x0141f6b8) Line 4226 C
mono-2.0-sgen.dll!mono_jit_exec(_MonoDomain * domain=0x00170900,
_MonoAssembly * assembly=0x0016db00, int argc=1, char * * argv=0x00171538)
Line 1027 C
MonoTest.exe!main(int argc=1, char * * argv=0x00171538) Line 65 C++
MonoTest.exe!invoke_main() Line 64 C++
MonoTest.exe!__scrt_common_main_seh() Line 253 C++
MonoTest.exe!__scrt_common_main() Line 296 C++
MonoTest.exe!mainCRTStartup() Line 17 C++
kernel32.dll!@***@12 () Unknown
ntdll.dll!__RtlUserThreadStart() Unknown
ntdll.dll!***@8 () Unknown

Loading...