shithub: hugo

Download patch

ref: d15fda500028c05fde2aa28ea53868eec01140f6
parent: 7d5c9fbf44ad9f2fd5baed405f79f2b132dd9178
author: Cameron Moore <[email protected]>
date: Tue Mar 29 16:50:54 EDT 2016

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.

--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -1054,7 +1054,24 @@
 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
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1535,6 +1535,21 @@
 			"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},