Skip to content
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

Implement hdt_get_function_pointer #37696

Merged
merged 2 commits into from
Jun 16, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,55 @@ public static unsafe int LoadAssemblyAndGetFunctionPointer(IntPtr assemblyPathNa
return 0;
}

/// <summary>
/// Native hosting entry point for creating a native delegate
/// </summary>
/// <param name="typeNameNative">Assembly qualified type name</param>
/// <param name="methodNameNative">Public static method name compatible with delegateType</param>
/// <param name="delegateTypeNative">Assembly qualified delegate type name</param>
/// <param name="loadContext">Extensibility parameter (currently unused)</param>
/// <param name="reserved">Extensibility parameter (currently unused)</param>
/// <param name="functionHandle">Pointer where to store the function pointer result</param>
[UnmanagedCallersOnly]
public static unsafe int GetFunctionPointer(IntPtr typeNameNative,
IntPtr methodNameNative,
IntPtr delegateTypeNative,
IntPtr loadContext,
IntPtr reserved,
IntPtr functionHandle)
{
try
{
// Validate all parameters first.
string typeName = MarshalToString(typeNameNative, nameof(typeNameNative));
string methodName = MarshalToString(methodNameNative, nameof(methodNameNative));

if (loadContext != IntPtr.Zero)
{
throw new ArgumentOutOfRangeException(nameof(loadContext));
}

if (reserved != IntPtr.Zero)
{
throw new ArgumentOutOfRangeException(nameof(reserved));
}

if (functionHandle == IntPtr.Zero)
{
throw new ArgumentNullException(nameof(functionHandle));
}

// Create the function pointer.
*(IntPtr*)functionHandle = InternalGetFunctionPointer(AssemblyLoadContext.Default, typeName, methodName, delegateTypeNative);
}
catch (Exception e)
{
return e.HResult;
}

return 0;
}

private static IsolatedComponentLoadContext GetIsolatedComponentLoadContext(string assemblyPath)
{
IsolatedComponentLoadContext? alc;
Expand Down
10 changes: 10 additions & 0 deletions src/installer/corehost/cli/coreclr_delegates.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,14 @@ typedef int (CORECLR_DELEGATE_CALLTYPE *load_assembly_and_get_function_pointer_f
// Signature of delegate returned by load_assembly_and_get_function_pointer_fn when delegate_type_name == null (default)
typedef int (CORECLR_DELEGATE_CALLTYPE *component_entry_point_fn)(void *arg, int32_t arg_size_in_bytes);

typedef int (CORECLR_DELEGATE_CALLTYPE *get_function_pointer_fn)(
const char_t *type_name /* Assembly qualified type name */,
const char_t *method_name /* Public static method name compatible with delegateType */,
const char_t *delegate_type_name /* Assembly qualified delegate type name or null,
or UNMANAGEDCALLERSONLY_METHOD if the method is marked with
the UnmanagedCallersOnlyAttribute. */,
void *load_context /* Extensibility parameter (currently unused and must be 0) */,
void *reserved /* Extensibility parameter (currently unused and must be 0) */,
/*out*/ void **delegate /* Pointer where to store the function pointer result */);

#endif // __CORECLR_DELEGATES_H__
1 change: 1 addition & 0 deletions src/installer/corehost/cli/corehost_context_contract.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum class coreclr_delegate_type
com_register,
com_unregister,
load_assembly_and_get_function_pointer,
get_function_pointer,

__last, // Sentinel value for determining the last known delegate type
};
Expand Down
3 changes: 3 additions & 0 deletions src/installer/corehost/cli/fxr/hostfxr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,8 @@ namespace
return coreclr_delegate_type::com_unregister;
case hostfxr_delegate_type::hdt_load_assembly_and_get_function_pointer:
return coreclr_delegate_type::load_assembly_and_get_function_pointer;
case hostfxr_delegate_type::hdt_get_function_pointer:
return coreclr_delegate_type::get_function_pointer;
}
return coreclr_delegate_type::invalid;
}
Expand All @@ -641,6 +643,7 @@ namespace
// If the host_context_handle was initialized using hostfxr_initialize_for_dotnet_command_line,
// then only the following delegate types are currently supported:
// hdt_load_assembly_and_get_function_pointer
// hdt_get_function_pointer
//
SHARED_API int32_t HOSTFXR_CALLTYPE hostfxr_get_runtime_delegate(
const hostfxr_handle host_context_handle,
Expand Down
3 changes: 2 additions & 1 deletion src/installer/corehost/cli/hostfxr.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ enum hostfxr_delegate_type
hdt_winrt_activation,
hdt_com_register,
hdt_com_unregister,
hdt_load_assembly_and_get_function_pointer
hdt_load_assembly_and_get_function_pointer,
hdt_get_function_pointer,
};

typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_main_fn)(const int argc, const char_t **argv);
Expand Down
6 changes: 6 additions & 0 deletions src/installer/corehost/cli/hostpolicy/hostpolicy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,12 @@ namespace
"Internal.Runtime.InteropServices.ComponentActivator",
"LoadAssemblyAndGetFunctionPointer",
delegate);
case coreclr_delegate_type::get_function_pointer:
return coreclr->create_delegate(
"System.Private.CoreLib",
"Internal.Runtime.InteropServices.ComponentActivator",
"GetFunctionPointer",
delegate);
default:
return StatusCode::LibHostInvalidArgs;
}
Expand Down
148 changes: 148 additions & 0 deletions src/installer/corehost/cli/test/nativehost/host_context_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,46 @@ namespace
return rc;
}

int call_get_function_pointer_flavour(
get_function_pointer_fn delegate,
const pal::char_t *type_name,
const pal::char_t *method_name,
const pal::char_t *log_prefix,
pal::stringstream_t &test_output)
{
const pal::char_t *delegate_name = nullptr;
pal::string_t method_name_local{ method_name };
if (pal::string_t::npos != method_name_local.find(_X("Unmanaged")))
delegate_name = UNMANAGEDCALLERSONLY_METHOD;

test_output << log_prefix << _X("calling get_function_pointer(\"")
<< type_name << _X("\", \"")
<< method_name << _X("\", ")
<< to_printable_delegate_name(delegate_name) << _X(", ")
<< _X("nullptr, nullptr, &functionPointerDelegate)")
<< std::endl;

component_entry_point_fn functionPointerDelegate = nullptr;
int rc = delegate(type_name,
method_name,
delegate_name,
nullptr /* reserved */,
nullptr /* reserved */,
(void **)&functionPointerDelegate);

if (rc != StatusCode::Success)
{
test_output << log_prefix << _X("get_function_pointer failed: ") << std::hex << std::showbase << rc << std::endl;
}
else
{
test_output << log_prefix << _X("get_function_pointer succeeded: ") << std::hex << std::showbase << rc << std::endl;
rc = call_delegate_with_try_except(functionPointerDelegate, method_name, log_prefix, test_output);
}

return rc;
}

bool component_load_assembly_and_get_function_pointer_test(
const hostfxr_exports &hostfxr,
const pal::char_t *config_path,
Expand Down Expand Up @@ -380,6 +420,91 @@ namespace

return rc == StatusCode::Success && rcClose == StatusCode::Success;
}

bool component_get_function_pointer_test(
const hostfxr_exports &hostfxr,
const pal::char_t *config_path,
int argc,
const pal::char_t *argv[],
const pal::char_t *log_prefix,
pal::stringstream_t &test_output)
{
hostfxr_handle handle;
int rc = hostfxr.init_config(config_path, nullptr, &handle);
if (!STATUS_CODE_SUCCEEDED(rc))
{
test_output << log_prefix << _X("hostfxr_initialize_for_runtime_config failed: ") << std::hex << std::showbase << rc << std::endl;
return false;
}

test_output << log_prefix << _X("hostfxr_initialize_for_runtime_config succeeded: ") << std::hex << std::showbase << rc << std::endl;

for (int i = 0; i <= argc - 2; i += 2)
{
const pal::char_t *type_name = argv[i];
const pal::char_t *method_name = argv[i + 1];

get_function_pointer_fn delegate = nullptr;
rc = hostfxr.get_delegate(handle, hostfxr_delegate_type::hdt_get_function_pointer, (void **)&delegate);
if (rc != StatusCode::Success)
{
test_output << log_prefix << _X("hostfxr_get_runtime_delegate failed: ") << std::hex << std::showbase << rc << std::endl;
}
else
{
test_output << log_prefix << _X("hostfxr_get_runtime_delegate succeeded: ") << std::hex << std::showbase << rc << std::endl;
rc = call_get_function_pointer_flavour(delegate, type_name, method_name, log_prefix, test_output);
}
}

int rcClose = hostfxr.close(handle);
if (rcClose != StatusCode::Success)
test_output << log_prefix << _X("hostfxr_close failed: ") << std::hex << std::showbase << rc << std::endl;

return rc == StatusCode::Success && rcClose == StatusCode::Success;
}

bool app_get_function_pointer_test(
const hostfxr_exports &hostfxr,
int argc,
const pal::char_t *argv[],
const pal::char_t *log_prefix,
pal::stringstream_t &test_output)
{
hostfxr_handle handle;
int rc = hostfxr.init_command_line(argc, argv, nullptr, &handle);
if (rc != StatusCode::Success)
{
test_output << _X("hostfxr_initialize_for_command_line failed: ") << std::hex << std::showbase << rc << std::endl;
return false;
}

test_output << log_prefix << _X("hostfxr_initialize_for_command_line succeeded: ") << std::hex << std::showbase << rc << std::endl;

for (int i = 1; i <= argc - 2; i += 2)
{
const pal::char_t *type_name = argv[i];
const pal::char_t *method_name = argv[i + 1];

get_function_pointer_fn delegate = nullptr;
rc = hostfxr.get_delegate(handle, hostfxr_delegate_type::hdt_get_function_pointer, (void **)&delegate);
if (rc != StatusCode::Success)
{
test_output << log_prefix << _X("hostfxr_get_runtime_delegate failed: ") << std::hex << std::showbase << rc << std::endl;
}
else
{
test_output << log_prefix << _X("hostfxr_get_runtime_delegate succeeded: ") << std::hex << std::showbase << rc << std::endl;
rc = call_get_function_pointer_flavour(delegate, type_name, method_name, log_prefix, test_output);
}
}

int rcClose = hostfxr.close(handle);
if (rcClose != StatusCode::Success)
test_output << log_prefix << _X("hostfxr_close failed: ") << std::hex << std::showbase << rc << std::endl;

return rc == StatusCode::Success && rcClose == StatusCode::Success;
}
}

host_context_test::check_properties host_context_test::check_properties_from_string(const pal::char_t *str)
Expand Down Expand Up @@ -625,3 +750,26 @@ bool host_context_test::app_load_assembly_and_get_function_pointer(

return app_load_assembly_and_get_function_pointer_test(hostfxr, argc, argv, config_log_prefix, test_output);
}

bool host_context_test::component_get_function_pointer(
const pal::string_t &hostfxr_path,
const pal::char_t *config_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output)
{
hostfxr_exports hostfxr{ hostfxr_path };

return component_get_function_pointer_test(hostfxr, config_path, argc, argv, config_log_prefix, test_output);
}

bool host_context_test::app_get_function_pointer(
const pal::string_t &hostfxr_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output)
{
hostfxr_exports hostfxr{ hostfxr_path };

return app_get_function_pointer_test(hostfxr, argc, argv, config_log_prefix, test_output);
}
11 changes: 11 additions & 0 deletions src/installer/corehost/cli/test/nativehost/host_context_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,15 @@ namespace host_context_test
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output);
bool component_get_function_pointer(
const pal::string_t &hostfxr_path,
const pal::char_t *config_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output);
bool app_get_function_pointer(
const pal::string_t &hostfxr_path,
int argc,
const pal::char_t *argv[],
pal::stringstream_t &test_output);
}
51 changes: 51 additions & 0 deletions src/installer/corehost/cli/test/nativehost/nativehost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,57 @@ int main(const int argc, const pal::char_t *argv[])
std::cout << tostr(test_output.str()).data() << std::endl;
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
else if (pal::strcmp(command, _X("component_get_function_pointer")) == 0)
{
// args: ... <hostfxr_path> <app_or_config_path> <type_name> <method_name> [<type_name> <method_name>...]
const int min_argc = 4;
if (argc < min_argc + 2)
{
std::cerr << "Invalid arguments" << std::endl;
return -1;
}

const pal::string_t hostfxr_path = argv[2];
const pal::char_t *app_or_config_path = argv[3];

int remaining_argc = argc - min_argc;
const pal::char_t **remaining_argv = nullptr;
if (argc > min_argc)
remaining_argv = &argv[min_argc];

pal::stringstream_t test_output;
bool success = false;

success = host_context_test::component_get_function_pointer(hostfxr_path, app_or_config_path, remaining_argc, remaining_argv, test_output);

std::cout << tostr(test_output.str()).data() << std::endl;
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
else if (pal::strcmp(command, _X("app_get_function_pointer")) == 0)
{
// args: ... <hostfxr_path> <app_path> <type_name> <method_name> [<type_name> <method_name>...]
const int min_argc = 3;
if (argc < min_argc + 3)
{
std::cerr << "Invalid arguments" << std::endl;
return -1;
}

const pal::string_t hostfxr_path = argv[2];

int remaining_argc = argc - min_argc;
const pal::char_t **remaining_argv = nullptr;
if (argc > min_argc)
remaining_argv = &argv[min_argc];

pal::stringstream_t test_output;
bool success = false;

success = host_context_test::app_get_function_pointer(hostfxr_path, remaining_argc, remaining_argv, test_output);

std::cout << tostr(test_output.str()).data() << std::endl;
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}
else if (pal::strcmp(command, _X("run_app")) == 0)
{
// args: ... <hostfxr_path> <dotnet_command_line>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
<OutputType>Exe</OutputType>
<RuntimeIdentifier>$(TestTargetRid)</RuntimeIdentifier>
<RuntimeFrameworkVersion>$(MNAVersion)</RuntimeFrameworkVersion>
</PropertyGroup>

</Project>
Loading