1 | // |
2 | // RefCountedObject.cpp |
3 | // |
4 | // Library: Foundation |
5 | // Package: Core |
6 | // Module: RefCountedObject |
7 | // |
8 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/RefCountedObject.h" |
16 | #ifdef ENABLE_REFCOUNT_DC |
17 | #include "Poco/String.h" |
18 | #include "Poco/AtomicFlag.h" |
19 | #include <iostream> |
20 | #endif // ENABLE_REFCOUNT_DC |
21 | |
22 | |
23 | namespace Poco { |
24 | |
25 | |
26 | // |
27 | // RefCounter |
28 | // |
29 | |
30 | RefCounter::RefCounter(): _counter(1) |
31 | { |
32 | poco_rcdc_log; |
33 | } |
34 | |
35 | |
36 | RefCounter::~RefCounter() |
37 | { |
38 | poco_rcdc_log; |
39 | } |
40 | |
41 | |
42 | // |
43 | // RefCountedObject |
44 | // |
45 | |
46 | RefCountedObject::RefCountedObject() |
47 | { |
48 | } |
49 | |
50 | |
51 | RefCountedObject::~RefCountedObject() |
52 | { |
53 | } |
54 | |
55 | |
56 | // |
57 | // WeakRefCounter |
58 | // |
59 | |
60 | WeakRefCounter::WeakRefCounter() |
61 | { |
62 | } |
63 | |
64 | |
65 | WeakRefCounter::~WeakRefCounter() |
66 | { |
67 | } |
68 | |
69 | |
70 | // |
71 | // WeakRefCounter |
72 | // |
73 | |
74 | WeakRefCountedObject::WeakRefCountedObject(): _pCounter(new WeakRefCounter) |
75 | { |
76 | } |
77 | |
78 | |
79 | WeakRefCountedObject::~WeakRefCountedObject() |
80 | { |
81 | // prevent leak if release() was never called |
82 | // (eg. this object new-ed into bare pointer |
83 | // and deleted from outside using delete) |
84 | // to prevent double delete, release() flags |
85 | // access by setting the counter pointer to 0 |
86 | // before deleting `this` |
87 | delete _pCounter.load(); |
88 | } |
89 | |
90 | |
91 | void* WeakRefCounter::operator new(std::size_t) |
92 | { |
93 | return getFastMemoryPool<WeakRefCounter>().get(); |
94 | } |
95 | |
96 | |
97 | void WeakRefCounter::operator delete(void* ptr) |
98 | { |
99 | if (!ptr) return; |
100 | getFastMemoryPool<WeakRefCounter>().release(reinterpret_cast<WeakRefCounter*>(ptr)); |
101 | } |
102 | |
103 | |
104 | void* WeakRefCounter::operator new [] (std::size_t) |
105 | { |
106 | throw InvalidAccessException("WeakRefCounter arrays not allowed." ); |
107 | } |
108 | |
109 | |
110 | void WeakRefCounter::operator delete [] (void* /*ptr*/) |
111 | { |
112 | } |
113 | |
114 | |
115 | #ifdef ENABLE_REFCOUNT_DC |
116 | |
117 | |
118 | RCDC::TraceRecord::TraceRecord(void *ptr, int refCount, const char* func, const std::string &backtrace) : _ptr(ptr), |
119 | _refCount(refCount), |
120 | _functionName(func), |
121 | _backtrace(backtrace) |
122 | { |
123 | } |
124 | |
125 | |
126 | RCDC::TraceRecord::TraceRecord(const TraceRecord& other): _ptr(other._ptr), |
127 | _refCount(other._refCount), |
128 | _functionName(other._functionName), |
129 | _backtrace(other._backtrace) |
130 | { |
131 | } |
132 | |
133 | |
134 | RCDC::TraceRecord::TraceRecord(TraceRecord&& other): _ptr(other._ptr), |
135 | _refCount(other._refCount), |
136 | _functionName(other._functionName), |
137 | _backtrace(std::move(other._backtrace)) |
138 | { |
139 | other._backtrace.clear(); |
140 | } |
141 | |
142 | |
143 | RCDC::TraceRecord& RCDC::TraceRecord::operator == (const TraceRecord& other) |
144 | { |
145 | SpinlockMutex::ScopedLock l(_mutex); |
146 | if (&other != this) |
147 | { |
148 | _ptr = other._ptr; |
149 | _refCount = other._refCount; |
150 | _functionName = other._functionName; |
151 | _backtrace = other._backtrace; |
152 | } |
153 | return *this; |
154 | } |
155 | |
156 | |
157 | RCDC::TraceRecord& RCDC::TraceRecord::operator == (TraceRecord&& other) |
158 | { |
159 | SpinlockMutex::ScopedLock l(_mutex); |
160 | if (&other != this) |
161 | { |
162 | _ptr = other._ptr; |
163 | _refCount = other._refCount; |
164 | _functionName = std::move(other._functionName); |
165 | _backtrace = std::move(other._backtrace); |
166 | other._backtrace.clear(); |
167 | } |
168 | return *this; |
169 | } |
170 | |
171 | |
172 | RefCountDiagnosticContext::RefCountDiagnosticContext(bool full) |
173 | { |
174 | _full = full; |
175 | } |
176 | |
177 | |
178 | RefCountDiagnosticContext::~RefCountDiagnosticContext() |
179 | { |
180 | dumpLeakRef(std::cerr); |
181 | } |
182 | |
183 | |
184 | void RCDC::dumpRef(std::ostream& os, bool leakOnly) const |
185 | { |
186 | typedef OrderedMap<void*, int> SummaryMap; |
187 | AtomicFlag firstStep; |
188 | SummaryMap* pSummary = 0; |
189 | SpinlockMutex::ScopedLock l(_mutex); |
190 | for(const auto &entry : traceMap()) |
191 | { |
192 | bool out = true; |
193 | const TraceRecord& record = entry.second.back(); |
194 | |
195 | if(leakOnly) |
196 | { |
197 | out = out && entry.second.size() && record._refCount > 1; |
198 | } |
199 | |
200 | if(entry.second.size() > 0 && out) |
201 | { |
202 | if(firstStep) os << std::endl; |
203 | if(leakOnly) |
204 | { |
205 | if(!pSummary) pSummary = new SummaryMap; |
206 | (*pSummary)[entry.first] = record._refCount; |
207 | os << "Leaks detected for object at " ; |
208 | } |
209 | os << "[0x" << std::hex << entry.first << "]:" << std::endl; |
210 | for(const auto &trace : entry.second) |
211 | { |
212 | std::string nl(1, '\n'); |
213 | std::string prevIndent(nl); |
214 | if(trace._refCount > 1) |
215 | { |
216 | for(int i = 0;;) |
217 | { |
218 | prevIndent.append(1, '\t'); |
219 | if(++i == trace._refCount) break; |
220 | prevIndent.append(1, '|'); |
221 | } |
222 | } |
223 | else prevIndent.append(1, '\t'); |
224 | std::string indent; |
225 | std::string nlIndent(nl); |
226 | nlIndent.append(indent); |
227 | os << prevIndent << "refCount=" << trace._refCount |
228 | << " (" << trace._functionName << ')' |
229 | << prevIndent << indent |
230 | << Poco::replace(trace._backtrace, nl, prevIndent + indent) |
231 | << std::endl; |
232 | } |
233 | os << std::endl; |
234 | } |
235 | } |
236 | if (pSummary) |
237 | { |
238 | os << std::endl; |
239 | os << "Leak summary:\n------------" << std::endl; |
240 | for (const auto& s : *pSummary) |
241 | os << s.first << ", refcount=" << s.second << std::endl; |
242 | delete pSummary; |
243 | } |
244 | } |
245 | |
246 | |
247 | #endif // ENABLE_REFCOUNT_DC |
248 | |
249 | |
250 | } // namespace Poco |
251 | |