From 3af7e3eda0076ed44414e671501da358c146c549 Mon Sep 17 00:00:00 2001 From: PJ Fanning Date: Tue, 29 Nov 2022 01:40:48 +0100 Subject: [PATCH] Add num size limit (#827) --- .../fasterxml/jackson/core/JsonFactory.java | 6 +-- .../jackson/core/StreamReadConstraints.java | 2 + .../jackson/core/base/ParserBase.java | 18 ++++++- .../jackson/core/base/ParserMinimalBase.java | 9 +++- .../fasterxml/jackson/core/io/IOContext.java | 37 +++++++++++++-- .../core/io/SegmentedStringWriter.java | 3 +- .../jackson/core/util/TextBuffer.java | 47 ++++++++++++++++--- .../core/ParserFeatureDefaultsTest.java | 5 ++ .../jackson/core/read/NumberOverflowTest.java | 8 ++-- .../jackson/core/read/NumberParsingTest.java | 8 ++-- .../jackson/core/util/TestTextBuffer.java | 34 +++++++------- 11 files changed, 135 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java index d825c0331a..6d04b34d50 100644 --- a/src/main/java/com/fasterxml/jackson/core/JsonFactory.java +++ b/src/main/java/com/fasterxml/jackson/core/JsonFactory.java @@ -1978,7 +1978,7 @@ protected IOContext _createContext(ContentReference contentRef, boolean resource if (contentRef == null) { contentRef = ContentReference.unknown(); } - return new IOContext(_getBufferRecycler(), contentRef, resourceManaged); + return new IOContext(_streamReadConstraints, _getBufferRecycler(), contentRef, resourceManaged); } /** @@ -1993,7 +1993,7 @@ protected IOContext _createContext(ContentReference contentRef, boolean resource */ @Deprecated // @since 2.13 protected IOContext _createContext(Object rawContentRef, boolean resourceManaged) { - return new IOContext(_getBufferRecycler(), + return new IOContext(_streamReadConstraints, _getBufferRecycler(), _createContentReference(rawContentRef), resourceManaged); } @@ -2011,7 +2011,7 @@ protected IOContext _createContext(Object rawContentRef, boolean resourceManaged protected IOContext _createNonBlockingContext(Object srcRef) { // [jackson-core#479]: allow recycling for non-blocking parser again // now that access is thread-safe - return new IOContext(_getBufferRecycler(), + return new IOContext(_streamReadConstraints, _getBufferRecycler(), _createContentReference(srcRef), false); } diff --git a/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java b/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java index ce810e0cd6..33ec533bf7 100644 --- a/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java +++ b/src/main/java/com/fasterxml/jackson/core/StreamReadConstraints.java @@ -11,6 +11,8 @@ public class StreamReadConstraints { private final int _maxNumLen; + public static final StreamReadConstraints UNLIMITED = new StreamReadConstraints(Integer.MAX_VALUE); + public static final class Builder { private int _maxNumLen = StreamReadConstraints.DEFAULT_MAX_NUM_LEN; diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java index ab95f6b26a..f14a7f7701 100644 --- a/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java +++ b/src/main/java/com/fasterxml/jackson/core/base/ParserBase.java @@ -938,10 +938,16 @@ private void _parseSlowInt(int expType) throws IOException _reportTooLongIntegral(expType, numStr); } if ((expType == NR_DOUBLE) || (expType == NR_FLOAT)) { + if (getMaxNumLen() >= 0 && numStr.length() > getMaxNumLen()) { + throw new NumberFormatException("number length exceeds the max number length of " + getMaxNumLen()); + } _numberDouble = NumberInput.parseDouble(numStr, isEnabled(Feature.USE_FAST_DOUBLE_PARSER)); _numTypesValid = NR_DOUBLE; } else { // nope, need the heavy guns... (rare case) - since Jackson v2.14, BigInteger parsing is lazy + if (getMaxNumLen() >= 0 && numStr.length() > getMaxNumLen()) { + throw new NumberFormatException("number length exceeds the max number length of " + getMaxNumLen()); + } _numberBigInt = null; _numberString = numStr; _numTypesValid = NR_BIGINT; @@ -973,7 +979,7 @@ protected void convertNumberToInt() throws IOException { // First, converting from long ought to be easy if ((_numTypesValid & NR_LONG) != 0) { - // Let's verify it's lossless conversion by simple roundtrip + // Let's verify its lossless conversion by simple roundtrip int result = (int) _numberLong; if (((long) result) != _numberLong) { reportOverflowInt(getText(), currentToken()); @@ -1111,7 +1117,11 @@ protected void convertNumberToBigDecimal() throws IOException if ((_numTypesValid & NR_DOUBLE) != 0) { // Let's actually parse from String representation, to avoid // rounding errors that non-decimal floating operations could incur - _numberBigDecimal = NumberInput.parseBigDecimal(getText()); + final String numStr = getText(); + if (getMaxNumLen() >= 0 && numStr.length() > getMaxNumLen()) { + throw new NumberFormatException("number length exceeds the max number length of " + getMaxNumLen()); + } + _numberBigDecimal = NumberInput.parseBigDecimal(numStr); } else if ((_numTypesValid & NR_BIGINT) != 0) { _numberBigDecimal = new BigDecimal(_getBigInteger()); } else if ((_numTypesValid & NR_LONG) != 0) { @@ -1395,4 +1405,8 @@ protected void loadMoreGuaranteed() throws IOException { // Can't declare as deprecated, for now, but shouldn't be needed protected void _finishString() throws IOException { } + protected int getMaxNumLen() { + return _ioContext.streamReadConstraints().getMaxNumberLength(); + } + } diff --git a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java index 188d700ed1..1a93af3b94 100644 --- a/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java +++ b/src/main/java/com/fasterxml/jackson/core/base/ParserMinimalBase.java @@ -384,7 +384,7 @@ public int getValueAsInt(int defaultValue) throws IOException if (t != null) { switch (t.id()) { case ID_STRING: - String str = getText(); + final String str = getText(); if (_hasTextualNull(str)) { return 0; } @@ -425,7 +425,7 @@ public long getValueAsLong(long defaultValue) throws IOException if (t != null) { switch (t.id()) { case ID_STRING: - String str = getText(); + final String str = getText(); if (_hasTextualNull(str)) { return 0L; } @@ -456,6 +456,9 @@ public double getValueAsDouble(double defaultValue) throws IOException if (_hasTextualNull(str)) { return 0L; } + if (getMaxNumLen() >= 0 && str.length() > getMaxNumLen()) { + throw new NumberFormatException("number length exceeds the max number length of " + getMaxNumLen()); + } return NumberInput.parseAsDouble(str, defaultValue); case ID_NUMBER_INT: case ID_NUMBER_FLOAT: @@ -788,4 +791,6 @@ protected static String _ascii(byte[] b) { throw new RuntimeException(e); } } + + protected abstract int getMaxNumLen(); } diff --git a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java index f57c1d3224..d70781ecbb 100644 --- a/src/main/java/com/fasterxml/jackson/core/io/IOContext.java +++ b/src/main/java/com/fasterxml/jackson/core/io/IOContext.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.core.io; import com.fasterxml.jackson.core.JsonEncoding; +import com.fasterxml.jackson.core.StreamReadConstraints; import com.fasterxml.jackson.core.util.BufferRecycler; import com.fasterxml.jackson.core.util.TextBuffer; @@ -60,6 +61,8 @@ public class IOContext */ protected final BufferRecycler _bufferRecycler; + protected final StreamReadConstraints _streamReadConstraints; + /** * Reference to the allocated I/O buffer for low-level input reading, * if any allocated. @@ -108,26 +111,52 @@ public class IOContext /** * Main constructor to use. - * + * + * @param streamReadConstraints constraints for streaming reads * @param br BufferRecycler to use, if any ({@code null} if none) * @param contentRef Input source reference for location reporting * @param managedResource Whether input source is managed (owned) by Jackson library * - * @since 2.13 + * @since 2.15 */ - public IOContext(BufferRecycler br, ContentReference contentRef, boolean managedResource) + public IOContext(StreamReadConstraints streamReadConstraints, BufferRecycler br, + ContentReference contentRef, boolean managedResource) { + _streamReadConstraints = streamReadConstraints == null ? + StreamReadConstraints.builder().build() : + streamReadConstraints; _bufferRecycler = br; _contentReference = contentRef; _sourceRef = contentRef.getRawContent(); _managedResource = managedResource; } + /** + * @param br BufferRecycler to use, if any ({@code null} if none) + * @param contentRef Input source reference for location reporting + * @param managedResource Whether input source is managed (owned) by Jackson library + * + * @since 2.13 + */ + @Deprecated // since 2.15 + public IOContext(BufferRecycler br, ContentReference contentRef, boolean managedResource) + { + this(null, br, contentRef, managedResource); + } + @Deprecated // since 2.13 public IOContext(BufferRecycler br, Object rawContent, boolean managedResource) { this(br, ContentReference.rawReference(rawContent), managedResource); } + /** + * @return constraints for streaming reads + * @since 2.15 + */ + public StreamReadConstraints streamReadConstraints() { + return _streamReadConstraints; + } + public void setEncoding(JsonEncoding enc) { _encoding = enc; } @@ -172,7 +201,7 @@ public ContentReference contentReference() { */ public TextBuffer constructTextBuffer() { - return new TextBuffer(_bufferRecycler); + return new TextBuffer(_streamReadConstraints, _bufferRecycler); } /** diff --git a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java index b2594d6796..570791c173 100644 --- a/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java +++ b/src/main/java/com/fasterxml/jackson/core/io/SegmentedStringWriter.java @@ -2,6 +2,7 @@ import java.io.*; +import com.fasterxml.jackson.core.StreamReadConstraints; import com.fasterxml.jackson.core.util.BufferRecycler; import com.fasterxml.jackson.core.util.TextBuffer; @@ -19,7 +20,7 @@ public final class SegmentedStringWriter extends Writer public SegmentedStringWriter(BufferRecycler br) { super(); - _buffer = new TextBuffer(br); + _buffer = new TextBuffer(StreamReadConstraints.UNLIMITED, br); } /* diff --git a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java index c1b1a9c17a..ab725b65e7 100644 --- a/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java +++ b/src/main/java/com/fasterxml/jackson/core/util/TextBuffer.java @@ -4,6 +4,7 @@ import java.math.BigDecimal; import java.util.*; +import com.fasterxml.jackson.core.StreamReadConstraints; import com.fasterxml.jackson.core.io.NumberInput; /** @@ -49,6 +50,8 @@ public final class TextBuffer private final BufferRecycler _allocator; + private final StreamReadConstraints _streamReadConstraints; + /* /********************************************************** /* Shared input buffers @@ -120,13 +123,16 @@ public final class TextBuffer /********************************************************** */ - public TextBuffer(BufferRecycler allocator) { + public TextBuffer(StreamReadConstraints streamReadConstraints, BufferRecycler allocator) { + _streamReadConstraints = streamReadConstraints == null ? + StreamReadConstraints.builder().build() : + streamReadConstraints; _allocator = allocator; } // @since 2.10 - protected TextBuffer(BufferRecycler allocator, char[] initialSegment) { - _allocator = allocator; + protected TextBuffer(StreamReadConstraints streamReadConstraints, BufferRecycler allocator, char[] initialSegment) { + this(streamReadConstraints, allocator); _currentSegment = initialSegment; _currentSize = initialSegment.length; _inputStart = -1; @@ -144,7 +150,7 @@ protected TextBuffer(BufferRecycler allocator, char[] initialSegment) { * @since 2.10 */ public static TextBuffer fromInitial(char[] initialSegment) { - return new TextBuffer(null, initialSegment); + return new TextBuffer(null, null, initialSegment); } /** @@ -491,18 +497,35 @@ public BigDecimal contentsAsDecimal() throws NumberFormatException { // Already got a pre-cut array? if (_resultArray != null) { + if (_streamReadConstraints.getMaxNumberLength() >= 0 && _resultArray.length > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } return NumberInput.parseBigDecimal(_resultArray); } // Or a shared buffer? if ((_inputStart >= 0) && (_inputBuffer != null)) { + if (_streamReadConstraints.getMaxNumberLength() >= 0 && _inputLen > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } return NumberInput.parseBigDecimal(_inputBuffer, _inputStart, _inputLen); } // Or if not, just a single buffer (the usual case) if ((_segmentSize == 0) && (_currentSegment != null)) { + if (_streamReadConstraints.getMaxNumberLength() >= 0 && _currentSize > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } return NumberInput.parseBigDecimal(_currentSegment, 0, _currentSize); } // If not, let's just get it aggregated... - return NumberInput.parseBigDecimal(contentsAsArray()); + final char[] numArray = contentsAsArray(); + if (_streamReadConstraints.getMaxNumberLength() >= 0 && numArray.length > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } + return NumberInput.parseBigDecimal(numArray); } /** @@ -530,7 +553,12 @@ public double contentsAsDouble() throws NumberFormatException { * @since 2.14 */ public double contentsAsDouble(final boolean useFastParser) throws NumberFormatException { - return NumberInput.parseDouble(contentsAsString(), useFastParser); + final String numStr = contentsAsString(); + if (_streamReadConstraints.getMaxNumberLength() >= 0 && numStr.length() > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } + return NumberInput.parseDouble(numStr, useFastParser); } /** @@ -559,7 +587,12 @@ public float contentsAsFloat() throws NumberFormatException { * @since 2.14 */ public float contentsAsFloat(final boolean useFastParser) throws NumberFormatException { - return NumberInput.parseFloat(contentsAsString(), useFastParser); + final String numStr = contentsAsString(); + if (_streamReadConstraints.getMaxNumberLength() >= 0 && numStr.length() > _streamReadConstraints.getMaxNumberLength()) { + throw new NumberFormatException( + "number length exceeds the max number length of " + _streamReadConstraints.getMaxNumberLength()); + } + return NumberInput.parseFloat(numStr, useFastParser); } /** diff --git a/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java b/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java index 92c57aab93..f6024dc4ac 100644 --- a/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java +++ b/src/test/java/com/fasterxml/jackson/core/ParserFeatureDefaultsTest.java @@ -134,6 +134,11 @@ public double getDoubleValue() { public BigDecimal getDecimalValue() { return null; } + + @Override + protected int getMaxNumLen() { + return -1; + } } public void testParserFlagDefaults() throws Exception diff --git a/src/test/java/com/fasterxml/jackson/core/read/NumberOverflowTest.java b/src/test/java/com/fasterxml/jackson/core/read/NumberOverflowTest.java index 8de42c935d..19a995756e 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NumberOverflowTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NumberOverflowTest.java @@ -8,7 +8,9 @@ public class NumberOverflowTest extends com.fasterxml.jackson.core.BaseTest { - private final JsonFactory FACTORY = new JsonFactory(); + private final JsonFactory FACTORY = JsonFactory.builder() + .streamReadConstraints(StreamReadConstraints.builder().withMaxNumberLength(1000000).build()) + .build(); // NOTE: this should be long enough to trigger perf problems private final static int BIG_NUM_LEN = 199999; @@ -105,7 +107,7 @@ public void testMaliciousBigIntToDouble() throws Exception { for (int mode : ALL_STREAMING_MODES) { final String doc = BIG_POS_DOC; - JsonParser p = createParser(mode, doc); + JsonParser p = createParser(FACTORY, mode, doc); assertToken(JsonToken.START_ARRAY, p.nextToken()); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); double d = p.getDoubleValue(); @@ -120,7 +122,7 @@ public void testMaliciousBigIntToFloat() throws Exception { for (int mode : ALL_STREAMING_MODES) { final String doc = BIG_POS_DOC; - JsonParser p = createParser(mode, doc); + JsonParser p = createParser(FACTORY, mode, doc); assertToken(JsonToken.START_ARRAY, p.nextToken()); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); float f = p.getFloatValue(); diff --git a/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java index 912720ef59..3c95f9e120 100644 --- a/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java +++ b/src/test/java/com/fasterxml/jackson/core/read/NumberParsingTest.java @@ -708,7 +708,9 @@ public void testLongNumbers2() throws Exception input.append(1); } final String DOC = input.toString(); - JsonFactory f = new JsonFactory(); + JsonFactory f = JsonFactory.builder() + .streamReadConstraints(StreamReadConstraints.builder().withMaxNumberLength(10000).build()) + .build(); _testIssue160LongNumbers(f, DOC, false); _testIssue160LongNumbers(f, DOC, true); } @@ -716,8 +718,8 @@ public void testLongNumbers2() throws Exception private void _testIssue160LongNumbers(JsonFactory f, String doc, boolean useStream) throws Exception { JsonParser p = useStream - ? jsonFactory().createParser(doc.getBytes("UTF-8")) - : jsonFactory().createParser(doc); + ? f.createParser(doc.getBytes("UTF-8")) + : f.createParser(doc); assertToken(JsonToken.VALUE_NUMBER_INT, p.nextToken()); BigInteger v = p.getBigIntegerValue(); assertNull(p.nextToken()); diff --git a/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java b/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java index f7eb410f02..0615cb0e69 100644 --- a/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java +++ b/src/test/java/com/fasterxml/jackson/core/util/TestTextBuffer.java @@ -11,7 +11,7 @@ public class TestTextBuffer */ public void testSimple() { - TextBuffer tb = new TextBuffer(new BufferRecycler()); + TextBuffer tb = new TextBuffer(null, new BufferRecycler()); tb.append('a'); tb.append(new char[] { 'X', 'b' }, 1, 1); tb.append("c", 0, 1); @@ -26,7 +26,7 @@ public void testSimple() public void testLonger() { - TextBuffer tb = new TextBuffer(null); + TextBuffer tb = new TextBuffer(null, null); for (int i = 0; i < 2000; ++i) { tb.append("abc", 0, 3); } @@ -50,7 +50,7 @@ public void testLongAppend() final String EXP = "a" + STR + "c"; // ok: first test with String: - TextBuffer tb = new TextBuffer(new BufferRecycler()); + TextBuffer tb = new TextBuffer(null, new BufferRecycler()); tb.append('a'); tb.append(STR, 0, len); tb.append('c'); @@ -58,7 +58,7 @@ public void testLongAppend() assertEquals(EXP, tb.contentsAsString()); // then char[] - tb = new TextBuffer(new BufferRecycler()); + tb = new TextBuffer(null, new BufferRecycler()); tb.append('a'); tb.append(STR.toCharArray(), 0, len); tb.append('c'); @@ -69,7 +69,7 @@ public void testLongAppend() // [core#152] public void testExpand() { - TextBuffer tb = new TextBuffer(new BufferRecycler()); + TextBuffer tb = new TextBuffer(null, new BufferRecycler()); char[] buf = tb.getCurrentSegment(); while (buf.length < 500 * 1000) { @@ -85,7 +85,7 @@ public void testExpand() // [core#182] public void testEmpty() { - TextBuffer tb = new TextBuffer(new BufferRecycler()); + TextBuffer tb = new TextBuffer(null, new BufferRecycler()); tb.resetWithEmpty(); assertTrue(tb.getTextBuffer().length == 0); @@ -94,13 +94,13 @@ public void testEmpty() { } public void testResetWithAndSetCurrentAndReturn() { - TextBuffer textBuffer = new TextBuffer(null); + TextBuffer textBuffer = new TextBuffer(null, null); textBuffer.resetWith('l'); textBuffer.setCurrentAndReturn(349); } public void testGetCurrentSegment() { - TextBuffer textBuffer = new TextBuffer(null); + TextBuffer textBuffer = new TextBuffer(null, null); textBuffer.emptyAndGetCurrentSegment(); // 26-Aug-2019, tatu: Value depends on "minimum segment size": textBuffer.setCurrentAndReturn(500); @@ -111,7 +111,7 @@ public void testGetCurrentSegment() { public void testAppendTakingTwoAndThreeInts() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.ensureNotShared(); char[] charArray = textBuffer.getTextBuffer(); textBuffer.append(charArray, 0, 200); @@ -122,7 +122,7 @@ public void testAppendTakingTwoAndThreeInts() { public void testEnsureNotSharedAndResetWithString() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.resetWithString(""); assertFalse(textBuffer.hasTextAsCharacters()); @@ -133,7 +133,7 @@ public void testEnsureNotSharedAndResetWithString() { } public void testContentsAsDecimalThrowsNumberFormatException() { - TextBuffer textBuffer = new TextBuffer( null); + TextBuffer textBuffer = new TextBuffer(null, null); try { textBuffer.contentsAsDecimal(); @@ -145,7 +145,7 @@ public void testContentsAsDecimalThrowsNumberFormatException() { public void testGetTextBufferAndEmptyAndGetCurrentSegmentAndFinishCurrentSegment() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.emptyAndGetCurrentSegment(); textBuffer.finishCurrentSegment(); textBuffer.getTextBuffer(); @@ -155,7 +155,7 @@ public void testGetTextBufferAndEmptyAndGetCurrentSegmentAndFinishCurrentSegment public void testGetTextBufferAndAppendTakingCharAndContentsAsArray() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.append('('); textBuffer.contentsAsArray(); textBuffer.getTextBuffer(); @@ -165,7 +165,7 @@ public void testGetTextBufferAndAppendTakingCharAndContentsAsArray() { public void testGetTextBufferAndResetWithString() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.resetWithString(""); assertFalse(textBuffer.hasTextAsCharacters()); @@ -177,7 +177,7 @@ public void testGetTextBufferAndResetWithString() { public void testResetWithString() { BufferRecycler bufferRecycler = new BufferRecycler(); - TextBuffer textBuffer = new TextBuffer(bufferRecycler); + TextBuffer textBuffer = new TextBuffer(null, bufferRecycler); textBuffer.ensureNotShared(); textBuffer.finishCurrentSegment(); @@ -189,7 +189,7 @@ public void testResetWithString() { } public void testGetCurrentSegmentSizeResetWith() { - TextBuffer textBuffer = new TextBuffer(null); + TextBuffer textBuffer = new TextBuffer(null, null); textBuffer.resetWith('.'); textBuffer.resetWith('q'); @@ -197,7 +197,7 @@ public void testGetCurrentSegmentSizeResetWith() { } public void testGetSizeFinishCurrentSegmentAndResetWith() { - TextBuffer textBuffer = new TextBuffer(null); + TextBuffer textBuffer = new TextBuffer(null, null); textBuffer.resetWith('.'); textBuffer.finishCurrentSegment(); textBuffer.resetWith('q');