Bug 846298 - Misc cleanups to the write poisoning base/OS split. r=BenWa.

This commit is contained in:
Rafael Ávila de Espíndola 2013-02-28 16:35:18 -05:00
parent 1934177bf8
commit 4a0c9499e8
3 changed files with 82 additions and 84 deletions

View File

@ -30,7 +30,43 @@
#endif
using namespace mozilla;
namespace mozilla {
namespace {
struct DebugFDAutoLockTraits {
typedef PRLock *type;
const static type empty() {
return nullptr;
}
const static void release(type aL) {
PR_Unlock(aL);
}
};
class DebugFDAutoLock : public Scoped<DebugFDAutoLockTraits> {
static PRLock *Lock;
public:
static void Clear();
static PRLock *getDebugFDsLock() {
// On windows this static is not thread safe, but we know that the first
// call is from
// * An early registration of a debug FD or
// * The call to InitWritePoisoning.
// Since the early debug FDs are logs created early in the main thread
// and no writes are trapped before InitWritePoisoning, we are safe.
static bool Initialized = false;
if (!Initialized) {
Lock = PR_NewLock();
Initialized = true;
}
// We have to use something lower level than a mutex. If we don't, we
// can get recursive in here when called from logging a call to free.
return Lock;
}
DebugFDAutoLock() : Scoped<DebugFDAutoLockTraits>(getDebugFDsLock()) {
PR_Lock(get());
}
};
PRLock *DebugFDAutoLock::Lock;
void DebugFDAutoLock::Clear() {
@ -48,22 +84,6 @@ std::vector<int>& getDebugFDs() {
return *DebugFDs;
}
void InitWritePoisoning()
{
// Call to make sure it is initialized.
DebugFDAutoLock::getDebugFDsLock();
nsCOMPtr<nsIFile> mozFile;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
if (mozFile) {
nsAutoCString nativePath;
nsresult rv = mozFile->GetNativePath(nativePath);
if (NS_SUCCEEDED(rv)) {
sProfileDirectory = PL_strdup(nativePath.get());
}
}
}
// This a wrapper over a file descriptor that provides a Printf method and
// computes the sha1 of the data that passes through it.
class SHA1Stream
@ -107,6 +127,40 @@ static void RecordStackWalker(void *aPC, void *aSP, void *aClosure)
stack->push_back(reinterpret_cast<uintptr_t>(aPC));
}
enum PoisonState {
POISON_UNINITIALIZED = 0,
POISON_ON,
POISON_OFF
};
// POISON_OFF has two consequences
// * It prevents PoisonWrite from patching the write functions.
// * If the patching has already been done, it prevents AbortOnBadWrite from
// asserting. Note that not all writes use AbortOnBadWrite at this point
// (aio_write for example), so disabling writes after patching doesn't
// completely undo it.
PoisonState sPoisoningState = POISON_UNINITIALIZED;
}
namespace mozilla {
void InitWritePoisoning()
{
// Call to make sure it is initialized.
DebugFDAutoLock::getDebugFDsLock();
nsCOMPtr<nsIFile> mozFile;
NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(mozFile));
if (mozFile) {
nsAutoCString nativePath;
nsresult rv = mozFile->GetNativePath(nativePath);
if (NS_SUCCEEDED(rv)) {
sProfileDirectory = PL_strdup(nativePath.get());
}
}
}
bool ValidWriteAssert(bool ok)
{
if (gShutdownChecks == SCM_CRASH && !ok) {
@ -207,20 +261,6 @@ bool ValidWriteAssert(bool ok)
return false;
}
enum PoisonState {
POISON_UNINITIALIZED = 0,
POISON_ON,
POISON_OFF
};
// POISON_OFF has two consequences
// * It prevents PoisonWrite from patching the write functions.
// * If the patching has already been done, it prevents AbortOnBadWrite from
// asserting. Note that not all writes use AbortOnBadWrite at this point
// (aio_write for example), so disabling writes after patching doesn't
// completely undo it.
PoisonState sPoisoningState = POISON_UNINITIALIZED;
void DisableWritePoisoning() {
if (sPoisoningState != POISON_ON)
return;
@ -247,6 +287,13 @@ bool PoisonWriteEnabled()
return sPoisoningState == POISON_ON;
}
bool IsDebugFD(int fd) {
DebugFDAutoLock lockedScope;
std::vector<int> &Vec = getDebugFDs();
return std::find(Vec.begin(), Vec.end(), fd) != Vec.end();
}
} // mozilla
extern "C" {

View File

@ -17,53 +17,9 @@
#include "mozilla/Scoped.h"
namespace mozilla {
struct DebugFDAutoLockTraits {
typedef PRLock *type;
const static type empty() {
return nullptr;
}
const static void release(type aL) {
PR_Unlock(aL);
}
};
class DebugFDAutoLock : public Scoped<DebugFDAutoLockTraits> {
static PRLock *Lock;
public:
static void Clear();
static PRLock *getDebugFDsLock() {
// On windows this static is not thread safe, but we know that the first
// call is from
// * An early registration of a debug FD or
// * The call to InitWritePoisoning.
// Since the early debug FDs are logs created early in the main thread
// and no writes are trapped before InitWritePoisoning, we are safe.
static bool Initialized = false;
if (!Initialized) {
Lock = PR_NewLock();
Initialized = true;
}
// We have to use something lower level than a mutex. If we don't, we
// can get recursive in here when called from logging a call to free.
return Lock;
}
DebugFDAutoLock() : Scoped<DebugFDAutoLockTraits>(getDebugFDsLock()) {
PR_Lock(get());
}
};
bool PoisonWriteEnabled();
bool ValidWriteAssert(bool ok);
void BaseCleanup();
// This method should always be called with the debugFDs lock.
// Note: MSVC Local static is NOT thread safe
// http://stackoverflow.com/questions/10585928/is-static-init-thread-safe-with-vc2010
std::vector<int>& getDebugFDs();
bool IsDebugFD(int fd);
}
#endif

View File

@ -175,14 +175,9 @@ void AbortOnBadWrite(int fd, const void *wbuf, size_t count) {
if (IsIPCWrite(fd, buf))
return;
{
DebugFDAutoLock lockedScope;
// Debugging FDs are OK
std::vector<int> &Vec = getDebugFDs();
if (std::find(Vec.begin(), Vec.end(), fd) != Vec.end())
if (IsDebugFD(fd))
return;
}
// For writev we pass NULL in wbuf. We should only get here from
// dbm, and it uses write, so assert that we have wbuf.