This still assumes proper usage, i.e holding on to activeCert. I don’t see how it’s really any better than calling reference counting functions to decide when to remove the pointer from the map and let the GC collect it.
I agree that the post is disappointing, because what it presents is an unsafe workaround to the absence of weak references. This being said, I think that it is a bit better than what you mention, because:
I think it is less invasive than having to add reference-count updates, because it naturally follows the data flow. If I’m responsible for a subsystem that carries a certificate in another structure with other things, I just need to make sure that I carry the cache-evictor as well and voilà, my entire subsystem is safe. Compare this to auditing all places where I get a certificate in input, and having to decide whether I have to put refcounting updates there and whether they are correct. (Does my borrowing of the certificate extend after the runtime of the function?)
In this particular case where we are only dealing about cache eviction, evicting too early is probably better than evicting too late. If you forget reference-increment instruction (or if you get rid of the finalized evictor, in the finalizer approach) you evict too early. But if you forget a reference-decrement instruction, you evict too late, and this gives you a cache leak. I suspect that it is harder to do the same mistake with the gc-based solution – this would correspond to leaking the finalized evictor, for example by storing it into a global variable.
I wouldn’t call it unsafe – if you misuse the API, you won’t get a crash or a resource leak.
We use weak references or ephemerons to guarantee that our code does not modify the liveness of objects and does not extend their lifetime. In this context by “correct” or “safe” I mean “preserving this guarantee”, and by “unsafe” I meant “the guarantee now depends on programmer discipline”. If you get this workaround wrong, you can have a resource leak where things stay alive longer than you expected. (But indeed, no segfault or something like that.)
(In the present case, if I understand correctly, this is all internal to the Go stdlib implementation, so the set of people that need to be careful is restricted in a good way.)