Skip to content

Commit a6005f3

Browse files
authored
Move .NET method invocation logging to after the needed type conversion is done for method arguments (PowerShell#25022)
1 parent 0ca17fd commit a6005f3

File tree

1 file changed

+66
-20
lines changed
  • src/System.Management.Automation/engine/runtime/Binding

1 file changed

+66
-20
lines changed

src/System.Management.Automation/engine/runtime/Binding/Binders.cs

+66-20
Original file line numberDiff line numberDiff line change
@@ -6943,12 +6943,6 @@ internal static DynamicMetaObject InvokeDotNetMethod(
69436943
expr = Expression.Block(expr, ExpressionCache.AutomationNullConstant);
69446944
}
69456945

6946-
// Expression block runs two expressions in order:
6947-
// - Log method invocation to AMSI Notifications (can throw PSSecurityException)
6948-
// - Invoke method
6949-
string targetName = methodInfo.ReflectedType?.FullName ?? string.Empty;
6950-
expr = MaybeAddMemberInvocationLogging(expr, targetName, name, args);
6951-
69526946
// If we're calling SteppablePipeline.{Begin|Process|End}, we don't want
69536947
// to wrap exceptions - this is very much a special case to help error
69546948
// propagation and ensure errors are attributed to the correct code (the
@@ -7111,6 +7105,7 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
71117105
invocationType != MethodInvocationType.NonVirtual;
71127106
var parameters = mi.GetParameters();
71137107
var argExprs = new Expression[parameters.Length];
7108+
var argsToLog = new List<Expression>(Math.Max(parameters.Length, args.Length));
71147109

71157110
for (int i = 0; i < parameters.Length; ++i)
71167111
{
@@ -7135,16 +7130,21 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
71357130

71367131
if (expandParameters)
71377132
{
7138-
argExprs[i] = Expression.NewArrayInit(
7139-
paramElementType,
7140-
args.Skip(i).Select(
7141-
a => a.CastOrConvertMethodArgument(
7133+
IEnumerable<Expression> elements = args
7134+
.Skip(i)
7135+
.Select(a =>
7136+
a.CastOrConvertMethodArgument(
71427137
paramElementType,
71437138
paramName,
71447139
mi.Name,
71457140
allowCastingToByRefLikeType: false,
71467141
temps,
7147-
initTemps)));
7142+
initTemps))
7143+
.ToList();
7144+
7145+
argExprs[i] = Expression.NewArrayInit(paramElementType, elements);
7146+
// User specified the element arguments, so we log them instead of the compiler-created array.
7147+
argsToLog.AddRange(elements);
71487148
}
71497149
else
71507150
{
@@ -7155,13 +7155,18 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
71557155
allowCastingToByRefLikeType: false,
71567156
temps,
71577157
initTemps);
7158+
71587159
argExprs[i] = arg;
7160+
argsToLog.Add(arg);
71597161
}
71607162
}
71617163
else if (i >= args.Length)
71627164
{
7163-
Diagnostics.Assert(parameters[i].IsOptional,
7165+
// We don't log the default value for an optional parameter, as it's not specified by the user.
7166+
Diagnostics.Assert(
7167+
parameters[i].IsOptional,
71647168
"if there are too few arguments, FindBestMethod should only succeed if parameters are optional");
7169+
71657170
var argValue = parameters[i].DefaultValue;
71667171
if (argValue == null)
71677172
{
@@ -7199,17 +7204,25 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
71997204
var psRefValue = Expression.Property(args[i].Expression.Cast(typeof(PSReference)), CachedReflectionInfo.PSReference_Value);
72007205
initTemps.Add(Expression.Assign(temp, psRefValue.Convert(temp.Type)));
72017206
copyOutTemps.Add(Expression.Assign(psRefValue, temp.Cast(typeof(object))));
7207+
72027208
argExprs[i] = temp;
7209+
argsToLog.Add(temp);
72037210
}
72047211
else
72057212
{
7206-
argExprs[i] = args[i].CastOrConvertMethodArgument(
7213+
var convertedArg = args[i].CastOrConvertMethodArgument(
72077214
parameterType,
72087215
paramName,
72097216
mi.Name,
72107217
allowCastingToByRefLikeType,
72117218
temps,
72127219
initTemps);
7220+
7221+
argExprs[i] = convertedArg;
7222+
// If the converted arg is a byref-like type, then we log the original arg.
7223+
argsToLog.Add(convertedArg.Type.IsByRefLike
7224+
? args[i].Expression
7225+
: convertedArg);
72137226
}
72147227
}
72157228
}
@@ -7255,6 +7268,12 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
72557268
}
72567269
}
72577270

7271+
// We need to add one expression to log the .NET invocation before actually invoking:
7272+
// - Log method invocation to AMSI Notifications (can throw PSSecurityException)
7273+
// - Invoke method
7274+
string targetName = mi.ReflectedType?.FullName ?? string.Empty;
7275+
string methodName = mi.Name is ".ctor" ? "new" : mi.Name;
7276+
72587277
if (temps.Count > 0)
72597278
{
72607279
if (call.Type != typeof(void) && copyOutTemps.Count > 0)
@@ -7265,8 +7284,13 @@ internal static Expression InvokeMethod(MethodBase mi, DynamicMetaObject target,
72657284
copyOutTemps.Add(retValue);
72667285
}
72677286

7287+
AddMemberInvocationLogging(initTemps, targetName, methodName, argsToLog);
72687288
call = Expression.Block(call.Type, temps, initTemps.Append(call).Concat(copyOutTemps));
72697289
}
7290+
else
7291+
{
7292+
call = AddMemberInvocationLogging(call, targetName, methodName, argsToLog);
7293+
}
72707294

72717295
return call;
72727296
}
@@ -7559,28 +7583,50 @@ internal static void InvalidateCache()
75597583
}
75607584

75617585
#nullable enable
7562-
private static Expression MaybeAddMemberInvocationLogging(
7586+
private static Expression AddMemberInvocationLogging(
75637587
Expression expr,
75647588
string targetName,
75657589
string name,
7566-
DynamicMetaObject[] args)
7590+
List<Expression> args)
75677591
{
7568-
#if UNIX && !DEBUG
7569-
// For efficiency this is a no-op on non-Windows platforms in release builds.
7592+
#if UNIX
7593+
// For efficiency this is a no-op on non-Windows platforms.
75707594
return expr;
75717595
#else
7572-
Expression[] invocationArgs = new Expression[args.Length];
7573-
for (int i = 0; i < args.Length; i++)
7596+
Expression[] invocationArgs = new Expression[args.Count];
7597+
for (int i = 0; i < args.Count; i++)
75747598
{
7575-
invocationArgs[i] = args[i].Expression.Cast(typeof(object));
7599+
invocationArgs[i] = args[i].Cast(typeof(object));
75767600
}
7601+
75777602
return Expression.Block(
75787603
Expression.Call(
75797604
CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation,
75807605
Expression.Constant(targetName),
75817606
Expression.Constant(name),
75827607
Expression.NewArrayInit(typeof(object), invocationArgs)),
75837608
expr);
7609+
#endif
7610+
}
7611+
7612+
private static void AddMemberInvocationLogging(
7613+
List<Expression> exprs,
7614+
string targetName,
7615+
string name,
7616+
List<Expression> args)
7617+
{
7618+
#if !UNIX
7619+
Expression[] invocationArgs = new Expression[args.Count];
7620+
for (int i = 0; i < args.Count; i++)
7621+
{
7622+
invocationArgs[i] = args[i].Cast(typeof(object));
7623+
}
7624+
7625+
exprs.Add(Expression.Call(
7626+
CachedReflectionInfo.MemberInvocationLoggingOps_LogMemberInvocation,
7627+
Expression.Constant(targetName),
7628+
Expression.Constant(name),
7629+
Expression.NewArrayInit(typeof(object), invocationArgs)));
75847630
#endif
75857631
}
75867632
#nullable disable

0 commit comments

Comments
 (0)