From 16d3e3063c53da1b900eeb65ae96d616965f90ba Mon Sep 17 00:00:00 2001 From: James Shubin Date: Tue, 22 Apr 2025 05:17:46 -0400 Subject: [PATCH] lang: funcs: facts: Do not reuse fact pointers In my carelessness, I was re-using pointers when a fact was used twice! This could cause disastrous consequences like a double close panic on a datetime.now() fact for example. In other news, we should consider if it's possible to get more clever about graph shape optimization so that we don't need more than once instance of certain functions like datetime.now() in our graph. --- lang/funcs/facts/facts.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lang/funcs/facts/facts.go b/lang/funcs/facts/facts.go index 75056f1d..1f6a3f57 100644 --- a/lang/funcs/facts/facts.go +++ b/lang/funcs/facts/facts.go @@ -51,18 +51,18 @@ const ( ErrCantSpeculate = funcs.ErrCantSpeculate ) -// RegisteredFacts is a global map of all possible facts which can be used. You +// registeredFacts is a global map of all possible facts which can be used. You // should never touch this map directly. Use methods like Register instead. -var RegisteredFacts = make(map[string]func() Fact) // must initialize +var registeredFacts = make(map[string]struct{}) // must initialize // Register takes a fact and its name and makes it available for use. It is // commonly called in the init() method of the fact at program startup. There is // no matching Unregister function. func Register(name string, fn func() Fact) { - if _, ok := RegisteredFacts[name]; ok { + if _, ok := registeredFacts[name]; ok { panic(fmt.Sprintf("a fact named %s is already registered", name)) } - f := fn() + f := fn() // don't wrap this more than once! metadata, err := funcs.GetFunctionMetadata(f) if err != nil { @@ -72,12 +72,12 @@ func Register(name string, fn func() Fact) { //gob.Register(fn()) funcs.Register(name, func() interfaces.Func { // implement in terms of func interface return &FactFunc{ - Fact: f, + Fact: fn(), // this MUST be a fresh/unique pointer! Metadata: metadata, } }) - RegisteredFacts[name] = fn + registeredFacts[name] = struct{}{} } // ModuleRegister is exactly like Register, except that it registers within a