]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: prevent structs with invalid field name
authorPravendra Singh <hackpravj@gmail.com>
Tue, 13 Jun 2017 16:43:07 +0000 (22:13 +0530)
committerBrad Fitzpatrick <bradfitz@golang.org>
Tue, 13 Jun 2017 21:51:17 +0000 (21:51 +0000)
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>

src/reflect/all_test.go
src/reflect/type.go

index 4953e4ff83b2a394fb31a4c3a6c4332a2a9f1fb2..308cb77a8f29f256ff903594f6fcf71dfdfa8946 100644 (file)
@@ -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{
index 58f39a19b22b136acaeb9210ea7c8c88971ae862..14c16fc83285ec54700218e7fa3732b933688509 100644 (file)
@@ -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")
                }