Skip to content

Commit 48f1755

Browse files
committed
Fix MessagePackObject deserializer cannot handle empty collection correctly. Issue #92.
Return itself when ReadSubtree() just calls duplicatedly. In addition, there is a bug that disposing SubTreeUnpacker twice causes InvalidOperationException. It is just a bug even if the issue #92 was not found.
1 parent b493d96 commit 48f1755

File tree

3 files changed

+68
-13
lines changed

3 files changed

+68
-13
lines changed

CHANGES.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ Release 0.6.0 Beta3 - 2015/06/14
277277
BUG FIXES
278278
* Remove FILETIME dependency to avoid build error in Xamarin/Unity. Issue #87
279279

280-
Release 0.6 - 2015/06/29
280+
Release 0.6.0 Beta4 - 2015/07/05
281281

282282
BREAKING CHANGES / IMPROVEMENTS
283283
* Unity3D DLL now only depends on mscorlib.dll. This breaks compabitlity because the library cannot recognize Stack<T>, Queue<T> and NameValueCollection. If you want to these types support, use Unity3D.Full drop instead.
@@ -287,3 +287,6 @@ Release 0.6 - 2015/06/29
287287

288288
BUG FIXES
289289
* Fix Unity source code to avoid nullable equality operator. Issue #88
290+
* Fix MessagePackObject deserializer cannot handle empty collection correctly. Issue #92.
291+
* Fix disposing "subtree" Unpacker twice causes Exception.
292+

src/MsgPack/SubtreeUnpacker.cs

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ internal sealed partial class SubtreeUnpacker : Unpacker
5151
private readonly BooleanStack _isMap;
5252
private readonly Int64Stack _unpacked;
5353
private readonly Int64Stack _itemsCount;
54+
private State _state;
5455

5556
public override long ItemsCount
5657
{
@@ -113,24 +114,31 @@ private SubtreeUnpacker( ItemsUnpacker root, SubtreeUnpacker parent )
113114
this._unpacked.Push( 0 );
114115
this._isMap.Push( root.InternalCollectionType == ItemsUnpacker.CollectionType.Map );
115116
}
117+
118+
this._state = State.InHead;
116119
}
117120

118121
protected override void Dispose( bool disposing )
119122
{
120123
if ( disposing )
121124
{
122-
// Drain...
123-
while ( this.ReadCore() )
124-
{
125-
// nop
126-
}
127-
if ( this._parent != null )
125+
if ( this._state != State.Disposed )
128126
{
129-
this._parent.EndReadSubtree();
130-
}
131-
else
132-
{
133-
this._root.EndReadSubtree();
127+
// Drain...
128+
while ( this.ReadCore() )
129+
{
130+
// nop
131+
}
132+
if ( this._parent != null )
133+
{
134+
this._parent.EndReadSubtree();
135+
}
136+
else
137+
{
138+
this._root.EndReadSubtree();
139+
}
140+
141+
this._state = State.Disposed;
134142
}
135143
}
136144

@@ -149,7 +157,13 @@ protected internal override void EndReadSubtree()
149157

150158
protected override Unpacker ReadSubtreeCore()
151159
{
152-
if ( this._unpacked.Count == 0 )
160+
if ( this._state == State.InHead )
161+
{
162+
// Duplicate call -- just return me.
163+
return this;
164+
}
165+
166+
if ( this._unpacked.Count == 0 )
153167
{
154168
throw new InvalidOperationException( "This unpacker is located in the tail." );
155169
}
@@ -194,6 +208,7 @@ protected override bool ReadCore()
194208
}
195209
}
196210

211+
this._state = State.InProgress;
197212
return true;
198213
}
199214

@@ -242,5 +257,12 @@ private void DiscardCompletedStacks()
242257
this._unpacked.Push( this._unpacked.Pop() + 1 );
243258
}
244259
}
260+
261+
private enum State
262+
{
263+
InHead = 0,
264+
InProgress,
265+
Disposed
266+
}
245267
}
246268
}

test/MsgPack.UnitTest/Serialization/RegressionTests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,35 @@ public void TestIssue73()
8686
SerializationContext.Default = original;
8787
}
8888
}
89+
90+
[Test]
91+
public void TestIssue92_EmptyAsMpo()
92+
{
93+
var bytes = new byte[] { 0x82, 0xA1, 0x74, 0x81, 0xA1, 0x74, 0x04, 0xA4, 0x64, 0x61, 0x74, 0x61, 0x80 };
94+
using ( var buffer = new MemoryStream( bytes ) )
95+
{
96+
var serializer = MessagePackSerializer.Get<Dictionary<string, MessagePackObject>>( new SerializationContext() );
97+
var d = serializer.Unpack( buffer );
98+
}
99+
}
100+
101+
[Test]
102+
public void TestIssue92_EmptyAsCollection()
103+
{
104+
var value = new int[][] { new[] { 1, 2 }, new int[ 0 ] };
105+
var serializer = MessagePackSerializer.Get<int[][]>( new SerializationContext() );
106+
using ( var buffer = new MemoryStream() )
107+
{
108+
serializer.Pack( buffer, value );
109+
Console.WriteLine( Binary.ToHexString( buffer.ToArray() ) );
110+
buffer.Position = 0;
111+
var a = serializer.Unpack( buffer );
112+
Assert.That( a.Length, Is.EqualTo( 2 ) );
113+
Assert.That( a[ 0 ].Length, Is.EqualTo( 2 ) );
114+
Assert.That( a[ 0 ][ 0 ], Is.EqualTo( 1 ) );
115+
Assert.That( a[ 0 ][ 1 ], Is.EqualTo( 2 ) );
116+
Assert.That( a[ 1 ].Length, Is.EqualTo( 0 ) );
117+
}
118+
}
89119
}
90120
}

0 commit comments

Comments
 (0)