Skip to content

Commit c5c1d45

Browse files
committed
pgraph: fix double free if weak ptr to state is locked while being gc'ed
Fixes panda3d#499
1 parent 17776b0 commit c5c1d45

File tree

5 files changed

+29
-9
lines changed

5 files changed

+29
-9
lines changed

panda/src/express/referenceCount.I

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,21 @@ ref_if_nonzero() const {
317317
return true;
318318
}
319319

320+
/**
321+
* Atomically decreases the reference count of this object if it is one.
322+
* Do not use this. This exists only to implement a special case with the
323+
* state cache.
324+
* @return true if the reference count was decremented to zero.
325+
*/
326+
INLINE bool ReferenceCount::
327+
unref_if_one() const {
328+
#ifdef _DEBUG
329+
nassertr(test_ref_count_integrity(), 0);
330+
nassertr(_ref_count > 0, 0);
331+
#endif
332+
return (AtomicAdjust::compare_and_exchange(_ref_count, 1, 0) == 1);
333+
}
334+
320335
/**
321336
* This global helper function will unref the given ReferenceCount object, and
322337
* if the reference count reaches zero, automatically delete it. It can't be

panda/src/express/referenceCount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ class EXPCL_PANDA_EXPRESS ReferenceCount : public MemoryBase {
6464
INLINE void weak_unref();
6565

6666
INLINE bool ref_if_nonzero() const;
67+
INLINE bool unref_if_one() const;
6768

6869
protected:
6970
bool do_test_ref_count_integrity() const;

panda/src/pgraph/renderAttrib.cxx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,14 +215,15 @@ garbage_collect() {
215215

216216
do {
217217
RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si);
218-
if (attrib->get_ref_count() == 1) {
218+
if (attrib->unref_if_one()) {
219219
// This attrib has recently been unreffed to 1 (the one we added when
220220
// we stored it in the cache). Now it's time to delete it. This is
221221
// safe, because we're holding the _attribs_lock, so it's not possible
222222
// for some other thread to find the attrib in the cache and ref it
223-
// while we're doing this.
223+
// while we're doing this. Also, we've just made sure to unref it to 0,
224+
// to ensure that another thread can't get it via a weak pointer.
224225
attrib->release_new();
225-
unref_delete(attrib);
226+
delete attrib;
226227

227228
// When we removed it from the hash map, it swapped the last element
228229
// with the one we just removed. So the current index contains one we

panda/src/pgraph/renderState.cxx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -934,15 +934,17 @@ garbage_collect() {
934934
}
935935
}
936936

937-
if (state->get_ref_count() == 1) {
937+
if (state->unref_if_one()) {
938938
// This state has recently been unreffed to 1 (the one we added when
939939
// we stored it in the cache). Now it's time to delete it. This is
940940
// safe, because we're holding the _states_lock, so it's not possible
941941
// for some other thread to find the state in the cache and ref it
942-
// while we're doing this.
942+
// while we're doing this. Also, we've just made sure to unref it to 0,
943+
// to ensure that another thread can't get it via a weak pointer.
944+
943945
state->release_new();
944946
state->remove_cache_pointers();
945-
state->cache_unref();
947+
state->cache_unref_only();
946948
delete state;
947949

948950
// When we removed it from the hash map, it swapped the last element

panda/src/pgraph/transformState.cxx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,15 +1204,16 @@ garbage_collect() {
12041204
}
12051205
}
12061206

1207-
if (state->get_ref_count() == 1) {
1207+
if (state->unref_if_one()) {
12081208
// This state has recently been unreffed to 1 (the one we added when
12091209
// we stored it in the cache). Now it's time to delete it. This is
12101210
// safe, because we're holding the _states_lock, so it's not possible
12111211
// for some other thread to find the state in the cache and ref it
1212-
// while we're doing this.
1212+
// while we're doing this. Also, we've just made sure to unref it to 0,
1213+
// to ensure that another thread can't get it via a weak pointer.
12131214
state->release_new();
12141215
state->remove_cache_pointers();
1215-
state->cache_unref();
1216+
state->cache_unref_only();
12161217
delete state;
12171218

12181219
// When we removed it from the hash map, it swapped the last element

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy