Skip to content

Commit ef6eda1

Browse files
committed
Bug 1267980 - Leak buffers in CacheFileChunk and CacheFileMetadata during shutdown, r=honzab
1 parent c6c1bde commit ef6eda1

File tree

8 files changed

+65
-74
lines changed

8 files changed

+65
-74
lines changed

netwerk/cache2/CacheFileChunk.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,14 @@ CacheFileChunk::~CacheFileChunk()
131131
MOZ_COUNT_DTOR(CacheFileChunk);
132132

133133
if (mBuf) {
134-
free(mBuf);
134+
CacheFileUtils::FreeBuffer(mBuf);
135135
mBuf = nullptr;
136136
mBufSize = 0;
137137
ChunkAllocationChanged();
138138
}
139139

140140
if (mRWBuf) {
141-
free(mRWBuf);
141+
CacheFileUtils::FreeBuffer(mRWBuf);
142142
mRWBuf = nullptr;
143143
mRWBufSize = 0;
144144
ChunkAllocationChanged();
@@ -447,7 +447,7 @@ CacheFileChunk::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
447447
mRWBuf = nullptr;
448448
mRWBufSize = 0;
449449
} else {
450-
free(mRWBuf);
450+
CacheFileUtils::FreeBuffer(mRWBuf);
451451
mRWBuf = nullptr;
452452
mRWBufSize = 0;
453453
ChunkAllocationChanged();
@@ -513,7 +513,7 @@ CacheFileChunk::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
513513
}
514514
mValidityMap.Clear();
515515

516-
free(mBuf);
516+
CacheFileUtils::FreeBuffer(mBuf);
517517
mBuf = mRWBuf;
518518
mBufSize = mRWBufSize;
519519
mRWBuf = nullptr;
@@ -545,7 +545,7 @@ CacheFileChunk::OnDataRead(CacheFileHandle *aHandle, char *aBuf,
545545
}
546546
mValidityMap.Clear();
547547

548-
free(mRWBuf);
548+
CacheFileUtils::FreeBuffer(mRWBuf);
549549
mRWBuf = nullptr;
550550
mRWBufSize = 0;
551551
ChunkAllocationChanged();

netwerk/cache2/CacheFileIOManager.cpp

Lines changed: 8 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,6 @@ class ShutdownEvent : public Runnable {
537537
ShutdownEvent()
538538
: mMonitor("ShutdownEvent.mMonitor")
539539
, mNotified(false)
540-
, mPrepare(true)
541540
{
542541
MOZ_COUNT_CTOR(ShutdownEvent);
543542
}
@@ -551,21 +550,6 @@ class ShutdownEvent : public Runnable {
551550
public:
552551
NS_IMETHOD Run()
553552
{
554-
if (mPrepare) {
555-
MOZ_ASSERT(CacheFileIOManager::gInstance->mIOThread->IsCurrentThread());
556-
557-
mPrepare = false;
558-
559-
// This event is first posted to the XPCOM level (executed ASAP) of the IO thread
560-
// and sets the timestamp of the shutdown start. This will cause some operations
561-
// to be bypassed when due (actually leak most of the open files).
562-
CacheFileIOManager::gInstance->mShutdownDemandedTime = TimeStamp::NowLoRes();
563-
564-
// Redispatch to the right level to proceed with shutdown.
565-
CacheFileIOManager::gInstance->mIOThread->Dispatch(this, CacheIOThread::CLOSE);
566-
return NS_OK;
567-
}
568-
569553
MonitorAutoLock mon(mMonitor);
570554

571555
CacheFileIOManager::gInstance->ShutdownInternal();
@@ -581,10 +565,8 @@ class ShutdownEvent : public Runnable {
581565
MonitorAutoLock mon(mMonitor);
582566

583567
DebugOnly<nsresult> rv;
584-
nsCOMPtr<nsIEventTarget> ioTarget =
585-
CacheFileIOManager::gInstance->mIOThread->Target();
586-
MOZ_ASSERT(ioTarget);
587-
rv = ioTarget->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
568+
rv = CacheFileIOManager::gInstance->mIOThread->Dispatch(
569+
this, CacheIOThread::CLOSE);
588570
MOZ_ASSERT(NS_SUCCEEDED(rv));
589571
while (!mNotified) {
590572
mon.Wait();
@@ -594,7 +576,6 @@ class ShutdownEvent : public Runnable {
594576
protected:
595577
mozilla::Monitor mMonitor;
596578
bool mNotified;
597-
bool mPrepare;
598579
};
599580

600581
class OpenFileEvent : public Runnable {
@@ -735,7 +716,7 @@ class WriteEvent : public Runnable {
735716
// We usually get here only after the internal shutdown
736717
// (i.e. mShuttingDown == true). Pretend write has succeeded
737718
// to avoid any past-shutdown file dooming.
738-
rv = (CacheFileIOManager::gInstance->IsPastShutdownIOLag() ||
719+
rv = (CacheObserver::IsPastShutdownIOLag() ||
739720
CacheFileIOManager::gInstance->mShuttingDown)
740721
? NS_OK
741722
: NS_ERROR_NOT_INITIALIZED;
@@ -1176,8 +1157,6 @@ CacheFileIOManager::Shutdown()
11761157
return NS_ERROR_NOT_INITIALIZED;
11771158
}
11781159

1179-
gInstance->mShutdownDemanded = true;
1180-
11811160
Telemetry::AutoTimer<Telemetry::NETWORK_DISK_CACHE_SHUTDOWN_V2> shutdownTimer;
11821161

11831162
CacheIndex::PreShutdown();
@@ -1274,26 +1253,6 @@ CacheFileIOManager::ShutdownInternal()
12741253
return NS_OK;
12751254
}
12761255

1277-
bool
1278-
CacheFileIOManager::IsPastShutdownIOLag()
1279-
{
1280-
#ifdef DEBUG
1281-
return false;
1282-
#endif
1283-
1284-
if (mShutdownDemandedTime.IsNull()) {
1285-
return false;
1286-
}
1287-
1288-
TimeDuration const& preferredIOLag = CacheObserver::MaxShutdownIOLag();
1289-
if (preferredIOLag < TimeDuration(0)) {
1290-
return false;
1291-
}
1292-
1293-
TimeDuration currentIOLag = TimeStamp::NowLoRes() - mShutdownDemandedTime;
1294-
return currentIOLag > preferredIOLag;
1295-
}
1296-
12971256
// static
12981257
nsresult
12991258
CacheFileIOManager::OnProfile()
@@ -1979,7 +1938,7 @@ CacheFileIOManager::WriteInternal(CacheFileHandle *aHandle, int64_t aOffset,
19791938

19801939
nsresult rv;
19811940

1982-
if (IsPastShutdownIOLag()) {
1941+
if (CacheObserver::IsPastShutdownIOLag()) {
19831942
LOG((" past the shutdown I/O lag, nothing written"));
19841943
// Pretend the write has succeeded, otherwise upper layers will doom
19851944
// the file and we end up with I/O anyway.
@@ -2306,9 +2265,11 @@ CacheFileIOManager::ReleaseNSPRHandleInternal(CacheFileHandle *aHandle,
23062265
// Leak other handles when past the shutdown time maximum lag.
23072266
if (
23082267
#ifndef DEBUG
2309-
((aHandle->mInvalid || aHandle->mIsDoomed) && MOZ_UNLIKELY(mShutdownDemanded)) ||
2268+
((aHandle->mInvalid || aHandle->mIsDoomed) &&
2269+
MOZ_UNLIKELY(CacheObserver::ShuttingDown())) ||
23102270
#endif
2311-
MOZ_UNLIKELY(!aIgnoreShutdownLag && IsPastShutdownIOLag())) {
2271+
MOZ_UNLIKELY(!aIgnoreShutdownLag &&
2272+
CacheObserver::IsPastShutdownIOLag())) {
23122273
// Pretend this file has been validated (the metadata has been written)
23132274
// to prevent removal I/O on this apparently used file. The entry will
23142275
// never be used, since it doesn't have correct metadata, thus we don't

netwerk/cache2/CacheFileIOManager.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -432,20 +432,11 @@ class CacheFileIOManager : public nsITimerCallback
432432
// before we start an eviction loop.
433433
nsresult UpdateSmartCacheSize(int64_t aFreeSpace);
434434

435-
// May return true after shutdown only when time for flushing all data
436-
// has already passed.
437-
bool IsPastShutdownIOLag();
438-
439435
// Memory reporting (private part)
440436
size_t SizeOfExcludingThisInternal(mozilla::MallocSizeOf mallocSizeOf) const;
441437

442438
static CacheFileIOManager *gInstance;
443439
TimeStamp mStartTime;
444-
// Shutdown time stamp, accessed only on the I/O thread. Used to bypass
445-
// I/O after a certain time pass the shutdown has been demanded.
446-
TimeStamp mShutdownDemandedTime;
447-
// Set true on the main thread when cache shutdown is first demanded.
448-
Atomic<bool, Relaxed> mShutdownDemanded;
449440
// Set true on the IO thread, CLOSE level as part of the internal shutdown
450441
// procedure.
451442
bool mShuttingDown;

netwerk/cache2/CacheFileMetadata.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,13 @@ CacheFileMetadata::~CacheFileMetadata()
133133
MOZ_ASSERT(!mListener);
134134

135135
if (mHashArray) {
136-
free(mHashArray);
136+
CacheFileUtils::FreeBuffer(mHashArray);
137137
mHashArray = nullptr;
138138
mHashArraySize = 0;
139139
}
140140

141141
if (mBuf) {
142-
free(mBuf);
142+
CacheFileUtils::FreeBuffer(mBuf);
143143
mBuf = nullptr;
144144
mBufSize = 0;
145145
}
@@ -302,7 +302,7 @@ CacheFileMetadata::WriteMetadata(uint32_t aOffset,
302302

303303
mListener = nullptr;
304304
if (mWriteBuf) {
305-
free(mWriteBuf);
305+
CacheFileUtils::FreeBuffer(mWriteBuf);
306306
mWriteBuf = nullptr;
307307
}
308308
NS_ENSURE_SUCCESS(rv, rv);
@@ -651,7 +651,7 @@ CacheFileMetadata::OnDataWritten(CacheFileHandle *aHandle, const char *aBuf,
651651
MOZ_ASSERT(mListener);
652652
MOZ_ASSERT(mWriteBuf);
653653

654-
free(mWriteBuf);
654+
CacheFileUtils::FreeBuffer(mWriteBuf);
655655
mWriteBuf = nullptr;
656656

657657
nsCOMPtr<CacheFileMetadataListener> listener;
@@ -828,7 +828,7 @@ void
828828
CacheFileMetadata::InitEmptyMetadata()
829829
{
830830
if (mBuf) {
831-
free(mBuf);
831+
CacheFileUtils::FreeBuffer(mBuf);
832832
mBuf = nullptr;
833833
mBufSize = 0;
834834
}

netwerk/cache2/CacheFileUtils.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,17 @@ DetailedCacheHitTelemetry::AddRecord(ERecType aType, TimeStamp aLoadStart)
508508
}
509509
}
510510

511+
void
512+
FreeBuffer(void *aBuf) {
513+
#ifndef NS_FREE_PERMANENT_DATA
514+
if (CacheObserver::ShuttingDown()) {
515+
return;
516+
}
517+
#endif
518+
519+
free(aBuf);
520+
}
521+
511522
} // namespace CacheFileUtils
512523
} // namespace net
513524
} // namespace mozilla

netwerk/cache2/CacheFileUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,9 @@ class DetailedCacheHitTelemetry {
146146
static HitRate sHRStats[kNumOfRanges];
147147
};
148148

149+
void
150+
FreeBuffer(void *aBuf);
151+
149152
} // namespace CacheFileUtils
150153
} // namespace net
151154
} // namespace mozilla

netwerk/cache2/CacheObserver.cpp

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ bool CacheObserver::sCacheFSReported = kDefaultCacheFSReported;
9494
static bool kDefaultHashStatsReported = false;
9595
bool CacheObserver::sHashStatsReported = kDefaultHashStatsReported;
9696

97-
static int32_t const kDefaultMaxShutdownIOLag = 2; // seconds
98-
int32_t CacheObserver::sMaxShutdownIOLag = kDefaultMaxShutdownIOLag;
97+
static uint32_t const kDefaultMaxShutdownIOLag = 2; // seconds
98+
Atomic<uint32_t, Relaxed> CacheObserver::sMaxShutdownIOLag(kDefaultMaxShutdownIOLag);
99+
100+
Atomic<PRIntervalTime, Relaxed> CacheObserver::sShutdownDemandedTime(PR_INTERVAL_NO_TIMEOUT);
99101

100102
NS_IMPL_ISUPPORTS(CacheObserver,
101103
nsIObserver,
@@ -248,7 +250,7 @@ CacheObserver::AttachToPreferences()
248250
mozilla::Preferences::AddBoolVarCache(
249251
&sClearCacheOnShutdown, "privacy.clearOnShutdown.cache", kDefaultClearCacheOnShutdown);
250252

251-
mozilla::Preferences::AddIntVarCache(
253+
mozilla::Preferences::AddAtomicUintVarCache(
252254
&sMaxShutdownIOLag, "browser.cache.max_shutdown_io_lag", kDefaultMaxShutdownIOLag);
253255
}
254256

@@ -480,10 +482,25 @@ bool CacheObserver::EntryIsTooBig(int64_t aSize, bool aUsingDisk)
480482
}
481483

482484
// static
483-
TimeDuration const& CacheObserver::MaxShutdownIOLag()
485+
bool CacheObserver::IsPastShutdownIOLag()
484486
{
485-
static TimeDuration period = TimeDuration::FromSeconds(sMaxShutdownIOLag);
486-
return period;
487+
#ifdef DEBUG
488+
return false;
489+
#endif
490+
491+
if (sShutdownDemandedTime == PR_INTERVAL_NO_TIMEOUT ||
492+
sMaxShutdownIOLag == UINT32_MAX) {
493+
return false;
494+
}
495+
496+
static const PRIntervalTime kMaxShutdownIOLag =
497+
PR_SecondsToInterval(sMaxShutdownIOLag);
498+
499+
if ((PR_IntervalNow() - sShutdownDemandedTime) > kMaxShutdownIOLag) {
500+
return true;
501+
}
502+
503+
return false;
487504
}
488505

489506
NS_IMETHODIMP
@@ -512,6 +529,10 @@ CacheObserver::Observe(nsISupports* aSubject,
512529
if (!strcmp(aTopic, "profile-change-net-teardown") ||
513530
!strcmp(aTopic, "profile-before-change") ||
514531
!strcmp(aTopic, "xpcom-shutdown")) {
532+
if (sShutdownDemandedTime == PR_INTERVAL_NO_TIMEOUT) {
533+
sShutdownDemandedTime = PR_IntervalNow();
534+
}
535+
515536
RefPtr<CacheStorageService> service = CacheStorageService::Self();
516537
if (service) {
517538
service->Shutdown();

netwerk/cache2/CacheObserver.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ class CacheObserver : public nsIObserver
7171

7272
static bool EntryIsTooBig(int64_t aSize, bool aUsingDisk);
7373

74-
static TimeDuration const& MaxShutdownIOLag();
74+
static bool IsPastShutdownIOLag();
75+
76+
static bool ShuttingDown()
77+
{ return sShutdownDemandedTime != PR_INTERVAL_NO_TIMEOUT; }
7578

7679
private:
7780
static CacheObserver* sSelf;
@@ -103,7 +106,8 @@ class CacheObserver : public nsIObserver
103106
static bool sClearCacheOnShutdown;
104107
static bool sCacheFSReported;
105108
static bool sHashStatsReported;
106-
static int32_t sMaxShutdownIOLag;
109+
static Atomic<uint32_t, Relaxed> sMaxShutdownIOLag;
110+
static Atomic<PRIntervalTime, Relaxed> sShutdownDemandedTime;
107111

108112
// Non static properties, accessible via sSelf
109113
nsCOMPtr<nsIFile> mCacheParentDirectoryOverride;

0 commit comments

Comments
 (0)