Skip to content

Commit c345828

Browse files
niemyjskiCopilot
andcommitted
Fix dictionary depth limit bypass in WriteValue
WriteValue for IDictionary entries wrote the property name before checking whether the value could actually be serialized at the current depth. When a complex value exceeded maxDepth, WriteValue returned without writing anything, leaving the JSON writer in an invalid state. The error was silently swallowed by continueOnSerializationError, causing a fallback to full serialization (effectively ignoring the depth limit entirely). Fix: check depth before writing the property name. Skip complex dictionary entries that would exceed maxDepth, consistent with the object property path. Added regression test that fails before the fix (depth limit violated) and passes after. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 2b82d4c commit c345828

2 files changed

Lines changed: 33 additions & 4 deletions

File tree

src/Exceptionless/Serializer/DefaultJsonSerializer.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,17 @@ private void WriteValue(Utf8JsonWriter writer, object value, Type type, string[]
9595
string key = entry.Key?.ToString() ?? "";
9696
if (hasExclusions && key.AnyWildcardMatches(exclusions, ignoreCase: true))
9797
continue;
98-
writer.WritePropertyName(key);
99-
if (entry.Value == null)
98+
if (entry.Value == null) {
99+
writer.WritePropertyName(key);
100100
writer.WriteNullValue();
101-
else
102-
WriteValue(writer, entry.Value, entry.Value.GetType(), exclusions, hasExclusions, maxDepth, currentDepth + 1);
101+
} else {
102+
Type entryType = entry.Value.GetType();
103+
// Skip complex values that would exceed max depth
104+
if (!IsPrimitiveType(entryType) && currentDepth + 1 >= maxDepth)
105+
continue;
106+
writer.WritePropertyName(key);
107+
WriteValue(writer, entry.Value, entryType, exclusions, hasExclusions, maxDepth, currentDepth + 1);
108+
}
103109
}
104110
writer.WriteEndObject();
105111
return;

test/Exceptionless.Tests/Serializer/JsonSerializerTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,29 @@ public void Serialize_Event_DataDictionaryRoundTrip_PreservesObjectStructure() {
624624
Assert.Contains("\"o_s_name\":\"Windows\"", apiJson);
625625
}
626626

627+
[Fact]
628+
public void Serialize_DictionaryWithNestedObjectAtDepthLimit_ProducesValidJson() {
629+
// Regression test: When a dictionary contains a nested complex object and
630+
// the depth limit is reached, WriteValue returned without writing a value
631+
// after the property name was already written. The error was silently swallowed
632+
// by continueOnSerializationError, falling back to full serialization (violating
633+
// the depth limit). This means depth limits don't work for dictionaries.
634+
var serializer = GetSerializer();
635+
var dict = new Dictionary<string, object> {
636+
{ "simple", "hello" },
637+
{ "nested", new Dictionary<string, object> { { "deep", "value" } } }
638+
};
639+
640+
// maxDepth=1: top-level dict is written, nested complex values should be truncated
641+
string json = serializer.Serialize(dict, null, maxDepth: 1);
642+
643+
// Must produce valid JSON
644+
Assert.NotNull(json);
645+
Assert.Contains("\"simple\":\"hello\"", json);
646+
// The nested dictionary should NOT appear at depth (depth limit should be respected)
647+
Assert.DoesNotContain("\"deep\"", json);
648+
}
649+
627650
[Fact]
628651
public void Deserialize_Event_ShouldDeserializeReferenceIds() {
629652
// Arrange

0 commit comments

Comments
 (0)