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

Basic implementation for testing of COM activation of a .NET class #19760

Merged

Conversation

AaronRobinsonMSFT
Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT commented Aug 30, 2018

This represents a partial implementation for dotnet/core-setup#4476

It current contains the following:

  • minimal SPCL API implementation - only for RegFree COM scenario
  • implementation of a host library for testing of activation scenarios
    • Note the CoreShim library is analogous to the CoreRun exe and only for testing
  • basic unit test of the SPCL API
  • simple e2e test using RegFree COM

cc @jkotas @jeffschwMSFT @luqunl

@AaronRobinsonMSFT AaronRobinsonMSFT added area-Interop * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) labels Aug 30, 2018
@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 3.0 milestone Aug 30, 2018
@@ -0,0 +1,275 @@
// Licensed to the .NET Foundation under one or more agreements.
Copy link
Member Author

Choose a reason for hiding this comment

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

cc @morganbr This is the library I am adding to enable hosting when starting in a native entry point. I have also written a mechanism that allows native EXEs to be launched as the test entry point.

Copy link
Member

Choose a reason for hiding this comment

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

Is this library a shipping code, or just a test-only code (like corerun.exe)?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is equivalent to corerun.exe - my understanding is that all the projects under the hosts/ are for testing and all real hosts should be contained in the core-setup repo. Am I missing the point of this directory?

@AaronRobinsonMSFT
Copy link
Member Author

Will be filling out the Native client to match the support already present in the .NET client. Once this is complete, the basics for managed activation will be defined. Additional investigations will can then be used to address the gaps in the proposal dotnet/core-setup#4476.

@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test all please

Console.WriteLine($"Searching for exe to launch in {workingDir}...");

string startExe = string.Empty;
foreach (string exeMaybe in Directory.EnumerateFiles(workingDir, "*.exe"))
Copy link
Member Author

Choose a reason for hiding this comment

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

Need to filter out the launch module itself.

assemPathLocal = Path.ChangeExtension(assemPath, ".dll");
}

assem = Assembly.LoadFrom(assemPathLocal);
Copy link
Member

Choose a reason for hiding this comment

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

Loading a bunch of assemblies using LoadFrom is asking for problems. The dependencies of these assemblies may not be resolved correctly, and the app may not expect all of them to be loaded.

And then loading all types in these assemblies using GetTypes is performance trap.

Is this temporary hack?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes. This is purely for satisfying test bring up. Once the API surface area is signed off, we need to do a lot more here. Figure out ALC and such along with probably trying to parse metadata instead of loading the assembly itself. Perhaps using Assembly.ReflectionOnlyLoadFrom() in the long run?

Copy link
Member Author

Choose a reason for hiding this comment

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

I will be looking to @vitek-karas to keep my honest here :-) Is the Assembly.ReflectionOnlyLoadFrom() the right API to interrogate the types in an assembly without perturbing the running CLR instance?

Copy link
Member

Choose a reason for hiding this comment

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

ReflectionOnlyLoadFrom is not supported in .NET Core.

Is there no way to avoid the linear search to find the right type? I think we should have the type name in some manifest to avoid the linear search.

Copy link
Member Author

Choose a reason for hiding this comment

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

Is there no way to avoid the linear search to find the right type? I think we should have the type name in some manifest to avoid the linear search.

There are options I still need to explore, but in this case that is really secondary. The real issue is finding which assembly in the activation context is the assembly with the type in question. In the example there is one assembly, but conceivably there could be N assemblies and each need to be queried to determine the one that provides the type.

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess the better question here is what is the appropriate way to read an assemblies metadata without loading the assembly into the current CLR?

Copy link
Member

Choose a reason for hiding this comment

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

@AaronRobinsonMSFT
Copy link
Member Author

cc @vitek-karas This PR represents the broad strokes of the design described in dotnet/core-setup#4476

{
private readonly Guid classId;
private readonly Type classType;
private readonly Assembly classAssembly;
Copy link
Member

Choose a reason for hiding this comment

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

There's no need to store the assembly here - if nothing else it can be asked on the type, but the class should not need to know the assembly to do anything anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done

@AaronRobinsonMSFT AaronRobinsonMSFT changed the title [WIP] Rough outline of managed implementation for COM activation in SPCL [WIP] Basic implementation for testing of COM activation of a .NET class Sep 5, 2018
@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test all please

@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot help

@dotnet-bot
Copy link

Welcome to the dotnet/coreclr Repository

The following is a list of valid commands on this PR. To invoke a command, comment the indicated phrase on the PR

The following commands are valid for all PRs and repositories.

Click to expand
Comment Phrase Action
@dotnet-bot test this please Re-run all legs. Use sparingly
@dotnet-bot test ci please Generates (but does not run) jobs based on changes to the groovy job definitions in this branch
@dotnet-bot help Print this help message

The following jobs are launched by default for each PR against dotnet/coreclr:master.

Click to expand
Comment Phrase Job Launched
@dotnet-bot test Linux-musl x64 Debug Build Linux-musl x64 Debug Build

The following optional jobs are available in PRs against dotnet/coreclr:master.

Click to expand
Comment Phrase Job Launched
@dotnet-bot test Outerloop Linux-musl x64 Debug Build Queues Outerloop Linux-musl x64 Debug Build
@dotnet-bot test Linux-musl x64 Release Build Queues Linux-musl x64 Release Build
@dotnet-bot test Outerloop Linux-musl x64 Release Build Queues Outerloop Linux-musl x64 Release Build

Have a nice day!

@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test ci please

@dotnet-bot
Copy link

Welcome to the dotnet/coreclr Perf help

The following is a list of valid commands on this PR. To invoke a command, comment the indicated phrase on the PR

The following commands are valid for all PRs and repositories.

Click to expand
Comment Phrase Action
@dotnet-bot test this please Re-run all legs. Use sparingly
@dotnet-bot test ci please Generates (but does not run) jobs based on changes to the groovy job definitions in this branch
@dotnet-bot help Print this help message

The following jobs are launched by default for each PR against dotnet/coreclr:master.

Click to expand
Comment Phrase Job Launched
@dotnet-bot test \QWindows_NT x64 full_opt ryujit CoreCLR Perf Tests Correctness\E Windows_NT x64 full_opt ryujit CoreCLR Perf Tests Correctness
@dotnet-bot test \QWindows_NT x64 min_opt ryujit CoreCLR Perf Tests Correctness\E Windows_NT x64 min_opt ryujit CoreCLR Perf Tests Correctness
@dotnet-bot test \QWindows_NT x86 full_opt ryujit CoreCLR Perf Tests Correctness\E Windows_NT x86 full_opt ryujit CoreCLR Perf Tests Correctness
@dotnet-bot test \QWindows_NT x86 min_opt ryujit CoreCLR Perf Tests Correctness\E Windows_NT x86 min_opt ryujit CoreCLR Perf Tests Correctness

The following optional jobs are available in PRs against dotnet/coreclr:master.

Click to expand
Comment Phrase Job Launched
@dotnet-bot test Windows_NT x64 illink Queues Windows_NT x64 full_opt ryujit IlLink Tests
@dotnet-bot test linux perf flow Queues Linux Perf Test Flow
@dotnet-bot test Windows_NT x64 perf Queues Windows_NT x64 full_opt ryujit CoreCLR Perf Tests
@dotnet-bot test Windows_NT x64 min_opts perf Queues Windows_NT x64 min_opt ryujit CoreCLR Perf Tests
@dotnet-bot test Windows_NT x86 perf Queues Windows_NT x86 full_opt ryujit CoreCLR Perf Tests
@dotnet-bot test Windows_NT x86 min_opts perf Queues Windows_NT x86 min_opt ryujit CoreCLR Perf Tests
@dotnet-bot test Windows_NT x64 perf scenarios Queues Windows_NT x64 full_opt ryujit Performance Scenarios Tests
@dotnet-bot test Windows_NT x64 min_opts perf scenarios Queues Windows_NT x64 min_opt ryujit Performance Scenarios Tests
@dotnet-bot test Windows_NT x64 perf scenarios Queues Windows_NT x64 tiered ryujit Performance Scenarios Tests
@dotnet-bot test Windows_NT x86 perf scenarios Queues Windows_NT x86 full_opt ryujit Performance Scenarios Tests
@dotnet-bot test Windows_NT x86 min_opts perf scenarios Queues Windows_NT x86 min_opt ryujit Performance Scenarios Tests
@dotnet-bot test Windows_NT x86 perf scenarios Queues Windows_NT x86 tiered ryujit Performance Scenarios Tests
@dotnet-bot test linux throughput flow Queues Linux arm Throughput Perf Test Flow
@dotnet-bot test linux throughput flow Queues Linux x64 Throughput Perf Test Flow
@dotnet-bot test Windows_NT x64 throughput Queues Windows_NT x64 full_opt ryujit nopgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x64 nopgo throughput Queues Windows_NT x64 full_opt ryujit pgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x64 min_opts throughput Queues Windows_NT x64 min_opt ryujit nopgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x64 min_opts nopgo throughput Queues Windows_NT x64 min_opt ryujit pgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x86 throughput Queues Windows_NT x86 full_opt ryujit nopgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x86 nopgo throughput Queues Windows_NT x86 full_opt ryujit pgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x86 min_opts throughput Queues Windows_NT x86 min_opt ryujit nopgo CoreCLR Throughput Perf Tests
@dotnet-bot test Windows_NT x86 min_opts nopgo throughput Queues Windows_NT x86 min_opt ryujit pgo CoreCLR Throughput Perf Tests

Have a nice day!

@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test this please

@AaronRobinsonMSFT AaronRobinsonMSFT changed the title [WIP] Basic implementation for testing of COM activation of a .NET class Basic implementation for testing of COM activation of a .NET class Sep 5, 2018
@AaronRobinsonMSFT
Copy link
Member Author

AaronRobinsonMSFT commented Sep 5, 2018

@jkotas @luqunl @vitek-karas @jeffschwMSFT Any additional concerns/comments on this?

std::wstring pathLocal;
if (path == nullptr)
{
pathLocal = GetEnvVar(W("CORE_ROOT"));
Copy link

Choose a reason for hiding this comment

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

Is this temporary? If you intend for it to be permanent, we should talk about it.

Copy link
Member Author

Choose a reason for hiding this comment

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

This is what we want for testing because that is where coreclr is consumed during testing. What are you thinking it should be?

Copy link

Choose a reason for hiding this comment

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

If this is test code only, no concerns.


pathLocal.append(W("\\coreclr.dll"));

AutoModule hmod = ::LoadLibraryExW(pathLocal.c_str() , nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
Copy link

Choose a reason for hiding this comment

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

We don't want the full behavior of altered_search_path, we just want to search the directory we asked for. I think that would be LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR. Note that using that flag requires first probing for the AddDllDirectory API similar to:

coreclr/src/vm/dllimport.cpp

Lines 6524 to 6532 in 246ae78

// Check if the OS supports the new secure LoadLibraryEx flags introduced in KB2533623
HMODULE hMod = CLRGetModuleHandle(WINDOWS_KERNEL32_DLLNAME_W);
_ASSERTE(hMod != NULL);
if (GetProcAddress(hMod, "AddDllDirectory") != NULL)
{
// The AddDllDirectory export was added in KB2533623 together with the new flag support
s_fSecureLoadLibrarySupported = true;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

I can change to that, but I want to be clear here this shim is only for the testing environment. There are way bigger issues in here if this was going to be used as the actual product shim.

Copy link

Choose a reason for hiding this comment

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

If this is just testing, I'm not concerned. You might still want LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR to avoid accidentally picking up stray CoreCLRs from your path or working directory though.

Copy link
Member Author

Choose a reason for hiding this comment

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

That is a good suggestion and i will update it. Thanks.

std::wstring w_dirLocal;
if (dir == nullptr)
{
w_dirLocal = GetEnvVar(W("CORE_ROOT"));
Copy link

Choose a reason for hiding this comment

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

Same question about this variable.

@vitek-karas
Copy link
Member

The test hosts are fine (test code for now, so no trouble). But the managed part in System.Private.* should be product quality. Currently there are several todos there:

  • Finding the type by GUID - loading the assemblies, linear search and so on.
  • Logging
  • Registry interaction

I think we should have at least understanding what are the plans on these.

@AaronRobinsonMSFT
Copy link
Member Author

AaronRobinsonMSFT commented Sep 6, 2018

Finding the type by GUID - loading the assemblies, linear search and so on.

This is going to be done through metadata, but at the moment isn't needed for testing. There are several outstanding questions here, but the API contract is sound and is basically the point of the PR at present. A side note here, is that we have a basic trade-off here. Do a linear search, create yet another parser in native code (i.e. XML), or move activation into an external NuGet library. All are valid options, but have significantly different costs. At present the linear search is enough for testing and isn't exposed and can be improved upon behind the present interface.

Logging

I have stubs for logging and will fill them in as soon as I hear of an option. Rumor has it, you are going to be providing a design doc/proposal soon? 😄

Registry interaction

I will add a stub for this. My plan is to handle all registry access in native instead of relying on the managed API. The stub I will add will be a QCall into coreclr.dll and it will return the registry details. The intent of doing the work in native is that it will keep registry access in a location that is quick to implement and avoid creating additional managed library dependencies.

@jkotas
Copy link
Member

jkotas commented Sep 6, 2018

it will keep registry access in a location that is quick to implement and avoid creating additional managed library dependencies.

The managed registry APIs are available in CoreLib. (I do not have a problem with doing this via QCall ... but just want to make sure you will do it for the right reason.)

private static bool IsLoggingEnabled()
{
#if DEBUG
return true;
Copy link
Member

Choose a reason for hiding this comment

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

We should not be doing this logging by default to debug output in debug builds. It is annoying to keep looking at somebody else's logs in debug output that you do not care about.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sounds good. I think the enable/disable logic is something I need guidance on, but is really apart of the general logging/diagnostic approach. @vitek-karas any thoughts on how we would like to enable disable this?

Copy link
Member

Choose a reason for hiding this comment

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

If it's only for development of this thing for now, then a compile time define would be enough.
If we think we need this a bit broadly... the answer depends on the discussion about logging below. If we're going to use the same infra as binder, then you'll get it for free.
If not, then you could use EventSource directly.

@AaronRobinsonMSFT
Copy link
Member Author

The managed registry APIs are available in CoreLib.

@jkotas w00t! Thanks for letting me know. I was just trying to avoid bringing in more managed dependencies, but if this already exists, I will investigate this approach. Another factor in my natice decision was to consolidate registry access logic. If I can remove the existing native registry logic, I will do it all in managed, otherwise back to QCall 😄

@vitek-karas
Copy link
Member

@AaronRobinsonMSFT RE logging
I'll have to think about this - I didn't realize that there might be a connection between what I'm doing for the binder and this.
Really the only added value of the tracing infra I'm working on is related to the binder. So if this code doesn't call into the binder, or is not related to it in any way, there would be little value in using the same thing (it would probably just bring in confusion).

@AaronRobinsonMSFT AaronRobinsonMSFT removed the * NO MERGE * The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 7, 2018
@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test
@dotnet-bot test Ubuntu x64 Checked Innerloop Build and Test (Jit - TieredCompilation=0)

@AaronRobinsonMSFT
Copy link
Member Author

@dotnet-bot test Ubuntu x64 Checked CoreFX Tests

…launch a local EXE.

This is useful when the test scenario's entry point is native.
Add property to exclude default assertion file
Display exe ExeLaunchProgram class is going to launch
Consume the ExeLauncherProgram.cs file as a wrapper for the native test
…there

is no way to determine that is the platform.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants