Skip to content

Commit bfc90ae

Browse files
committed
fix for clr exception in some cases
1 parent 184e6f7 commit bfc90ae

10 files changed

Lines changed: 299 additions & 11 deletions

File tree

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#if !NETCORE
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Reflection;
5+
6+
using Force.DeepCloner.Helpers;
7+
8+
using NUnit.Framework;
9+
10+
using ServiceStack.FluentValidation;
11+
12+
namespace Force.DeepCloner.Tests
13+
{
14+
[TestFixture]
15+
public class ClrExpectionSpec
16+
{
17+
public sealed class ItemToBeCloned2 : BaseClassForTest2
18+
{
19+
public SomeCollection2 SomeCollectionProperty { get; set; }
20+
21+
public ItemToBeCloned2()
22+
{
23+
SomeCollectionProperty = new SomeCollection2();
24+
}
25+
26+
protected override IValidator GetValidator()
27+
{
28+
return new FVInventoryValidator();
29+
}
30+
31+
private class FVInventoryValidator : AbstractValidator<ItemToBeCloned2>
32+
{
33+
public FVInventoryValidator()
34+
{
35+
RuleFor(x => x.SomeCollectionProperty).SetValidator(new SomeCollection2.SomeCollectionValidator2());
36+
}
37+
}
38+
39+
public class SomeCollection2 : List<string>
40+
{
41+
internal SomeCollection2()
42+
{
43+
}
44+
45+
#region Validation
46+
47+
internal sealed class SomeCollectionValidator2 : AbstractValidator<SomeCollection2>
48+
{
49+
public SomeCollectionValidator2()
50+
{
51+
/*
52+
* case 1: if commented out - no crash
53+
* case 2: if left as is then works only with BaseClassForTest2.Validate #region #1
54+
*/
55+
RuleFor(x => 1 == 1);
56+
}
57+
}
58+
59+
#endregion
60+
}
61+
}
62+
63+
public abstract class BaseClassForTest2
64+
{
65+
private IValidator _validator;
66+
67+
protected virtual IValidator GetValidator()
68+
{
69+
return null;
70+
}
71+
72+
public void Validate()
73+
{
74+
#region #1 This works
75+
76+
//var validator = GetValidator();
77+
//Console.WriteLine( validator );
78+
79+
#endregion
80+
81+
#region #2 This crashes
82+
83+
_validator = GetValidator();
84+
85+
#endregion
86+
}
87+
}
88+
89+
[Test]
90+
[Repeat(1000)]
91+
public void TestMethod2()
92+
{
93+
// typeof(ShallowObjectCloner).GetMethod("SwitchTo", BindingFlags.NonPublic | BindingFlags.Static)
94+
// .Invoke(null, new object[] { true });
95+
96+
// ServiceStack.FluentValidation.AbstractValidator
97+
var toBeCloned = new ItemToBeCloned2();
98+
toBeCloned.Validate();
99+
100+
var cloned = DeepClonerExtensions.DeepClone(toBeCloned);
101+
102+
Console.WriteLine(cloned);
103+
}
104+
}
105+
}
106+
#endif

DeepCloner.Tests/DeepCloner.Tests.csproj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,26 @@
7474
<SpecificVersion>False</SpecificVersion>
7575
<HintPath>..\packages\NUnit.3.6.0\lib\net45\nunit.framework.dll</HintPath>
7676
</Reference>
77+
<Reference Include="ServiceStack, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587, processorArchitecture=MSIL">
78+
<HintPath>..\packages\ServiceStack.5.0.0\lib\net45\ServiceStack.dll</HintPath>
79+
<Private>True</Private>
80+
</Reference>
81+
<Reference Include="ServiceStack.Client, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587, processorArchitecture=MSIL">
82+
<HintPath>..\packages\ServiceStack.Client.5.0.0\lib\net45\ServiceStack.Client.dll</HintPath>
83+
<Private>True</Private>
84+
</Reference>
85+
<Reference Include="ServiceStack.Common, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587, processorArchitecture=MSIL">
86+
<HintPath>..\packages\ServiceStack.Common.5.0.0\lib\net45\ServiceStack.Common.dll</HintPath>
87+
<Private>True</Private>
88+
</Reference>
89+
<Reference Include="ServiceStack.Interfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587, processorArchitecture=MSIL">
90+
<HintPath>..\packages\ServiceStack.Interfaces.5.0.0\lib\net45\ServiceStack.Interfaces.dll</HintPath>
91+
<Private>True</Private>
92+
</Reference>
93+
<Reference Include="ServiceStack.Text, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587, processorArchitecture=MSIL">
94+
<HintPath>..\packages\ServiceStack.Text.5.0.0\lib\net45\ServiceStack.Text.dll</HintPath>
95+
<Private>True</Private>
96+
</Reference>
7797
<Reference Include="System" />
7898
<Reference Include="System.ComponentModel.DataAnnotations" />
7999
<Reference Include="System.Core" />
@@ -88,6 +108,7 @@
88108
<Compile Include="ArraysSpec.cs" />
89109
<Compile Include="BaseTest.cs" />
90110
<Compile Include="CloneExtensionsSpec.cs" />
111+
<Compile Include="ClrExceptionSpec.cs" />
91112
<Compile Include="ConstructorsSpec.cs" />
92113
<Compile Include="CopyToObjectSpec.cs" />
93114
<Compile Include="GenericsSpec.cs" />

DeepCloner.Tests/packages.config

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,9 @@
1010
<package id="NClone" version="1.1.1" targetFramework="net461" />
1111
<package id="Nuclex.Cloning" version="1.0.0.0" targetFramework="net40" />
1212
<package id="NUnit" version="3.6.0" targetFramework="net461" />
13+
<package id="ServiceStack" version="5.0.0" targetFramework="net461" />
14+
<package id="ServiceStack.Client" version="5.0.0" targetFramework="net461" />
15+
<package id="ServiceStack.Common" version="5.0.0" targetFramework="net461" />
16+
<package id="ServiceStack.Interfaces" version="5.0.0" targetFramework="net461" />
17+
<package id="ServiceStack.Text" version="5.0.0" targetFramework="net461" />
1318
</packages>

DeepCloner.Tests/project.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121
"Nuclex.Cloning": "1.0.0",
2222
"FastDeepCloner": "1.0.9",
2323
"DesertOctopus": "0.1.1",
24-
"EntityFramework": "6.1.3"
24+
"EntityFramework": "6.1.3",
25+
"ServiceStack": "5.0.0"
26+
2527
},
2628
"frameworkAssemblies": {
2729
"System.ComponentModel.DataAnnotations": "4.0.0"

DeepCloner.Tests/project.lock.json

Lines changed: 131 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2959,7 +2959,7 @@
29592959
"lib/netstandard1.3/System.Xml.XPath.XDocument.dll": {}
29602960
}
29612961
},
2962-
"DeepCloner/0.11.0": {
2962+
"DeepCloner/0.10.1": {
29632963
"type": "project",
29642964
"framework": ".NETStandard,Version=v1.3",
29652965
"dependencies": {
@@ -3093,7 +3093,64 @@
30933093
"lib/net45/nunit.framework.dll": {}
30943094
}
30953095
},
3096-
"DeepCloner/0.11.0": {
3096+
"ServiceStack/5.0.0": {
3097+
"type": "package",
3098+
"dependencies": {
3099+
"ServiceStack.Client": "5.0.0",
3100+
"ServiceStack.Common": "5.0.0"
3101+
},
3102+
"compile": {
3103+
"lib/net45/ServiceStack.dll": {}
3104+
},
3105+
"runtime": {
3106+
"lib/net45/ServiceStack.dll": {}
3107+
}
3108+
},
3109+
"ServiceStack.Client/5.0.0": {
3110+
"type": "package",
3111+
"dependencies": {
3112+
"ServiceStack.Interfaces": "5.0.0",
3113+
"ServiceStack.Text": "5.0.0"
3114+
},
3115+
"compile": {
3116+
"lib/net45/ServiceStack.Client.dll": {}
3117+
},
3118+
"runtime": {
3119+
"lib/net45/ServiceStack.Client.dll": {}
3120+
}
3121+
},
3122+
"ServiceStack.Common/5.0.0": {
3123+
"type": "package",
3124+
"dependencies": {
3125+
"ServiceStack.Interfaces": "5.0.0",
3126+
"ServiceStack.Text": "5.0.0"
3127+
},
3128+
"compile": {
3129+
"lib/net45/ServiceStack.Common.dll": {}
3130+
},
3131+
"runtime": {
3132+
"lib/net45/ServiceStack.Common.dll": {}
3133+
}
3134+
},
3135+
"ServiceStack.Interfaces/5.0.0": {
3136+
"type": "package",
3137+
"compile": {
3138+
"lib/net45/ServiceStack.Interfaces.dll": {}
3139+
},
3140+
"runtime": {
3141+
"lib/net45/ServiceStack.Interfaces.dll": {}
3142+
}
3143+
},
3144+
"ServiceStack.Text/5.0.0": {
3145+
"type": "package",
3146+
"compile": {
3147+
"lib/net45/ServiceStack.Text.dll": {}
3148+
},
3149+
"runtime": {
3150+
"lib/net45/ServiceStack.Text.dll": {}
3151+
}
3152+
},
3153+
"DeepCloner/0.10.1": {
30973154
"type": "project",
30983155
"framework": ".NETFramework,Version=v4.0",
30993156
"compile": {
@@ -4279,6 +4336,75 @@
42794336
"runtimes/win7-x86/native/sni.dll"
42804337
]
42814338
},
4339+
"ServiceStack/5.0.0": {
4340+
"sha512": "exojE2gXZ+XcxngxYxBBDldMgX/2ScyChRGrBB4bJayyEzWU/1ABR920DLnZgLI6gYExBTsbHYNa5YFHrvDNtw==",
4341+
"type": "package",
4342+
"path": "ServiceStack/5.0.0",
4343+
"files": [
4344+
"ServiceStack.5.0.0.nupkg.sha512",
4345+
"ServiceStack.nuspec",
4346+
"lib/net45/ServiceStack.dll",
4347+
"lib/net45/ServiceStack.xml",
4348+
"lib/netstandard2.0/ServiceStack.dll",
4349+
"lib/netstandard2.0/ServiceStack.xml"
4350+
]
4351+
},
4352+
"ServiceStack.Client/5.0.0": {
4353+
"sha512": "8swfDWZNWAc+GoIqivo6yQhYB/jr89lrqsfbspusCZguFZZEzYvfIDVVvcfiBmIqHUvQD2Q4Qma7FqFf1TOeAQ==",
4354+
"type": "package",
4355+
"path": "ServiceStack.Client/5.0.0",
4356+
"files": [
4357+
"ServiceStack.Client.5.0.0.nupkg.sha512",
4358+
"ServiceStack.Client.nuspec",
4359+
"lib/net45/ServiceStack.Client.dll",
4360+
"lib/net45/ServiceStack.Client.xml",
4361+
"lib/netstandard2.0/ServiceStack.Client.deps.json",
4362+
"lib/netstandard2.0/ServiceStack.Client.dll",
4363+
"lib/netstandard2.0/ServiceStack.Client.xml"
4364+
]
4365+
},
4366+
"ServiceStack.Common/5.0.0": {
4367+
"sha512": "yvpN6b5wHivSTIilJuJKYgODPpptJ5Z/UQQwoZARVTK1S9K4g0HxZnPBfIX5E9zPcPM+eOjGsgic30EdWWR6ew==",
4368+
"type": "package",
4369+
"path": "ServiceStack.Common/5.0.0",
4370+
"files": [
4371+
"ServiceStack.Common.5.0.0.nupkg.sha512",
4372+
"ServiceStack.Common.nuspec",
4373+
"lib/net45/ServiceStack.Common.dll",
4374+
"lib/net45/ServiceStack.Common.xml",
4375+
"lib/netstandard2.0/ServiceStack.Common.deps.json",
4376+
"lib/netstandard2.0/ServiceStack.Common.dll",
4377+
"lib/netstandard2.0/ServiceStack.Common.xml"
4378+
]
4379+
},
4380+
"ServiceStack.Interfaces/5.0.0": {
4381+
"sha512": "hQZIqZyPXyHwBhVje6jEz4I4l/Vk2Tqe1+NpEFpDthVwfmxhQ4bX7CRJiB18KkdLyWIwwc18AaDFi8Vvrn/WDA==",
4382+
"type": "package",
4383+
"path": "ServiceStack.Interfaces/5.0.0",
4384+
"files": [
4385+
"ServiceStack.Interfaces.5.0.0.nupkg.sha512",
4386+
"ServiceStack.Interfaces.nuspec",
4387+
"lib/net45/ServiceStack.Interfaces.dll",
4388+
"lib/net45/ServiceStack.Interfaces.xml",
4389+
"lib/netstandard2.0/ServiceStack.Interfaces.deps.json",
4390+
"lib/netstandard2.0/ServiceStack.Interfaces.dll",
4391+
"lib/netstandard2.0/ServiceStack.Interfaces.xml"
4392+
]
4393+
},
4394+
"ServiceStack.Text/5.0.0": {
4395+
"sha512": "/j7NxhuCQrIBnrWYt2drTdY7lJDFAbAd3jYl0DJr5gCIqb4Mka651WlpzwdCUwY4cMpXYgTBesgky33izols+w==",
4396+
"type": "package",
4397+
"path": "ServiceStack.Text/5.0.0",
4398+
"files": [
4399+
"ServiceStack.Text.5.0.0.nupkg.sha512",
4400+
"ServiceStack.Text.nuspec",
4401+
"lib/net45/ServiceStack.Text.dll",
4402+
"lib/net45/ServiceStack.Text.xml",
4403+
"lib/netstandard2.0/ServiceStack.Text.deps.json",
4404+
"lib/netstandard2.0/ServiceStack.Text.dll",
4405+
"lib/netstandard2.0/ServiceStack.Text.xml"
4406+
]
4407+
},
42824408
"System.AppContext/4.3.0": {
42834409
"sha512": "5pkS8P4PK6kvIBtDxx3qA9GoTStKUoMvLKQUYH/IY64zteZZJe5iZmw2GTyk7OD1eQd+x779Va7Re2mI1oxvUA==",
42844410
"type": "package",
@@ -8706,15 +8832,15 @@
87068832
"ref/xamarinwatchos10/_._"
87078833
]
87088834
},
8709-
"DeepCloner/0.11.0": {
8835+
"DeepCloner/0.10.1": {
87108836
"type": "project",
87118837
"path": "../DeepCloner/project.json",
87128838
"msbuildProject": "../DeepCloner/DeepCloner.xproj"
87138839
}
87148840
},
87158841
"projectFileDependencyGroups": {
87168842
"": [
8717-
"DeepCloner",
8843+
"DeepCloner >= 0.10.1",
87188844
"NUnit >= 3.6.0"
87198845
],
87208846
".NETCoreApp,Version=v1.0": [
@@ -8732,6 +8858,7 @@
87328858
"GeorgeCloney >= 1.1.2.20",
87338859
"NClone >= 1.1.1",
87348860
"Nuclex.Cloning >= 1.0.0",
8861+
"ServiceStack >= 5.0.0",
87358862
"System.ComponentModel.DataAnnotations >= 4.0.0"
87368863
]
87378864
},

DeepCloner/Helpers/DeepClonerMsilGenerator.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,19 @@ private static void GenerateProcessMethod(ILGenerator il, Type type, bool unboxS
6464
}
6565
else
6666
{
67-
il.Emit(OpCodes.Ldarg_0);
68-
il.Emit(OpCodes.Call, typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic));
67+
// if (type.IsContextful)
68+
// {
69+
il.Emit(OpCodes.Ldarg_0);
70+
il.Emit(OpCodes.Call, typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic));
71+
// }
72+
/*else <-- just for tests
73+
{
74+
isGoodConstructor = true;
75+
il.Emit(OpCodes.Ldarg_0);
76+
il.Emit(OpCodes.Call, typeof(object).GetMethod("GetType"));
77+
il.Emit(OpCodes.Call, typeof(System.Runtime.Serialization.FormatterServices).GetMethod("GetUninitializedObject"));
78+
}*/
79+
6980
}
7081

7182
il.Emit(OpCodes.Stloc, typeLocal);

DeepCloner/Helpers/DeepClonerMsilHelper.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ public static bool IsConstructorDoNothing(Type type, ConstructorInfo constructor
1111
if (constructor == null) return false;
1212
try
1313
{
14+
// will not try to determine body for this types
15+
if (type.IsGenericType || type.IsContextful || type.IsCOMObject || type.Assembly.IsDynamic) return false;
16+
1417
var methodBody = constructor.GetMethodBody();
1518

1619
// this situation can be for com

DeepCloner/Helpers/DeepClonerSafeTypes.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ var x in
2525
typeof(float), typeof(double), typeof(decimal), typeof(char), typeof(string), typeof(bool), typeof(DateTime),
2626
typeof(IntPtr), typeof(UIntPtr),
2727
// do not clone such native type
28-
Type.GetType("System.RuntimeType")
28+
Type.GetType("System.RuntimeType"),
29+
Type.GetType("System.RuntimeTypeHandle")
2930
}) KnownTypes.TryAdd(x, true);
3031
}
3132

@@ -51,7 +52,12 @@ internal static bool IsTypeSafe(Type type, HashSet<Type> processingTypes)
5152
return true;
5253
}
5354

54-
55+
if (type.FullName.StartsWith("System.Reflection.Emit") && type.Assembly == typeof(System.Reflection.Emit.OpCode).Assembly)
56+
{
57+
KnownTypes.TryAdd(type, true);
58+
return true;
59+
}
60+
5561
// this types are serious native resources, it is better not to clone it
5662
if (type.IsSubclassOf(typeof(System.Runtime.ConstrainedExecution.CriticalFinalizerObject)))
5763
{

0 commit comments

Comments
 (0)