From edc347b3b6c1d630004587dd69d23061a7ee0613 Mon Sep 17 00:00:00 2001 From: Peter Hunt Date: Mon, 3 May 2021 15:06:34 -0400 Subject: [PATCH] resource store: prevent segfault on cleanup step if a resource has a watcher, but has not yet been put to the store, we should not be marking it as stale. Signed-off-by: Peter Hunt --- internal/resourcestore/resourcestore.go | 10 ++++++++++ internal/resourcestore/resourcestore_test.go | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/internal/resourcestore/resourcestore.go b/internal/resourcestore/resourcestore.go index cf4ceec8f56..94a55370209 100644 --- a/internal/resourcestore/resourcestore.go +++ b/internal/resourcestore/resourcestore.go @@ -94,6 +94,15 @@ func (rc *ResourceStore) cleanupStaleResources() { resourcesToReap := []*Resource{} rc.Lock() for name, r := range rc.resources { + // this resource shouldn't be marked as stale if it + // hasn't yet been added to the store. + // This can happen if a creation is in progress, and a watcher is added + // before the creation completes. + // If this resource isn't skipped from being marked as stale, + // we risk segfaulting in the Cleanup() step. + if !r.wasPut() { + continue + } if r.stale { resourcesToReap = append(resourcesToReap, r) delete(rc.resources, name) @@ -177,6 +186,7 @@ func (rc *ResourceStore) WatcherForResource(name string) chan struct{} { if !ok { rc.resources[name] = &Resource{ watchers: []chan struct{}{watcher}, + name: name, } return watcher } diff --git a/internal/resourcestore/resourcestore_test.go b/internal/resourcestore/resourcestore_test.go index 2e1c0c8298a..6722aa45863 100644 --- a/internal/resourcestore/resourcestore_test.go +++ b/internal/resourcestore/resourcestore_test.go @@ -135,5 +135,25 @@ var _ = t.Describe("ResourceStore", func() { id := sut.Get(testName) Expect(id).To(BeEmpty()) }) + It("should not call cleanup until after resource is put", func() { + // Given + timeout := 2 * time.Second + sut = resourcestore.NewWithTimeout(timeout) + + _ = sut.WatcherForResource(testName) + + timedOutChan := make(chan bool) + + // When + go func() { + time.Sleep(timeout * 6) + Expect(sut.Put(testName, e, cleaner)).To(BeNil()) + timedOutChan <- true + }() + + // Then + didStoreWaitForPut := <-timedOutChan + Expect(didStoreWaitForPut).To(Equal(true)) + }) }) })