Bug 1866220 - Prevent refcounted non-WrapperCached DOM objects. r=farre,extension-reviewers,rpl

Differential Revision: https://phabricator.services.mozilla.com/D194469
This commit is contained in:
Peter Van der Beken 2023-11-24 10:38:18 +00:00
parent e3989e26b1
commit a86f38d65b
7 changed files with 25 additions and 49 deletions

View file

@ -36,11 +36,9 @@ using mozilla::dom::GlobalObject;
using mozilla::dom::Optional; using mozilla::dom::Optional;
// static // static
already_AddRefed<FileReaderSync> FileReaderSync::Constructor( UniquePtr<FileReaderSync> FileReaderSync::Constructor(
const GlobalObject& aGlobal) { const GlobalObject& aGlobal) {
RefPtr<FileReaderSync> frs = new FileReaderSync(); return MakeUnique<FileReaderSync>();
return frs.forget();
} }
bool FileReaderSync::WrapObject(JSContext* aCx, bool FileReaderSync::WrapObject(JSContext* aCx,

View file

@ -8,7 +8,7 @@
#define mozilla_dom_filereadersync_h__ #define mozilla_dom_filereadersync_h__
#include "mozilla/dom/WorkerCommon.h" #include "mozilla/dom/WorkerCommon.h"
#include "nsISupports.h" #include "mozilla/dom/NonRefcountedDOMObject.h"
class nsIInputStream; class nsIInputStream;
@ -21,13 +21,8 @@ class GlobalObject;
template <typename> template <typename>
class Optional; class Optional;
class FileReaderSync final { class FileReaderSync final : public NonRefcountedDOMObject {
NS_INLINE_DECL_REFCOUNTING(FileReaderSync)
private: private:
// Private destructor, to discourage deletion outside of Release():
~FileReaderSync() = default;
nsresult ConvertStream(nsIInputStream* aStream, const char* aCharset, nsresult ConvertStream(nsIInputStream* aStream, const char* aCharset,
nsAString& aResult); nsAString& aResult);
@ -39,8 +34,7 @@ class FileReaderSync final {
uint32_t aBufferSize, uint32_t* aTotalBytesRead); uint32_t aBufferSize, uint32_t* aTotalBytesRead);
public: public:
static already_AddRefed<FileReaderSync> Constructor( static UniquePtr<FileReaderSync> Constructor(const GlobalObject& aGlobal);
const GlobalObject& aGlobal);
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
JS::MutableHandle<JSObject*> aReflector); JS::MutableHandle<JSObject*> aReflector);

View file

@ -23,21 +23,21 @@ using namespace mozilla;
using namespace mozilla::dom; using namespace mozilla::dom;
// static // static
already_AddRefed<ClonedErrorHolder> ClonedErrorHolder::Constructor( UniquePtr<ClonedErrorHolder> ClonedErrorHolder::Constructor(
const GlobalObject& aGlobal, JS::Handle<JSObject*> aError, const GlobalObject& aGlobal, JS::Handle<JSObject*> aError,
ErrorResult& aRv) { ErrorResult& aRv) {
return Create(aGlobal.Context(), aError, aRv); return Create(aGlobal.Context(), aError, aRv);
} }
// static // static
already_AddRefed<ClonedErrorHolder> ClonedErrorHolder::Create( UniquePtr<ClonedErrorHolder> ClonedErrorHolder::Create(
JSContext* aCx, JS::Handle<JSObject*> aError, ErrorResult& aRv) { JSContext* aCx, JS::Handle<JSObject*> aError, ErrorResult& aRv) {
RefPtr<ClonedErrorHolder> ceh = new ClonedErrorHolder(); UniquePtr<ClonedErrorHolder> ceh(new ClonedErrorHolder());
ceh->Init(aCx, aError, aRv); ceh->Init(aCx, aError, aRv);
if (aRv.Failed()) { if (aRv.Failed()) {
return nullptr; return nullptr;
} }
return ceh.forget(); return ceh;
} }
ClonedErrorHolder::ClonedErrorHolder() ClonedErrorHolder::ClonedErrorHolder()
@ -224,7 +224,7 @@ JSObject* ClonedErrorHolder::ReadStructuredClone(
// to avoid a potential rooting hazard. // to avoid a potential rooting hazard.
JS::Rooted<JS::Value> errorVal(aCx); JS::Rooted<JS::Value> errorVal(aCx);
{ {
RefPtr<ClonedErrorHolder> ceh = new ClonedErrorHolder(); UniquePtr<ClonedErrorHolder> ceh(new ClonedErrorHolder());
if (!ceh->Init(aCx, aReader) || !ceh->ToErrorValue(aCx, &errorVal)) { if (!ceh->Init(aCx, aReader) || !ceh->ToErrorValue(aCx, &errorVal)) {
return nullptr; return nullptr;
} }

View file

@ -7,6 +7,7 @@
#ifndef mozilla_dom_ClonedErrorHolder_h #ifndef mozilla_dom_ClonedErrorHolder_h
#define mozilla_dom_ClonedErrorHolder_h #define mozilla_dom_ClonedErrorHolder_h
#include "mozilla/dom/NonRefcountedDOMObject.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin #include "js/ColumnNumber.h" // JS::ColumnNumberOneOrigin
#include "js/ErrorReport.h" #include "js/ErrorReport.h"
@ -23,16 +24,15 @@ class ErrorResult;
namespace dom { namespace dom {
class ClonedErrorHolder final { class ClonedErrorHolder final : public NonRefcountedDOMObject {
NS_INLINE_DECL_REFCOUNTING(ClonedErrorHolder)
public: public:
static already_AddRefed<ClonedErrorHolder> Constructor( static UniquePtr<ClonedErrorHolder> Constructor(const GlobalObject& aGlobal,
const GlobalObject& aGlobal, JS::Handle<JSObject*> aError, JS::Handle<JSObject*> aError,
ErrorResult& aRv); ErrorResult& aRv);
static already_AddRefed<ClonedErrorHolder> Create( static UniquePtr<ClonedErrorHolder> Create(JSContext* aCx,
JSContext* aCx, JS::Handle<JSObject*> aError, ErrorResult& aRv); JS::Handle<JSObject*> aError,
ErrorResult& aRv);
enum class Type : uint8_t { enum class Type : uint8_t {
Uninitialized, Uninitialized,
@ -57,7 +57,6 @@ class ClonedErrorHolder final {
private: private:
ClonedErrorHolder(); ClonedErrorHolder();
~ClonedErrorHolder() = default;
void Init(JSContext* aCx, JS::Handle<JSObject*> aError, ErrorResult& aRv); void Init(JSContext* aCx, JS::Handle<JSObject*> aError, ErrorResult& aRv);

View file

@ -12,7 +12,6 @@
#include "mozilla/FunctionRef.h" #include "mozilla/FunctionRef.h"
#include "mozilla/dom/AutoEntryScript.h" #include "mozilla/dom/AutoEntryScript.h"
#include "mozilla/dom/ClonedErrorHolder.h" #include "mozilla/dom/ClonedErrorHolder.h"
#include "mozilla/dom/ClonedErrorHolderBinding.h"
#include "mozilla/dom/DOMException.h" #include "mozilla/dom/DOMException.h"
#include "mozilla/dom/DOMExceptionBinding.h" #include "mozilla/dom/DOMExceptionBinding.h"
#include "mozilla/dom/JSActorManager.h" #include "mozilla/dom/JSActorManager.h"
@ -407,14 +406,9 @@ void JSActor::QueryHandler::RejectedCallback(JSContext* aCx,
JS::Rooted<JS::Value> value(aCx, aValue); JS::Rooted<JS::Value> value(aCx, aValue);
if (value.isObject()) { if (value.isObject()) {
JS::Rooted<JSObject*> error(aCx, &value.toObject()); JS::Rooted<JSObject*> error(aCx, &value.toObject());
if (RefPtr<ClonedErrorHolder> ceh = if (UniquePtr<ClonedErrorHolder> ceh =
ClonedErrorHolder::Create(aCx, error, IgnoreErrors())) { ClonedErrorHolder::Create(aCx, error, IgnoreErrors())) {
JS::RootedObject obj(aCx); if (!ToJSValue(aCx, std::move(ceh), &value)) {
// Note: We can't use `ToJSValue` here because ClonedErrorHolder isn't
// wrapper cached.
if (ceh->WrapObject(aCx, nullptr, &obj)) {
value.setObject(*obj);
} else {
JS_ClearPendingException(aCx); JS_ClearPendingException(aCx);
} }
} else { } else {

View file

@ -12,7 +12,6 @@
#include "mozilla/dom/Client.h" #include "mozilla/dom/Client.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ClonedErrorHolder.h" #include "mozilla/dom/ClonedErrorHolder.h"
#include "mozilla/dom/ClonedErrorHolderBinding.h"
#include "mozilla/dom/ExtensionBrowserBinding.h" #include "mozilla/dom/ExtensionBrowserBinding.h"
#include "mozilla/dom/FunctionBinding.h" #include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/WorkerScope.h" #include "mozilla/dom/WorkerScope.h"
@ -264,7 +263,7 @@ bool ExtensionAPIRequestStructuredCloneWrite(JSContext* aCx,
// Try to serialize the object as a CloneErrorHolder, if it fails then // Try to serialize the object as a CloneErrorHolder, if it fails then
// the object wasn't an error. // the object wasn't an error.
IgnoredErrorResult rv; IgnoredErrorResult rv;
RefPtr<dom::ClonedErrorHolder> ceh = UniquePtr<dom::ClonedErrorHolder> ceh =
dom::ClonedErrorHolder::Create(aCx, aObj, rv); dom::ClonedErrorHolder::Create(aCx, aObj, rv);
if (NS_WARN_IF(rv.Failed()) || !ceh) { if (NS_WARN_IF(rv.Failed()) || !ceh) {
return false; return false;
@ -503,14 +502,10 @@ bool RequestWorkerRunnable::HandleAPIRequest(
// runtime.lastError). // runtime.lastError).
JS::Rooted<JSObject*> errObj(aCx, &aRetval.toObject()); JS::Rooted<JSObject*> errObj(aCx, &aRetval.toObject());
IgnoredErrorResult rv; IgnoredErrorResult rv;
RefPtr<dom::ClonedErrorHolder> ceh = UniquePtr<dom::ClonedErrorHolder> ceh =
dom::ClonedErrorHolder::Create(aCx, errObj, rv); dom::ClonedErrorHolder::Create(aCx, errObj, rv);
if (!rv.Failed() && ceh) { if (!rv.Failed() && ceh) {
JS::Rooted<JSObject*> obj(aCx); okSerializedError = ToJSValue(aCx, std::move(ceh), aRetval);
// Note: `ToJSValue` cannot be used because ClonedErrorHolder isn't
// wrapper cached.
okSerializedError = ceh->WrapObject(aCx, nullptr, &obj);
aRetval.setObject(*obj);
} else { } else {
okSerializedError = false; okSerializedError = false;
} }

View file

@ -595,14 +595,10 @@ void ExtensionListenerCallPromiseResultHandler::WorkerRunCallback(
// in case the value is an Error object. // in case the value is an Error object.
IgnoredErrorResult rv; IgnoredErrorResult rv;
JS::Rooted<JSObject*> errObj(aCx, &retval.toObject()); JS::Rooted<JSObject*> errObj(aCx, &retval.toObject());
RefPtr<dom::ClonedErrorHolder> ceh = UniquePtr<dom::ClonedErrorHolder> ceh =
dom::ClonedErrorHolder::Create(aCx, errObj, rv); dom::ClonedErrorHolder::Create(aCx, errObj, rv);
if (!rv.Failed() && ceh) { if (!rv.Failed() && ceh) {
JS::Rooted<JSObject*> obj(aCx); Unused << NS_WARN_IF(!ToJSValue(aCx, std::move(ceh), &retval));
// Note: `ToJSValue` cannot be used because ClonedErrorHolder isn't
// wrapped cached.
Unused << NS_WARN_IF(!ceh->WrapObject(aCx, nullptr, &obj));
retval.setObject(*obj);
} }
} }