зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1595596 - Use MMAP_FAULT_HANDLER in StartupCache r=aklotz
Please double check that I am using this correctly. I believe we are seeing the crash in the linked bug because we are not handling hardware faults when reading from the memory mapped file. This patch just wraps all accesses in the MMAP_FAULT_HANDLER_ macros. Depends on D53042 Differential Revision: https://phabricator.services.mozilla.com/D53043 --HG-- rename : modules/libjar/MmapFaultHandler.cpp => mozglue/misc/MmapFaultHandler.cpp rename : modules/libjar/MmapFaultHandler.h => mozglue/misc/MmapFaultHandler.h extra : moz-landing-system : lando
This commit is contained in:
Родитель
28daeac06d
Коммит
13ecdfb5c8
|
@ -30,7 +30,6 @@ EXPORTS += [
|
|||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'MmapFaultHandler.cpp',
|
||||
'nsJAR.cpp',
|
||||
'nsJARChannel.cpp',
|
||||
'nsJARInputStream.cpp',
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
# include "brotli/decode.h" // brotli
|
||||
#endif
|
||||
#include "nsZipArchive.h"
|
||||
#include "MmapFaultHandler.h"
|
||||
#include "mozilla/MmapFaultHandler.h"
|
||||
|
||||
#include "nsEscape.h"
|
||||
#include "nsDebug.h"
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
# include "brotli/decode.h" // brotli
|
||||
#endif
|
||||
#include "nsISupportsUtils.h"
|
||||
#include "MmapFaultHandler.h"
|
||||
#include "mozilla/MmapFaultHandler.h"
|
||||
#include "prio.h"
|
||||
#include "plstr.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
|
|
@ -8,13 +8,43 @@
|
|||
|
||||
#if defined(XP_UNIX) && !defined(XP_DARWIN)
|
||||
|
||||
# include "nsZipArchive.h"
|
||||
# include "mozilla/Atomics.h"
|
||||
# include "mozilla/StaticMutex.h"
|
||||
# include "PlatformMutex.h"
|
||||
# include "MainThreadUtils.h"
|
||||
# include "mozilla/Atomics.h"
|
||||
# include "mozilla/GuardObjects.h"
|
||||
# include "mozilla/ThreadLocal.h"
|
||||
# include <signal.h>
|
||||
|
||||
class MmapMutex : private mozilla::detail::MutexImpl {
|
||||
public:
|
||||
MmapMutex() : mozilla::detail::MutexImpl() {}
|
||||
void Lock() { mozilla::detail::MutexImpl::lock(); }
|
||||
void Unlock() { mozilla::detail::MutexImpl::unlock(); }
|
||||
};
|
||||
|
||||
class StaticMmapMutex {
|
||||
public:
|
||||
void Lock() { Mutex()->Lock(); }
|
||||
|
||||
void Unlock() { Mutex()->Unlock(); }
|
||||
|
||||
private:
|
||||
MmapMutex* Mutex() {
|
||||
if (mMutex) {
|
||||
return mMutex;
|
||||
}
|
||||
|
||||
MmapMutex* mutex = new MmapMutex();
|
||||
if (!mMutex.compareExchange(nullptr, mutex)) {
|
||||
delete mutex;
|
||||
}
|
||||
|
||||
return mMutex;
|
||||
}
|
||||
|
||||
mozilla::Atomic<MmapMutex*, mozilla::SequentiallyConsistent> mMutex;
|
||||
};
|
||||
|
||||
static MOZ_THREAD_LOCAL(MmapAccessScope*) sMmapAccessScope;
|
||||
|
||||
static struct sigaction sPrevSIGBUSHandler;
|
||||
|
@ -31,7 +61,6 @@ static void MmapSIGBUSHandler(int signum, siginfo_t* info, void* context) {
|
|||
|
||||
// The address is inside the buffer, handle the failure.
|
||||
siglongjmp(mas->mJmpBuf, signum);
|
||||
return;
|
||||
}
|
||||
|
||||
// This signal is not caused by accessing region protected by MmapAccessScope.
|
||||
|
@ -49,7 +78,20 @@ static void MmapSIGBUSHandler(int signum, siginfo_t* info, void* context) {
|
|||
}
|
||||
|
||||
mozilla::Atomic<bool> gSIGBUSHandlerInstalled(false);
|
||||
mozilla::StaticMutex gSIGBUSHandlerMutex;
|
||||
StaticMmapMutex gSIGBUSHandlerMutex;
|
||||
|
||||
class MOZ_RAII MmapMutexAutoLock {
|
||||
public:
|
||||
explicit MmapMutexAutoLock(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) {
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
gSIGBUSHandlerMutex.Lock();
|
||||
}
|
||||
|
||||
~MmapMutexAutoLock() { gSIGBUSHandlerMutex.Unlock(); }
|
||||
|
||||
private:
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
void InstallMmapFaultHandler() {
|
||||
// This function is called from MmapAccessScope's constructor because there is
|
||||
|
@ -60,7 +102,7 @@ void InstallMmapFaultHandler() {
|
|||
return;
|
||||
}
|
||||
|
||||
mozilla::StaticMutexAutoLock lock(gSIGBUSHandlerMutex);
|
||||
MmapMutexAutoLock lock;
|
||||
|
||||
// We must check it again, because the handler could be installed on another
|
||||
// thread when we were waiting for the lock.
|
||||
|
@ -81,29 +123,15 @@ void InstallMmapFaultHandler() {
|
|||
gSIGBUSHandlerInstalled = true;
|
||||
}
|
||||
|
||||
MmapAccessScope::MmapAccessScope(void* aBuf, uint32_t aBufLen) {
|
||||
MmapAccessScope::MmapAccessScope(void* aBuf, uint32_t aBufLen,
|
||||
const char* aFilename) {
|
||||
// Install signal handler if it wasn't installed yet.
|
||||
InstallMmapFaultHandler();
|
||||
|
||||
// We'll handle the signal only if the crashing address is inside this buffer.
|
||||
mBuf = aBuf;
|
||||
mBufLen = aBufLen;
|
||||
|
||||
SetThreadLocalScope();
|
||||
}
|
||||
|
||||
MmapAccessScope::MmapAccessScope(nsZipHandle* aZipHandle)
|
||||
: mBuf(nullptr), mBufLen(0) {
|
||||
// Install signal handler if it wasn't installed yet.
|
||||
InstallMmapFaultHandler();
|
||||
|
||||
// It's OK if aZipHandle is null (e.g. called from nsJARInputStream::Read
|
||||
// when mFd was already release), because no access to mmapped memory is made
|
||||
// in this case.
|
||||
if (aZipHandle && aZipHandle->mMap) {
|
||||
// Handle SIGBUS only when it's an mmaped zip file.
|
||||
mZipHandle = aZipHandle;
|
||||
}
|
||||
mFilename = aFilename;
|
||||
|
||||
SetThreadLocalScope();
|
||||
}
|
||||
|
@ -129,48 +157,15 @@ void MmapAccessScope::SetThreadLocalScope() {
|
|||
}
|
||||
|
||||
bool MmapAccessScope::IsInsideBuffer(void* aPtr) {
|
||||
bool isIn;
|
||||
|
||||
if (mZipHandle) {
|
||||
isIn =
|
||||
aPtr >= mZipHandle->mFileStart &&
|
||||
aPtr < (void*)((char*)mZipHandle->mFileStart + mZipHandle->mTotalLen);
|
||||
} else {
|
||||
isIn = aPtr >= mBuf && aPtr < (void*)((char*)mBuf + mBufLen);
|
||||
}
|
||||
|
||||
return isIn;
|
||||
return aPtr >= mBuf && aPtr < (void*)((char*)mBuf + mBufLen);
|
||||
}
|
||||
|
||||
void MmapAccessScope::CrashWithInfo(void* aPtr) {
|
||||
if (!mZipHandle) {
|
||||
// All we have is the buffer and the crashing address.
|
||||
MOZ_CRASH_UNSAFE_PRINTF(
|
||||
"SIGBUS received when accessing mmaped zip file [buffer=%p, "
|
||||
"buflen=%" PRIu32 ", address=%p]",
|
||||
mBuf, mBufLen, aPtr);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> file = mZipHandle->mFile.GetBaseFile();
|
||||
nsCString fileName;
|
||||
file->GetNativeLeafName(fileName);
|
||||
|
||||
// Get current file size
|
||||
int fileSize = -1;
|
||||
if (PR_Seek64(mZipHandle->mNSPRFileDesc, 0, PR_SEEK_SET) != -1) {
|
||||
fileSize = PR_Available64(mZipHandle->mNSPRFileDesc);
|
||||
}
|
||||
|
||||
// MOZ_CRASH_UNSAFE_PRINTF has limited number of arguments, so append fileSize
|
||||
// to fileName
|
||||
fileName.Append(", filesize=");
|
||||
fileName.AppendInt(fileSize);
|
||||
|
||||
// All we have is the buffer and the crashing address.
|
||||
MOZ_CRASH_UNSAFE_PRINTF(
|
||||
"SIGBUS received when accessing mmaped zip file [file=%s, buffer=%p, "
|
||||
"buflen=%" PRIu32 ", address=%p]",
|
||||
fileName.get(), (char*)mZipHandle->mFileStart, mZipHandle->mTotalLen,
|
||||
aPtr);
|
||||
"SIGBUS received when accessing mmaped file [buffer=%p, "
|
||||
"buflen=%u, address=%p, filename=%s]",
|
||||
mBuf, mBufLen, aPtr, mFilename);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -36,18 +36,15 @@
|
|||
#else
|
||||
// Linux
|
||||
|
||||
# include "mozilla/RefPtr.h"
|
||||
# include "mozilla/GuardObjects.h"
|
||||
# include <stdint.h>
|
||||
# include <setjmp.h>
|
||||
|
||||
class nsZipHandle;
|
||||
|
||||
class MOZ_RAII MmapAccessScope {
|
||||
public:
|
||||
MmapAccessScope(void* aBuf, uint32_t aBufLen);
|
||||
explicit MmapAccessScope(nsZipHandle* aZipHandle);
|
||||
~MmapAccessScope();
|
||||
MFBT_API MmapAccessScope(void* aBuf, uint32_t aBufLen,
|
||||
const char* aFilename = nullptr);
|
||||
MFBT_API ~MmapAccessScope();
|
||||
|
||||
MmapAccessScope(const MmapAccessScope&) = delete;
|
||||
MmapAccessScope& operator=(const MmapAccessScope&) = delete;
|
||||
|
@ -63,14 +60,26 @@ class MOZ_RAII MmapAccessScope {
|
|||
|
||||
private:
|
||||
void* mBuf;
|
||||
const char* mFilename;
|
||||
uint32_t mBufLen;
|
||||
RefPtr<nsZipHandle> mZipHandle;
|
||||
MmapAccessScope* mPreviousScope;
|
||||
};
|
||||
|
||||
# define MMAP_FAULT_HANDLER_BEGIN_HANDLE(fd) \
|
||||
{ \
|
||||
MmapAccessScope mmapScope(fd); \
|
||||
# define MMAP_FAULT_HANDLER_BEGIN_HANDLE(fd) \
|
||||
{ \
|
||||
void* mmapScopeBuf = nullptr; \
|
||||
nsCString mmapScopeFilename; \
|
||||
uint32_t mmapScopeBufLen = 0; \
|
||||
if (fd && fd->mMap) { \
|
||||
mmapScopeBuf = (void*)fd->mFileStart; \
|
||||
mmapScopeBufLen = fd->mTotalLen; \
|
||||
} \
|
||||
if (fd && fd->mFile) { \
|
||||
nsCOMPtr<nsIFile> file = fd->mFile.GetBaseFile(); \
|
||||
file->GetNativeLeafName(mmapScopeFilename); \
|
||||
} \
|
||||
MmapAccessScope mmapScope(mmapScopeBuf, mmapScopeBufLen, \
|
||||
mmapScopeFilename.get()); \
|
||||
if (sigsetjmp(mmapScope.mJmpBuf, 0) == 0) {
|
||||
# define MMAP_FAULT_HANDLER_BEGIN_BUFFER(buf, bufLen) \
|
||||
{ \
|
|
@ -10,6 +10,7 @@ EXPORTS.mozilla += [
|
|||
'AutoProfilerLabel.h',
|
||||
'decimal/Decimal.h',
|
||||
'decimal/DoubleConversion.h',
|
||||
'MmapFaultHandler.h',
|
||||
'PlatformConditionVariable.h',
|
||||
'PlatformMutex.h',
|
||||
'Printf.h',
|
||||
|
@ -30,6 +31,7 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
|
||||
SOURCES += [
|
||||
'AutoProfilerLabel.cpp',
|
||||
'MmapFaultHandler.cpp',
|
||||
'Printf.cpp',
|
||||
'StackWalk.cpp',
|
||||
'TimeStamp.cpp',
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "mozilla/IOBuffers.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/MemUtils.h"
|
||||
#include "mozilla/MmapFaultHandler.h"
|
||||
#include "mozilla/ResultExtensions.h"
|
||||
#include "mozilla/scache/StartupCache.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
|
@ -35,6 +36,10 @@
|
|||
#include "nsIProtocolHandler.h"
|
||||
#include "GeckoProfiler.h"
|
||||
|
||||
#if defined(XP_WIN)
|
||||
# include <windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef IS_BIG_ENDIAN
|
||||
# define SC_ENDIAN "big"
|
||||
#else
|
||||
|
@ -254,6 +259,8 @@ Result<Ok, nsresult> StartupCache::LoadArchive() {
|
|||
auto data = mCacheData.get<uint8_t>();
|
||||
auto end = data + size;
|
||||
|
||||
MMAP_FAULT_HANDLER_BEGIN_BUFFER(data.get(), size)
|
||||
|
||||
if (memcmp(MAGIC, data.get(), sizeof(MAGIC))) {
|
||||
return Err(NS_ERROR_UNEXPECTED);
|
||||
}
|
||||
|
@ -327,6 +334,8 @@ Result<Ok, nsresult> StartupCache::LoadArchive() {
|
|||
cleanup.release();
|
||||
}
|
||||
|
||||
MMAP_FAULT_HANDLER_CATCH(Err(NS_ERROR_UNEXPECTED))
|
||||
|
||||
return Ok();
|
||||
}
|
||||
|
||||
|
@ -373,6 +382,8 @@ nsresult StartupCache::GetBuffer(const char* id, const char** outbuf,
|
|||
value.mData = MakeUnique<char[]>(value.mUncompressedSize);
|
||||
Span<char> uncompressed =
|
||||
MakeSpan(value.mData.get(), value.mUncompressedSize);
|
||||
MMAP_FAULT_HANDLER_BEGIN_BUFFER(uncompressed.Elements(),
|
||||
uncompressed.Length())
|
||||
bool finished = false;
|
||||
while (!finished) {
|
||||
auto result = mDecompressionContext->Decompress(
|
||||
|
@ -388,6 +399,8 @@ nsresult StartupCache::GetBuffer(const char* id, const char** outbuf,
|
|||
finished = decompressionResult.mFinished;
|
||||
}
|
||||
|
||||
MMAP_FAULT_HANDLER_CATCH(NS_ERROR_FAILURE)
|
||||
|
||||
label = Telemetry::LABELS_STARTUP_CACHE_REQUESTS::HitDisk;
|
||||
}
|
||||
|
||||
|
@ -642,8 +655,11 @@ void StartupCache::ThreadedPrefetch(void* aClosure) {
|
|||
NS_SetCurrentThreadName("StartupCache");
|
||||
mozilla::IOInterposer::RegisterCurrentThread();
|
||||
StartupCache* startupCacheObj = static_cast<StartupCache*>(aClosure);
|
||||
PrefetchMemory(startupCacheObj->mCacheData.get<uint8_t>().get(),
|
||||
startupCacheObj->mCacheData.size());
|
||||
uint8_t* buf = startupCacheObj->mCacheData.get<uint8_t>().get();
|
||||
size_t size = startupCacheObj->mCacheData.size();
|
||||
MMAP_FAULT_HANDLER_BEGIN_BUFFER(buf, size)
|
||||
PrefetchMemory(buf, size);
|
||||
MMAP_FAULT_HANDLER_CATCH()
|
||||
mozilla::IOInterposer::UnregisterCurrentThread();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче