From abe7c4fb56a728072bf001fcec0c32f8d7b5c789 Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Thu, 11 Dec 2014 17:21:32 +0900 Subject: [PATCH] Do not register types with encoding/gob Registering the same type multiple times can lead to a panic. While the panic is handled in Save, the handling prevents saving the cache. While doing this seems like a good idea (since then the caller wouldn't have to register the types themselves), the need to deal with duplicate entries causes issues with Load. If calling Load to initialize a cache right after startup, encoding/gob will have no information about the types written in the cache, and thus won't be able to load the cache. There are also issues w.r.t. how the type is registered in gob, and if they are registered in a different form inside go-cache than they were outside, a panic happens due to different paths being generated: https://github.com/golang/go/blob/master/src/encoding/gob/type.go#L857 Make sure that it's the caller's respansibility to register types with encoding/gob, to avoid issues with gob's Register and so that they can both Save and Load without having to Save beforehand in the same instance. --- cache.go | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cache.go b/cache.go index de300fa..08a66da 100644 --- a/cache.go +++ b/cache.go @@ -869,24 +869,22 @@ func (c *cache) DeleteExpired() { } // Write the cache's items (using Gob) to an io.Writer. +// +// The caller should register any custom types with encoding/gob.Register +// before calling this function. func (c *cache) Save(w io.Writer) (err error) { enc := gob.NewEncoder(w) - defer func() { - if x := recover(); x != nil { - err = fmt.Errorf("Error registering item types with Gob library") - } - }() c.RLock() defer c.RUnlock() - for _, v := range c.items { - gob.Register(v.Object) - } err = enc.Encode(&c.items) return } // Save the cache's items to the given filename, creating the file if it // doesn't exist, and overwriting it if it does. +// +// The caller should register any custom types with encoding/gob.Register +// before calling this function. func (c *cache) SaveFile(fname string) error { fp, err := os.Create(fname) if err != nil { @@ -902,6 +900,9 @@ func (c *cache) SaveFile(fname string) error { // Add (Gob-serialized) cache items from an io.Reader, excluding any items with // keys that already exist (and haven't expired) in the current cache. +// +// The caller should register any custom types with encoding/gob.Register +// before calling this function. func (c *cache) Load(r io.Reader) error { dec := gob.NewDecoder(r) items := map[string]*Item{} @@ -921,6 +922,9 @@ func (c *cache) Load(r io.Reader) error { // Load and add cache items from the given filename, excluding any items with // keys that already exist in the current cache. +// +// The caller should register any custom types with encoding/gob.Register +// before calling this function. func (c *cache) LoadFile(fname string) error { fp, err := os.Open(fname) if err != nil {