e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
384 lines
18 KiB
C#
384 lines
18 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Dispatcher
|
|
{
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Globalization;
|
|
using System.Reflection;
|
|
using System.Reflection.Emit;
|
|
using System.Runtime;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.ServiceModel.Description;
|
|
|
|
delegate object InvokeDelegate(object target, object[] inputs, object[] outputs);
|
|
delegate IAsyncResult InvokeBeginDelegate(object target, object[] inputs, AsyncCallback asyncCallback, object state);
|
|
delegate object InvokeEndDelegate(object target, object[] outputs, IAsyncResult result);
|
|
delegate object CreateInstanceDelegate();
|
|
|
|
sealed class InvokerUtil
|
|
{
|
|
[Fx.Tag.SecurityNote(Critical = "Holds instance of CriticalHelper which keeps state that was produced within an assert.")]
|
|
[SecurityCritical]
|
|
CriticalHelper helper;
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Initializes SecurityCritical field 'helper'.",
|
|
Safe = "Doesn't leak anything.")]
|
|
[SecuritySafeCritical]
|
|
public InvokerUtil()
|
|
{
|
|
helper = new CriticalHelper();
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.",
|
|
Safe = "Resultant delegate is self-contained and safe for general consumption, nothing else leaks.")]
|
|
[SecuritySafeCritical]
|
|
internal CreateInstanceDelegate GenerateCreateInstanceDelegate(Type type, ConstructorInfo constructor)
|
|
{
|
|
return helper.GenerateCreateInstanceDelegate(type, constructor);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.",
|
|
Safe = "Resultant delegate is self-contained and safe for general consumption, parameter counts are safe, nothing else leaks.")]
|
|
[SecuritySafeCritical]
|
|
internal InvokeDelegate GenerateInvokeDelegate(MethodInfo method, out int inputParameterCount, out int outputParameterCount)
|
|
{
|
|
return helper.GenerateInvokeDelegate(method, out inputParameterCount, out outputParameterCount);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.",
|
|
Safe = "Resultant delegate is self-contained and safe for general consumption, parameter counts are safe, nothing else leaks.")]
|
|
[SecuritySafeCritical]
|
|
internal InvokeBeginDelegate GenerateInvokeBeginDelegate(MethodInfo method, out int inputParameterCount)
|
|
{
|
|
return helper.GenerateInvokeBeginDelegate(method, out inputParameterCount);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Accesses SecurityCritical helper class 'CriticalHelper'.",
|
|
Safe = "Resultant delegate is self-contained and safe for general consumption, parameter counts are safe, nothing else leaks.")]
|
|
[SecuritySafeCritical]
|
|
internal InvokeEndDelegate GenerateInvokeEndDelegate(MethodInfo method, out int outputParameterCount)
|
|
{
|
|
return helper.GenerateInvokeEndDelegate(method, out outputParameterCount);
|
|
}
|
|
|
|
[Fx.Tag.SecurityNote(Critical = "Handles all aspects of IL generation including initializing the DynamicMethod, which requires an elevation."
|
|
+ "Since the ILGenerator is created under an elevation, we lock down access to every aspect of the generation.")]
|
|
#pragma warning disable 618 // have not moved to the v4 security model yet
|
|
[SecurityCritical(SecurityCriticalScope.Everything)]
|
|
#pragma warning restore 618
|
|
class CriticalHelper
|
|
{
|
|
static Type TypeOfObject = typeof(object);
|
|
|
|
CodeGenerator ilg;
|
|
|
|
internal CreateInstanceDelegate GenerateCreateInstanceDelegate(Type type, ConstructorInfo constructor)
|
|
{
|
|
bool requiresMemberAccess = !IsTypeVisible(type) || ConstructorRequiresMemberAccess(constructor);
|
|
|
|
this.ilg = new CodeGenerator();
|
|
try
|
|
{
|
|
ilg.BeginMethod("Create" + type.FullName, typeof(CreateInstanceDelegate), requiresMemberAccess);
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
if (requiresMemberAccess && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
|
|
{
|
|
DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(
|
|
SR.PartialTrustServiceCtorNotVisible,
|
|
type.FullName)));
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
if (type.IsValueType)
|
|
{
|
|
LocalBuilder instanceLocal = ilg.DeclareLocal(type, type.Name + "Instance");
|
|
ilg.LoadZeroValueIntoLocal(type, instanceLocal);
|
|
ilg.Load(instanceLocal);
|
|
}
|
|
else
|
|
{
|
|
ilg.New(constructor);
|
|
}
|
|
ilg.ConvertValue(type, ilg.CurrentMethod.ReturnType);
|
|
return (CreateInstanceDelegate)ilg.EndMethod();
|
|
}
|
|
|
|
internal InvokeDelegate GenerateInvokeDelegate(MethodInfo method, out int inputParameterCount, out int outputParameterCount)
|
|
{
|
|
bool requiresMemberAccess = MethodRequiresMemberAccess(method);
|
|
|
|
this.ilg = new CodeGenerator();
|
|
try
|
|
{
|
|
this.ilg.BeginMethod("SyncInvoke" + method.Name, typeof(InvokeDelegate), requiresMemberAccess);
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
if (requiresMemberAccess && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
|
|
{
|
|
DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(
|
|
SR.PartialTrustServiceMethodNotVisible,
|
|
method.DeclaringType.FullName,
|
|
method.Name)));
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
ArgBuilder targetArg = ilg.GetArg(0);
|
|
ArgBuilder inputParametersArg = ilg.GetArg(1);
|
|
ArgBuilder outputParametersArg = ilg.GetArg(2);
|
|
|
|
ParameterInfo[] parameters = method.GetParameters();
|
|
LocalBuilder returnLocal = ilg.DeclareLocal(ilg.CurrentMethod.ReturnType, "returnParam");
|
|
LocalBuilder[] parameterLocals = new LocalBuilder[parameters.Length];
|
|
DeclareParameterLocals(parameters, parameterLocals);
|
|
|
|
LoadInputParametersIntoLocals(parameters, parameterLocals, inputParametersArg, out inputParameterCount);
|
|
LoadTarget(targetArg, method.ReflectedType);
|
|
LoadParameters(parameters, parameterLocals);
|
|
InvokeMethod(method, returnLocal);
|
|
LoadOutputParametersIntoArray(parameters, parameterLocals, outputParametersArg, out outputParameterCount);
|
|
|
|
ilg.Load(returnLocal);
|
|
return (InvokeDelegate)this.ilg.EndMethod();
|
|
}
|
|
|
|
internal InvokeBeginDelegate GenerateInvokeBeginDelegate(MethodInfo method, out int inputParameterCount)
|
|
{
|
|
bool requiresMemberAccess = MethodRequiresMemberAccess(method);
|
|
|
|
this.ilg = new CodeGenerator();
|
|
try
|
|
{
|
|
this.ilg.BeginMethod("AsyncInvokeBegin" + method.Name, typeof(InvokeBeginDelegate), requiresMemberAccess);
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
if (requiresMemberAccess && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
|
|
{
|
|
DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(
|
|
SR.PartialTrustServiceMethodNotVisible,
|
|
method.DeclaringType.FullName,
|
|
method.Name)));
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
ArgBuilder targetArg = ilg.GetArg(0);
|
|
ArgBuilder inputParametersArg = ilg.GetArg(1);
|
|
ArgBuilder callbackArg = ilg.GetArg(2);
|
|
ArgBuilder stateArg = ilg.GetArg(3);
|
|
|
|
ParameterInfo[] parameters = method.GetParameters();
|
|
LocalBuilder returnLocal = ilg.DeclareLocal(ilg.CurrentMethod.ReturnType, "returnParam");
|
|
LocalBuilder[] parameterLocals = new LocalBuilder[parameters.Length - 2];
|
|
DeclareParameterLocals(parameters, parameterLocals);
|
|
|
|
LoadInputParametersIntoLocals(parameters, parameterLocals, inputParametersArg, out inputParameterCount);
|
|
LoadTarget(targetArg, method.ReflectedType);
|
|
LoadParameters(parameters, parameterLocals);
|
|
ilg.Load(callbackArg);
|
|
ilg.Load(stateArg);
|
|
InvokeMethod(method, returnLocal);
|
|
|
|
ilg.Load(returnLocal);
|
|
return (InvokeBeginDelegate)this.ilg.EndMethod();
|
|
}
|
|
|
|
internal InvokeEndDelegate GenerateInvokeEndDelegate(MethodInfo method, out int outputParameterCount)
|
|
{
|
|
bool requiresMemberAccess = MethodRequiresMemberAccess(method);
|
|
|
|
this.ilg = new CodeGenerator();
|
|
try
|
|
{
|
|
this.ilg.BeginMethod("AsyncInvokeEnd" + method.Name, typeof(InvokeEndDelegate), requiresMemberAccess);
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
if (requiresMemberAccess && securityException.PermissionType.Equals(typeof(ReflectionPermission)))
|
|
{
|
|
DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(
|
|
SR.PartialTrustServiceMethodNotVisible,
|
|
method.DeclaringType.FullName,
|
|
method.Name)));
|
|
}
|
|
else
|
|
{
|
|
throw;
|
|
}
|
|
}
|
|
|
|
ArgBuilder targetArg = ilg.GetArg(0);
|
|
ArgBuilder outputParametersArg = ilg.GetArg(1);
|
|
ArgBuilder resultArg = ilg.GetArg(2);
|
|
|
|
ParameterInfo[] parameters = method.GetParameters();
|
|
LocalBuilder returnLocal = ilg.DeclareLocal(ilg.CurrentMethod.ReturnType, "returnParam");
|
|
LocalBuilder[] parameterLocals = new LocalBuilder[parameters.Length - 1];
|
|
DeclareParameterLocals(parameters, parameterLocals);
|
|
|
|
LoadZeroValueInputParametersIntoLocals(parameters, parameterLocals);
|
|
LoadTarget(targetArg, method.ReflectedType);
|
|
LoadParameters(parameters, parameterLocals);
|
|
ilg.Load(resultArg);
|
|
InvokeMethod(method, returnLocal);
|
|
LoadOutputParametersIntoArray(parameters, parameterLocals, outputParametersArg, out outputParameterCount);
|
|
|
|
ilg.Load(returnLocal);
|
|
return (InvokeEndDelegate)this.ilg.EndMethod();
|
|
}
|
|
|
|
void DeclareParameterLocals(ParameterInfo[] parameters, LocalBuilder[] parameterLocals)
|
|
{
|
|
for (int i = 0; i < parameterLocals.Length; i++)
|
|
{
|
|
parameterLocals[i] = ilg.DeclareLocal(TypeLoader.GetParameterType(parameters[i]), "param" + i.ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
|
|
void LoadInputParametersIntoLocals(ParameterInfo[] parameters, LocalBuilder[] parameterLocals, ArgBuilder inputParametersArg, out int inputParameterCount)
|
|
{
|
|
inputParameterCount = 0;
|
|
for (int i = 0; i < parameterLocals.Length; i++)
|
|
{
|
|
if (ServiceReflector.FlowsIn(parameters[i]))
|
|
{
|
|
Type parameterType = parameterLocals[i].LocalType;
|
|
ilg.LoadArrayElement(inputParametersArg, inputParameterCount);
|
|
if (!parameterType.IsValueType)
|
|
{
|
|
ilg.ConvertValue(TypeOfObject, parameterType);
|
|
ilg.Store(parameterLocals[i]);
|
|
}
|
|
else
|
|
{
|
|
ilg.Dup();
|
|
ilg.If();
|
|
ilg.ConvertValue(TypeOfObject, parameterType);
|
|
ilg.Store(parameterLocals[i]);
|
|
ilg.Else();
|
|
ilg.Pop();
|
|
ilg.LoadZeroValueIntoLocal(parameterType, parameterLocals[i]);
|
|
ilg.EndIf();
|
|
}
|
|
inputParameterCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void LoadZeroValueInputParametersIntoLocals(ParameterInfo[] parameters, LocalBuilder[] parameterLocals)
|
|
{
|
|
for (int i = 0; i < parameterLocals.Length; i++)
|
|
{
|
|
if (ServiceReflector.FlowsIn(parameters[i]))
|
|
{
|
|
ilg.LoadZeroValueIntoLocal(parameterLocals[i].LocalType, parameterLocals[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void LoadTarget(ArgBuilder targetArg, Type targetType)
|
|
{
|
|
ilg.Load(targetArg);
|
|
ilg.ConvertValue(targetArg.ArgType, targetType);
|
|
if (targetType.IsValueType)
|
|
{
|
|
LocalBuilder targetLocal = ilg.DeclareLocal(targetType, "target");
|
|
ilg.Store(targetLocal);
|
|
ilg.LoadAddress(targetLocal);
|
|
}
|
|
}
|
|
|
|
void LoadParameters(ParameterInfo[] parameters, LocalBuilder[] parameterLocals)
|
|
{
|
|
for (int i = 0; i < parameterLocals.Length; i++)
|
|
{
|
|
if (parameters[i].ParameterType.IsByRef)
|
|
ilg.Ldloca(parameterLocals[i]);
|
|
else
|
|
ilg.Ldloc(parameterLocals[i]);
|
|
}
|
|
}
|
|
|
|
void InvokeMethod(MethodInfo method, LocalBuilder returnLocal)
|
|
{
|
|
ilg.Call(method);
|
|
if (method.ReturnType == typeof(void))
|
|
ilg.Load(null);
|
|
else
|
|
ilg.ConvertValue(method.ReturnType, ilg.CurrentMethod.ReturnType);
|
|
ilg.Store(returnLocal);
|
|
}
|
|
|
|
void LoadOutputParametersIntoArray(ParameterInfo[] parameters, LocalBuilder[] parameterLocals, ArgBuilder outputParametersArg, out int outputParameterCount)
|
|
{
|
|
outputParameterCount = 0;
|
|
for (int i = 0; i < parameterLocals.Length; i++)
|
|
{
|
|
if (ServiceReflector.FlowsOut(parameters[i]))
|
|
{
|
|
ilg.Load(outputParametersArg);
|
|
ilg.Load(outputParameterCount);
|
|
ilg.Load(parameterLocals[i]);
|
|
ilg.ConvertValue(parameterLocals[i].LocalType, TypeOfObject);
|
|
ilg.Stelem(TypeOfObject);
|
|
outputParameterCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool IsTypeVisible(Type t)
|
|
{
|
|
if (t.Module == typeof(InvokerUtil).Module)
|
|
return true;
|
|
|
|
if (!t.IsVisible)
|
|
return false;
|
|
|
|
foreach (Type genericType in t.GetGenericArguments())
|
|
{
|
|
if (!genericType.IsGenericParameter && !IsTypeVisible(genericType))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ConstructorRequiresMemberAccess(ConstructorInfo ctor)
|
|
{
|
|
return ctor != null && (!ctor.IsPublic || !IsTypeVisible(ctor.DeclaringType)) && ctor.Module != typeof(InvokerUtil).Module;
|
|
}
|
|
|
|
static bool MethodRequiresMemberAccess(MethodInfo method)
|
|
{
|
|
return method != null && (!method.IsPublic || !IsTypeVisible(method.DeclaringType)) && method.Module != typeof(InvokerUtil).Module;
|
|
}
|
|
}
|
|
}
|
|
}
|