From e69ffaa9c44642e0deb7b105eadafd9305f02320 Mon Sep 17 00:00:00 2001 From: Richard Knop Date: Wed, 16 Dec 2015 00:18:36 +0800 Subject: [PATCH] Fixed a bug with invalid zero value in preload When using pointers in model structs, there is an edge case. When using preload to eagerly preload a many to many relationship and the main row is not found by a primary key, use of reflect.Indirect in preload.go results in a zero value and the subsequent call to FieldByName panics the program. --- preload.go | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/preload.go b/preload.go index 417a0d8c..f3f9dabc 100644 --- a/preload.go +++ b/preload.go @@ -10,8 +10,15 @@ import ( func getRealValue(value reflect.Value, columns []string) (results []interface{}) { for _, column := range columns { - if reflect.Indirect(value).FieldByName(column).IsValid() { - result := reflect.Indirect(value).FieldByName(column).Interface() + pointedValue := reflect.Indirect(value) + // If v is a nil pointer, Indirect returns a zero Value! + // Therefor we need to check for a zero value, + // as FieldByName could panic + if !pointedValue.IsValid() { + continue + } + if pointedValue.FieldByName(column).IsValid() { + result := pointedValue.FieldByName(column).Interface() if r, ok := result.(driver.Valuer); ok { result, _ = r.Value() } @@ -290,6 +297,12 @@ func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface } } } else { + // If v is a nil pointer, Indirect returns a zero Value! + // Therefor we need to check for a zero value, + // as FieldByName could panic + if !scope.IndirectValue().IsValid() { + return + } object := scope.IndirectValue() source := getRealValue(object, associationForeignStructFieldNames) field := object.FieldByName(field.Name)