Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Add Per-assembly Load Native Library callbacks #21555

Merged
merged 2 commits into from
Jan 18, 2019

Conversation

swaroop-sridhar
Copy link

@swaroop-sridhar swaroop-sridhar commented Dec 15, 2018

This Change implements the Native Library resolution
Call-backs proposed in dotnet/corefx#32015

@@ -32,6 +32,11 @@ public static partial class Marshal
internal static Guid IID_IUnknown = new Guid("00000000-0000-0000-C000-000000000046");
#endif //FEATURE_COMINTEROP

static Marshal()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explicit static constructor is bad for performance and in this case also causes an infinite loop during startup. Maybe nativeDllResolveMap should be lazy-initialized on first use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

@jkotas
Copy link
Member

jkotas commented Dec 15, 2018

This API is not yet approved, and the API contracts in CoreFX will not be added until the API approval is complete

That's not the usual process...

/// Therefore, this table uses weak assembly pointers to indirectly achieve
/// similar behavior.
/// </summary>
public static ConditionalWeakTable<Assembly, Func<string, Assembly, DllImportSearchPath?, IntPtr>> nativeDllResolveMap;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

internal static IntPtr LoadLibraryCallbackStub(string libraryName, Assembly assembly,
bool hasDllImportSearchPathFlags, uint dllImportSearchPathFlags)
{
Func<string, Assembly, DllImportSearchPath?, IntPtr> callBack;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callback is one word. B should be lowercase.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(multiple places)

@@ -6280,23 +6280,32 @@ INT_PTR NDirect::GetNativeLibraryExport(NATIVE_LIBRARY_HANDLE handle, LPCWSTR sy
return address;
}

#ifndef PLATFORM_UNIX
BOOL IsWindowsAPI(PCWSTR wszLibName)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not return whether the name is Windows API. It returns whether the name is Windows API set. Change the name to IsWindowsAPISet ?

NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
{
#ifndef PLATFORM_UNIX
if (IsWindowsAPI(wszLibName))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the rationale behind blocking this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only concern with not blocking this is the scenario where we deploy Windows API sets on downlevel Windows SKUs (i.e. Windows 7). The issue here would be why are we looking in the system if they are app local? This is largely a hedge about not trusting Windows to deploy API sets that are guaranteed backwards compatible. I think that is a fair assumption the API sets will always be backwards compat, but note that the behavior will be different on different platforms if we rely on a system API set in some cases and our applocal version of the API sets in others.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When it comes to Windows 7, API sets are incompatible mess. Note that there are no officially shipped API sets for Windows 7, except for the few that support universal CRT. We learned this hard-way during the .NET Core 1.0 days when we were using API sets everywhere, only to find out that there is no way to make things work well with Windows 7 if you do that.

If somebody wants to resolve API sets on their own to make stuff work, we should not stand in the way.

@@ -566,6 +566,7 @@ enum DispatchCallSimpleFlags
#define STRINGREF_TO_ARGHOLDER(x) (LPVOID)STRINGREFToObject(x)
#define PTR_TO_ARGHOLDER(x) (LPVOID)x
#define DWORD_TO_ARGHOLDER(x) (LPVOID)(SIZE_T)x
#define BOOL_TO_ARGHOLDER(x) DWORD_TO_ARGHOLDER(x)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not quite right. Assuming the managed argument is going to be bool, this value should be normalized, e.g. using !!


Assembly* pAssembly = pMD->GetMethodTable()->GetAssembly();
protect.libNameRef = StringObject::NewString(wszLibName);
protect.assemblyRef = pAssembly->GetExposedObject();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has GC hole. You are assigning object references without them being protected.

This exact situation is described in "Your first GC hole" in https://github.com/dotnet/coreclr/blob/master/Documentation/coding-guidelines/clr-code-guide.md#2.1.2.

@@ -6362,6 +6371,55 @@ NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaHost(NDirectMethodDesc * pMD,
return (NATIVE_LIBRARY_HANDLE)hmod;
}

NATIVE_LIBRARY_HANDLE NDirect::LoadLibraryModuleViaCallBack(NDirectMethodDesc * pMD, LPCWSTR wszLibName)
{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add contracts to all new methods.

return false;
}

nativeDllResolveMap.Add(assembly, callBack);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has race condition: if the method is called from multiple threads on same assembly, we may end up throwing here.

/// and returns
/// - The handle to the loaded native library (on success) or null (on failure)
/// The parameters on this callback are such that they can be directly passed to
/// Marhall.LoadLibrary(libraryName, assembly, dllImportSearchPath) to approximately achieve
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/// Marhall.LoadLibrary(libraryName, assembly, dllImportSearchPath) to approximately achieve
/// Marhal.LoadLibrary(libraryName, assembly, dllImportSearchPath) to approximately achieve

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Marshal ?

@swaroop-sridhar
Copy link
Author

@jkotas @AaronRobinsonMSFT @pentp I have addressed your feedback in the new commit.
NativeLibrary APIs are approved. The API now lives in the NativeLibrary class instead of Marshal

@swaroop-sridhar swaroop-sridhar force-pushed the cb branch 5 times, most recently from 886fc14 to f84249e Compare January 16, 2019 23:41
@swaroop-sridhar
Copy link
Author

@dotnet-bot test Windows_NT x64 Release CoreFX Tests
@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test

@swaroop-sridhar
Copy link
Author

The "OSX10.12 x64 Checked Innerloop Build and Test" failure seems unrelated. It is failing on all runs.

This Change implements the Native Library resolution
Call-backs proposed in https://github.com/dotnet/corefx/issues/32015
@jkotas
Copy link
Member

jkotas commented Jan 17, 2019

Looks good to me, but it can use a second pair of eyes. I have looked at this too many times...

@AaronRobinsonMSFT
Copy link
Member

@jkotas I will take another look.

src/vm/dllimport.h Outdated Show resolved Hide resolved
src/vm/dllimport.h Outdated Show resolved Hide resolved
src/vm/dllimport.cpp Outdated Show resolved Hide resolved
src/vm/dllimport.cpp Show resolved Hide resolved
src/vm/dllimport.cpp Show resolved Hide resolved
src/vm/dllimport.cpp Outdated Show resolved Hide resolved
src/vm/interoputil.cpp Outdated Show resolved Hide resolved
@swaroop-sridhar
Copy link
Author

Thanks for the feedback @AaronRobinsonMSFT.
I've addressed it in a306c61 -- made the changes you've suggested, except as noted in the comments.

@swaroop-sridhar
Copy link
Author

@dotnet-bot test Ubuntu arm Cross Checked no_tiered_compilation_innerloop Build and Test
@dotnet-bot test OSX10.12 x64 Checked Innerloop Build and Test

@swaroop-sridhar swaroop-sridhar merged commit 732f892 into dotnet:master Jan 18, 2019
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Add Per-assembly Load Native Library callbacks

This Change implements the Native Library resolution
Call-backs proposed in https://github.com/dotnet/corefx/issues/32015

Commit migrated from dotnet/coreclr@732f892
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants