mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 05:11:03 +00:00
import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 777067 - "Fuzzing: IPC Protocol Definition Language (IPDL) Protocols". r=wmccloskey (248c48ba96) - Bug 1269056: Part 1 - Implement a rough PostDelayedTask equivalent on nsThread. r=froydnj (f9d8694b4d) - Bug 1269056: Part 2 - Consolidate XPCOM and chromium event queues for non-main nsThreads. r=froydnj (14e156126b) - Bug 1269056: Part 3 - Consolidate XPCOM and chromium event queues for the main thread. r=froydnj (90e5dabb4d) - Bug 1271102 - Revert back to 256 MiB message limit. r=billm (d71cb26d74) - Bug 950401 - Add process logging to OS X / BSD. r=bsmedberg (f3819e7f3b) - Bug 1269319 - Make AlignedStorage/AlignedStorage2 non-copyable to fix strict aliasing issues. r=Waldo (d86ae927e1) - Bug 1268754 - Tweak some MFBT return values. r=Ms2ger. (a71415c34e) - Bug 1269317 - Don't use AlignedStorage2 in RegisterSets.h. r=nbp (f628be93a2) - Bug 1269319 followup - Don't swap an entry with itself to avoid Variant self assignment. r=bustage (929bc926ca) - mfbt: Alignment.h: partly disable changes of Bug 1269319 for VC2013 or older as they can't handle this. (253e78c5e6)
This commit is contained in:
@@ -1742,6 +1742,24 @@ if test "$MOZ_PROFILING" -a -z "$STRIP_FLAGS"; then
|
||||
esac
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable Gecko integrated IPC fuzzer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(ipc-fuzzer,
|
||||
[ --enable-ipc-fuzzer Enable IPC fuzzer (default=no)],
|
||||
MOZ_FAULTY=1,
|
||||
MOZ_FAULTY= )
|
||||
AC_SUBST(MOZ_FAULTY)
|
||||
|
||||
if test -n "$MOZ_FAULTY" && test "$OS_ARCH" = "WINNT"; then
|
||||
AC_MSG_ERROR([--enable-ipc-fuzzer is not supported on this platform.])
|
||||
fi
|
||||
|
||||
if test -n "$MOZ_FAULTY"; then
|
||||
MOZ_FAULTY=1
|
||||
AC_DEFINE(MOZ_FAULTY)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Enable DMD
|
||||
dnl ========================================================
|
||||
|
||||
@@ -2824,6 +2824,12 @@ WebSocketImpl::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketImpl::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,13 @@ ContextLossWorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
return mEventTarget->Dispatch(wrappedEvent, aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&,
|
||||
uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ContextLossWorkerEventTarget::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
|
||||
@@ -38,8 +38,17 @@ public:
|
||||
JS::TraceEdge(trc, &mJSObj, "nsJSObjWrapperKey");
|
||||
}
|
||||
|
||||
nsJSObjWrapperKey(const nsJSObjWrapperKey& other)
|
||||
: mJSObj(other.mJSObj),
|
||||
mNpp(other.mNpp)
|
||||
{}
|
||||
void operator=(const nsJSObjWrapperKey& other) {
|
||||
mJSObj = other.mJSObj;
|
||||
mNpp = other.mNpp;
|
||||
}
|
||||
|
||||
JS::Heap<JSObject*> mJSObj;
|
||||
const NPP mNpp;
|
||||
NPP mNpp;
|
||||
};
|
||||
|
||||
class nsJSObjWrapper : public NPObject
|
||||
|
||||
@@ -1826,6 +1826,12 @@ TimerThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TimerThreadEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TimerThreadEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread)
|
||||
{
|
||||
@@ -6720,6 +6726,14 @@ EventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
NS_IMETHODIMP
|
||||
WorkerPrivateParent<Derived>::
|
||||
|
||||
@@ -1528,6 +1528,9 @@ protected:
|
||||
NS_IMETHOD
|
||||
Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t) override;
|
||||
|
||||
NS_IMETHOD
|
||||
IsOnCurrentThread(bool* aIsOnCurrentThread) override;
|
||||
};
|
||||
|
||||
@@ -292,6 +292,12 @@ WorkerThread::Dispatch(already_AddRefed<nsIRunnable>&& aRunnable, uint32_t aFlag
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
WorkerThread::RecursionDepth(const WorkerThreadFriendKey& /* aKey */) const
|
||||
{
|
||||
|
||||
@@ -88,6 +88,9 @@ private:
|
||||
|
||||
NS_IMETHOD
|
||||
DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) override;
|
||||
|
||||
NS_IMETHOD
|
||||
DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t) override;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
||||
@@ -118,7 +118,7 @@ const mozilla::EmptyLog& operator <<(const mozilla::EmptyLog& log, const T&)
|
||||
#define NOTIMPLEMENTED() CHROMIUM_LOG(ERROR)
|
||||
|
||||
#undef CHECK
|
||||
#define CHECK(condition) LOG_IF(FATAL, condition)
|
||||
#define CHECK(condition) LOG_IF(WARNING, condition)
|
||||
|
||||
#define DCHECK_EQ(v1, v2) DCHECK((v1) == (v2))
|
||||
#define DCHECK_NE(v1, v2) DCHECK((v1) != (v2))
|
||||
|
||||
@@ -280,6 +280,17 @@ void MessageLoop::PostIdleTask(already_AddRefed<Runnable> task) {
|
||||
|
||||
// Possibly called on a background thread!
|
||||
void MessageLoop::PostTask_Helper(already_AddRefed<Runnable> task, int delay_ms) {
|
||||
if (nsIEventTarget* target = pump_->GetXPCOMThread()) {
|
||||
nsresult rv;
|
||||
if (delay_ms) {
|
||||
rv = target->DelayedDispatch(Move(task), delay_ms);
|
||||
} else {
|
||||
rv = target->Dispatch(Move(task), 0);
|
||||
}
|
||||
MOZ_ALWAYS_SUCCEEDS(rv);
|
||||
return;
|
||||
}
|
||||
|
||||
PendingTask pending_task(Move(task), true);
|
||||
|
||||
if (delay_ms > 0) {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
class nsIEventTarget;
|
||||
|
||||
namespace base {
|
||||
|
||||
class TimeTicks;
|
||||
@@ -126,6 +128,12 @@ class MessagePump {
|
||||
// used on the thread that called Run.
|
||||
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
|
||||
|
||||
// If returned, just use the nsThread.
|
||||
virtual nsIEventTarget* GetXPCOMThread()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~MessagePump() {};
|
||||
};
|
||||
|
||||
@@ -516,22 +516,47 @@ bool Pickle::WriteBytes(const void* data, uint32_t data_len, uint32_t alignment)
|
||||
}
|
||||
|
||||
bool Pickle::WriteString(const std::string& value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
std::string v(value);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzString(v);
|
||||
if (!WriteInt(static_cast<int>(v.size())))
|
||||
return false;
|
||||
|
||||
return WriteBytes(v.data(), static_cast<int>(v.size()));
|
||||
#else
|
||||
if (!WriteInt(static_cast<int>(value.size())))
|
||||
return false;
|
||||
|
||||
return WriteBytes(value.data(), static_cast<int>(value.size()));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Pickle::WriteWString(const std::wstring& value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
std::wstring v(value);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzWString(v);
|
||||
if (!WriteInt(static_cast<int>(v.size())))
|
||||
return false;
|
||||
|
||||
return WriteBytes(v.data(),
|
||||
static_cast<int>(v.size() * sizeof(wchar_t)));
|
||||
#else
|
||||
if (!WriteInt(static_cast<int>(value.size())))
|
||||
return false;
|
||||
|
||||
return WriteBytes(value.data(),
|
||||
static_cast<int>(value.size() * sizeof(wchar_t)));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Pickle::WriteData(const char* data, uint32_t length) {
|
||||
return WriteInt(length) && WriteBytes(data, length);
|
||||
#ifdef MOZ_FAULTY
|
||||
std::string v(data, length);
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzData(v, v.size());
|
||||
return WriteInt(v.size()) && WriteBytes(v.data(), v.size());
|
||||
#else
|
||||
return WriteInt(length) && WriteBytes(data, length);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Pickle::InputBytes(const char* data, uint32_t length) {
|
||||
|
||||
@@ -17,6 +17,11 @@
|
||||
#include "mozilla/BufferList.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
|
||||
#ifdef MOZ_FAULTY
|
||||
#include "base/singleton.h"
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#endif
|
||||
|
||||
class Pickle;
|
||||
|
||||
class PickleIterator {
|
||||
@@ -118,45 +123,81 @@ class Pickle {
|
||||
// Pickle, it is important to read them in the order in which they were added
|
||||
// to the Pickle.
|
||||
bool WriteBool(bool value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzBool(&value);
|
||||
#endif
|
||||
return WriteInt(value ? 1 : 0);
|
||||
}
|
||||
bool WriteInt16(int16_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt16(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt16(uint16_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt16(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteInt(int value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteLong(long value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzLong(&value);
|
||||
#endif
|
||||
return WriteInt64(int64_t(value));
|
||||
}
|
||||
bool WriteULong(unsigned long value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzULong(&value);
|
||||
#endif
|
||||
return WriteUInt64(uint64_t(value));
|
||||
}
|
||||
bool WriteSize(size_t value) {
|
||||
// Always written as a 64-bit value since the size for this type can
|
||||
// differ between architectures.
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzSize(&value);
|
||||
#endif
|
||||
return WriteUInt64(uint64_t(value));
|
||||
}
|
||||
bool WriteInt32(int32_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt32(uint32_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt32(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteInt64(int64_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzInt64(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteUInt64(uint64_t value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUInt64(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteDouble(double value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzDouble(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteIntPtr(intptr_t value) {
|
||||
@@ -165,6 +206,9 @@ class Pickle {
|
||||
return WriteInt64(int64_t(value));
|
||||
}
|
||||
bool WriteUnsignedChar(unsigned char value) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->FuzzUChar(&value);
|
||||
#endif
|
||||
return WriteBytes(&value, sizeof(value));
|
||||
}
|
||||
bool WriteString(const std::string& value);
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
#include "nspr.h"
|
||||
#include "base/eintr_wrapper.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
void FreeEnvVarsArray(char* array[], int length)
|
||||
@@ -135,6 +141,8 @@ bool LaunchApp(const std::vector<std::string>& argv,
|
||||
if (!spawn_succeeded || !process_handle_valid) {
|
||||
retval = false;
|
||||
} else {
|
||||
gProcessLog.print("==> process %d launched child process %d\n",
|
||||
GetCurrentProcId(), pid);
|
||||
if (wait)
|
||||
HANDLE_EINTR(waitpid(pid, 0, 0));
|
||||
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
#include "base/string_util.h"
|
||||
#include "base/time.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace base {
|
||||
|
||||
void FreeEnvVarsArray(char* array[], int length)
|
||||
@@ -170,6 +176,8 @@ bool LaunchApp(const std::vector<std::string>& argv,
|
||||
if (!spawn_succeeded || !process_handle_valid) {
|
||||
retval = false;
|
||||
} else {
|
||||
gProcessLog.print("==> process %d launched child process %d\n",
|
||||
GetCurrentProcId(), pid);
|
||||
if (wait)
|
||||
HANDLE_EINTR(waitpid(pid, 0, 0));
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ class Channel : public Message::Sender {
|
||||
enum {
|
||||
// The maximum message size in bytes. Attempting to receive a
|
||||
// message of this size or bigger results in a channel error.
|
||||
kMaximumMessageSize = 128 * 1024 * 1024,
|
||||
kMaximumMessageSize = 256 * 1024 * 1024,
|
||||
|
||||
// Ammount of data to read at once from the pipe.
|
||||
kReadBufferSize = 4 * 1024,
|
||||
|
||||
@@ -35,6 +35,10 @@
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
#ifdef MOZ_FAULTY
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#endif
|
||||
|
||||
// Work around possible OS limitations.
|
||||
static const size_t kMaxIOVecSize = 256;
|
||||
|
||||
@@ -561,6 +565,9 @@ bool Channel::ChannelImpl::ProcessOutgoingMessages() {
|
||||
// Write out all the messages we can till the write blocks or there are no
|
||||
// more outgoing messages.
|
||||
while (!output_queue_.empty()) {
|
||||
#ifdef MOZ_FAULTY
|
||||
Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
|
||||
#endif
|
||||
Message* msg = output_queue_.front();
|
||||
|
||||
struct msghdr msgh = {0};
|
||||
|
||||
@@ -0,0 +1,654 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/ipc/Faulty.h"
|
||||
#include <cerrno>
|
||||
#include <prinrval.h>
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "base/string_util.h"
|
||||
#include "chrome/common/ipc_message.h"
|
||||
#include "chrome/common/ipc_channel.h"
|
||||
#include "prenv.h"
|
||||
#include "mozilla/TypeTraits.h"
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
const unsigned int Faulty::sDefaultProbability = Faulty::DefaultProbability();
|
||||
const bool Faulty::sIsLoggingEnabled = Faulty::Logging();
|
||||
|
||||
/**
|
||||
* RandomNumericValue generates negative and positive integrals.
|
||||
*/
|
||||
template <typename T>
|
||||
T RandomIntegral()
|
||||
{
|
||||
static_assert(mozilla::IsIntegral<T>::value == true,
|
||||
"T must be an integral type");
|
||||
double r = static_cast<double>(random() % ((sizeof(T) * CHAR_BIT) + 1));
|
||||
T x = static_cast<T>(pow(2.0, r)) - 1;
|
||||
if (std::numeric_limits<T>::is_signed && random() % 2 == 0) {
|
||||
return (x * -1) - 1;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* RandomNumericLimit returns either the min or max limit of an arithmetic
|
||||
* data type.
|
||||
*/
|
||||
template <typename T>
|
||||
T RandomNumericLimit() {
|
||||
static_assert(mozilla::IsArithmetic<T>::value == true,
|
||||
"T must be an arithmetic type");
|
||||
return random() % 2 == 0 ? std::numeric_limits<T>::min()
|
||||
: std::numeric_limits<T>::max();
|
||||
}
|
||||
|
||||
/**
|
||||
* RandomIntegerRange returns a random integral within a user defined range.
|
||||
*/
|
||||
template <typename T>
|
||||
T RandomIntegerRange(T min, T max)
|
||||
{
|
||||
static_assert(mozilla::IsIntegral<T>::value == true,
|
||||
"T must be an integral type");
|
||||
MOZ_ASSERT(min < max);
|
||||
return static_cast<T>(random() % (max - min) + min);
|
||||
}
|
||||
|
||||
/**
|
||||
* RandomFloatingPointRange returns a random floating-point number within a
|
||||
* user defined range.
|
||||
*/
|
||||
template <typename T>
|
||||
T RandomFloatingPointRange(T min, T max)
|
||||
{
|
||||
static_assert(mozilla::IsFloatingPoint<T>::value == true,
|
||||
"T must be a floating point type");
|
||||
MOZ_ASSERT(min < max);
|
||||
T x = static_cast<T>(random()) / static_cast<T>(RAND_MAX);
|
||||
return min + x * (max - min);
|
||||
}
|
||||
|
||||
/**
|
||||
* RandomFloatingPoint returns a random floating-point number.
|
||||
*/
|
||||
template <typename T>
|
||||
T RandomFloatingPoint()
|
||||
{
|
||||
static_assert(mozilla::IsFloatingPoint<T>::value == true,
|
||||
"T must be a floating point type");
|
||||
int radix = RandomIntegerRange<int>(std::numeric_limits<T>::min_exponent,
|
||||
std::numeric_limits<T>::max_exponent);
|
||||
T x = static_cast<T>(pow(2.0, static_cast<double>(radix)));
|
||||
return x * RandomFloatingPointRange<T>(1.0, 2.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* FuzzIntegralType mutates an incercepted integral type of a pickled message.
|
||||
*/
|
||||
template <typename T>
|
||||
void FuzzIntegralType(T* v, bool largeValues)
|
||||
{
|
||||
static_assert(mozilla::IsIntegral<T>::value == true,
|
||||
"T must be an integral type");
|
||||
switch (random() % 6) {
|
||||
case 0:
|
||||
if (largeValues) {
|
||||
(*v) = RandomIntegral<T>();
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case 1:
|
||||
if (largeValues) {
|
||||
(*v) = RandomNumericLimit<T>();
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case 2:
|
||||
if (largeValues) {
|
||||
(*v) = RandomIntegerRange<T>(std::numeric_limits<T>::min(),
|
||||
std::numeric_limits<T>::max());
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
switch(random() % 2) {
|
||||
case 0:
|
||||
// Prevent underflow
|
||||
if (*v != std::numeric_limits<T>::min()) {
|
||||
(*v)--;
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case 1:
|
||||
// Prevent overflow
|
||||
if (*v != std::numeric_limits<T>::max()) {
|
||||
(*v)++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FuzzFloatingPointType mutates an incercepted floating-point type of a
|
||||
* pickled message.
|
||||
*/
|
||||
template <typename T>
|
||||
void FuzzFloatingPointType(T* v, bool largeValues)
|
||||
{
|
||||
static_assert(mozilla::IsFloatingPoint<T>::value == true,
|
||||
"T must be a floating point type");
|
||||
switch (random() % 6) {
|
||||
case 0:
|
||||
if (largeValues) {
|
||||
(*v) = RandomNumericLimit<T>();
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
case 1:
|
||||
if (largeValues) {
|
||||
(*v) = RandomFloatingPointRange<T>(std::numeric_limits<T>::min(),
|
||||
std::numeric_limits<T>::max());
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
(*v) = RandomFloatingPoint<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FuzzStringType mutates an incercepted string type of a pickled message.
|
||||
*/
|
||||
template <typename T>
|
||||
void FuzzStringType(T& v, const T& literal1, const T& literal2)
|
||||
{
|
||||
switch (random() % 5) {
|
||||
case 4:
|
||||
v = v + v;
|
||||
// Fall through
|
||||
case 3:
|
||||
v = v + v;
|
||||
// Fall through
|
||||
case 2:
|
||||
v = v + v;
|
||||
break;
|
||||
case 1:
|
||||
v += literal1;
|
||||
break;
|
||||
case 0:
|
||||
v = literal2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Faulty::Faulty()
|
||||
// Enables the strategy for fuzzing pipes.
|
||||
: mFuzzPipes(!!PR_GetEnv("FAULTY_PIPE"))
|
||||
// Enables the strategy for fuzzing pickled messages.
|
||||
, mFuzzPickle(!!PR_GetEnv("FAULTY_PICKLE"))
|
||||
// Uses very large values while fuzzing pickled messages.
|
||||
// This may cause a high amount of malloc_abort() / NS_ABORT_OOM crashes.
|
||||
, mUseLargeValues(!!PR_GetEnv("FAULTY_LARGE_VALUES"))
|
||||
// Sets up our target process.
|
||||
, mIsValidProcessType(IsValidProcessType())
|
||||
{
|
||||
FAULTY_LOG("Initializing.");
|
||||
|
||||
const char* userSeed = PR_GetEnv("FAULTY_SEED");
|
||||
unsigned long randomSeed = static_cast<unsigned long>(PR_IntervalNow());
|
||||
if (userSeed) {
|
||||
long n = std::strtol(userSeed, nullptr, 10);
|
||||
if (n != 0) {
|
||||
randomSeed = static_cast<unsigned long>(n);
|
||||
}
|
||||
}
|
||||
srandom(randomSeed);
|
||||
|
||||
FAULTY_LOG("Fuzz probability = %u", sDefaultProbability);
|
||||
FAULTY_LOG("Random seed = %lu", randomSeed);
|
||||
FAULTY_LOG("Strategy: pickle = %s", mFuzzPickle ? "enabled" : "disabled");
|
||||
FAULTY_LOG("Strategy: pipe = %s", mFuzzPipes ? "enabled" : "disabled");
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Faulty::IsValidProcessType(void)
|
||||
{
|
||||
bool isValidProcessType;
|
||||
const bool targetChildren = !!PR_GetEnv("FAULTY_CHILDREN");
|
||||
const bool targetParent = !!PR_GetEnv("FAULTY_PARENT");
|
||||
|
||||
if (targetChildren && !targetParent) {
|
||||
// Fuzz every process type but not the content process.
|
||||
isValidProcessType = XRE_GetProcessType() != GeckoProcessType_Content;
|
||||
} else if (targetChildren && targetParent) {
|
||||
// Fuzz every process type.
|
||||
isValidProcessType = true;
|
||||
} else {
|
||||
// Fuzz the content process only.
|
||||
isValidProcessType = XRE_GetProcessType() == GeckoProcessType_Content;
|
||||
}
|
||||
|
||||
// Parent and children are different threads in the same process on
|
||||
// desktop builds.
|
||||
if (!isValidProcessType) {
|
||||
FAULTY_LOG("Invalid process type for pid=%d", getpid());
|
||||
}
|
||||
|
||||
return isValidProcessType;
|
||||
}
|
||||
|
||||
// static
|
||||
unsigned int
|
||||
Faulty::DefaultProbability(void)
|
||||
{
|
||||
// Defines the likelihood of fuzzing a message.
|
||||
const char* probability = PR_GetEnv("FAULTY_PROBABILITY");
|
||||
if (probability) {
|
||||
long n = std::strtol(probability, nullptr, 10);
|
||||
if (n != 0) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
return FAULTY_DEFAULT_PROBABILITY;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
Faulty::Logging(void)
|
||||
{
|
||||
// Enables logging of sendmsg() calls even in optimized builds.
|
||||
return !!PR_GetEnv("FAULTY_ENABLE_LOGGING");
|
||||
}
|
||||
|
||||
unsigned int
|
||||
Faulty::Random(unsigned int aMax)
|
||||
{
|
||||
MOZ_ASSERT(aMax > 0);
|
||||
return static_cast<unsigned int>(random() % aMax);
|
||||
}
|
||||
|
||||
bool
|
||||
Faulty::GetChance(unsigned int aProbability)
|
||||
{
|
||||
return Random(aProbability) == 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Strategy: Pipes
|
||||
//
|
||||
|
||||
void
|
||||
Faulty::MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability)
|
||||
{
|
||||
if (!mFuzzPipes) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aPipe > -1) {
|
||||
FAULTY_LOG("collecting pipe %d to bucket of pipes (count: %ld)",
|
||||
aPipe, mFds.size());
|
||||
mFds.insert(aPipe);
|
||||
}
|
||||
|
||||
if (mFds.size() > 0 && GetChance(aProbability)) {
|
||||
std::set<int>::iterator it(mFds.begin());
|
||||
std::advance(it, Random(mFds.size()));
|
||||
FAULTY_LOG("trying to close collected pipe: %d", *it);
|
||||
errno = 0;
|
||||
while ((close(*it) == -1 && (errno == EINTR))) {
|
||||
;
|
||||
}
|
||||
FAULTY_LOG("pipe status after attempt to close: %d", errno);
|
||||
mFds.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Strategy: Pickle
|
||||
//
|
||||
|
||||
void
|
||||
Faulty::MutateBool(bool* aValue)
|
||||
{
|
||||
*aValue = !(*aValue);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzBool(bool* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
bool oldValue = *aValue;
|
||||
MutateBool(aValue);
|
||||
FAULTY_LOG("pickle field {bool} of value: %d changed to: %d",
|
||||
(int)oldValue, (int)*aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateChar(char* aValue)
|
||||
{
|
||||
FuzzIntegralType<char>(aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzChar(char* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
char oldValue = *aValue;
|
||||
MutateChar(aValue);
|
||||
FAULTY_LOG("pickle field {char} of value: %c changed to: %c",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateUChar(unsigned char* aValue)
|
||||
{
|
||||
FuzzIntegralType<unsigned char>(aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzUChar(unsigned char* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
unsigned char oldValue = *aValue;
|
||||
MutateUChar(aValue);
|
||||
FAULTY_LOG("pickle field {unsigned char} of value: %u changed to: %u",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateInt16(int16_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<int16_t>(aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzInt16(int16_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
int16_t oldValue = *aValue;
|
||||
MutateInt16(aValue);
|
||||
FAULTY_LOG("pickle field {Int16} of value: %d changed to: %d",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateUInt16(uint16_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<uint16_t>(aValue, true);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzUInt16(uint16_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
uint16_t oldValue = *aValue;
|
||||
MutateUInt16(aValue);
|
||||
FAULTY_LOG("pickle field {UInt16} of value: %d changed to: %d",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateInt(int* aValue)
|
||||
{
|
||||
FuzzIntegralType<int>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzInt(int* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
int oldValue = *aValue;
|
||||
MutateInt(aValue);
|
||||
FAULTY_LOG("pickle field {int} of value: %d changed to: %d",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateUInt32(uint32_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<uint32_t>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzUInt32(uint32_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
uint32_t oldValue = *aValue;
|
||||
MutateUInt32(aValue);
|
||||
FAULTY_LOG("pickle field {UInt32} of value: %u changed to: %u",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateLong(long* aValue)
|
||||
{
|
||||
FuzzIntegralType<long>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzLong(long* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
long oldValue = *aValue;
|
||||
MutateLong(aValue);
|
||||
FAULTY_LOG("pickle field {long} of value: %ld changed to: %ld",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateULong(unsigned long* aValue)
|
||||
{
|
||||
FuzzIntegralType<unsigned long>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzULong(unsigned long* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
unsigned long oldValue = *aValue;
|
||||
MutateULong(aValue);
|
||||
FAULTY_LOG("pickle field {unsigned long} of value: %lu changed to: %lu",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateSize(size_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<size_t>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzSize(size_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
size_t oldValue = *aValue;
|
||||
MutateSize(aValue);
|
||||
FAULTY_LOG("pickle field {size_t} of value: %zu changed to: %zu",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateUInt64(uint64_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<uint64_t>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzUInt64(uint64_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
uint64_t oldValue = *aValue;
|
||||
MutateUInt64(aValue);
|
||||
FAULTY_LOG("pickle field {UInt64} of value: %llu changed to: %llu",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateInt64(int64_t* aValue)
|
||||
{
|
||||
FuzzIntegralType<int64_t>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzInt64(int64_t* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
int64_t oldValue = *aValue;
|
||||
MutateInt64(aValue);
|
||||
FAULTY_LOG("pickle field {Int64} of value: %lld changed to: %lld",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateDouble(double* aValue)
|
||||
{
|
||||
FuzzFloatingPointType<double>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzDouble(double* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
double oldValue = *aValue;
|
||||
MutateDouble(aValue);
|
||||
FAULTY_LOG("pickle field {double} of value: %f changed to: %f",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::MutateFloat(float* aValue)
|
||||
{
|
||||
FuzzFloatingPointType<float>(aValue, mUseLargeValues);
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzFloat(float* aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
float oldValue = *aValue;
|
||||
MutateFloat(aValue);
|
||||
FAULTY_LOG("pickle field {float} of value: %f changed to: %f",
|
||||
oldValue, *aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzString(std::string& aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
std::string oldValue = aValue;
|
||||
FuzzStringType<std::string>(aValue, "xoferiF", std::string());
|
||||
FAULTY_LOG("pickle field {string} of value: %s changed to: %s",
|
||||
oldValue.c_str(), aValue.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzWString(std::wstring& aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
std::wstring oldValue = aValue;
|
||||
FAULTY_LOG("pickle field {wstring}");
|
||||
FuzzStringType<std::wstring>(aValue, L"xoferiF", std::wstring());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzString16(string16& aValue, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
string16 oldValue = aValue;
|
||||
FAULTY_LOG("pickle field {string16}");
|
||||
FuzzStringType<string16>(aValue,
|
||||
string16(ASCIIToUTF16(std::string("xoferiF"))),
|
||||
string16(ASCIIToUTF16(std::string())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzBytes(void* aData, int aLength, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
FAULTY_LOG("pickle field {bytes}");
|
||||
// Too destructive. |WriteBytes| is used in many of the above data
|
||||
// types as base function.
|
||||
//FuzzData(static_cast<char*>(aData), aLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Faulty::FuzzData(std::string& aValue, int aLength, unsigned int aProbability)
|
||||
{
|
||||
if (mIsValidProcessType) {
|
||||
if (mFuzzPickle && GetChance(aProbability)) {
|
||||
FAULTY_LOG("pickle field {data}");
|
||||
for (int i = 0; i < aLength; ++i) {
|
||||
if (GetChance(aProbability)) {
|
||||
FuzzIntegralType<char>(&aValue[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
@@ -0,0 +1,100 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_ipc_Faulty_h
|
||||
#define mozilla_ipc_Faulty_h
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include "nsDebug.h"
|
||||
#include "base/string16.h"
|
||||
#include "base/singleton.h"
|
||||
|
||||
#define FAULTY_DEFAULT_PROBABILITY 1000
|
||||
#define FAULTY_LOG(fmt, args...) \
|
||||
if (mozilla::ipc::Faulty::IsLoggingEnabled()) { \
|
||||
printf_stderr("[Faulty] " fmt "\n", ## args); \
|
||||
}
|
||||
|
||||
namespace IPC {
|
||||
// Needed for blacklisting messages.
|
||||
class Message;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class Faulty
|
||||
{
|
||||
public:
|
||||
// Used as a default argument for the Fuzz|datatype| methods.
|
||||
static const unsigned int sDefaultProbability;
|
||||
|
||||
static unsigned int DefaultProbability(void);
|
||||
static bool Logging(void);
|
||||
static bool IsLoggingEnabled(void) { return sIsLoggingEnabled; }
|
||||
|
||||
void FuzzBool(bool* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzChar(char* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzUChar(unsigned char* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzInt16(int16_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzUInt16(uint16_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzInt(int* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzUInt32(uint32_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzLong(long* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzULong(unsigned long* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzInt64(int64_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzUInt64(uint64_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzSize(size_t* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzFloat(float* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzDouble(double* aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzString(std::string& aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzWString(std::wstring& aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzString16(string16& aValue, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzData(std::string& aData, int aLength, unsigned int aProbability=sDefaultProbability);
|
||||
void FuzzBytes(void* aData, int aLength, unsigned int aProbability=sDefaultProbability);
|
||||
|
||||
void MaybeCollectAndClosePipe(int aPipe, unsigned int aProbability=sDefaultProbability);
|
||||
|
||||
private:
|
||||
std::set<int> mFds;
|
||||
|
||||
const bool mFuzzPipes;
|
||||
const bool mFuzzPickle;
|
||||
const bool mUseLargeValues;
|
||||
const bool mIsValidProcessType;
|
||||
|
||||
static const bool sIsLoggingEnabled;
|
||||
|
||||
Faulty();
|
||||
friend struct DefaultSingletonTraits<Faulty>;
|
||||
DISALLOW_EVIL_CONSTRUCTORS(Faulty);
|
||||
|
||||
static bool IsValidProcessType(void);
|
||||
|
||||
unsigned int Random(unsigned int aMax);
|
||||
bool GetChance(unsigned int aProbability);
|
||||
|
||||
void MutateBool(bool* aValue);
|
||||
void MutateChar(char* aValue);
|
||||
void MutateUChar(unsigned char* aValue);
|
||||
void MutateInt16(int16_t* aValue);
|
||||
void MutateUInt16(uint16_t* aValue);
|
||||
void MutateInt(int* aValue);
|
||||
void MutateUInt32(uint32_t* aValue);
|
||||
void MutateLong(long* aValue);
|
||||
void MutateULong(unsigned long* aValue);
|
||||
void MutateInt64(int64_t* aValue);
|
||||
void MutateUInt64(uint64_t* aValue);
|
||||
void MutateSize(size_t* aValue);
|
||||
void MutateFloat(float* aValue);
|
||||
void MutateDouble(double* aValue);
|
||||
};
|
||||
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -485,14 +485,20 @@ class MessageChannel : HasResultCodes
|
||||
|
||||
// Wrap an existing task which can be cancelled at any time
|
||||
// without the wrapper's knowledge.
|
||||
class DequeueTask : public Runnable
|
||||
class DequeueTask : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
explicit DequeueTask(RefCountedTask* aTask)
|
||||
: mTask(aTask)
|
||||
{ }
|
||||
NS_IMETHOD Run() override {
|
||||
mTask->Run();
|
||||
if (mTask) {
|
||||
mTask->Run();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
nsresult Cancel() override {
|
||||
mTask = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -200,6 +200,18 @@ MessagePump::ScheduleDelayedWork(const base::TimeTicks& aDelayedTime)
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
nsIEventTarget*
|
||||
MessagePump::GetXPCOMThread()
|
||||
{
|
||||
if (mThread) {
|
||||
return mThread;
|
||||
}
|
||||
|
||||
// Main thread
|
||||
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
|
||||
return mainThread;
|
||||
}
|
||||
|
||||
void
|
||||
MessagePump::DoDelayedWork(base::MessagePump::Delegate* aDelegate)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,9 @@ public:
|
||||
virtual void
|
||||
ScheduleDelayedWork(const base::TimeTicks& aDelayedWorkTime) override;
|
||||
|
||||
virtual nsIEventTarget*
|
||||
GetXPCOMThread() override;
|
||||
|
||||
protected:
|
||||
virtual ~MessagePump();
|
||||
|
||||
@@ -128,6 +131,12 @@ public:
|
||||
// The main run loop for this thread.
|
||||
virtual void DoRunLoop() override;
|
||||
|
||||
virtual nsIEventTarget*
|
||||
GetXPCOMThread() override
|
||||
{
|
||||
return nullptr; // not sure what to do with this one
|
||||
}
|
||||
|
||||
protected:
|
||||
void SetInWait() {
|
||||
MutexAutoLock lock(mWaitLock);
|
||||
|
||||
@@ -37,6 +37,10 @@ EXPORTS.mozilla.ipc += [
|
||||
'WindowsMessageLoop.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_FAULTY'] == '1':
|
||||
EXPORTS.mozilla.ipc += ['Faulty.h']
|
||||
SOURCES += ['Faulty.cpp']
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['WEBRTC_WIN'] = True
|
||||
EXPORTS.mozilla.ipc += [
|
||||
|
||||
+14
-1
@@ -704,6 +704,11 @@ class HashMapEntry
|
||||
value_(mozilla::Move(rhs.value_))
|
||||
{}
|
||||
|
||||
void operator=(HashMapEntry&& rhs) {
|
||||
key_ = mozilla::Move(rhs.key_);
|
||||
value_ = mozilla::Move(rhs.value_);
|
||||
}
|
||||
|
||||
typedef Key KeyType;
|
||||
typedef Value ValueType;
|
||||
|
||||
@@ -774,8 +779,16 @@ class HashTableEntry
|
||||
}
|
||||
|
||||
void swap(HashTableEntry* other) {
|
||||
if (this == other)
|
||||
return;
|
||||
MOZ_ASSERT(isLive());
|
||||
if (other->isLive()) {
|
||||
mozilla::Swap(*mem.addr(), *other->mem.addr());
|
||||
} else {
|
||||
*other->mem.addr() = mozilla::Move(*mem.addr());
|
||||
destroy();
|
||||
}
|
||||
mozilla::Swap(keyHash, other->keyHash);
|
||||
mozilla::Swap(mem, other->mem);
|
||||
}
|
||||
|
||||
T& get() { MOZ_ASSERT(isLive()); return *mem.addr(); }
|
||||
|
||||
@@ -403,6 +403,10 @@ struct CacheIRStubKey : public DefaultHasher<CacheIRStubKey> {
|
||||
|
||||
explicit CacheIRStubKey(CacheIRStubInfo* info) : stubInfo(info) {}
|
||||
CacheIRStubKey(CacheIRStubKey&& other) : stubInfo(Move(other.stubInfo)) { }
|
||||
|
||||
void operator=(CacheIRStubKey&& other) {
|
||||
stubInfo = Move(other.stubInfo);
|
||||
}
|
||||
};
|
||||
|
||||
class JitCompartment
|
||||
|
||||
+15
-35
@@ -7,7 +7,6 @@
|
||||
#ifndef jit_RegisterSets_h
|
||||
#define jit_RegisterSets_h
|
||||
|
||||
#include "mozilla/Alignment.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include "jit/JitAllocPolicy.h"
|
||||
@@ -26,8 +25,8 @@ struct AnyRegister {
|
||||
Code code_;
|
||||
|
||||
public:
|
||||
AnyRegister()
|
||||
{ }
|
||||
AnyRegister() = default;
|
||||
|
||||
explicit AnyRegister(Register gpr) {
|
||||
code_ = gpr.code();
|
||||
}
|
||||
@@ -169,46 +168,25 @@ class TypedOrValueRegister
|
||||
// Type of value being stored.
|
||||
MIRType type_;
|
||||
|
||||
// Space to hold either an AnyRegister or a ValueOperand.
|
||||
union U {
|
||||
mozilla::AlignedStorage2<AnyRegister> typed;
|
||||
mozilla::AlignedStorage2<ValueOperand> value;
|
||||
AnyRegister typed;
|
||||
ValueOperand value;
|
||||
} data;
|
||||
|
||||
AnyRegister& dataTyped() {
|
||||
MOZ_ASSERT(hasTyped());
|
||||
return *data.typed.addr();
|
||||
}
|
||||
ValueOperand& dataValue() {
|
||||
MOZ_ASSERT(hasValue());
|
||||
return *data.value.addr();
|
||||
}
|
||||
|
||||
AnyRegister dataTyped() const {
|
||||
MOZ_ASSERT(hasTyped());
|
||||
return *data.typed.addr();
|
||||
}
|
||||
const ValueOperand& dataValue() const {
|
||||
MOZ_ASSERT(hasValue());
|
||||
return *data.value.addr();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
TypedOrValueRegister()
|
||||
: type_(MIRType::None)
|
||||
{}
|
||||
TypedOrValueRegister() = default;
|
||||
|
||||
TypedOrValueRegister(MIRType type, AnyRegister reg)
|
||||
: type_(type)
|
||||
{
|
||||
dataTyped() = reg;
|
||||
data.typed = reg;
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT TypedOrValueRegister(ValueOperand value)
|
||||
: type_(MIRType::Value)
|
||||
{
|
||||
dataValue() = value;
|
||||
data.value = value;
|
||||
}
|
||||
|
||||
MIRType type() const {
|
||||
@@ -224,11 +202,13 @@ class TypedOrValueRegister
|
||||
}
|
||||
|
||||
AnyRegister typedReg() const {
|
||||
return dataTyped();
|
||||
MOZ_ASSERT(hasTyped());
|
||||
return data.typed;
|
||||
}
|
||||
|
||||
ValueOperand valueReg() const {
|
||||
return dataValue();
|
||||
MOZ_ASSERT(hasValue());
|
||||
return data.value;
|
||||
}
|
||||
|
||||
AnyRegister scratchReg() {
|
||||
@@ -246,17 +226,17 @@ class ConstantOrRegister
|
||||
|
||||
// Space to hold either a Value or a TypedOrValueRegister.
|
||||
union U {
|
||||
mozilla::AlignedStorage2<Value> constant;
|
||||
mozilla::AlignedStorage2<TypedOrValueRegister> reg;
|
||||
Value constant;
|
||||
TypedOrValueRegister reg;
|
||||
} data;
|
||||
|
||||
Value& dataValue() {
|
||||
MOZ_ASSERT(constant());
|
||||
return *data.constant.addr();
|
||||
return data.constant;
|
||||
}
|
||||
TypedOrValueRegister& dataReg() {
|
||||
MOZ_ASSERT(!constant());
|
||||
return *data.reg.addr();
|
||||
return data.reg;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
+19
-1
@@ -504,7 +504,25 @@ class SnapshotReader
|
||||
}
|
||||
};
|
||||
|
||||
typedef mozilla::AlignedStorage<4 * sizeof(uint32_t)> RInstructionStorage;
|
||||
class RInstructionStorage
|
||||
{
|
||||
static const size_t Size = 4 * sizeof(uint32_t);
|
||||
mozilla::AlignedStorage<Size> mem;
|
||||
|
||||
public:
|
||||
const void* addr() const { return mem.addr(); }
|
||||
void* addr() { return mem.addr(); }
|
||||
|
||||
RInstructionStorage() = default;
|
||||
|
||||
RInstructionStorage(const RInstructionStorage& other) {
|
||||
memcpy(addr(), other.addr(), Size);
|
||||
}
|
||||
void operator=(const RInstructionStorage& other) {
|
||||
memcpy(addr(), other.addr(), Size);
|
||||
}
|
||||
};
|
||||
|
||||
class RInstruction;
|
||||
|
||||
class RecoverReader
|
||||
|
||||
@@ -1342,6 +1342,13 @@ struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<Allocati
|
||||
MOZ_ASSERT(offset_ < OFFSET_LIMIT);
|
||||
}
|
||||
|
||||
AllocationSiteKey(const AllocationSiteKey& key)
|
||||
: script(key.script),
|
||||
offset(key.offset),
|
||||
kind(key.kind),
|
||||
proto(key.proto)
|
||||
{ }
|
||||
|
||||
AllocationSiteKey(AllocationSiteKey&& key)
|
||||
: script(mozilla::Move(key.script)),
|
||||
offset(key.offset),
|
||||
@@ -1349,12 +1356,12 @@ struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher<Allocati
|
||||
proto(mozilla::Move(key.proto))
|
||||
{ }
|
||||
|
||||
AllocationSiteKey(const AllocationSiteKey& key)
|
||||
: script(key.script),
|
||||
offset(key.offset),
|
||||
kind(key.kind),
|
||||
proto(key.proto)
|
||||
{ }
|
||||
void operator=(AllocationSiteKey&& key) {
|
||||
script = mozilla::Move(key.script);
|
||||
offset = key.offset;
|
||||
kind = key.kind;
|
||||
proto = mozilla::Move(key.proto);
|
||||
}
|
||||
|
||||
static inline uint32_t hash(AllocationSiteKey key) {
|
||||
return uint32_t(size_t(key.script->offsetToPC(key.offset)) ^ key.kind ^
|
||||
|
||||
@@ -120,6 +120,15 @@ struct AlignedStorage
|
||||
|
||||
const void* addr() const { return u.mBytes; }
|
||||
void* addr() { return u.mBytes; }
|
||||
|
||||
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
AlignedStorage() = default;
|
||||
|
||||
// AlignedStorage is non-copyable: the default copy constructor violates
|
||||
// strict aliasing rules, per bug 1269319.
|
||||
AlignedStorage(const AlignedStorage&) = delete;
|
||||
void operator=(const AlignedStorage&) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
@@ -133,6 +142,15 @@ struct MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS AlignedStorage2
|
||||
|
||||
const T* addr() const { return reinterpret_cast<const T*>(u.mBytes); }
|
||||
T* addr() { return static_cast<T*>(static_cast<void*>(u.mBytes)); }
|
||||
|
||||
#if !defined(_MSC_VER) || (defined(_MSC_VER) && _MSC_VER >= 1900)
|
||||
AlignedStorage2() = default;
|
||||
|
||||
// AlignedStorage2 is non-copyable: the default copy constructor violates
|
||||
// strict aliasing rules, per bug 1269319.
|
||||
AlignedStorage2(const AlignedStorage2&) = delete;
|
||||
void operator=(const AlignedStorage2&) = delete;
|
||||
#endif
|
||||
};
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool checkSimulatedOOM() const
|
||||
MOZ_MUST_USE bool checkSimulatedOOM() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
+5
-5
@@ -61,8 +61,7 @@ public:
|
||||
|
||||
/**
|
||||
* If the source stream is malformed, the function will stop decoding
|
||||
* and return a negative result, indicating the byte position of the
|
||||
* faulty instruction
|
||||
* and return false.
|
||||
*
|
||||
* This function never writes outside of provided buffers, and never
|
||||
* modifies input buffer.
|
||||
@@ -71,9 +70,9 @@ public:
|
||||
* minimum of |aOutputSize| bytes.
|
||||
*
|
||||
* @param aOutputSize is the output size, therefore the original size
|
||||
* @return the number of bytes read in the source buffer
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
static MFBT_API bool
|
||||
static MFBT_API MOZ_MUST_USE bool
|
||||
decompress(const char* aSource, char* aDest, size_t aOutputSize);
|
||||
|
||||
/**
|
||||
@@ -91,8 +90,9 @@ public:
|
||||
* already allocated)
|
||||
* @param aOutputSize the actual number of bytes decoded in the destination
|
||||
* buffer (necessarily <= aMaxOutputSize)
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
static MFBT_API bool
|
||||
static MFBT_API MOZ_MUST_USE bool
|
||||
decompress(const char* aSource, size_t aInputSize, char* aDest,
|
||||
size_t aMaxOutputSize, size_t* aOutputSize);
|
||||
|
||||
|
||||
+7
-6
@@ -76,19 +76,19 @@ public:
|
||||
return Comparator::compare(aValue, *last) == 0 ? last : nullptr;
|
||||
}
|
||||
|
||||
bool insert(T* aValue)
|
||||
void insert(T* aValue)
|
||||
{
|
||||
MOZ_ASSERT(!find(*aValue), "Duplicate elements are not allowed.");
|
||||
|
||||
if (!mRoot) {
|
||||
mRoot = aValue;
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
T* last = lookup(*aValue);
|
||||
int cmp = Comparator::compare(*aValue, *last);
|
||||
|
||||
finishInsertion(last, cmp, aValue);
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
T* findOrInsert(const T& aValue);
|
||||
@@ -194,7 +194,7 @@ private:
|
||||
return parent;
|
||||
}
|
||||
|
||||
T* finishInsertion(T* aLast, int32_t aCmp, T* aNew)
|
||||
void finishInsertion(T* aLast, int32_t aCmp, T* aNew)
|
||||
{
|
||||
MOZ_ASSERT(aCmp, "Nodes shouldn't be equal!");
|
||||
|
||||
@@ -204,7 +204,6 @@ private:
|
||||
aNew->mParent = aLast;
|
||||
|
||||
splay(aNew);
|
||||
return aNew;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +320,9 @@ SplayTree<T, Comparator>::findOrInsert(const T& aValue)
|
||||
return last;
|
||||
}
|
||||
|
||||
return finishInsertion(last, cmp, new T(aValue));
|
||||
T* t = new T(aValue);
|
||||
finishInsertion(last, cmp, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
} /* namespace mozilla */
|
||||
|
||||
+2
-2
@@ -128,7 +128,7 @@ struct VectorImpl
|
||||
* aNewCap has not overflowed, and (2) multiplying aNewCap by sizeof(T) will
|
||||
* not overflow.
|
||||
*/
|
||||
static inline bool
|
||||
static inline MOZ_MUST_USE bool
|
||||
growTo(Vector<T, N, AP>& aV, size_t aNewCap)
|
||||
{
|
||||
MOZ_ASSERT(!aV.usingInlineStorage());
|
||||
@@ -215,7 +215,7 @@ struct VectorImpl<T, N, AP, true>
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
static inline MOZ_MUST_USE bool
|
||||
growTo(Vector<T, N, AP>& aV, size_t aNewCap)
|
||||
{
|
||||
MOZ_ASSERT(!aV.usingInlineStorage());
|
||||
|
||||
@@ -173,6 +173,12 @@ nsSocketTransportService::Dispatch(already_AddRefed<nsIRunnable>&& event, uint32
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::IsOnCurrentThread(bool *result)
|
||||
{
|
||||
|
||||
@@ -526,6 +526,12 @@ nsStreamTransportService::Dispatch(already_AddRefed<nsIRunnable>&& task, uint32_
|
||||
return pool->Dispatch(event.forget(), flags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStreamTransportService::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsStreamTransportService::IsOnCurrentThread(bool *result)
|
||||
{
|
||||
|
||||
@@ -430,6 +430,12 @@ LazyIdleThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
return mThread->Dispatch(event.forget(), aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LazyIdleThread::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LazyIdleThread::IsOnCurrentThread(bool* aIsOnCurrentThread)
|
||||
{
|
||||
|
||||
@@ -67,6 +67,9 @@ public:
|
||||
NS_IMETHOD Dispatch(already_AddRefed<nsIRunnable>&& event, uint32_t flags) override
|
||||
{ return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->Dispatch(Move(event), flags); }
|
||||
|
||||
NS_IMETHOD DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t) override
|
||||
{ return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
|
||||
using nsIEventTarget::Dispatch;
|
||||
|
||||
NS_IMETHOD IsOnCurrentThread(bool *_retval) override { return !mEventTarget ? NS_ERROR_NULL_POINTER : mEventTarget->IsOnCurrentThread(_retval); }
|
||||
|
||||
@@ -97,6 +97,26 @@ interface nsIEventTarget : nsISupports
|
||||
* events, so this event would never run and has not been dispatched.
|
||||
*/
|
||||
[binaryname(DispatchFromScript)] void dispatch(in nsIRunnable event, in unsigned long flags);
|
||||
/**
|
||||
* Dispatch an event to this event target, but do not run it before delay
|
||||
* milliseconds have passed. This function may be called from any thread.
|
||||
*
|
||||
* @param event
|
||||
* The alreadyAddrefed<> event to dispatch.
|
||||
* @param delay
|
||||
* The delay (in ms) before running the event. If event does not rise to
|
||||
* the top of the event queue before the delay has passed, it will be set
|
||||
* aside to execute once the delay has passed. Otherwise, it will be
|
||||
* executed immediately.
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG
|
||||
* Indicates that event is null.
|
||||
* @throws NS_ERROR_UNEXPECTED
|
||||
* Indicates that the thread is shutting down and has finished processing
|
||||
* events, so this event would never run and has not been dispatched, or
|
||||
* that delay is zero.
|
||||
*/
|
||||
[noscript] void delayedDispatch(in alreadyAddRefed_nsIRunnable event, in unsigned long delay);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
||||
@@ -230,6 +230,75 @@ private:
|
||||
ReentrantMonitor mMon;
|
||||
bool mInitialized;
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
namespace {
|
||||
class DelayedRunnable : public Runnable,
|
||||
public nsITimerCallback
|
||||
{
|
||||
public:
|
||||
DelayedRunnable(already_AddRefed<nsIRunnable> aRunnable,
|
||||
uint32_t aDelay)
|
||||
: mWrappedRunnable(aRunnable),
|
||||
mDelayedFrom(TimeStamp::NowLoRes()),
|
||||
mDelay(aDelay)
|
||||
{ }
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
nsresult Init()
|
||||
{
|
||||
nsresult rv;
|
||||
mTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
MOZ_ASSERT(mTimer);
|
||||
return mTimer->InitWithCallback(this, mDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
nsresult DoRun()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = mWrappedRunnable.forget();
|
||||
return r->Run();
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
// Already ran?
|
||||
if (!mWrappedRunnable) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Are we too early?
|
||||
if ((TimeStamp::NowLoRes() - mDelayedFrom).ToMilliseconds() < mDelay) {
|
||||
return NS_OK; // Let the nsITimer run us.
|
||||
}
|
||||
|
||||
mTimer->Cancel();
|
||||
return DoRun();
|
||||
}
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) override
|
||||
{
|
||||
// If we already ran, the timer should have been canceled.
|
||||
MOZ_ASSERT(mWrappedRunnable);
|
||||
MOZ_ASSERT(aTimer == mTimer);
|
||||
|
||||
return DoRun();
|
||||
}
|
||||
|
||||
private:
|
||||
~DelayedRunnable() {}
|
||||
|
||||
nsCOMPtr<nsIRunnable> mWrappedRunnable;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
TimeStamp mDelayedFrom;
|
||||
uint32_t mDelay;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(DelayedRunnable, Runnable, nsITimerCallback)
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -668,6 +737,18 @@ nsThread::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
return DispatchInternal(Move(aEvent), aFlags, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::DelayedDispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs)
|
||||
{
|
||||
NS_ENSURE_TRUE(!!aDelayMs, NS_ERROR_UNEXPECTED);
|
||||
|
||||
RefPtr<DelayedRunnable> r = new DelayedRunnable(Move(aEvent), aDelayMs);
|
||||
nsresult rv = r->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return DispatchInternal(r.forget(), 0, nullptr);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
@@ -1217,6 +1298,12 @@ nsThread::nsNestedEventTarget::Dispatch(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
return mThread->DispatchInternal(Move(aEvent), aFlags, this);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::nsNestedEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::nsNestedEventTarget::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
|
||||
@@ -278,6 +278,12 @@ nsThreadPool::Dispatch(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aFlags)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::DelayedDispatch(already_AddRefed<nsIRunnable>&&, uint32_t)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThreadPool::IsOnCurrentThread(bool* aResult)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user