Skip to content

Commit

Permalink
Retire ProxyGenerationException & introduce DynamicProxyException
Browse files Browse the repository at this point in the history
… for internal faults (#528)

* Throw `NotImplementedException` in `DefaultValueExpression`

when an unexpected type is encountered. Chances are that IL could be
emitted for those, so this will be more fitting than `NotSupported-
Exception`.

* Assert, don't throw in `ConstReference`

* Refactor `NewInstanceExpression` to throw early

* `InvalidOperationException` for "big sanity check"

If it weren't for that comment, an assertion would likely do instead.

* Remove pre-VS2010 bug detection code in `AbstractTypeEmitter`

* Throw `InvalidOperationException` for uninitialized `ArgumentReference`

* Throw `InvalidOperationException` when `IProxyTargetAccessor` is manually implemented

* `NotSupportedException` when attribute cannot be replicated

* New `DynamicProxyException` for failed assertions / bugs

* Update the changelog
  • Loading branch information
stakx committed Jun 29, 2020
1 parent 8339051 commit b6c3be6
Show file tree
Hide file tree
Showing 16 changed files with 87 additions and 112 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -14,6 +14,7 @@ Deprecations:
- `Castle.Core.Internal.PermissionUtil.IsGranted` (method)
- all type members in `Castle.DynamicProxy.ModuleScope` that gave direct access to DynamicProxy's type cache and `ModuleBuilder`s. Only `SaveAssembly`, `LoadAssemblyIntoCache`, and members supporting these two facilities are left public.
- almost all types and type members in the `Castle.DynamicProxy.*` sub-namespaces, as most of them are intended for internal use only.
- DynamicProxy's custom exception types have been replaced by standard BCL exceptions (where appropriate), and by a single `DynamicProxyException` type for internal DynamicProxy errors.

## 4.4.1 (2020-05-06)

Expand Down
3 changes: 2 additions & 1 deletion ref/Castle.Core-net45.cs
Expand Up @@ -2516,6 +2516,8 @@ public class DefaultProxyBuilder : Castle.DynamicProxy.IProxyBuilder
public System.Type CreateInterfaceProxyTypeWithTargetInterface(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
public System.Type CreateInterfaceProxyTypeWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
}
[System.Serializable]
public sealed class DynamicProxyException : System.Exception { }
public interface IChangeProxyTarget
{
void ChangeInvocationTarget(object target);
Expand Down Expand Up @@ -2661,7 +2663,6 @@ public class PersistentProxyBuilder : Castle.DynamicProxy.DefaultProxyBuilder
public PersistentProxyBuilder() { }
public string SaveAssembly() { }
}
public class ProxyGenerationException : System.Exception { }
[System.Serializable]
public class ProxyGenerationOptions : System.Runtime.Serialization.ISerializable
{
Expand Down
3 changes: 2 additions & 1 deletion ref/Castle.Core-netstandard2.0.cs
Expand Up @@ -2482,6 +2482,8 @@ public class DefaultProxyBuilder : Castle.DynamicProxy.IProxyBuilder
public System.Type CreateInterfaceProxyTypeWithTargetInterface(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
public System.Type CreateInterfaceProxyTypeWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
}
[System.Serializable]
public sealed class DynamicProxyException : System.Exception { }
public interface IChangeProxyTarget
{
void ChangeInvocationTarget(object target);
Expand Down Expand Up @@ -2617,7 +2619,6 @@ public class ModuleScope
public string WeakNamedModuleName { get; }
public static byte[] GetKeyPair() { }
}
public class ProxyGenerationException : System.Exception { }
public class ProxyGenerationOptions
{
public static readonly Castle.DynamicProxy.ProxyGenerationOptions Default;
Expand Down
3 changes: 2 additions & 1 deletion ref/Castle.Core-netstandard2.1.cs
Expand Up @@ -2482,6 +2482,8 @@ public class DefaultProxyBuilder : Castle.DynamicProxy.IProxyBuilder
public System.Type CreateInterfaceProxyTypeWithTargetInterface(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
public System.Type CreateInterfaceProxyTypeWithoutTarget(System.Type interfaceToProxy, System.Type[] additionalInterfacesToProxy, Castle.DynamicProxy.ProxyGenerationOptions options) { }
}
[System.Serializable]
public sealed class DynamicProxyException : System.Exception { }
public interface IChangeProxyTarget
{
void ChangeInvocationTarget(object target);
Expand Down Expand Up @@ -2617,7 +2619,6 @@ public class ModuleScope
public string WeakNamedModuleName { get; }
public static byte[] GetKeyPair() { }
}
public class ProxyGenerationException : System.Exception { }
public class ProxyGenerationOptions
{
public static readonly Castle.DynamicProxy.ProxyGenerationOptions Default;
Expand Down
Expand Up @@ -34,7 +34,7 @@ private ProxyGenerationOptions MixIn(object mixin)
[Test]
public void ClassProxy_AdditionalInterfaces()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateClassProxy(typeof(object), new[] { typeof(IProxyTargetAccessor) }));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}
Expand All @@ -50,7 +50,7 @@ public void ClassProxy_base()
[Test]
public void ClassProxy_Mixin()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateClassProxy(typeof(object), MixIn(new ImplementsProxyTargetAccessor())));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}
Expand All @@ -60,15 +60,15 @@ public void ClassProxy_Mixin()
[Test]
public void InterfaceProxyWithoutTarget_AdditionalInterfaces()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithoutTarget(typeof(IOne), new[] { typeof(IProxyTargetAccessor) }));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithoutTarget_Mixin()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithoutTarget(typeof(IOne), new[] { typeof(IProxyTargetAccessor) },
MixIn(new ImplementsProxyTargetAccessor())));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
Expand All @@ -77,31 +77,31 @@ public void InterfaceProxyWithoutTarget_Mixin()
[Test]
public void InterfaceProxyWithoutTarget_TargetInterface()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithoutTarget(typeof(IProxyTargetAccessor)));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithoutTarget_TargetInterface_derived()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithoutTarget(typeof(IProxyTargetAccessorDerived)));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithTarget_AdditionalInterfaces()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTarget(typeof(IOne), new[] { typeof(IProxyTargetAccessor) }, new One()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithTarget_Mixin()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTarget(typeof(IOne), new[] { typeof(IProxyTargetAccessor) }, new One(),
MixIn(new ImplementsProxyTargetAccessor())));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
Expand All @@ -110,15 +110,15 @@ public void InterfaceProxyWithTarget_Mixin()
[Test]
public void InterfaceProxyWithTarget_Target()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTarget(typeof(IProxyTargetAccessor), new ImplementsProxyTargetAccessor()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithTarget_Target_derived()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTarget(typeof(IProxyTargetAccessorDerived), new ImplementsProxyTargetAccessorDerived()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}
Expand All @@ -128,15 +128,15 @@ public void InterfaceProxyWithTarget_Target_derived()
[Test]
public void InterfaceProxyWithTargetInterface_AdditionalInterfaces()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTargetInterface(typeof(IOne), new[] { typeof(IProxyTargetAccessor) }, new One()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithTargetInterface_Mixin()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTargetInterface(typeof(IOne), new[] { typeof(IProxyTargetAccessor) }, new One(),
MixIn(new ImplementsProxyTargetAccessor())));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
Expand All @@ -145,15 +145,15 @@ public void InterfaceProxyWithTargetInterface_Mixin()
[Test]
public void InterfaceProxyWithTargetInterface_Target()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTargetInterface(typeof(IProxyTargetAccessor), new ImplementsProxyTargetAccessor()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
}

[Test]
public void InterfaceProxyWithTargetInterface_Target_derived()
{
var ex = Assert.Throws(typeof(ProxyGenerationException), () =>
var ex = Assert.Throws<InvalidOperationException>(() =>
generator.CreateInterfaceProxyWithTargetInterface(typeof(IProxyTargetAccessorDerived),
new ImplementsProxyTargetAccessorDerived()));
StringAssert.Contains("IProxyTargetAccessor", ex.Message);
Expand Down
39 changes: 39 additions & 0 deletions src/Castle.Core/DynamicProxy/DynamicProxyException.cs
@@ -0,0 +1,39 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.DynamicProxy
{
using System;
using System.Runtime.Serialization;

// NOTE TO MAINTAINERS:
// Prefer throwing Base Class Library exception types wherever appropriate.
// This exception type is to be used mostly when something inside DynamicProxy goes wrong.
// Think of it as a "failed assertion" / "bug" exception.
[Serializable]
public sealed class DynamicProxyException : Exception
{
internal DynamicProxyException(string message) : base(message)
{
}

internal DynamicProxyException(string message, Exception innerException) : base(message, innerException)
{
}

internal DynamicProxyException(SerializationInfo info, StreamingContext context) : base(info, context)
{
}
}
}
7 changes: 5 additions & 2 deletions src/Castle.Core/DynamicProxy/Generators/BaseProxyGenerator.cs
Expand Up @@ -313,7 +313,7 @@ protected void GenerateParameterlessConstructor(ClassEmitter emitter, Type baseC
constructor.CodeBuilder.AddStatement(new AssignStatement(interceptorField,
new NewArrayExpression(1, typeof(IInterceptor))));
constructor.CodeBuilder.AddStatement(
new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor), new Type[0])));
new AssignArrayStatement(interceptorField, 0, new NewInstanceExpression(typeof(StandardInterceptor))));

// Invoke base constructor

Expand All @@ -339,6 +339,7 @@ protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter)
string.Format(
"Target type for the proxy implements {0} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to proxy an existing proxy?",
interfaceName);
throw new InvalidOperationException("This is a DynamicProxy2 error: " + message);
}
else if (ProxyGenerationOptions.MixinData.ContainsMixin(typeof(IProxyTargetAccessor)))
{
Expand All @@ -347,21 +348,23 @@ protected ConstructorEmitter GenerateStaticConstructor(ClassEmitter emitter)
string.Format(
"Mixin type {0} implements {1} which is a DynamicProxy infrastructure interface and you should never implement it yourself. Are you trying to mix in an existing proxy?",
mixinType.Name, interfaceName);
throw new InvalidOperationException("This is a DynamicProxy2 error: " + message);
}
else if (additionalInterfaces.Contains(typeof(IProxyTargetAccessor)))
{
message =
string.Format(
"You passed {0} as one of additional interfaces to proxy which is a DynamicProxy infrastructure interface and is implemented by every proxy anyway. Please remove it from the list of additional interfaces to proxy.",
interfaceName);
throw new InvalidOperationException("This is a DynamicProxy2 error: " + message);
}
else
{
// this can technically never happen
message = string.Format("It looks like we have a bug with regards to how we handle {0}. Please report it.",
interfaceName);
throw new DynamicProxyException(message);
}
throw new ProxyGenerationException("This is a DynamicProxy2 error: " + message);
}

protected void InitializeStaticFields(Type builtType)
Expand Down
Expand Up @@ -115,7 +115,7 @@ public void CopyGenericParametersFromMethod(MethodInfo methodToCopyGenericsFrom)
// big sanity check
if (genericTypeParams != null)
{
throw new ProxyGenerationException("CopyGenericParametersFromMethod: cannot invoke me twice");
throw new InvalidOperationException("Cannot invoke me twice");
}

SetGenericTypeParameters(GenericUtil.CopyGenericArguments(methodToCopyGenericsFrom, typebuilder, name2GenericType));
Expand Down Expand Up @@ -316,36 +316,7 @@ public void SetGenericTypeParameters(GenericTypeParameterBuilder[] genericTypePa

protected Type CreateType(TypeBuilder type)
{
try
{
return type.CreateTypeInfo();
}
catch (BadImageFormatException ex)
{
if (Debugger.IsAttached == false)
{
throw;
}

if (ex.Message.Contains(@"HRESULT: 0x8007000B") == false)
{
throw;
}

if (type.IsGenericTypeDefinition == false)
{
throw;
}

var message =
"This is a DynamicProxy2 error: It looks like you encountered a bug in Visual Studio debugger, " +
"which causes this exception when proxying types with generic methods having constraints on their generic arguments." +
"This code will work just fine without the debugger attached. " +
"If you wish to use debugger you may have to switch to Visual Studio 2010 where this bug was fixed.";
var exception = new ProxyGenerationException(message);
exception.Data.Add("ProxyType", type.ToString());
throw exception;
}
return type.CreateTypeInfo();
}

protected virtual void EnsureBuildersAreInAValidState()
Expand Down
Expand Up @@ -44,7 +44,7 @@ public override void LoadReference(ILGenerator gen)
{
if (Position == -1)
{
throw new ProxyGenerationException("ArgumentReference uninitialized");
throw new InvalidOperationException("ArgumentReference uninitialized");
}
switch (Position)
{
Expand All @@ -70,7 +70,7 @@ public override void StoreReference(ILGenerator gen)
{
if (Position == -1)
{
throw new ProxyGenerationException("ArgumentReference uninitialized");
throw new InvalidOperationException("ArgumentReference uninitialized");
}
gen.Emit(OpCodes.Starg, Position);
}
Expand Down
Expand Up @@ -27,10 +27,7 @@ internal class ConstReference : TypeReference
public ConstReference(object value)
: base(value.GetType())
{
if (!value.GetType().IsPrimitive && !(value is String))
{
throw new ProxyGenerationException("Invalid type to ConstReference");
}
Debug.Assert(value.GetType().IsPrimitive || value is string, "Invalid type to ConstReference");

this.value = value;
}
Expand Down
Expand Up @@ -48,7 +48,7 @@ public override void Emit(IMemberEmitter member, ILGenerator gen)
}
else
{
throw new ProxyGenerationException("Can't emit default value for type " + type);
throw new NotImplementedException("Can't emit default value for type " + type);
}
}

Expand All @@ -66,7 +66,7 @@ private void EmitByRef(ILGenerator gen)
}
else
{
throw new ProxyGenerationException("Can't emit default value for reference of type " + elementType);
throw new NotImplementedException("Can't emit default value for reference of type " + elementType);
}
}

Expand Down

0 comments on commit b6c3be6

Please sign in to comment.