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:
2024-10-09 07:22:03 +08:00
parent 81a1b46bb3
commit ef3af9173b
40 changed files with 1200 additions and 63 deletions
+18
View File
@@ -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 ========================================================
+6
View File
@@ -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)
{
+7
View File
@@ -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)
{
+10 -1
View File
@@ -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
+14
View File
@@ -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>::
+3
View File
@@ -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;
};
+6
View File
@@ -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
{
+3
View File
@@ -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
+1 -1
View File
@@ -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))
+11
View File
@@ -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) {
+8
View File
@@ -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() {};
};
+26 -1
View File
@@ -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) {
+44
View File
@@ -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));
+1 -1
View File
@@ -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};
+654
View File
@@ -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
+100
View File
@@ -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
+8 -2
View File
@@ -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;
}
+12
View File
@@ -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)
{
+9
View File
@@ -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);
+4
View File
@@ -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
View File
@@ -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(); }
+4
View File
@@ -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
View File
@@ -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
View File
@@ -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
+13 -6
View File
@@ -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 ^
+18
View File
@@ -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
View File
@@ -122,7 +122,7 @@ public:
{
}
bool checkSimulatedOOM() const
MOZ_MUST_USE bool checkSimulatedOOM() const
{
return true;
}
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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)
{
+6
View File
@@ -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)
{
+3
View File
@@ -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); }
+20
View File
@@ -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++
+87
View File
@@ -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)
{
+6
View File
@@ -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)
{