diff --git a/csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvParser.java b/csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvParser.java index 0ca67c90..279742b9 100644 --- a/csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvParser.java +++ b/csv/src/main/java/com/fasterxml/jackson/dataformat/csv/CsvParser.java @@ -24,7 +24,10 @@ public class CsvParser extends ParserMinimalBase { - /** + // @since 2.9.9: just to protect against bugs, DoS, limit number of column defs we may read + private final static int MAX_COLUMNS = 99999; + + /** * Enumeration that defines all togglable features for CSV parsers */ public enum Feature @@ -351,7 +354,10 @@ private Feature(boolean defaultState) { public CsvParser(CsvIOContext ctxt, int stdFeatures, int csvFeatures, ObjectCodec codec, Reader reader) { - super(stdFeatures); + super(stdFeatures); + if (reader == null) { + throw new IllegalArgumentException("Can not pass `null` as `java.io.Reader` to read from"); + } _objectCodec = codec; _textBuffer = ctxt.csvTextBuffer(); DupDetector dups = JsonParser.Feature.STRICT_DUPLICATE_DETECTION.enabledIn(stdFeatures) @@ -720,10 +726,14 @@ protected void _readHeaderLine() throws IOException { if ((name = _reader.nextString()) != null) { _reportError(String.format("Extra header %s", name)); } - } - else { - //noinspection StatementWithEmptyBody - while (_reader.nextString() != null) { /* does nothing */ } + } else { + int allowed = MAX_COLUMNS; + while (_reader.nextString() != null) { + // If we don't care about validation, just skip. But protect against infinite loop + if (--allowed < 0) { + _reportError("Internal error: skipped "+MAX_COLUMNS+" header columns"); + } + } } return; } @@ -731,6 +741,7 @@ protected void _readHeaderLine() throws IOException { // either the schema is empty or reorder columns flag is set String name; CsvSchema.Builder builder = _schema.rebuild().clearColumns(); + int count = 0; while ((name = _reader.nextString()) != null) { // one more thing: always trim names, regardless of config settings @@ -743,6 +754,9 @@ protected void _readHeaderLine() throws IOException { } else { builder.addColumn(name); } + if (++count > MAX_COLUMNS) { + _reportError("Internal error: reached maximum of "+MAX_COLUMNS+" header columns"); + } } // Ok: did we get any columns? @@ -777,9 +791,8 @@ protected JsonToken _handleStartDoc() throws IOException _reader.skipLeadingComments(); } - /* Only one real complication, actually; empy documents (zero bytes). - * Those have no entries. Should be easy enough to detect like so: - */ + // Only one real complication, actually; empty documents (zero bytes). + // Those have no entries. Should be easy enough to detect like so: final boolean wrapAsArray = Feature.WRAP_AS_ARRAY.enabledIn(_formatFeatures); if (!_reader.hasMoreInput()) { _state = STATE_DOC_END; diff --git a/csv/src/test/java/com/fasterxml/jackson/dataformat/csv/NullReader122Test.java b/csv/src/test/java/com/fasterxml/jackson/dataformat/csv/NullReader122Test.java new file mode 100644 index 00000000..5e04825d --- /dev/null +++ b/csv/src/test/java/com/fasterxml/jackson/dataformat/csv/NullReader122Test.java @@ -0,0 +1,23 @@ +package com.fasterxml.jackson.dataformat.csv; + +import java.io.*; +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectReader; + +public class NullReader122Test extends ModuleTestBase +{ + private final CsvMapper MAPPER = mapperForCsv(); + + // for [dataformats-text#122]: passing `null` Reader leads to infinite loop + public void testEmptyStream() throws Exception { + CsvSchema columns = CsvSchema.emptySchema().withHeader().withColumnSeparator(';'); + ObjectReader r = MAPPER.readerFor(Map.class).with(columns); + try { + /*Object ob =*/ r.readValue((Reader) null); + fail("Should not pass"); + } catch (IllegalArgumentException e) { + verifyException(e, "Can not pass `null`"); + } + } +} diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index 86957721..1d7a60d9 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -10,8 +10,10 @@ Modules: 2.9.9 (not yet released) -#63: `null` Object Id serialized as anchor for YAML +#63: (yaml) `null` Object Id serialized as anchor for YAML (reported by jflefebvre06@github) +#122: (csv) `readValues(null)` causes infinite loop + (reported by andyeko@github) 2.9.8 (15-Dec-2018)