[Mono-dev] mono_method_desc_search_in_image problem, and some question...

pierre pierre.saunier at ppmodeler.com
Wed Feb 21 10:20:03 UTC 2018


Hi,

Anyone about this??
if I run "mono_domain_unload(domain);"
and after do
assembly = mono_assembly_load_from_full(image, referenceName, &status, 
FALSE);
it is not working properly if referenceName is kept from one launch to 
the next...
I think the code bellow is showing it... or am I doing something wrong??
may be it is linked to the "[DllImport ("__Internal"..." which blocking 
the unloading of the assembly?

And a question: Is there a way to debug a running assembly (embeded)?
On python and lua, you can register a function that is called on every 
line executed... I totally understand it is different for mono, but what 
are my options? where can I find documentations about debugging from and 
embedding application?

Thanks,
Pierre

The source to test is (mono_test.c):
/******************************************************************************************************************/
#include <mono/jit/jit.h>

#include <mono/metadata/mono-config.h>
#include <mono/metadata/threads.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-gc.h>
#include <mono/metadata/environment.h>
#include <mono/metadata/debug-helpers.h>
#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-logger.h>



/**********************************************************************************/
/* */
/**********************************************************************************/
#define TRUE  1
#define FALSE 0
#define BYTE unsigned char
#define gMalloc malloc
#define gFree free

BYTE *readFile(FILE *f, size_t *size)
{
   BYTE *buffer;
   size_t i;

   fseek(f, 0, SEEK_END);
   *size = ftell(f);
   fseek(f, 0, SEEK_SET);

   buffer = (BYTE *) gMalloc(*size);
   if(buffer == NULL) return NULL;

   i = fread(buffer, 1, *size, f);
   if(i != *size)
   {
     gFree(buffer);
     return NULL;
   }
   return buffer;
}


/**********************************************************************************/
/* */
/**********************************************************************************/
static MonoDomain *rootDomain;
static MonoDomain *domain;
static MonoImage *image;
static MonoAssembly *assembly;




/**********************************************************************************/
/* */
/**********************************************************************************/
__declspec(dllexport) void mono_report(char* str)
{
   printf("%s\n", str);
}


/**********************************************************************************/
/* */
/**********************************************************************************/
static int monoScriptCompile(char *fileName, char *referenceName)
{

   int res;
   char *ret, *strErr, *str;
   char buffer[256];
   FILE *f;
   BYTE *data;
   size_t dataLen;
   MonoImageOpenStatus status;
   MonoAssemblyName *aName;


   if(domain != NULL)
   {
     res = mono_domain_set(rootDomain, FALSE);
     if(!res)
     {
       printf("Failed to set root domain\n");
       return FALSE;
     }

     mono_domain_unload(domain);
     mono_gc_collect(mono_gc_max_generation());
   }
   domain = NULL;
   image = NULL;
   assembly = NULL;


   domain = mono_domain_create_appdomain("ScriptSubDomain", NULL);
   res = mono_domain_set(domain, FALSE);
   if(!res)
   {
     printf("Failed to set domain\n");
     return FALSE;
   }

   sprintf(buffer, "%s.dll", fileName);
   f = fopen(buffer, "rb");
   if(f == NULL)
   {
     printf("Cannot open file: %s\n", buffer);
     return FALSE;
   }
   data = readFile(f, &dataLen);
   fclose(f);




     // open the assembly from the data we read, so we never lock files
   image = mono_image_open_from_data_with_name(data, dataLen,
                                               TRUE /* copy data */,
&status,
                                               FALSE /* ref only */,
referenceName);
   gFree(data);
   if (status != MONO_IMAGE_OK || image == NULL)
   {
     printf("Cannot create image from data\n");
     return FALSE;
   }

     // load the assembly
   assembly = mono_assembly_load_from_full(image, referenceName, 
&status, FALSE);
   if (status != MONO_IMAGE_OK || assembly == NULL)
   {
     printf("failed to load assembly\n");
     mono_image_close(image);
     return FALSE;
   }

   aName = mono_assembly_get_name(assembly);
   printf("Assembly Name: %s\n", mono_stringify_assembly_name(aName));

   res = mono_domain_set(rootDomain, FALSE);

   return TRUE;
}



/**********************************************************************************/
/* */
/**********************************************************************************/
static int monoScriptRun(void)
{
   int res, base;
   char *ret, *strErr;
   MonoMethodDesc* monoMethodDesc;
   MonoMethod* method;
   MonoObject *exception;


   if(domain == NULL || assembly == NULL)
   {
    printf("Run Failed: Not compiled\n");
     return FALSE;
   }

   if (!mono_domain_set(domain, FALSE))
   {
     printf("Run Failed: set domain failed\n");
     return FALSE;
   }

   monoMethodDesc = mono_method_desc_new("Script:Main", 0);
   if(monoMethodDesc == NULL)
   {
     printf("mono_method_desc_new failed\n" );
     return FALSE;
   }

   //Search the method in the image
   method = mono_method_desc_search_in_image(monoMethodDesc, image);
   mono_free(monoMethodDesc);
   if(method == NULL)
   {
     printf("mono_method_desc_search_in_image failed\n");
     return FALSE;
   }

   //run the method
   exception = NULL;
   mono_runtime_invoke(method, NULL, NULL, &exception);
   if(exception != NULL)
   {
     printf("An exception was thrown when calling Script:Main!\n");
     return FALSE;
   }

   res = mono_domain_set(rootDomain, FALSE);

   return TRUE;
}


/**********************************************************************************/
/* */
/**********************************************************************************/
static void monoInit(void)
{
   if(rootDomain == NULL)
   {
     mono_set_dirs("C:\\Program Files\\Mono\\lib",
                   "C:\\Program Files\\Mono\\etc");
     rootDomain = mono_jit_init("ScriptEngine");

     mono_thread_set_main(mono_thread_current());
   }
}



/**********************************************************************************/
/* */
/**********************************************************************************/
int main(int argc, char **argv)
{
   mono_report("Starting");
   monoInit();
   monoScriptCompile("code1", "code.dll");
   monoScriptRun();
   monoScriptCompile("code2", "code.dll");
   monoScriptRun();
   monoScriptCompile("code2", "code2.dll");
   monoScriptRun();
}
/******************************************************************************************************************/



The cs source (code1.cs) for the first ddl (compiled with mcs code1.cs 
-target:library):
/******************************************************************************************************************/
using System;
using System.Runtime.InteropServices;

public class ScriptEngine
{
[DllImport ("__Internal", EntryPoint="mono_report")]
static extern public void report (String str);
}

public class Script
{
   static void Main ()
   {
     ScriptEngine.report("Code 1");
   }
}
/******************************************************************************************************************/


The cs source(code2.cs) for the second ddl (compiled with mcs code2.cs 
-target:library):
/******************************************************************************************************************/
using System;
using System.Runtime.InteropServices;

public class ScriptEngine
{
[DllImport ("__Internal", EntryPoint="mono_report")]
static extern public void report (String str);
}



public class Script
{
   static void Main ()
   {
     ScriptEngine.report("Code 2");
   }
}
/******************************************************************************************************************/



On 13/02/2018 18:22, pierre wrote:
> Here a sample in one (dirty) c file...
> the file can be compiled easily, just adding the mono library and the 
> mono include path.
>
> the core is doing:
>
>       monoScriptCompile("code1", "code.dll");
>       monoScriptRun();
>       monoScriptCompile("code2", "code.dll");
>       monoScriptRun();
>       monoScriptCompile("code2", "code2.dll");
>       monoScriptRun();
>
> And the result on my system is:
>
>     Starting
>     Assembly Name: code1, Version=0.0.0.0, Culture=neutral,
>     PublicKeyToken=null
>     Code 1
>     Assembly Name: code1, Version=0.0.0.0, Culture=neutral,
>     PublicKeyToken=null
>     *Code 1*
>     Assembly Name: code2, Version=0.0.0.0, Culture=neutral,
>     PublicKeyToken=null
>     Code 2
>
> and as you can see, the code is not reloaded properly when the 
> reference is kept, but reloaded in the second case!!!
>
>
> On 13/02/2018 14:15, R Zaghi wrote:
>> Just for the record, I mean write it in a C# class and load that one 
>> class so you can handle everything in C# itself - much more robust.
>>
>>
>> On Tue, 13 Feb 2018 at 19:04, R Zaghi <rzaghi at mosaic3dx.com 
>> <mailto:rzaghi at mosaic3dx.com>> wrote:
>>
>>     If this is actually a problem with a library like mono then it
>>     sounds like a caching problem. If you build mono from source then
>>     it's easier to look into this...
>>
>>     Compare your code with this example. In the example, the .dll
>>     assembly is re-loaded in a loop. You can see the clean up portion
>>     and the shutdown or initialisation portions too:
>>
>>     https://github.com/ramin-zaghi/mono-embedding
>>
>>     Regarding how to compile code at runtime without a system() call,
>>     you can use CodeDom (look it up) to compile from files, or in a
>>     mono-specific way use Mono Compiler Service (e.g the Evaluator
>>     and CompilerContext classes - google them) which allow you to
>>     evaluate partial expressions/statements/etc.
>>
>>     I use both depending on situation and they work pretty well.
>>     Roslyn is apparently another option but let's not go there :)
>>
>>     R.
>>
>>
>>
>>
>>
>>     On Tue, 13 Feb 2018 at 16:17, pierre
>>     <pierre.saunier at ppmodeler.com
>>     <mailto:pierre.saunier at ppmodeler.com>> wrote:
>>
>>         Thanks for the answer.
>>
>>
>>         > you 100% sure the old files are all overwritten?
>>         Yes, I have checked the file time... and also included a
>>
>>             remove(fileName);
>>
>>         to be sure!
>>
>>
>>         >There are a couple of different ways to get compiled binary
>>         at runtime without a system() call
>>         Which ones?
>>
>>         I have tried something:
>>         calling mono_image_open_from_data_with_name and
>>         mono_assembly_load_from_full with a different file name on
>>         every compile and it is working!!!
>>
>>         so, the following code is not reloading properly:
>>
>>             monoEngine->fileName = strdup("code.dll");
>>
>>
>>             monoEngine->image =
>>             mono_image_open_from_data_with_name(data, dataLen,
>>             TRUE /* copy data */,
>>             &status,
>>             FALSE /* ref only */,
>>             monoEngine->fileName);
>>             if (status != MONO_IMAGE_OK || monoEngine->image == NULL)
>>             {
>>             }
>>             monoEngine->assembly =
>>             mono_assembly_load_from_full(monoEngine->image,
>>             monoEngine->fileName,
>>             &status, FALSE);
>>             if (status != MONO_IMAGE_OK || monoEngine->assembly == NULL)
>>             {
>>             }
>>
>>
>>         but, the same with a different file name on every run (only
>>         the monoEngine->fileName creation differ) is working:
>>
>>             static int version = 1;
>>             ...
>>
>>             sprintf(monoEngine->fileName, "code%03d.dll", version);
>>             version ++;
>>
>>
>>             monoEngine->image =
>>             mono_image_open_from_data_with_name(data, dataLen,
>>             TRUE /* copy data */,
>>             &status,
>>             FALSE /* ref only */,
>>             monoEngine->fileName);
>>             if (status != MONO_IMAGE_OK || monoEngine->image == NULL)
>>             {
>>             }
>>             monoEngine->assembly =
>>             mono_assembly_load_from_full(monoEngine->image,
>>             monoEngine->fileName,
>>             &status, FALSE);
>>             if (status != MONO_IMAGE_OK || monoEngine->assembly == NULL)
>>             {
>>             }
>>
>>         Is there a wait to be introduced after a mono_domain_unload?
>>         It is like doing mono_domain_unload,
>>         mono_image_open_from_data_with_name and
>>         mono_assembly_load_from_full with the same file name is
>>         detected and the unload is not performed....
>>
>>
>>         > This is more likely to be a problem outside of mono.
>>         I do agree... but I am running out of idea on why!!!
>>
>>
>>         and for mono_method_desc_search_in_image? is it bug?
>>
>>
>>         Pierre
>>
>>
>>         On 13/02/2018 07:15, R Zaghi wrote:
>>>         I think we need to know a bit more about what you are doing
>>>         in the code exactly but as a quick first guess if you are
>>>         recompiling using a system() call then are you 100% sure the
>>>         old files are all overwritten? There are a couple of
>>>         different ways to get compiled binary at runtime without a
>>>         system() call which I prefer but if you are using a system()
>>>         call then have you tried two separate calls with two
>>>         parallel binaries loaded as a start to debug your code?
>>>
>>>         This is more likely to be a problem outside of mono.
>>>
>>>         Ramin
>>>
>>>
>>>
>>>
>>>         Ramin Zaghi
>>>
>>>         *Mosaic3DX™ | User Interface Technology*
>>>         St John's Innovation Centre,
>>>         Cowley Road,
>>>         Cambridge,
>>>         CB4 0WS, UK*
>>>         *
>>>         *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>>>         *T*: +44 1223 421 311 <tel:+44%201223%20421311>
>>>         http://linkedin.com/in/raminzaghi
>>>
>>>
>>>
>>>         On Tue, 13 Feb 2018 at 01:27, pierre
>>>         <pierre.saunier at ppmodeler.com
>>>         <mailto:pierre.saunier at ppmodeler.com>> wrote:
>>>
>>>             Hi,
>>>
>>>             I am trying to embed mono... and I ran into a problem
>>>             with the code:
>>>
>>>                 monoMethodDesc = mono_method_desc_new("Script:Main", 0);
>>>                 method =
>>>                 mono_method_desc_search_in_image(monoMethodDesc,
>>>                 monoEngine->image);
>>>
>>>
>>>             It is returning a method on the cs code:
>>>
>>>                 public class Script
>>>                 {
>>>                   static public void Main ()
>>>                   {
>>>                 ScriptEngine.report("--Main Called ");
>>>                   }
>>>                 }
>>>
>>>
>>>             but it is also returning a method on the cs code (with
>>>             the wrong class name):
>>>
>>>                 public class Script*2*
>>>                 {
>>>                   static public void Main ()
>>>                   {
>>>                 ScriptEngine.report("--Main Called ");
>>>                   }
>>>                 }
>>>
>>>             while it should only return for:
>>>
>>>                 monoMethodDesc =
>>>                 mono_method_desc_new("Script2:Main", 0);
>>>
>>>
>>>             Am i doing something wrong or is this a bug? It seem
>>>             that mono_method_desc_search_in_image is returning a
>>>             value if the actual class name is starting with the
>>>             given  class name.... so, the same method is returned if
>>>             I look for "Script:Main" but the declared class is
>>>             "Script:Main", "Script_test:Main" or "Script2:Main"...
>>>
>>>             and a question:
>>>             is there a way to know if mono_domain_unload was
>>>             successful or not?
>>>
>>>             I am creating an app domain per script so that I can
>>>             recompile and reload the script at will...
>>>             I do not detect any error, but the new script seems not
>>>             to replace the old one...
>>>             Basically, I am doing:
>>>
>>>                 res = mono_domain_set(rootDomain, FALSE);
>>>                 mono_domain_unload(monoEngine->domain);
>>>                 monoEngine->domain =
>>>                 mono_domain_create_appdomain("ScriptEngine-sub", NULL);
>>>
>>>                 data = readFile(f, &dataLen);
>>>                 fclose(f);
>>>                 monoEngine->image =
>>>                 mono_image_open_from_data_with_name(data, dataLen,
>>>                 TRUE /* copy data */,
>>>                 &status,
>>>                 FALSE /* ref only */,
>>>                 monoEngine->fileName);
>>>                   free(data);
>>>                   if (status != MONO_IMAGE_OK || monoEngine->image
>>>                 == NULL)
>>>                   {
>>>                     return FALSE;
>>>                   }
>>>
>>>                     // load the assembly
>>>                   monoEngine->assembly =
>>>                 mono_assembly_load_from_full(monoEngine->image,
>>>                 monoEngine->fileName,
>>>                 &status, FALSE);
>>>                   if (status != MONO_IMAGE_OK ||
>>>                 monoEngine->assembly == NULL)
>>>                   {
>>>                 mono_image_close(monoEngine->image);
>>>                     return FALSE;
>>>                   }
>>>
>>>             but it does not seem to work. The code that runs is
>>>             always the first loaded one!!
>>>
>>>             I also added the following code to my engine:
>>>
>>>                 mono_trace_set_log_handler(monoLogCallback, NULL);
>>>                 mono_trace_set_print_handler(monoPrintCallback);
>>>                 mono_trace_set_printerr_handler(monoPrintCallback);
>>>                 mono_trace_set_level_string ("debug");
>>>
>>>
>>>             but it is reporting debug info only on the first run...
>>>             is there a way to having it working on every run?
>>>
>>>             Lastly, Is there a way to compile cs source without
>>>             launching a
>>>
>>>                 system("msc.code.cs -target:library");
>>>
>>>             thanks in advance
>>>
>>>             Pierre
>>>
>>>
>>>
>>>             _______________________________________________
>>>             Mono-list maillist  -Mono-list at lists.dot.net <mailto:Mono-list at lists.dot.net>
>>>             http://lists.dot.net/mailman/listinfo/mono-list
>>>
>>>             _______________________________________________
>>>             Mono-devel-list mailing list
>>>             Mono-devel-list at lists.dot.net
>>>             <mailto:Mono-devel-list at lists.dot.net>
>>>             http://lists.dot.net/mailman/listinfo/mono-devel-list
>>>
>>>         -- 
>>>
>>>
>>>
>>>         Ramin Zaghi
>>>
>>>         *Mosaic3DX™ | User Interface Technology*
>>>         St John's Innovation Centre,
>>>         Cowley Road,
>>>         Cambridge,
>>>         CB4 0WS, UK*
>>>         *
>>>         *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>>>         *T*: +44 1223 421 311
>>>         http://linkedin.com/in/raminzaghi
>>>
>>
>>     -- 
>>
>>
>>
>>     Ramin Zaghi
>>
>>     *Mosaic3DX™ | User Interface Technology*
>>     St John's Innovation Centre,
>>     Cowley Road,
>>     Cambridge,
>>     CB4 0WS, UK*
>>     *
>>     *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>>     *T*: +44 1223 421 311
>>     http://linkedin.com/in/raminzaghi
>>
>> -- 
>>
>>
>>
>> Ramin Zaghi
>>
>> *Mosaic3DX™ | User Interface Technology*
>> St John's Innovation Centre,
>> Cowley Road,
>> Cambridge,
>> CB4 0WS, UK*
>> *
>> *E*:**rzaghi at mosaic3dx.com <mailto:rzaghi at mosaic3dx.com>
>> *T*: +44 1223 421 311
>> http://linkedin.com/in/raminzaghi
>>
>

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.dot.net/pipermail/mono-devel-list/attachments/20180221/ec5f217f/attachment-0001.html>


More information about the Mono-devel-list mailing list