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
23namespace Poco {
24
25
26//
27// RefCounter
28//
29
30RefCounter::RefCounter(): _counter(1)
31{
32 poco_rcdc_log;
33}
34
35
36RefCounter::~RefCounter()
37{
38 poco_rcdc_log;
39}
40
41
42//
43// RefCountedObject
44//
45
46RefCountedObject::RefCountedObject()
47{
48}
49
50
51RefCountedObject::~RefCountedObject()
52{
53}
54
55
56//
57// WeakRefCounter
58//
59
60WeakRefCounter::WeakRefCounter()
61{
62}
63
64
65WeakRefCounter::~WeakRefCounter()
66{
67}
68
69
70//
71// WeakRefCounter
72//
73
74WeakRefCountedObject::WeakRefCountedObject(): _pCounter(new WeakRefCounter)
75{
76}
77
78
79WeakRefCountedObject::~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
91void* WeakRefCounter::operator new(std::size_t)
92{
93 return getFastMemoryPool<WeakRefCounter>().get();
94}
95
96
97void WeakRefCounter::operator delete(void* ptr)
98{
99 if (!ptr) return;
100 getFastMemoryPool<WeakRefCounter>().release(reinterpret_cast<WeakRefCounter*>(ptr));
101}
102
103
104void* WeakRefCounter::operator new [] (std::size_t)
105{
106 throw InvalidAccessException("WeakRefCounter arrays not allowed.");
107}
108
109
110void WeakRefCounter::operator delete [] (void* /*ptr*/)
111{
112}
113
114
115#ifdef ENABLE_REFCOUNT_DC
116
117
118RCDC::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
126RCDC::TraceRecord::TraceRecord(const TraceRecord& other): _ptr(other._ptr),
127 _refCount(other._refCount),
128 _functionName(other._functionName),
129 _backtrace(other._backtrace)
130{
131}
132
133
134RCDC::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
143RCDC::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
157RCDC::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
172RefCountDiagnosticContext::RefCountDiagnosticContext(bool full)
173{
174 _full = full;
175}
176
177
178RefCountDiagnosticContext::~RefCountDiagnosticContext()
179{
180 dumpLeakRef(std::cerr);
181}
182
183
184void 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