]> Cypherpunks repositories - gostls13.git/commitdiff
encoding/csv: forbid certain Comma and Comment runes
authorJoe Tsai <joetsai@digital-static.net>
Mon, 23 Oct 2017 21:43:51 +0000 (14:43 -0700)
committerJoe Tsai <thebrokentoaster@gmail.com>
Wed, 25 Oct 2017 01:43:46 +0000 (01:43 +0000)
The record delimiter (not configurable by user) is "\r\n" or "\n".
It is insensible for the user to set Comma or Comment delimiters
to be some character that conflicts with the record delimiter.
Furthermore, it is insensible for Comma or Comment to be the same rune.
Allowing this leaks implementation details to the user in regards to
the evaluation order of which rune is checked for first.

Fixes #22404

Change-Id: I31e86abc9b3a8fb4584e090477795587740970ae
Reviewed-on: https://go-review.googlesource.com/72793
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/encoding/csv/reader.go
src/encoding/csv/reader_test.go
src/encoding/csv/writer.go

index 00b9bbffee0c5d6998a7ab320f33fa87a04f9010..031ee6cedb0e1399e4b1a7f89930d9f616c81be3 100644 (file)
@@ -88,6 +88,12 @@ var (
        ErrFieldCount    = errors.New("wrong number of fields")
 )
 
+var errInvalidDelim = errors.New("csv: invalid field or comment delimiter")
+
+func validDelim(r rune) bool {
+       return r != 0 && r != '\r' && r != '\n' && utf8.ValidRune(r) && r != utf8.RuneError
+}
+
 // A Reader reads records from a CSV-encoded file.
 //
 // As returned by NewReader, a Reader expects input conforming to RFC 4180.
@@ -232,6 +238,10 @@ func nextRune(b []byte) rune {
 }
 
 func (r *Reader) readRecord(dst []string) ([]string, error) {
+       if r.Comma == r.Comment || !validDelim(r.Comma) || (r.Comment != 0 && !validDelim(r.Comment)) {
+               return nil, errInvalidDelim
+       }
+
        // Read line (automatically skipping past empty lines and any comments).
        var line, fullLine []byte
        var errRead error
index ed7d89dfe0645a83b335b096fb975180854327f9..48efbb67191548793edbcf5bbf1ed5bf65cafa46 100644 (file)
@@ -9,6 +9,7 @@ import (
        "reflect"
        "strings"
        "testing"
+       "unicode/utf8"
 )
 
 func TestRead(t *testing.T) {
@@ -312,6 +313,35 @@ x,,,
                Input:      `"""""""`,
                Output:     [][]string{{`"""`}},
                LazyQuotes: true,
+       }, {
+               Name:  "BadComma1",
+               Comma: '\n',
+               Error: errInvalidDelim,
+       }, {
+               Name:  "BadComma2",
+               Comma: '\r',
+               Error: errInvalidDelim,
+       }, {
+               Name:  "BadComma3",
+               Comma: utf8.RuneError,
+               Error: errInvalidDelim,
+       }, {
+               Name:    "BadComment1",
+               Comment: '\n',
+               Error:   errInvalidDelim,
+       }, {
+               Name:    "BadComment2",
+               Comment: '\r',
+               Error:   errInvalidDelim,
+       }, {
+               Name:    "BadComment3",
+               Comment: utf8.RuneError,
+               Error:   errInvalidDelim,
+       }, {
+               Name:    "BadCommaComment",
+               Comma:   'X',
+               Comment: 'X',
+               Error:   errInvalidDelim,
        }}
 
        for _, tt := range tests {
index 84b7aa1ed10d30ac6e32a4e70bbac546718bbbca..b23cae4517ef60f5a3146230035ec93f0df8acd7 100644 (file)
@@ -38,6 +38,10 @@ func NewWriter(w io.Writer) *Writer {
 // Writer writes a single CSV record to w along with any necessary quoting.
 // A record is a slice of strings with each string being one field.
 func (w *Writer) Write(record []string) error {
+       if !validDelim(w.Comma) {
+               return errInvalidDelim
+       }
+
        for n, field := range record {
                if n > 0 {
                        if _, err := w.w.WriteRune(w.Comma); err != nil {