From 4fe7c8be07f81e0e5a40828f9a5f3871266e8211 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 937654845bf..1d778600a32 100644 --- a/internal/resourcestore/resourcestore.go +++ b/internal/resourcestore/resourcestore.go @@ -77,6 +77,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) @@ -162,6 +171,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 6367adf649b..409e62417c6 100644 --- a/internal/resourcestore/resourcestore_test.go +++ b/internal/resourcestore/resourcestore_test.go @@ -129,5 +129,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)) + }) }) })