Skip to content

Commit bf67b3b

Browse files
committed
Revert "Remove memcmp from MessagePackString. Fix #206."
This reverts commit 208c0c7 and a part of 23effe8.
1 parent 6e21925 commit bf67b3b

11 files changed

Lines changed: 419 additions & 18 deletions

File tree

CHANGES.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -621,9 +621,6 @@ Release 0.9.0 beta1 2016/09/24
621621

622622
Release 0.9.0 beta2 2017/2/11
623623

624-
BREAKING CHANGES
625-
* MessagePackObject comparison which have large binary data will be about 2x - 18x slower in .NET 3.5/4.5/4.6(other platforms will not be affected).
626-
627624
NEW FEATURES
628625
* Users of serializer code generator API can specify TextWriter to output. This may improve tooling chain.
629626
* Users of serializer code generator API can suppress [DebuggerNonUserCode] attribute to enable debugger step in.
@@ -638,7 +635,6 @@ Release 0.9.0 beta2 2017/2/11
638635
* Fix extra field causes IndexOutOfBoundException when reflection based serializers are used. Issue #199
639636
* Fix some built-in serializers throws InvalidOperationException instead of SerializationException for type errors. Issue #204
640637
* Fix a combination of readonly members and collection members incorrect code generation when the type also have deserialization constructor. Issue #207.
641-
* Fix Windows Native build error. Issue #206.
642638
* Fix built-in collection serializers such as List<T> serializer causes SecurityException when the program run in restricted environment like Silverlight. Issue #205.
643639
* Fix null items of complex type in List<T> or Dictionary<TKey, TValue> will not be deserialized as null. Issue #211. (from 0.8.1)
644640
* Fix types which implement IPackable and IUnpackable but do not have any members cannot be serialized. Issue #202

MsgPack.sln

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ EndProject
4343
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MsgPack.Net45", "src\MsgPack.Net45\MsgPack.Net45.csproj", "{9C7B55A6-AF7F-4D26-AB5B-297B7FF25B6D}"
4444
EndProject
4545
Global
46+
GlobalSection(Performance) = preSolution
47+
HasPerformanceSessions = true
48+
EndGlobalSection
4649
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4750
CodeAnalysis|Any CPU = CodeAnalysis|Any CPU
4851
CodeAnalysis|ARM = CodeAnalysis|ARM

src/MsgPack.Net35/MsgPack.Net35.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1020,6 +1020,9 @@
10201020
<Compile Include="..\MsgPack\UnpackingStreamReader.cs">
10211021
<Link>UnpackingStreamReader.cs</Link>
10221022
</Compile>
1023+
<Compile Include="..\MsgPack\UnsafeNativeMethods.cs">
1024+
<Link>UnsafeNativeMethods.cs</Link>
1025+
</Compile>
10231026
<Compile Include="..\MsgPack\Validation.cs">
10241027
<Link>Validation.cs</Link>
10251028
</Compile>

src/MsgPack.Net45/MsgPack.Net45.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,9 @@
10571057
<Compile Include="..\MsgPack\UnpackingStreamReader.cs">
10581058
<Link>UnpackingStreamReader.cs</Link>
10591059
</Compile>
1060+
<Compile Include="..\MsgPack\UnsafeNativeMethods.cs">
1061+
<Link>UnsafeNativeMethods.cs</Link>
1062+
</Compile>
10601063
<Compile Include="..\MsgPack\Validation.cs">
10611064
<Link>Validation.cs</Link>
10621065
</Compile>

src/MsgPack.Silverlight.5/MsgPack.Silverlight.5.csproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,7 @@
5656
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'CodeAnalysis|AnyCPU'">
5757
<OutputPath>bin\CodeAnalysis\</OutputPath>
5858
<DefineConstants>TRACE;SILVERLIGHT;CODE_ANALYSIS</DefineConstants>
59-
<DocumentationFile>
60-
</DocumentationFile>
59+
<DocumentationFile></DocumentationFile>
6160
<Optimize>true</Optimize>
6261
<NoStdLib>true</NoStdLib>
6362
<DebugType>pdbonly</DebugType>
@@ -777,6 +776,9 @@
777776
<Compile Include="..\MsgPack\UnpackingStreamReader.cs">
778777
<Link>UnpackingStreamReader.cs</Link>
779778
</Compile>
779+
<Compile Include="..\MsgPack\UnsafeNativeMethods.cs">
780+
<Link>UnsafeNativeMethods.cs</Link>
781+
</Compile>
780782
<Compile Include="Properties\AssemblyInfo.cs" />
781783
<Compile Include="Serialization\LockRecursionPolicy.cs" />
782784
<Compile Include="Serialization\ReaderWriterLockSlim.cs" />

src/MsgPack.Xamarin.Android/MsgPack.Xamarin.Android.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,9 @@
758758
<Compile Include="..\MsgPack\UnpackingStreamReader.cs">
759759
<Link>UnpackingStreamReader.cs</Link>
760760
</Compile>
761+
<Compile Include="..\MsgPack\UnsafeNativeMethods.cs">
762+
<Link>UnsafeNativeMethods.cs</Link>
763+
</Compile>
761764
<Compile Include="Properties\AssemblyInfo.cs" />
762765
</ItemGroup>
763766
<ItemGroup>

src/MsgPack.Xamarin.iOS/MsgPack.Xamarin.iOS.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,9 @@
754754
<Compile Include="..\MsgPack\UnpackingStreamReader.cs">
755755
<Link>UnpackingStreamReader.cs</Link>
756756
</Compile>
757+
<Compile Include="..\MsgPack\UnsafeNativeMethods.cs">
758+
<Link>UnsafeNativeMethods.cs</Link>
759+
</Compile>
757760
<Compile Include="Properties\AssemblyInfo.cs" />
758761
</ItemGroup>
759762
<ItemGroup>

src/MsgPack/MessagePackString.cs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -266,21 +266,30 @@ private static bool EqualsEncoded( MessagePackString left, MessagePackString rig
266266
return false;
267267
}
268268

269+
#if !UNITY && !WINDOWS_PHONE && !NETFX_CORE
270+
if ( _isFastEqualsDisabled == 0 )
271+
{
272+
try
273+
{
274+
return UnsafeFastEquals( left._encoded, right._encoded );
275+
}
276+
catch ( SecurityException )
277+
{
278+
Interlocked.Exchange( ref _isFastEqualsDisabled, 1 );
279+
}
280+
catch ( MemberAccessException )
281+
{
282+
Interlocked.Exchange( ref _isFastEqualsDisabled, 1 );
283+
}
284+
}
285+
#endif // if !UNITY && !WINDOWS_PHONE && !NETFX_CORE
286+
269287
return SlowEquals( left._encoded, right._encoded );
270288
}
271289

272-
// It is 1.8x(not-aligned) - 11.1x (well-aligned) slower than memcmp, but this call is rare and it is acceptable in most cases.
273-
// It is roughly equal to String.Equals(String).
274290
private static bool SlowEquals( byte[] x, byte[] y )
275291
{
276-
if ( x.Length != y.Length )
277-
{
278-
return false;
279-
}
280-
281-
// This looks naive, but loop expansion or unsafe code is not effect here (unsafe is more slower).
282-
283-
for ( var i = 0; i < x.Length; i++ )
292+
for ( int i = 0; i < x.Length; i++ )
284293
{
285294
if ( x[ i ] != y[ i ] )
286295
{
@@ -291,6 +300,44 @@ private static bool SlowEquals( byte[] x, byte[] y )
291300
return true;
292301
}
293302

303+
#if !UNITY && !WINDOWS_PHONE && !NETFX_CORE
304+
#if SILVERLIGHT
305+
private static int _isFastEqualsDisabled =
306+
System.Windows.Application.Current.HasElevatedPermissions ? 0 : 1;
307+
#else
308+
private static int _isFastEqualsDisabled;
309+
#endif // if SILVERLIGHT
310+
311+
#if DEBUG
312+
// for testing
313+
internal static bool IsFastEqualsDisabled
314+
{
315+
get { return _isFastEqualsDisabled != 0; }
316+
}
317+
#endif
318+
319+
#if !NETFX_35 && !UNITY
320+
[SecuritySafeCritical]
321+
#endif // !NETFX_35 && !UNITY
322+
private static bool UnsafeFastEquals( byte[] x, byte[] y )
323+
{
324+
#if DEBUG
325+
Contract.Assert( x != null, "x != null" );
326+
Contract.Assert( y != null, "y != null" );
327+
Contract.Assert( 0 < x.Length, "0 < x.Length" );
328+
Contract.Assert( x.Length == y.Length, "x.Length == y.Length" );
329+
#endif // if DEBUG
330+
int result;
331+
if ( !UnsafeNativeMethods.TryMemCmp( x, y, new UIntPtr( unchecked( ( uint )x.Length ) ), out result ) )
332+
{
333+
Interlocked.Exchange( ref _isFastEqualsDisabled, 1 );
334+
return SlowEquals( x, y );
335+
}
336+
337+
return result == 0;
338+
}
339+
#endif // if !UNITY && !WINDOWS_PHONE && !NETFX_CORE
340+
294341
#if !SILVERLIGHT && !NETSTANDARD1_1 && !NETSTANDARD1_3
295342
[Serializable]
296343
#endif // !SILVERLIGHT && !NETSTANDARD1_1 && !NETSTANDARD1_3

src/MsgPack/MsgPack.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@
541541
<Compile Include="UnpackingMode.cs" />
542542
<Compile Include="UnpackingStream.cs" />
543543
<Compile Include="UnpackingStreamReader.cs" />
544+
<Compile Include="UnsafeNativeMethods.cs" />
544545
<Compile Include="Validation.cs" />
545546
<Compile Include="UnpackingResult.cs" />
546547
<Compile Include="Unpacker.cs" />

src/MsgPack/UnsafeNativeMethods.cs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#region -- License Terms --
2+
//
3+
// MessagePack for CLI
4+
//
5+
// Copyright (C) 2010-2016 FUJIWARA, Yusuke
6+
//
7+
// Licensed under the Apache License, Version 2.0 (the "License");
8+
// you may not use this file except in compliance with the License.
9+
// You may obtain a copy of the License at
10+
//
11+
// http://www.apache.org/licenses/LICENSE-2.0
12+
//
13+
// Unless required by applicable law or agreed to in writing, software
14+
// distributed under the License is distributed on an "AS IS" BASIS,
15+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
// See the License for the specific language governing permissions and
17+
// limitations under the License.
18+
//
19+
#endregion -- License Terms --
20+
21+
using System;
22+
using System.Runtime.InteropServices;
23+
using System.Security;
24+
using System.Threading;
25+
26+
namespace MsgPack
27+
{
28+
29+
#if !SILVERLIGHT && !NETSTANDARD1_1 && !NETSTANDARD1_3
30+
[SuppressUnmanagedCodeSecurity]
31+
#endif // !SILVERLIGHT && !NETSTANDARD1_1 && !NETSTANDARD1_3
32+
#if !NETFX_35
33+
[SecurityCritical]
34+
#endif // !NETFX_35
35+
internal static class UnsafeNativeMethods
36+
{
37+
private static int _libCAvailability = 0;
38+
private const int _libCAvailability_Unknown = 0;
39+
private const int _libCAvailability_MSVCRT = 1;
40+
private const int _libCAvailability_LibC = 2;
41+
private const int _libCAvailability_None = -1;
42+
43+
#if NETFX_35
44+
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Justification = "OK, this is SecurityCritical" )]
45+
#endif // NETFX_35
46+
[DllImport( "msvcrt", CallingConvention = CallingConvention.Cdecl, EntryPoint = "memcmp", ExactSpelling = true, SetLastError = false )]
47+
private static extern int memcmpVC( byte[] s1, byte[] s2, /*SIZE_T*/UIntPtr size );
48+
49+
#if !NETFX_CORE
50+
// libc is for non Windows environment.
51+
// Note that libc caused compilation error on .NET Native, so the DllImport itself should not be included in the first time.
52+
#if NETFX_35
53+
[System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Security", "CA5122:PInvokesShouldNotBeSafeCriticalFxCopRule", Justification = "OK, this is SecurityCritical" )]
54+
#endif // NETFX_35
55+
[DllImport( "libc", CallingConvention = CallingConvention.Cdecl, EntryPoint = "memcmp", ExactSpelling = true, SetLastError = false )]
56+
private static extern int memcmpLibC( byte[] s1, byte[] s2, /*SIZE_T*/UIntPtr size );
57+
#endif // !NETFX_CORE
58+
59+
public static bool TryMemCmp( byte[] s1, byte[] s2, /*SIZE_T*/UIntPtr size, out int result )
60+
{
61+
if ( _libCAvailability < 0 )
62+
{
63+
result = 0;
64+
return false;
65+
}
66+
67+
if ( _libCAvailability <= _libCAvailability_MSVCRT )
68+
{
69+
try
70+
{
71+
result = memcmpVC( s1, s2, size );
72+
return true;
73+
}
74+
catch ( DllNotFoundException )
75+
{
76+
#if !NETFX_CORE
77+
Interlocked.Exchange( ref _libCAvailability, _libCAvailability_LibC );
78+
#else
79+
Interlocked.Exchange( ref _libCAvailability, _libCAvailability_None );
80+
#endif // !NETFX_CORE
81+
}
82+
}
83+
84+
#if !NETFX_CORE
85+
if ( _libCAvailability <= _libCAvailability_LibC )
86+
{
87+
try
88+
{
89+
result = memcmpLibC( s1, s2, size );
90+
return true;
91+
}
92+
catch ( DllNotFoundException )
93+
{
94+
Interlocked.Exchange( ref _libCAvailability, _libCAvailability_None );
95+
}
96+
}
97+
#endif // !NETFX_CORE
98+
99+
result = 0;
100+
return false;
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)