summaryrefslogtreecommitdiffstats
path: root/tpl
diff options
context:
space:
mode:
authorCameron Moore <moorereason@gmail.com>2016-03-29 20:50:54 -0500
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2016-04-02 23:01:36 +0200
commitd15fda500028c05fde2aa28ea53868eec01140f6 (patch)
treefbfede9a9f8107c9f89366ff227e9728061a0130 /tpl
parent7d5c9fbf44ad9f2fd5baed405f79f2b132dd9178 (diff)
tpl: Fix panic in pairList.Less
While sorting on data sources with missing fields, a panic can occur in pairList.Less if `Interface()` is called on a invalid `reflect.Value`. This commit detects an invalid Value and replacing it with a zero value for the comparison.
Diffstat (limited to 'tpl')
-rw-r--r--tpl/template_funcs.go19
-rw-r--r--tpl/template_funcs_test.go15
2 files changed, 33 insertions, 1 deletions
diff --git a/tpl/template_funcs.go b/tpl/template_funcs.go
index e9cc26869..ad5b8db1e 100644
--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -1054,7 +1054,24 @@ type pairList struct {
func (p pairList) Swap(i, j int) { p.Pairs[i], p.Pairs[j] = p.Pairs[j], p.Pairs[i] }
func (p pairList) Len() int { return len(p.Pairs) }
func (p pairList) Less(i, j int) bool {
- return lt(p.Pairs[i].SortByValue.Interface(), p.Pairs[j].SortByValue.Interface())
+ iv := p.Pairs[i].SortByValue
+ jv := p.Pairs[j].SortByValue
+
+ if iv.IsValid() {
+ if jv.IsValid() {
+ // can only call Interface() on valid reflect Values
+ return lt(iv.Interface(), jv.Interface())
+ }
+ // if j is invalid, test i against i's zero value
+ return lt(iv.Interface(), reflect.Zero(iv.Type()))
+ }
+
+ if jv.IsValid() {
+ // if i is invalid, test j against j's zero value
+ return lt(reflect.Zero(jv.Type()), jv.Interface())
+ }
+
+ return false
}
// sorts a pairList and returns a slice of sorted values
diff --git a/tpl/template_funcs_test.go b/tpl/template_funcs_test.go
index a36629afd..4b49da41b 100644
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1535,6 +1535,21 @@ func TestSort(t *testing.T) {
"asc",
[]map[string]mid{{"foo": mid{Tst: TstX{A: "a", B: "b"}}}, {"foo": mid{Tst: TstX{A: "c", B: "d"}}}, {"foo": mid{Tst: TstX{A: "e", B: "f"}}}},
},
+ // interface slice with missing elements
+ {
+ []interface{}{
+ map[interface{}]interface{}{"Title": "Foo", "Weight": 10},
+ map[interface{}]interface{}{"Title": "Bar"},
+ map[interface{}]interface{}{"Title": "Zap", "Weight": 5},
+ },
+ "Weight",
+ "asc",
+ []interface{}{
+ map[interface{}]interface{}{"Title": "Bar"},
+ map[interface{}]interface{}{"Title": "Zap", "Weight": 5},
+ map[interface{}]interface{}{"Title": "Foo", "Weight": 10},
+ },
+ },
// test error cases
{(*[]TstX)(nil), nil, "asc", false},
{TstX{A: "a", B: "b"}, nil, "asc", false},