aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPravendra Singh <hackpravj@gmail.com>2017-06-13 22:13:07 +0530
committerBrad Fitzpatrick <bradfitz@golang.org>2017-06-13 21:51:17 +0000
commit538b3a5f37a5316a4ba081fd5a8eb5fb09992ba7 (patch)
tree9ad09131a1698fbb06e20922af4d22f24723034f
parentf363817f143a7cee0ccdb7833a99ac1e8f210197 (diff)
downloadgo-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.go48
-rw-r--r--src/reflect/type.go30
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")
}