summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Agopian2011-08-10 23:07:02 -0500
committerAlex Ray2013-07-30 15:56:57 -0500
commitad09965050f8226fda6f5238db060ce65abaa71c (patch)
treeea9fe13c4be2839f0677ea8f7a4392053518892c /libs/utils/RefBase.cpp
parentc3a5225d4ec0e98ca671ada8cba17878c656e3d5 (diff)
downloadplatform-system-core-ad09965050f8226fda6f5238db060ce65abaa71c.tar.gz
platform-system-core-ad09965050f8226fda6f5238db060ce65abaa71c.tar.xz
platform-system-core-ad09965050f8226fda6f5238db060ce65abaa71c.zip
fix a memory leak and memory corruption in RefBase
we would leak a weakref_impl if a RefBase was never incWeak()'ed. there was also a dangling pointer that would cause memory corruption and double-delete when a custom destroyer was used to delay the execution of ~RefBase. it turns out that the custom destroyer feature caused most of the problems, so it's now gone. The only client was SurfaceFlinger who now handles things on its own. RefBase is essentially back its "gingerbread" state, but the code was slightly cleaned-up. Bug: 5151207, 5084978 Change-Id: Id6ef1d707f96d96366f75068f77b30e0ce2722a5
Diffstat (limited to 'libs/utils/RefBase.cpp')
-rw-r--r--libs/utils/RefBase.cpp264
1 files changed, 180 insertions, 84 deletions
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 32e900a7f..37d061cb3 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -20,9 +20,9 @@
20 20
21#include <utils/Atomic.h> 21#include <utils/Atomic.h>
22#include <utils/CallStack.h> 22#include <utils/CallStack.h>
23#include <utils/KeyedVector.h>
24#include <utils/Log.h> 23#include <utils/Log.h>
25#include <utils/threads.h> 24#include <utils/threads.h>
25#include <utils/TextOutput.h>
26 26
27#include <stdlib.h> 27#include <stdlib.h>
28#include <stdio.h> 28#include <stdio.h>
@@ -34,6 +34,7 @@
34 34
35// compile with refcounting debugging enabled 35// compile with refcounting debugging enabled
36#define DEBUG_REFS 0 36#define DEBUG_REFS 0
37#define DEBUG_REFS_FATAL_SANITY_CHECKS 0
37#define DEBUG_REFS_ENABLED_BY_DEFAULT 1 38#define DEBUG_REFS_ENABLED_BY_DEFAULT 1
38#define DEBUG_REFS_CALLSTACK_ENABLED 1 39#define DEBUG_REFS_CALLSTACK_ENABLED 1
39 40
@@ -56,7 +57,6 @@ public:
56 RefBase* const mBase; 57 RefBase* const mBase;
57 volatile int32_t mFlags; 58 volatile int32_t mFlags;
58 59
59
60#if !DEBUG_REFS 60#if !DEBUG_REFS
61 61
62 weakref_impl(RefBase* base) 62 weakref_impl(RefBase* base)
@@ -69,8 +69,10 @@ public:
69 69
70 void addStrongRef(const void* /*id*/) { } 70 void addStrongRef(const void* /*id*/) { }
71 void removeStrongRef(const void* /*id*/) { } 71 void removeStrongRef(const void* /*id*/) { }
72 void renameStrongRefId(const void* /*old_id*/, const void* /*new_id*/) { }
72 void addWeakRef(const void* /*id*/) { } 73 void addWeakRef(const void* /*id*/) { }
73 void removeWeakRef(const void* /*id*/) { } 74 void removeWeakRef(const void* /*id*/) { }
75 void renameWeakRefId(const void* /*old_id*/, const void* /*new_id*/) { }
74 void printRefs() const { } 76 void printRefs() const { }
75 void trackMe(bool, bool) { } 77 void trackMe(bool, bool) { }
76 78
@@ -86,39 +88,91 @@ public:
86 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT) 88 , mTrackEnabled(!!DEBUG_REFS_ENABLED_BY_DEFAULT)
87 , mRetain(false) 89 , mRetain(false)
88 { 90 {
89 //LOGI("NEW weakref_impl %p for RefBase %p", this, base);
90 } 91 }
91 92
92 ~weakref_impl() 93 ~weakref_impl()
93 { 94 {
94 LOG_ALWAYS_FATAL_IF(!mRetain && mStrongRefs != NULL, "Strong references remain!"); 95 bool dumpStack = false;
95 LOG_ALWAYS_FATAL_IF(!mRetain && mWeakRefs != NULL, "Weak references remain!"); 96 if (!mRetain && mStrongRefs != NULL) {
97 dumpStack = true;
98#if DEBUG_REFS_FATAL_SANITY_CHECKS
99 LOG_ALWAYS_FATAL("Strong references remain!");
100#else
101 LOGE("Strong references remain:");
102#endif
103 ref_entry* refs = mStrongRefs;
104 while (refs) {
105 char inc = refs->ref >= 0 ? '+' : '-';
106 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
107#if DEBUG_REFS_CALLSTACK_ENABLED
108 refs->stack.dump();
109#endif
110 refs = refs->next;
111 }
112 }
113
114 if (!mRetain && mWeakRefs != NULL) {
115 dumpStack = true;
116#if DEBUG_REFS_FATAL_SANITY_CHECKS
117 LOG_ALWAYS_FATAL("Weak references remain:");
118#else
119 LOGE("Weak references remain!");
120#endif
121 ref_entry* refs = mWeakRefs;
122 while (refs) {
123 char inc = refs->ref >= 0 ? '+' : '-';
124 LOGD("\t%c ID %p (ref %d):", inc, refs->id, refs->ref);
125#if DEBUG_REFS_CALLSTACK_ENABLED
126 refs->stack.dump();
127#endif
128 refs = refs->next;
129 }
130 }
131 if (dumpStack) {
132 LOGE("above errors at:");
133 CallStack stack;
134 stack.update();
135 stack.dump();
136 }
96 } 137 }
97 138
98 void addStrongRef(const void* id) 139 void addStrongRef(const void* id) {
99 { 140 //LOGD_IF(mTrackEnabled,
141 // "addStrongRef: RefBase=%p, id=%p", mBase, id);
100 addRef(&mStrongRefs, id, mStrong); 142 addRef(&mStrongRefs, id, mStrong);
101 } 143 }
102 144
103 void removeStrongRef(const void* id) 145 void removeStrongRef(const void* id) {
104 { 146 //LOGD_IF(mTrackEnabled,
105 if (!mRetain) 147 // "removeStrongRef: RefBase=%p, id=%p", mBase, id);
148 if (!mRetain) {
106 removeRef(&mStrongRefs, id); 149 removeRef(&mStrongRefs, id);
107 else 150 } else {
108 addRef(&mStrongRefs, id, -mStrong); 151 addRef(&mStrongRefs, id, -mStrong);
152 }
109 } 153 }
110 154
111 void addWeakRef(const void* id) 155 void renameStrongRefId(const void* old_id, const void* new_id) {
112 { 156 //LOGD_IF(mTrackEnabled,
157 // "renameStrongRefId: RefBase=%p, oid=%p, nid=%p",
158 // mBase, old_id, new_id);
159 renameRefsId(mStrongRefs, old_id, new_id);
160 }
161
162 void addWeakRef(const void* id) {
113 addRef(&mWeakRefs, id, mWeak); 163 addRef(&mWeakRefs, id, mWeak);
114 } 164 }
115 165
116 void removeWeakRef(const void* id) 166 void removeWeakRef(const void* id) {
117 { 167 if (!mRetain) {
118 if (!mRetain)
119 removeRef(&mWeakRefs, id); 168 removeRef(&mWeakRefs, id);
120 else 169 } else {
121 addRef(&mWeakRefs, id, -mWeak); 170 addRef(&mWeakRefs, id, -mWeak);
171 }
172 }
173
174 void renameWeakRefId(const void* old_id, const void* new_id) {
175 renameRefsId(mWeakRefs, old_id, new_id);
122 } 176 }
123 177
124 void trackMe(bool track, bool retain) 178 void trackMe(bool track, bool retain)
@@ -132,8 +186,7 @@ public:
132 String8 text; 186 String8 text;
133 187
134 { 188 {
135 AutoMutex _l(const_cast<weakref_impl*>(this)->mMutex); 189 Mutex::Autolock _l(mMutex);
136
137 char buf[128]; 190 char buf[128];
138 sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this); 191 sprintf(buf, "Strong references on RefBase %p (weakref_type %p):\n", mBase, this);
139 text.append(buf); 192 text.append(buf);
@@ -172,6 +225,7 @@ private:
172 { 225 {
173 if (mTrackEnabled) { 226 if (mTrackEnabled) {
174 AutoMutex _l(mMutex); 227 AutoMutex _l(mMutex);
228
175 ref_entry* ref = new ref_entry; 229 ref_entry* ref = new ref_entry;
176 // Reference count at the time of the snapshot, but before the 230 // Reference count at the time of the snapshot, but before the
177 // update. Positive value means we increment, negative--we 231 // update. Positive value means we increment, negative--we
@@ -181,7 +235,6 @@ private:
181#if DEBUG_REFS_CALLSTACK_ENABLED 235#if DEBUG_REFS_CALLSTACK_ENABLED
182 ref->stack.update(2); 236 ref->stack.update(2);
183#endif 237#endif
184
185 ref->next = *refs; 238 ref->next = *refs;
186 *refs = ref; 239 *refs = ref;
187 } 240 }
@@ -192,20 +245,52 @@ private:
192 if (mTrackEnabled) { 245 if (mTrackEnabled) {
193 AutoMutex _l(mMutex); 246 AutoMutex _l(mMutex);
194 247
195 ref_entry* ref = *refs; 248 ref_entry* const head = *refs;
249 ref_entry* ref = head;
196 while (ref != NULL) { 250 while (ref != NULL) {
197 if (ref->id == id) { 251 if (ref->id == id) {
198 *refs = ref->next; 252 *refs = ref->next;
199 delete ref; 253 delete ref;
200 return; 254 return;
201 } 255 }
202
203 refs = &ref->next; 256 refs = &ref->next;
204 ref = *refs; 257 ref = *refs;
205 } 258 }
206 259
207 LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p (weakref_type %p) that doesn't exist!", 260#if DEBUG_REFS_FATAL_SANITY_CHECKS
208 id, mBase, this); 261 LOG_ALWAYS_FATAL("RefBase: removing id %p on RefBase %p"
262 "(weakref_type %p) that doesn't exist!",
263 id, mBase, this);
264#endif
265
266 LOGE("RefBase: removing id %p on RefBase %p"
267 "(weakref_type %p) that doesn't exist!",
268 id, mBase, this);
269
270 ref = head;
271 while (ref) {
272 char inc = ref->ref >= 0 ? '+' : '-';
273 LOGD("\t%c ID %p (ref %d):", inc, ref->id, ref->ref);
274 ref = ref->next;
275 }
276
277 CallStack stack;
278 stack.update();
279 stack.dump();
280 }
281 }
282
283 void renameRefsId(ref_entry* r, const void* old_id, const void* new_id)
284 {
285 if (mTrackEnabled) {
286 AutoMutex _l(mMutex);
287 ref_entry* ref = r;
288 while (ref != NULL) {
289 if (ref->id == old_id) {
290 ref->id = new_id;
291 }
292 ref = ref->next;
293 }
209 } 294 }
210 } 295 }
211 296
@@ -226,7 +311,7 @@ private:
226 } 311 }
227 } 312 }
228 313
229 Mutex mMutex; 314 mutable Mutex mMutex;
230 ref_entry* mStrongRefs; 315 ref_entry* mStrongRefs;
231 ref_entry* mWeakRefs; 316 ref_entry* mWeakRefs;
232 317
@@ -235,44 +320,6 @@ private:
235 // on removeref that match the address ones. 320 // on removeref that match the address ones.
236 bool mRetain; 321 bool mRetain;
237 322
238#if 0
239 void addRef(KeyedVector<const void*, int32_t>* refs, const void* id)
240 {
241 AutoMutex _l(mMutex);
242 ssize_t i = refs->indexOfKey(id);
243 if (i >= 0) {
244 ++(refs->editValueAt(i));
245 } else {
246 i = refs->add(id, 1);
247 }
248 }
249
250 void removeRef(KeyedVector<const void*, int32_t>* refs, const void* id)
251 {
252 AutoMutex _l(mMutex);
253 ssize_t i = refs->indexOfKey(id);
254 LOG_ALWAYS_FATAL_IF(i < 0, "RefBase: removing id %p that doesn't exist!", id);
255 if (i >= 0) {
256 int32_t val = --(refs->editValueAt(i));
257 if (val == 0) {
258 refs->removeItemsAt(i);
259 }
260 }
261 }
262
263 void printRefs(const KeyedVector<const void*, int32_t>& refs)
264 {
265 const size_t N=refs.size();
266 for (size_t i=0; i<N; i++) {
267 printf("\tID %p: %d remain\n", refs.keyAt(i), refs.valueAt(i));
268 }
269 }
270
271 mutable Mutex mMutex;
272 KeyedVector<const void*, int32_t> mStrongRefs;
273 KeyedVector<const void*, int32_t> mWeakRefs;
274#endif
275
276#endif 323#endif
277}; 324};
278 325
@@ -281,7 +328,6 @@ private:
281void RefBase::incStrong(const void* id) const 328void RefBase::incStrong(const void* id) const
282{ 329{
283 weakref_impl* const refs = mRefs; 330 weakref_impl* const refs = mRefs;
284 refs->addWeakRef(id);
285 refs->incWeak(id); 331 refs->incWeak(id);
286 332
287 refs->addStrongRef(id); 333 refs->addStrongRef(id);
@@ -295,7 +341,7 @@ void RefBase::incStrong(const void* id) const
295 } 341 }
296 342
297 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); 343 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
298 const_cast<RefBase*>(this)->onFirstRef(); 344 refs->mBase->onFirstRef();
299} 345}
300 346
301void RefBase::decStrong(const void* id) const 347void RefBase::decStrong(const void* id) const
@@ -308,19 +354,17 @@ void RefBase::decStrong(const void* id) const
308#endif 354#endif
309 LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs); 355 LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
310 if (c == 1) { 356 if (c == 1) {
311 const_cast<RefBase*>(this)->onLastStrongRef(id); 357 refs->mBase->onLastStrongRef(id);
312 if ((refs->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 358 if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
313 delete this; 359 delete this;
314 } 360 }
315 } 361 }
316 refs->removeWeakRef(id);
317 refs->decWeak(id); 362 refs->decWeak(id);
318} 363}
319 364
320void RefBase::forceIncStrong(const void* id) const 365void RefBase::forceIncStrong(const void* id) const
321{ 366{
322 weakref_impl* const refs = mRefs; 367 weakref_impl* const refs = mRefs;
323 refs->addWeakRef(id);
324 refs->incWeak(id); 368 refs->incWeak(id);
325 369
326 refs->addStrongRef(id); 370 refs->addStrongRef(id);
@@ -336,7 +380,7 @@ void RefBase::forceIncStrong(const void* id) const
336 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong); 380 android_atomic_add(-INITIAL_STRONG_VALUE, &refs->mStrong);
337 // fall through... 381 // fall through...
338 case 0: 382 case 0:
339 const_cast<RefBase*>(this)->onFirstRef(); 383 refs->mBase->onFirstRef();
340 } 384 }
341} 385}
342 386
@@ -345,8 +389,6 @@ int32_t RefBase::getStrongCount() const
345 return mRefs->mStrong; 389 return mRefs->mStrong;
346} 390}
347 391
348
349
350RefBase* RefBase::weakref_type::refBase() const 392RefBase* RefBase::weakref_type::refBase() const
351{ 393{
352 return static_cast<const weakref_impl*>(this)->mBase; 394 return static_cast<const weakref_impl*>(this)->mBase;
@@ -360,6 +402,7 @@ void RefBase::weakref_type::incWeak(const void* id)
360 LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this); 402 LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
361} 403}
362 404
405
363void RefBase::weakref_type::decWeak(const void* id) 406void RefBase::weakref_type::decWeak(const void* id)
364{ 407{
365 weakref_impl* const impl = static_cast<weakref_impl*>(this); 408 weakref_impl* const impl = static_cast<weakref_impl*>(this);
@@ -367,17 +410,26 @@ void RefBase::weakref_type::decWeak(const void* id)
367 const int32_t c = android_atomic_dec(&impl->mWeak); 410 const int32_t c = android_atomic_dec(&impl->mWeak);
368 LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this); 411 LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
369 if (c != 1) return; 412 if (c != 1) return;
370 413
371 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) != OBJECT_LIFETIME_WEAK) { 414 if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
372 if (impl->mStrong == INITIAL_STRONG_VALUE) 415 // This is the regular lifetime case. The object is destroyed
416 // when the last strong reference goes away. Since weakref_impl
417 // outlive the object, it is not destroyed in the dtor, and
418 // we'll have to do it here.
419 if (impl->mStrong == INITIAL_STRONG_VALUE) {
420 // Special case: we never had a strong reference, so we need to
421 // destroy the object now.
373 delete impl->mBase; 422 delete impl->mBase;
374 else { 423 } else {
375 // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase); 424 // LOGV("Freeing refs %p of old RefBase %p\n", this, impl->mBase);
376 delete impl; 425 delete impl;
377 } 426 }
378 } else { 427 } else {
428 // less common case: lifetime is OBJECT_LIFETIME_{WEAK|FOREVER}
379 impl->mBase->onLastWeakRef(id); 429 impl->mBase->onLastWeakRef(id);
380 if ((impl->mFlags&OBJECT_LIFETIME_FOREVER) != OBJECT_LIFETIME_FOREVER) { 430 if ((impl->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_WEAK) {
431 // this is the OBJECT_LIFETIME_WEAK case. The last weak-reference
432 // is gone, we can destroy the object.
381 delete impl->mBase; 433 delete impl->mBase;
382 } 434 }
383 } 435 }
@@ -432,7 +484,6 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
432 } 484 }
433 } 485 }
434 486
435 impl->addWeakRef(id);
436 impl->addStrongRef(id); 487 impl->addStrongRef(id);
437 488
438#if PRINT_REFS 489#if PRINT_REFS
@@ -450,7 +501,7 @@ bool RefBase::weakref_type::attemptIncStrong(const void* id)
450bool RefBase::weakref_type::attemptIncWeak(const void* id) 501bool RefBase::weakref_type::attemptIncWeak(const void* id)
451{ 502{
452 weakref_impl* const impl = static_cast<weakref_impl*>(this); 503 weakref_impl* const impl = static_cast<weakref_impl*>(this);
453 504
454 int32_t curCount = impl->mWeak; 505 int32_t curCount = impl->mWeak;
455 LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow", 506 LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
456 this); 507 this);
@@ -480,7 +531,7 @@ void RefBase::weakref_type::printRefs() const
480 531
481void RefBase::weakref_type::trackMe(bool enable, bool retain) 532void RefBase::weakref_type::trackMe(bool enable, bool retain)
482{ 533{
483 static_cast<const weakref_impl*>(this)->trackMe(enable, retain); 534 static_cast<weakref_impl*>(this)->trackMe(enable, retain);
484} 535}
485 536
486RefBase::weakref_type* RefBase::createWeak(const void* id) const 537RefBase::weakref_type* RefBase::createWeak(const void* id) const
@@ -497,14 +548,27 @@ RefBase::weakref_type* RefBase::getWeakRefs() const
497RefBase::RefBase() 548RefBase::RefBase()
498 : mRefs(new weakref_impl(this)) 549 : mRefs(new weakref_impl(this))
499{ 550{
500// LOGV("Creating refs %p with RefBase %p\n", mRefs, this);
501} 551}
502 552
503RefBase::~RefBase() 553RefBase::~RefBase()
504{ 554{
505 if (mRefs->mWeak == 0) { 555 if (mRefs->mStrong == INITIAL_STRONG_VALUE) {
556 // we never acquired a strong (and/or weak) reference on this object.
506 delete mRefs; 557 delete mRefs;
558 } else {
559 // life-time of this object is extended to WEAK or FOREVER, in
560 // which case weakref_impl doesn't out-live the object and we
561 // can free it now.
562 if ((mRefs->mFlags & OBJECT_LIFETIME_MASK) != OBJECT_LIFETIME_STRONG) {
563 // It's possible that the weak count is not 0 if the object
564 // re-acquired a weak reference in its destructor
565 if (mRefs->mWeak == 0) {
566 delete mRefs;
567 }
568 }
507 } 569 }
570 // for debugging purposes, clear this.
571 const_cast<weakref_impl*&>(mRefs) = NULL;
508} 572}
509 573
510void RefBase::extendObjectLifetime(int32_t mode) 574void RefBase::extendObjectLifetime(int32_t mode)
@@ -528,5 +592,37 @@ bool RefBase::onIncStrongAttempted(uint32_t flags, const void* id)
528void RefBase::onLastWeakRef(const void* /*id*/) 592void RefBase::onLastWeakRef(const void* /*id*/)
529{ 593{
530} 594}
531 595
596// ---------------------------------------------------------------------------
597
598void RefBase::moveReferences(void* dst, void const* src, size_t n,
599 const ReferenceConverterBase& caster)
600{
601#if DEBUG_REFS
602 const size_t itemSize = caster.getReferenceTypeSize();
603 for (size_t i=0 ; i<n ; i++) {
604 void* d = reinterpret_cast<void *>(intptr_t(dst) + i*itemSize);
605 void const* s = reinterpret_cast<void const*>(intptr_t(src) + i*itemSize);
606 RefBase* ref(reinterpret_cast<RefBase*>(caster.getReferenceBase(d)));
607 ref->mRefs->renameStrongRefId(s, d);
608 ref->mRefs->renameWeakRefId(s, d);
609 }
610#endif
611}
612
613// ---------------------------------------------------------------------------
614
615TextOutput& printStrongPointer(TextOutput& to, const void* val)
616{
617 to << "sp<>(" << val << ")";
618 return to;
619}
620
621TextOutput& printWeakPointer(TextOutput& to, const void* val)
622{
623 to << "wp<>(" << val << ")";
624 return to;
625}
626
627
532}; // namespace android 628}; // namespace android