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

Fix interception for private protected methods #556

Merged
merged 3 commits into from Jan 19, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -6,6 +6,7 @@ Enhancements:
- .NET Standard 2.0 and 2.1 support (@lg2de, #485)

Bugfixes:
- `private protected` methods are not intercepted (@CrispyDrone, #535)
- `System.UIntPtr` unsupported (@stakx, #546)

Deprecations:
Expand Down
46 changes: 46 additions & 0 deletions src/Castle.Core.Tests/DynamicProxy.Tests/AccessLevelTestCase.cs
Expand Up @@ -14,6 +14,7 @@

namespace Castle.DynamicProxy.Tests
{
using System;
using System.Collections.Generic;
using System.Reflection;

Expand Down Expand Up @@ -85,5 +86,50 @@ public void InternalConstructorIsReplicatedWhenInternalsVisibleTo()
object proxy = generator.CreateClassProxy(typeof(InternalClass), new StandardInterceptor());
Assert.IsNotNull(proxy.GetType().GetConstructor(new[] { typeof(IInterceptor[]) }));
}

[TestCase(typeof(InternalMethodClass))]
[TestCase(typeof(PrivateProtectedMethodClass))]
[TestCase(typeof(ProtectedMethodClass))]
[TestCase(typeof(ProtectedInternalMethodClass))]
public void Methods_made_visible_by_InternalsVisibleTo_can_be_intercepted(Type methodClass)
{
var method = methodClass.GetMethod("Method", BindingFlags.NonPublic | BindingFlags.Instance);
Assume.That(ProxyUtil.IsAccessible(method)); // because this assembly makes its internals visible to DynamicProxy

var realObj = (IMethodClass)Activator.CreateInstance(methodClass);
Assert.Throws<Exception>(realObj.InvokeMethod);

var proxy = (IMethodClass)generator.CreateClassProxy(methodClass, new DoNothingInterceptor());
Assert.DoesNotThrow(proxy.InvokeMethod);
}

private interface IMethodClass
{
void InvokeMethod();
}

public class InternalMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
internal virtual void Method() => throw new Exception();
}

public class PrivateProtectedMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
private protected virtual void Method() => throw new Exception();
}

public class ProtectedMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
protected virtual void Method() => throw new Exception();
}

public class ProtectedInternalMethodClass : IMethodClass
{
public void InvokeMethod() => Method();
protected internal virtual void Method() => throw new Exception();
}
}
}
Expand Up @@ -223,7 +223,7 @@ protected bool AcceptMethod(MethodInfo method, bool onlyVirtuals, IProxyGenerati
}

//can only proxy methods that are public or protected (or internals that have already been checked above)
if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly) == false)
if ((method.IsPublic || method.IsFamily || method.IsAssembly || method.IsFamilyOrAssembly || method.IsFamilyAndAssembly) == false)
{
return false;
}
Expand Down