From 6834c25cec6b037299970cc845de1a186e04ba1f Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Mon, 17 Aug 2020 12:02:41 +0800 Subject: [PATCH] Fix stack overflow for embedded self-referred associations, close #3269 --- schema/field.go | 8 +++++++- schema/model_test.go | 22 ++++++++++++++++++++++ schema/relationship.go | 17 +++++++---------- schema/schema_test.go | 6 ++++++ 4 files changed, 42 insertions(+), 11 deletions(-) diff --git a/schema/field.go b/schema/field.go index 84fdb695..78eeccdc 100644 --- a/schema/field.go +++ b/schema/field.go @@ -317,7 +317,13 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field { field.Creatable = false field.Updatable = false field.Readable = false - if field.EmbeddedSchema, err = Parse(fieldValue.Interface(), &sync.Map{}, schema.namer); err != nil { + + cacheStore := schema.cacheStore + if _, embedded := schema.cacheStore.Load("embedded_cache_store"); !embedded { + cacheStore = &sync.Map{} + cacheStore.Store("embedded_cache_store", true) + } + if field.EmbeddedSchema, err = Parse(fieldValue.Interface(), cacheStore, schema.namer); err != nil { schema.err = err } for _, ef := range field.EmbeddedSchema.Fields { diff --git a/schema/model_test.go b/schema/model_test.go index a13372b5..84c7b327 100644 --- a/schema/model_test.go +++ b/schema/model_test.go @@ -39,3 +39,25 @@ type AdvancedDataTypeUser struct { Active mybool Admin *mybool } + +type BaseModel struct { + ID uint `gorm:"primarykey"` + CreatedAt time.Time + CreatedBy *int + Created *VersionUser `gorm:"foreignKey:CreatedBy"` + UpdatedAt time.Time + DeletedAt gorm.DeletedAt `gorm:"index"` +} + +type VersionModel struct { + BaseModel + Version int + CompanyID int +} + +type VersionUser struct { + VersionModel + Name string + Age uint + Birthday *time.Time +} diff --git a/schema/relationship.go b/schema/relationship.go index 93080105..537a3582 100644 --- a/schema/relationship.go +++ b/schema/relationship.go @@ -5,7 +5,6 @@ import ( "reflect" "regexp" "strings" - "sync" "github.com/jinzhu/inflection" "gorm.io/gorm/clause" @@ -67,16 +66,14 @@ func (schema *Schema) parseRelation(field *Field) { } ) + cacheStore := schema.cacheStore if field.OwnerSchema != nil { - if relation.FieldSchema, err = Parse(fieldValue, &sync.Map{}, schema.namer); err != nil { - schema.err = err - return - } - } else { - if relation.FieldSchema, err = Parse(fieldValue, schema.cacheStore, schema.namer); err != nil { - schema.err = err - return - } + cacheStore = field.OwnerSchema.cacheStore + } + + if relation.FieldSchema, err = Parse(fieldValue, cacheStore, schema.namer); err != nil { + schema.err = err + return } if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" { diff --git a/schema/schema_test.go b/schema/schema_test.go index 99781e47..966f80e4 100644 --- a/schema/schema_test.go +++ b/schema/schema_test.go @@ -160,3 +160,9 @@ func TestCustomizeTableName(t *testing.T) { t.Errorf("Failed to customize table with TableName method") } } + +func TestNestedModel(t *testing.T) { + if _, err := schema.Parse(&VersionUser{}, &sync.Map{}, schema.NamingStrategy{}); err != nil { + t.Fatalf("failed to parse nested user, got error %v", err) + } +}