[CSHARP-1296] StackOverflowException when serializing a class C that implements IEnumerable<C> Created: 23/May/15 Updated: 13/Apr/16 Resolved: 26/May/15 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | Serialization |
| Affects Version/s: | None |
| Fix Version/s: | 2.1 |
| Type: | Bug | Priority: | Minor - P4 |
| Reporter: | Lenny Granovsky | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 0 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Attachments: |
|
||||||||||||||||
| Issue Links: |
|
||||||||||||||||
| Description |
|
If the object that is being inserted has a dynamic type with a JObject type in it (this is the default type used by JSON.NET for deserialize the JSON), then the InsertOneAsync method throws the StackOverflowException. It would be OK if driver does not support JObject and throws an appropriate exception, but since the StackOverflowException crashes the application and is very hard to debug, at very least the driver should not cause this type of exception. This is the code to replicate it: async Task Main() "; var data = new DomainEventData() ; MongoClient client = new MongoClient("mongodb://localhost/tests"); await items.InsertOneAsync(data); // Define other methods and classes here [BsonElement("eventName")] public string EventName { get; set; } [BsonElement("tenantId")] [BsonElement("aggregateId")] public Guid AggregateId { get; set; } [BsonElement("aggregateName")] [BsonElement("details")] public dynamic Details { get; set; } [BsonElement("utcTimestamp")] public DomainEventData() { this.Id = Guid.NewGuid(); this.TenantId = Guid.Empty; this.AggregateId = Guid.Empty; this.EventName = string.Empty; this.UtcTimestamp = DateTime.UtcNow; this.AggregateName = string.Empty; }} BTW, changing the: |
| Comments |
| Comment by Githook User [ 26/May/15 ] | ||
|
Author: {u'username': u'rstam', u'name': u'rstam', u'email': u'robert@robertstam.org'}Message: | ||
| Comment by Githook User [ 26/May/15 ] | ||
|
Author: {u'username': u'rstam', u'name': u'rstam', u'email': u'robert@robertstam.org'}Message: | ||
| Comment by Lenny Granovsky [ 23/May/15 ] | ||
|
Thank you for the explanation. It is good to know the actual reason. I don't see any problem with not supporting JObject by default. The only issue is the StackOverflow by itself. Maybe going into limited number of loops and throwing an exception upon that limit has more advantage. Based on documentation, the MongoDB document supports up to 100 nested levels, therefore it seems like a natural limit to stop and throw an exception after 100 recursive iterations. I'm sure you'll find the best option, I appreciate fixing the bug itself. | ||
| Comment by Robert Stam [ 23/May/15 ] | ||
|
The problematic type for us is JToken, which is declared as:
The problem can be reproduced with any type that implements IEnumerable of itself:
In the process of constructing a serializer for C we recursively create a serializer for the IEnumerable's items. But when the items are of the same type we get stuck in an infinite recursion loop. | ||
| Comment by Craig Wilson [ 23/May/15 ] | ||
|
Thanks Lenny. Yes, a stackoverflow is not good. We'll figure it out. However, we can't support just any dynamic type because we don't know that the callsite will be in C#. However, a serializer can be registered for JObject. As part of For this ticket, I'll make sure we fix the stackoverflow problem. Thanks for the report, | ||
| Comment by Lenny Granovsky [ 23/May/15 ] | ||
|
The file with code attached |