Commit 538b3a5f authored by Pravendra Singh's avatar Pravendra Singh Committed by Brad Fitzpatrick

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/45590Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent f363817f
...@@ -4063,6 +4063,54 @@ func TestSliceOfGC(t *testing.T) { ...@@ -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) { func TestStructOf(t *testing.T) {
// check construction and use of type not in binary // check construction and use of type not in binary
fields := []StructField{ fields := []StructField{
......
...@@ -19,6 +19,8 @@ import ( ...@@ -19,6 +19,8 @@ import (
"runtime" "runtime"
"strconv" "strconv"
"sync" "sync"
"unicode"
"unicode/utf8"
"unsafe" "unsafe"
) )
...@@ -2344,6 +2346,31 @@ type structTypeFixed32 struct { ...@@ -2344,6 +2346,31 @@ type structTypeFixed32 struct {
m [32]method 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. // StructOf returns the struct type containing fields.
// The Offset and Index fields are ignored and computed as they would be // The Offset and Index fields are ignored and computed as they would be
// by the compiler. // by the compiler.
...@@ -2373,6 +2400,9 @@ func StructOf(fields []StructField) Type { ...@@ -2373,6 +2400,9 @@ func StructOf(fields []StructField) Type {
if field.Name == "" { if field.Name == "" {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no 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 { if field.Type == nil {
panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type") panic("reflect.StructOf: field " + strconv.Itoa(i) + " has no type")
} }
......
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