diff -r 000000000000 -r 6474c204b198 xpcom/build/PoisonIOInterposerBase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xpcom/build/PoisonIOInterposerBase.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,150 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 ci et: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "mozilla/Mutex.h" +#include "mozilla/Scoped.h" + +#include +#include + +#include "PoisonIOInterposer.h" + +// Auxiliary method to convert file descriptors to ids +#if defined(XP_WIN32) +#include +inline intptr_t FileDescriptorToID(int aFd) { + return _get_osfhandle(aFd); +} +#else +inline intptr_t FileDescriptorToID(int aFd) { + return aFd; +} +#endif /* if not XP_WIN32 */ + +using namespace mozilla; + +namespace { +struct DebugFilesAutoLockTraits { + typedef PRLock *type; + const static type empty() { + return nullptr; + } + const static void release(type aL) { + PR_Unlock(aL); + } +}; + +class DebugFilesAutoLock : public Scoped { + static PRLock *Lock; +public: + static void Clear(); + static PRLock *getDebugFileIDsLock() { + // 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. + if (!Lock) { + Lock = PR_NewLock(); + } + + // 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; + } + + DebugFilesAutoLock() : + Scoped(getDebugFileIDsLock()) { + PR_Lock(get()); + } +}; + +PRLock *DebugFilesAutoLock::Lock; +void DebugFilesAutoLock::Clear() { + MOZ_ASSERT(Lock != nullptr); + Lock = nullptr; +} + +// Return a vector used to hold the IDs of the current debug files. On unix +// an ID is a file descriptor. On Windows it is a file HANDLE. +std::vector* getDebugFileIDs() { + PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(DebugFilesAutoLock::getDebugFileIDsLock()); + // We have to use new as some write happen during static destructors + // so an static std::vector might be destroyed while we still need it. + static std::vector *DebugFileIDs = new std::vector(); + return DebugFileIDs; +} + +} // anonymous namespace + +namespace mozilla{ + +// Auxiliary Method to test if a file descriptor is registered to be ignored +// by the poisoning IO interposer +bool IsDebugFile(intptr_t aFileID) { + DebugFilesAutoLock lockedScope; + + std::vector &Vec = *getDebugFileIDs(); + return std::find(Vec.begin(), Vec.end(), aFileID) != Vec.end(); +} + +// Clean-up for the registered debug files. +// We should probably make sure all debug files are unregistered instead. +// But as the poison IO interposer is used for late-write checks we're not +// disabling it at any point yet. So Really no need for this. +// +// void ClearDebugFileRegister() { +// PRLock *Lock; +// { +// DebugFilesAutoLock lockedScope; +// delete getDebugFileIDs(); +// Lock = DebugFilesAutoLock::getDebugFileIDsLock(); +// DebugFilesAutoLock::Clear(); +// } +// PR_DestroyLock(Lock); +// } + +} // namespace mozilla + +extern "C" { + + void MozillaRegisterDebugFD(int fd) { + intptr_t fileId = FileDescriptorToID(fd); + DebugFilesAutoLock lockedScope; + std::vector &Vec = *getDebugFileIDs(); + MOZ_ASSERT(std::find(Vec.begin(), Vec.end(), fileId) == Vec.end()); + Vec.push_back(fileId); + } + + void MozillaRegisterDebugFILE(FILE *f) { + int fd = fileno(f); + if (fd == 1 || fd == 2) { + return; + } + MozillaRegisterDebugFD(fd); + } + + void MozillaUnRegisterDebugFD(int fd) { + DebugFilesAutoLock lockedScope; + intptr_t fileId = FileDescriptorToID(fd); + std::vector &Vec = *getDebugFileIDs(); + std::vector::iterator i = + std::find(Vec.begin(), Vec.end(), fileId); + MOZ_ASSERT(i != Vec.end()); + Vec.erase(i); + } + + void MozillaUnRegisterDebugFILE(FILE *f) { + int fd = fileno(f); + if (fd == 1 || fd == 2) { + return; + } + fflush(f); + MozillaUnRegisterDebugFD(fd); + } + +} \ No newline at end of file