Commit e7fed7fa authored by Joe Tsai's avatar Joe Tsai Committed by Joe Tsai

encoding/csv: forbid certain Comma and Comment runes

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/72793Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent aedb79f0
......@@ -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
......
......@@ -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 {
......
......@@ -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 {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment