diff options
author | Pravendra Singh <hackpravj@gmail.com> | 2017-06-13 22:13:07 +0530 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2017-06-13 21:51:17 +0000 |
commit | 538b3a5f37a5316a4ba081fd5a8eb5fb09992ba7 (patch) | |
tree | 9ad09131a1698fbb06e20922af4d22f24723034f | |
parent | f363817f143a7cee0ccdb7833a99ac1e8f210197 (diff) | |
download | go-538b3a5f37a5316a4ba081fd5a8eb5fb09992ba7.tar.gz go-538b3a5f37a5316a4ba081fd5a8eb5fb09992ba7.zip |
reflect: prevent structs with invalid field name
According to the language spec, a struct field name should
be an identifier.
identifier = letter { letter | unicode_digit } .
letter = unicode_letter | "_" .
Implements a function 'isValidFieldName(fieldName string) bool'.
To check if the field name is a valid identifier or not.
It will panic if the field name is invalid.
It uses the non-exported function implementation 'isLetter'
from the package 'scanner', used to parse an identifier.
Fixes #20600.
Change-Id: I1db7db1ad88cab5dbea6565be15cc7461cc56c44
Reviewed-on: https://go-review.googlesource.com/45590
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
-rw-r--r-- | src/reflect/all_test.go | 48 | ||||
-rw-r--r-- | src/reflect/type.go | 30 |
2 files changed, 78 insertions, 0 deletions
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go index 4953e4ff83..308cb77a8f 100644 --- a/src/reflect/all_test.go +++ b/src/reflect/all_test.go @@ -4063,6 +4063,54 @@ func TestSliceOfGC(t *testing.T) { } } +func TestStructOfFieldName(t *testing.T) { + // invalid field name "1nvalid" + shouldPanic(func() { + StructOf([]StructField{ + StructField{Name: "valid", Type: TypeOf("")}, + StructField{Name: "1nvalid", Type: TypeOf("")}, + }) + }) + + // invalid field name "+" + shouldPanic(func() { + StructOf([]StructField{ + StructField{Name: "val1d", Type: TypeOf("")}, + StructField{Name: "+", Type: TypeOf("")}, + }) + }) + + // no field name + shouldPanic(func() { + StructOf([]StructField{ + StructField{Name: "", Type: TypeOf("")}, + }) + }) + + // verify creation of a struct with valid struct fields + validFields := []StructField{ + StructField{ + Name: "φ", + Type: TypeOf(""), + }, + StructField{ + Name: "ValidName", + Type: TypeOf(""), + }, + StructField{ + Name: "Val1dNam5", + Type: TypeOf(""), + }, + } + + validStruct := StructOf(validFields) + + const structStr = `struct { φ string; ValidName string; Val1dNam5 string }` + if got, want := validStruct.String(), structStr; got != want { + t.Errorf("StructOf(validFields).String()=%q, want %q", got, want) + } +} + func TestStructOf(t *testing.T) { // check construction and use of type not in binary fields := []StructField{ diff --git a/src/reflect/type.go b/src/reflect/type.go index 58f39a19b2..14c16fc832 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -19,6 +19,8 @@ import ( "runtime" "strconv" "sync" + "unicode" + "unicode/utf8" "unsafe" ) @@ -2344,6 +2346,31 @@ type structTypeFixed32 struct { m [32]method } +// isLetter returns true if a given 'rune' is classified as a Letter. +func isLetter(ch rune) bool { + return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= utf8.RuneSelf && unicode.IsLetter(ch) +} + +// isValidFieldName checks if a string is a valid (struct) field name or not. +// +// According to the language spec, a field name should be an identifier. +// +// identifier = letter { letter | unicode_digit } . +// letter = unicode_letter | "_" . +func isValidFieldName(fieldName string) bool { + for i, c := range fieldName { + if i == 0 && !isLetter(c) { + return false + } + + if !(isLetter(c) || unicode.IsDigit(c)) { + return false + } + } + + return len(fieldName) > 0 +} + // StructOf returns the struct type containing fields. // The Offset and Index fields are ignored and computed as they would be // by the compiler. @@ -2373,6 +2400,9 @@ func StructOf(fields []StructField) Type { if field.Name == "" { panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no name") } + if !isValidFieldName(field.Name) { + panic("reflect.StructOf: field " + strconv.Itoa(i) + " has invalid name") + } if field.Type == nil { panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") } |