Make memnew(RefCounted) return Ref, to improve ownership safety#111965
Conversation
memnew(RefCounted) return Ref, to force callers to take ownership of it through a referencememnew(RefCounted) return Ref, to improve ownership safety
|
There would probably need to be some way to create these without explicit ownership as there are times when we need to not do refcounting for safety, also in some low-level construction I'd say, though usually the cases where we want to avoid refcounting are when we already have a reference and we avoid referencing it again |
|
To me it looks like the problem is that some people used RefCounted wrong. You should either not use it with |
Could you provide an example? Usually the only reason to avoid ref counting is performance, and you can still pass
This is part of the problem, but just using
This PR basically enforces the
Yea, disallowing |
I can't remember where it was currently, but and I think that was related to creating
But that's establishing a different style than what is established |
I meant "new syntax" for RefCounted objects. After this PR you can do
Right, so I guess that would justify this change. |
That is fully code wise possible currently? You don't have to do |
I think using any refcounted object without a primary owner is an error. Passing it around via pointer is fine, but owning one without it is always unsafe, because anyone you pass it to can destroy your object (even by accident).
That's true. I have some problems with
This is already possible in |
188ec64 to
03f7a6e
Compare
dsnopek
left a comment
There was a problem hiding this comment.
This needs a rebase to address conflicts in the tests.
However, I'm strongly in support of this change! The core functional changes look good to me. And I've reviewed all the conversions where we were keeping refcounted objects as a pointer, and they all look good to me
36ce7e0 to
d446bcf
Compare
…rship of it through a reference.
|
Thanks! |
This PR improves
RefCountedownership semantics for newly created objects, preventing potential crashes and other footguns at build time.Background
When
memnewinitializesRefCountedsubclasses, they start with an (effective) allocation count of 0.This creates two ownership related problems:
RefCounted *initially, some code may increase and later decrease the refcount (e.g. when passing asVariant). This destructs the object, because the refcount is decreased to 0. The actual owner'sRefCounted *will be a dangling pointer. The owner should have storedRef<RefCounted>instead.postinitialize_handler/NOTIFICATION_POSTINITIALIZE,RefCountedobjects still have an allocation count of 0, because the caller ofmemnewdidn't claim a reference yet. If the allocation count is increased and later decreased during this function, the object will unexpectedly destruct (seeRefCountedreleases itself if it is referenced inNOTIFICATION_POSTINITIALIZE#108395).The ideal (only?) way to fix this is to start
RefCountedwith a refcount of 1. Thememnewcaller must take ownership of the refcount after the call. This just means we returnReffrommemnew. Most callers already store the result in aRef, so they are compatible with this change.Overview
Implementing the change was fairly straight-forward; I add and specialize
memnew_result_tsuch that forRefCountedtypes,memnewreturnsRef<T>.The rest of the changes are fixing current ownership problems. Mostly, it just involves changing
T *toRef<T>. It has some inherent risk, but I don't think it's huge.