Skip to content

Commit 4df1dd5

Browse files
committed
Fixed possible corruption of thread local state.
When this manifests the serializer will begin writing things like this: "{\"foo\":123}" instead of this: {"foo":123}
1 parent b23f7a1 commit 4df1dd5

File tree

4 files changed

+110
-37
lines changed

4 files changed

+110
-37
lines changed

src/ServiceStack.Text/Common/WriteDictionary.cs

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -123,22 +123,34 @@ public static void WriteIDictionary(TextWriter writer, object oMap)
123123
JsWriter.WriteItemSeperatorIfRanOnce(writer, ref ranOnce);
124124

125125
JsState.WritingKeyCount++;
126-
JsState.IsWritingValue = false;
127-
128-
if (encodeMapKey)
126+
try
129127
{
130-
JsState.IsWritingValue = true; //prevent ""null""
131-
writer.Write(JsWriter.QuoteChar);
132-
writeKeyFn(writer, key);
133-
writer.Write(JsWriter.QuoteChar);
128+
JsState.IsWritingValue = false;
129+
130+
if (encodeMapKey)
131+
{
132+
JsState.IsWritingValue = true; //prevent ""null""
133+
try
134+
{
135+
writer.Write(JsWriter.QuoteChar);
136+
writeKeyFn(writer, key);
137+
writer.Write(JsWriter.QuoteChar);
138+
}
139+
finally
140+
{
141+
JsState.IsWritingValue = false;
142+
}
143+
}
144+
else
145+
{
146+
writeKeyFn(writer, key);
147+
}
134148
}
135-
else
149+
finally
136150
{
137-
writeKeyFn(writer, key);
151+
JsState.WritingKeyCount--;
138152
}
139153

140-
JsState.WritingKeyCount--;
141-
142154
writer.Write(JsWriter.MapKeySeperator);
143155

144156
if (isNull)
@@ -155,8 +167,14 @@ public static void WriteIDictionary(TextWriter writer, object oMap)
155167
}
156168

157169
JsState.IsWritingValue = true;
158-
writeValueFn(writer, dictionaryValue);
159-
JsState.IsWritingValue = false;
170+
try
171+
{
172+
writeValueFn(writer, dictionaryValue);
173+
}
174+
finally
175+
{
176+
JsState.IsWritingValue = false;
177+
}
160178
}
161179
}
162180

@@ -203,22 +221,27 @@ public static void WriteGenericIDictionary(
203221
JsWriter.WriteItemSeperatorIfRanOnce(writer, ref ranOnce);
204222

205223
JsState.WritingKeyCount++;
206-
JsState.IsWritingValue = false;
207-
208-
if (encodeMapKey)
224+
try
209225
{
210-
JsState.IsWritingValue = true; //prevent ""null""
211-
writer.Write(JsWriter.QuoteChar);
212-
writeKeyFn(writer, kvp.Key);
213-
writer.Write(JsWriter.QuoteChar);
226+
JsState.IsWritingValue = false;
227+
228+
if (encodeMapKey)
229+
{
230+
JsState.IsWritingValue = true; //prevent ""null""
231+
writer.Write(JsWriter.QuoteChar);
232+
writeKeyFn(writer, kvp.Key);
233+
writer.Write(JsWriter.QuoteChar);
234+
}
235+
else
236+
{
237+
writeKeyFn(writer, kvp.Key);
238+
}
214239
}
215-
else
240+
finally
216241
{
217-
writeKeyFn(writer, kvp.Key);
242+
JsState.WritingKeyCount--;
218243
}
219244

220-
JsState.WritingKeyCount--;
221-
222245
writer.Write(JsWriter.MapKeySeperator);
223246

224247
if (isNull)
@@ -228,8 +251,14 @@ public static void WriteGenericIDictionary(
228251
else
229252
{
230253
JsState.IsWritingValue = true;
231-
writeValueFn(writer, kvp.Value);
232-
JsState.IsWritingValue = false;
254+
try
255+
{
256+
writeValueFn(writer, kvp.Value);
257+
}
258+
finally
259+
{
260+
JsState.IsWritingValue = false;
261+
}
233262
}
234263
}
235264

src/ServiceStack.Text/Common/WriteType.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -396,15 +396,21 @@ public static void WriteProperties(TextWriter writer, object value)
396396
writer.Write(JsWriter.MapKeySeperator);
397397

398398
if (typeof(TSerializer) == typeof(JsonTypeSerializer)) JsState.IsWritingValue = true;
399-
if (propertyValue == null)
399+
try
400400
{
401-
writer.Write(JsonUtils.Null);
401+
if (propertyValue == null)
402+
{
403+
writer.Write(JsonUtils.Null);
404+
}
405+
else
406+
{
407+
propertyWriter.WriteFn(writer, propertyValue);
408+
}
402409
}
403-
else
410+
finally
404411
{
405-
propertyWriter.WriteFn(writer, propertyValue);
412+
if (typeof(TSerializer) == typeof(JsonTypeSerializer)) JsState.IsWritingValue = false;
406413
}
407-
if (typeof(TSerializer) == typeof(JsonTypeSerializer)) JsState.IsWritingValue = false;
408414
}
409415
}
410416

src/ServiceStack.Text/QueryStringSerializer.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,28 @@ public static void WriteIDictionary(TextWriter writer, object oMap)
168168
ranOnce = true;
169169

170170
JsState.WritingKeyCount++;
171-
JsState.IsWritingValue = false;
172-
173-
writeKeyFn(writer, key);
171+
try
172+
{
173+
JsState.IsWritingValue = false;
174174

175-
JsState.WritingKeyCount--;
175+
writeKeyFn(writer, key);
176+
}
177+
finally
178+
{
179+
JsState.WritingKeyCount--;
180+
}
176181

177182
writer.Write("=");
178183

179184
JsState.IsWritingValue = true;
180-
writeValueFn(writer, dictionaryValue);
181-
JsState.IsWritingValue = false;
185+
try
186+
{
187+
writeValueFn(writer, dictionaryValue);
188+
}
189+
finally
190+
{
191+
JsState.IsWritingValue = false;
192+
}
182193
}
183194
}
184195
finally

tests/ServiceStack.Text.Tests/DictionaryTests.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,33 @@ public void Can_deserialize_null_string_string_dictionary()
575575
}
576576
}
577577

578+
[Test]
579+
public void Can_recover_from_exceptions_when_serializing_dictionary_keys()
580+
{
581+
var before = JsConfig<int>.SerializeFn;
582+
try
583+
{
584+
JsConfig<int>.SerializeFn = v =>
585+
{
586+
throw new Exception("Boom!");
587+
};
588+
var target = new Dictionary<int, string>
589+
{
590+
{ 1, "1" },
591+
};
592+
Assert.Throws<Exception>(() => JsonSerializer.SerializeToString(target));
593+
}
594+
finally
595+
{
596+
JsConfig<int>.SerializeFn = before;
597+
}
598+
var json = JsonSerializer.SerializeToString(new ModelWithDictionary());
599+
600+
json.Print();
601+
602+
Assert.That(json.StartsWith("{"), Is.True);
603+
}
604+
578605
private class ModelWithDictionary
579606
{
580607
public Dictionary<string, string> Value { get; set; }

0 commit comments

Comments
 (0)