Skip to content

Commit 95c10ca

Browse files
authored
police against issues with writing cyclic data (#421)
1 parent b6edbff commit 95c10ca

File tree

13 files changed

+176
-3
lines changed

13 files changed

+176
-3
lines changed

csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvGenerator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,11 @@ public CsvGenerator disable(Feature f) {
478478
return this;
479479
}
480480

481+
@Override
482+
public StreamWriteConstraints streamWriteConstraints() {
483+
return _ioContext.streamWriteConstraints();
484+
}
485+
481486
/*
482487
/**********************************************************
483488
/* Public API: low-level I/O
@@ -551,6 +556,7 @@ && _skipValue && isEnabled(JsonGenerator.Feature.IGNORE_UNKNOWN)) {
551556
}
552557
}
553558
_tokenWriteContext = _tokenWriteContext.createChildArrayContext(null);
559+
streamWriteConstraints().validateNestingDepth(_tokenWriteContext.getNestingDepth());
554560
// and that's about it, really
555561
}
556562

@@ -597,6 +603,7 @@ public final void writeStartObject() throws IOException
597603
}
598604
}
599605
_tokenWriteContext = _tokenWriteContext.createChildObjectContext(null);
606+
streamWriteConstraints().validateNestingDepth(_tokenWriteContext.getNestingDepth());
600607
}
601608

602609
@Override

csv/src/main/java/com/fasterxml/jackson/dataformat/csv/impl/SimpleTokenWriteContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ protected SimpleTokenWriteContext(int type, SimpleTokenWriteContext parent, DupD
6060
super();
6161
_type = type;
6262
_parent = parent;
63+
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
6364
_dups = dups;
6465
_index = -1;
6566
_currentValue = currentValue;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.fasterxml.jackson.dataformat.csv.ser.dos;
2+
3+
import com.fasterxml.jackson.core.StreamWriteConstraints;
4+
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
6+
import com.fasterxml.jackson.dataformat.csv.ModuleTestBase;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
/**
12+
* Simple unit tests to verify that we fail gracefully if you attempt to serialize
13+
* data that is cyclic (eg a list that contains itself).
14+
*/
15+
public class CyclicDataSerTest extends ModuleTestBase
16+
{
17+
private final CsvMapper MAPPER = mapperForCsv();
18+
19+
public void testListWithSelfReference() throws Exception {
20+
List<Object> list = new ArrayList<>();
21+
list.add(list);
22+
try {
23+
MAPPER.writeValueAsString(list);
24+
fail("expected JsonMappingException");
25+
} catch (JsonMappingException jmex) {
26+
String exceptionPrefix = String.format("Document nesting depth (%d) exceeds the maximum allowed",
27+
StreamWriteConstraints.DEFAULT_MAX_DEPTH + 1);
28+
assertTrue("JsonMappingException message is as expected?",
29+
jmex.getMessage().startsWith(exceptionPrefix));
30+
}
31+
}
32+
}

properties/src/main/java/com/fasterxml/jackson/dataformat/javaprop/JavaPropsGenerator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ public JavaPropsGenerator(IOContext ctxt, int stdFeatures, ObjectCodec codec)
8080
_jpropContext = JPropWriteContext.createRootContext();
8181
}
8282

83+
@Override
84+
public StreamWriteConstraints streamWriteConstraints() {
85+
return _ioContext.streamWriteConstraints();
86+
}
87+
8388
@Override // since 2.13
8489
public Object currentValue() {
8590
return _jpropContext.getCurrentValue();
@@ -267,6 +272,7 @@ public void writeFieldName(String name) throws IOException
267272
public void writeStartArray() throws IOException {
268273
_verifyValueWrite("start an array");
269274
_jpropContext = _jpropContext.createChildArrayContext(_basePath.length());
275+
streamWriteConstraints().validateNestingDepth(_jpropContext.getNestingDepth());
270276
}
271277

272278
@Override
@@ -281,6 +287,7 @@ public void writeEndArray() throws IOException {
281287
public void writeStartObject() throws IOException {
282288
_verifyValueWrite("start an object");
283289
_jpropContext = _jpropContext.createChildObjectContext(_basePath.length());
290+
streamWriteConstraints().validateNestingDepth(_jpropContext.getNestingDepth());
284291
}
285292

286293
@Override

properties/src/main/java/com/fasterxml/jackson/dataformat/javaprop/io/JPropWriteContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ protected JPropWriteContext(int type, JPropWriteContext parent,
5959
super();
6060
_type = type;
6161
_parent = parent;
62+
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
6263
_basePathLength = basePathLength;
6364
_index = -1;
6465
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.fasterxml.jackson.dataformat.javaprop.dos;
2+
3+
import com.fasterxml.jackson.core.StreamWriteConstraints;
4+
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.dataformat.javaprop.JavaPropsMapper;
6+
import com.fasterxml.jackson.dataformat.javaprop.ModuleTestBase;
7+
8+
import java.util.ArrayList;
9+
import java.util.List;
10+
11+
/**
12+
* Simple unit tests to verify that we fail gracefully if you attempt to serialize
13+
* data that is cyclic (eg a list that contains itself).
14+
*/
15+
public class CyclicDataSerTest extends ModuleTestBase
16+
{
17+
private final JavaPropsMapper MAPPER = newPropertiesMapper();
18+
19+
public void testListWithSelfReference() throws Exception {
20+
List<Object> list = new ArrayList<>();
21+
list.add(list);
22+
try {
23+
MAPPER.writeValueAsString(list);
24+
fail("expected JsonMappingException");
25+
} catch (JsonMappingException jmex) {
26+
String exceptionPrefix = String.format("Document nesting depth (%d) exceeds the maximum allowed",
27+
StreamWriteConstraints.DEFAULT_MAX_DEPTH + 1);
28+
assertTrue("JsonMappingException message is as expected?",
29+
jmex.getMessage().startsWith(exceptionPrefix));
30+
}
31+
}
32+
}

properties/src/test/java/com/fasterxml/jackson/dataformat/javaprop/dos/DeepNestParserTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ public void testDeeplyNestedData() throws IOException {
2323
}
2424
fail("expected StreamConstraintsException");
2525
} catch (StreamConstraintsException e) {
26+
String exceptionPrefix = String.format("Document nesting depth (%d) exceeds the maximum allowed",
27+
StreamReadConstraints.DEFAULT_MAX_DEPTH + 1);
2628
assertTrue("unexpected exception message: " + e.getMessage(),
27-
e.getMessage().startsWith("Document nesting depth (1001) exceeds the maximum allowed"));
29+
e.getMessage().startsWith(exceptionPrefix));
2830
}
2931
}
3032

toml/src/main/java/com/fasterxml/jackson/dataformat/toml/TomlGenerator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ public TomlGenerator(IOContext ioCtxt, int stdFeatures, int tomlFeatures, Object
9191
_outputEnd = _outputBuffer.length;
9292
}
9393

94+
@Override
95+
public StreamWriteConstraints streamWriteConstraints() {
96+
return _ioContext.streamWriteConstraints();
97+
}
98+
9499
/*
95100
/**********************************************************************
96101
/* Versioned
@@ -343,6 +348,7 @@ public void writeStartArray(Object currValue) throws IOException {
343348
_verifyValueWrite("start an array", true);
344349
_streamWriteContext = _streamWriteContext.createChildArrayContext(currValue,
345350
_basePath.length());
351+
streamWriteConstraints().validateNestingDepth(_streamWriteContext.getNestingDepth());
346352
if (_streamWriteContext._inline) {
347353
_writeRaw('[');
348354
}
@@ -373,6 +379,7 @@ public void writeStartObject(Object forValue) throws IOException {
373379
// objects aren't always materialized right now
374380
_verifyValueWrite("start an object", false);
375381
_streamWriteContext = _streamWriteContext.createChildObjectContext(forValue, _basePath.length());
382+
streamWriteConstraints().validateNestingDepth(_streamWriteContext.getNestingDepth());
376383
if (_streamWriteContext._inline) {
377384
writeRaw('{');
378385
}

toml/src/main/java/com/fasterxml/jackson/dataformat/toml/TomlWriteContext.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ final class TomlWriteContext extends JsonStreamContext {
5656
super();
5757
_type = type;
5858
_parent = parent;
59+
_nestingDepth = parent == null ? 0 : parent._nestingDepth + 1;
5960
_basePathLength = basePathLength;
6061
_index = -1;
6162
_currentValue = currValue;

toml/src/test/java/com/fasterxml/jackson/dataformat/toml/FuzzTomlReadTest.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import java.io.InputStream;
55
import java.util.Arrays;
66

7+
import com.fasterxml.jackson.core.StreamReadConstraints;
8+
import com.fasterxml.jackson.core.StreamWriteConstraints;
79
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
810
import org.junit.Assert;
911
import org.junit.Test;
@@ -62,7 +64,9 @@ public void testParseInlineTable50432() throws Exception
6264
TOML_MAPPER.readTree(is);
6365
Assert.fail("Should not pass");
6466
} catch (IOException e) {
65-
verifyException(e, "Document nesting depth (1001) exceeds the maximum allowed");
67+
String exceptionPrefix = String.format("Document nesting depth (%d) exceeds the maximum allowed",
68+
StreamReadConstraints.DEFAULT_MAX_DEPTH + 1);
69+
verifyException(e, exceptionPrefix);
6670
}
6771
}
6872
}
@@ -120,7 +124,9 @@ public void testStackOverflow50083() throws Exception
120124
TOML_MAPPER.readTree(input.toString());
121125
Assert.fail("Should not pass");
122126
} catch (StreamConstraintsException e) {
123-
verifyException(e, "Document nesting depth (1001) exceeds the maximum allowed");
127+
String exceptionPrefix = String.format("Document nesting depth (%d) exceeds the maximum allowed",
128+
StreamWriteConstraints.DEFAULT_MAX_DEPTH + 1);
129+
verifyException(e, exceptionPrefix);
124130
}
125131
}
126132

0 commit comments

Comments
 (0)