-
Notifications
You must be signed in to change notification settings - Fork 26
Support pythonnet for AppDomain #78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
Very nice, thank you! I'll fix the CI on master s.t. you can rebase on that. |
When using domain.Load for an assembly, the assembly resolution rules are awkward Even if the full path is given to the AssemblyName, when the domain tries to load the assembly, it does not use that context and tries to resolve the assembly using normal domain resolution rules, which would require an assembly resolver to be installed. However, the assembly resolver that is actually used at runtime is the one installed to the main appdomain. This prevents a library like Python.Runtime.dll (used by pythonnet) which is not installed to the application base directory to be loaded by clr_loader. To fix this issue, the assembly resolver of the main appdomain is lazily extending to include paths needed for libraries passed into GetFunction, and GetFunction internally uses AppDomain.DoCallBack() to marshal the function pointer inside the target app domain, using global domain data to access the function pointer and return it to the user of clr_loader.
e3b043b
to
f58e574
Compare
get | ||
{ | ||
string codeBase = Assembly.GetExecutingAssembly().CodeBase; | ||
UriBuilder uri = new UriBuilder(codeBase); | ||
string path = Uri.UnescapeDataString(uri.Path); | ||
return Path.GetDirectoryName(path); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a comment here that this contraption is needed in case the DLL was shadow-copied (otherwise one could simply use .Location
). I don't think this can happen with how we load it, but it doesn't hurt to pre-empt this issue.
|
||
_delegates[key] = result; | ||
Domain.DoCallBack(new CrossAppDomainDelegate(DomainSetup.StoreFunctorFromDomainData)); | ||
result = (IntPtr)Domain.GetData("_thisFunctor"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- It might make sense to unset this after it is read and check the value here
- This is not at all thread-safe. The simplest approach is probably to lock here in C#.
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath).Name; | ||
var assembly = domain.Load(AssemblyName.GetAssemblyName(assemblyPath)); | ||
var type = assembly.GetType(typeName, throwOnError: true); | ||
var deleg = Delegate.CreateDelegate(typeof(EntryPoint), type, function); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You must ensure that this delegate stays alive, e.g. by attaching it to the AppDomain
object via SetData
.
Related to pythonnet/pythonnet#2053
Fixes #53
When using domain.Load for an assembly, the assembly resolution rules are awkward Even if the full path is given to the AssemblyName, when the domain tries to load the assembly, it does not use that context and tries to resolve the assembly using normal domain resolution rules, which would require an assembly resolver to be installed. However, the assembly resolver that is actually used at runtime is the one installed to the main appdomain.
This prevents a library like Python.Runtime.dll (used by pythonnet) which is not installed to the application base directory to be loaded by clr_loader.
It is possible for an assembly to run code in another appdomain (using DoCallBack), but only if that assembly is reachable from the BaseDirectory. ClrLoader was not reachable because the base directory was hardcoded to that which contained python.exe, and ClrLoader.dll is not found there. I fixed this by making the folder which contains ClrLoader.dll the BaseDirectory for app domains created by ClrLoader.
To fix this issue, the assembly resolver of the main appdomain is lazily extending to include paths needed for libraries passed into GetFunction, and GetFunction internally uses AppDomain.DoCallBack() to marshal the function pointer inside the target app domain, using global domain data to access the function pointer and return it to the user of clr_loader.
With these changes, the following block:
will print "Python"