Skip to content

Commit 32df05b

Browse files
committed
Fix crash when unmounting/closing multifile while streams are open
It's not really reasonable to expect a user to find every occurrence of a cached resource that might be using an open stream and remove it or crash otherwise. This is fixed by keeping the multifile stream open as long as any substreams are still pointing to it, using a simplified reference counting (care is taken not to fully make StreamWrapper reference-counted, since it's not in express and existing uses should not be broken). Fixes panda3d#449 Also see panda3d#428
1 parent 7ed9655 commit 32df05b

File tree

5 files changed

+46
-1
lines changed

5 files changed

+46
-1
lines changed

dtool/src/prc/streamWrapper.I

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,24 @@ release() {
5858
_lock.unlock();
5959
}
6060

61+
/**
62+
* Increments the reference count. Only has impact if the class that manages
63+
* this StreamWrapper's lifetime (eg. Multifile) respects it.
64+
*/
65+
INLINE void StreamWrapperBase::
66+
ref() const {
67+
AtomicAdjust::inc(_ref_count);
68+
}
69+
70+
/**
71+
* Decrements the reference count. Only has impact if the class that manages
72+
* this StreamWrapper's lifetime (eg. Multifile) respects it.
73+
*/
74+
INLINE bool StreamWrapperBase::
75+
unref() const {
76+
return AtomicAdjust::dec(_ref_count);
77+
}
78+
6179
/**
6280
*
6381
*/

dtool/src/prc/streamWrapper.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "dtoolbase.h"
1818
#include "mutexImpl.h"
19+
#include "atomicAdjust.h"
1920

2021
/**
2122
* The base class for both IStreamWrapper and OStreamWrapper, this provides
@@ -30,8 +31,17 @@ class EXPCL_DTOOL_PRC StreamWrapperBase {
3031
INLINE void acquire();
3132
INLINE void release();
3233

34+
public:
35+
INLINE void ref() const;
36+
INLINE bool unref() const;
37+
3338
private:
3439
MutexImpl _lock;
40+
41+
// This isn't really designed as a reference counted class, but it is useful
42+
// to treat it as one when dealing with substreams created by Multifile.
43+
mutable AtomicAdjust::Integer _ref_count = 1;
44+
3545
#ifdef SIMPLE_THREADS
3646
// In the SIMPLE_THREADS case, we need to use a bool flag, because MutexImpl
3747
// defines to nothing in this case--but we still need to achieve a form of

panda/src/express/multifile.cxx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,10 @@ close() {
333333
if (_owns_stream) {
334334
// We prefer to delete the IStreamWrapper over the ostream, if possible.
335335
if (_read != nullptr) {
336-
delete _read;
336+
// Only delete it if no SubStream is still referencing it.
337+
if (!_read->unref()) {
338+
delete _read;
339+
}
337340
} else if (_write != nullptr) {
338341
delete _write;
339342
}

panda/src/express/subStreamBuf.cxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,13 @@ open(IStreamWrapper *source, OStreamWrapper *dest, streampos start, streampos en
8888
_append = append;
8989
_gpos = _start;
9090
_ppos = _start;
91+
92+
if (source != nullptr) {
93+
source->ref();
94+
}
95+
if (dest != nullptr) {
96+
dest->ref();
97+
}
9198
}
9299

93100
/**
@@ -98,6 +105,12 @@ close() {
98105
// Make sure the write buffer is flushed.
99106
sync();
100107

108+
if (_source != nullptr && !_source->unref()) {
109+
delete _source;
110+
}
111+
if (_dest != nullptr && !_dest->unref()) {
112+
delete _dest;
113+
}
101114
_source = nullptr;
102115
_dest = nullptr;
103116
_start = 0;

panda/src/express/subStreamBuf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
class EXPCL_PANDA_EXPRESS SubStreamBuf : public std::streambuf {
2424
public:
2525
SubStreamBuf();
26+
SubStreamBuf(const SubStreamBuf &copy) = delete;
2627
virtual ~SubStreamBuf();
2728

2829
void open(IStreamWrapper *source, OStreamWrapper *dest, std::streampos start, std::streampos end, bool append);

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