commit a7b2b6d5206d454b856c570eda5691a02f313b01
parent dd670349f93d8b8195404b2109be3c260dd02510
Author: Brad Werth <werth@efn.org>
Date: Wed, 15 Oct 2025 15:09:09 +0000
Bug 1927289: More strongly enforce WebGL context continuity. r=ahale
This makes more consistent the RefPtr holds of the WebGL context, and
greatly reduces the "bare" dereferences of mNotLost.
Differential Revision: https://phabricator.services.mozilla.com/D267501
Diffstat:
1 file changed, 296 insertions(+), 170 deletions(-)
diff --git a/dom/canvas/ClientWebGLContext.cpp b/dom/canvas/ClientWebGLContext.cpp
@@ -276,8 +276,9 @@ void ClientWebGLContext::OnContextLoss(
const webgl::ContextLossReason reason) const {
JsWarning("WebGL context was lost.");
- if (mNotLost) {
- for (const auto& ext : mNotLost->extensions) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (notLost) {
+ for (const auto& ext : notLost->extensions) {
if (!ext) continue;
ext->mContext = nullptr; // Detach.
}
@@ -421,14 +422,12 @@ template <typename MethodT, typename... Args>
void ClientWebGLContext::Run_WithDestArgTypes(
std::optional<JS::AutoCheckCannotGC>&& noGc, const MethodT method,
const size_t id, const Args&... args) const {
- const auto notLost =
- mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
-
// `AutoCheckCannotGC` must be reset after the GC data is done being used but
// *before* the `notLost` destructor runs, since the latter can GC.
const auto cleanup = MakeScopeExit([&]() { noGc.reset(); });
- if (IsContextLost()) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
return;
}
@@ -491,12 +490,18 @@ webgl::SwapChainOptions ClientWebGLContext::PrepareAsyncSwapChainOptions(
// Currently remote texture ids should only be set internally.
MOZ_ASSERT(!options.remoteTextureOwnerId.IsValid() &&
!options.remoteTextureId.IsValid());
+
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return options;
+ }
+
// Async present only works when out-of-process. It is not supported in WebVR.
// Allow it if it is either forced or if the pref is set.
if (fb || webvr) {
return options;
}
- if (!IsContextLost() && !mNotLost->inProcess &&
+ if (notLost->inProcess &&
(options.forceAsyncPresent ||
StaticPrefs::webgl_out_of_process_async_present())) {
if (!mRemoteTextureOwnerId) {
@@ -543,15 +548,18 @@ void ClientWebGLContext::EndOfFrame() {
Maybe<layers::SurfaceDescriptor> ClientWebGLContext::GetFrontBuffer(
WebGLFramebufferJS* const fb, bool vr) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return {};
+ }
const FuncScope funcScope(*this, "<GetFrontBuffer>");
- if (IsContextLost()) return {};
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetFrontBuffer(fb ? fb->mId : 0, vr);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
// Always synchronously get the front buffer if not using a remote texture.
@@ -626,18 +634,23 @@ void ClientWebGLContext::ClearVRSwapChain() { Run<RPROC(ClearVRSwapChain)>(); }
bool ClientWebGLContext::UpdateWebRenderCanvasData(
nsDisplayListBuilder* aBuilder, WebRenderCanvasData* aCanvasData) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return true;
+ }
+
CanvasRenderer* renderer = aCanvasData->GetCanvasRenderer();
- if (!IsContextLost() && !mResetLayer && renderer) {
+ if (!mResetLayer && renderer) {
return true;
}
const auto& size = DrawingBufferSize();
- if (!IsContextLost() && !renderer && mNotLost->mCanvasRenderer &&
- mNotLost->mCanvasRenderer->GetSize() == gfx::IntSize(size.x, size.y) &&
- aCanvasData->SetCanvasRenderer(mNotLost->mCanvasRenderer)) {
- mNotLost->mCanvasRenderer->SetDirty();
+ if (!renderer && notLost->mCanvasRenderer &&
+ notLost->mCanvasRenderer->GetSize() == gfx::IntSize(size.x, size.y) &&
+ aCanvasData->SetCanvasRenderer(notLost->mCanvasRenderer)) {
+ notLost->mCanvasRenderer->SetDirty();
mResetLayer = false;
return true;
}
@@ -649,7 +662,7 @@ bool ClientWebGLContext::UpdateWebRenderCanvasData(
return false;
}
- mNotLost->mCanvasRenderer = renderer;
+ notLost->mCanvasRenderer = renderer;
MOZ_ASSERT(renderer);
mResetLayer = false;
@@ -758,12 +771,17 @@ void ClientWebGLContext::SetUnpackColorSpace(
void ClientWebGLContext::GetContextAttributes(
dom::Nullable<dom::WebGLContextAttributes>& retval) {
retval.SetNull();
+
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getContextAttributes");
- if (IsContextLost()) return;
dom::WebGLContextAttributes& result = retval.SetValue();
- const auto& options = mNotLost->info.options;
+ const auto& options = notLost->info.options;
result.mAlpha.Construct(options.alpha);
result.mDepth = options.depth;
@@ -781,12 +799,17 @@ void ClientWebGLContext::GetContextAttributes(
NS_IMETHODIMP
ClientWebGLContext::SetDimensions(const int32_t signedWidth,
const int32_t signedHeight) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return NS_ERROR_FAILURE;
+ }
+
const FuncScope funcScope(*this, "<SetDimensions>");
MOZ_ASSERT(mInitialOptions);
if (mLossStatus != webgl::LossStatus::Ready) {
// Attempted resize of a lost context.
- return NS_OK;
+ return NS_ERROR_FAILURE;
}
uvec2 size = {static_cast<uint32_t>(signedWidth),
@@ -802,29 +825,19 @@ ClientWebGLContext::SetDimensions(const int32_t signedWidth,
mResetLayer = true; // Always treat this as resize.
- if (mNotLost) {
- auto& state = State();
-
- auto curSize = prevRequestedSize;
- if (state.mDrawingBufferSize) {
- curSize = *state.mDrawingBufferSize;
- }
- if (size == curSize) return NS_OK; // MUST skip no-op resize
-
- state.mDrawingBufferSize = Nothing();
- Run<RPROC(Resize)>(size);
+ auto& state = State();
- UpdateCanvasParameters();
- MarkCanvasDirty();
- return NS_OK;
+ auto curSize = prevRequestedSize;
+ if (state.mDrawingBufferSize) {
+ curSize = *state.mDrawingBufferSize;
}
+ if (size == curSize) return NS_OK; // MUST skip no-op resize
- // -
- // Context (re-)creation
+ state.mDrawingBufferSize = Nothing();
+ Run<RPROC(Resize)>(size);
- if (!CreateHostContext(size)) {
- return NS_ERROR_FAILURE;
- }
+ UpdateCanvasParameters();
+ MarkCanvasDirty();
return NS_OK;
}
@@ -847,8 +860,10 @@ static bool IsWebglOutOfProcessEnabled() {
}
bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
- const auto pNotLost = MakeRefPtr<webgl::NotLostData>(*this);
- auto& notLost = *pNotLost;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return false;
+ }
auto res = [&]() -> Result<Ok, std::string> {
auto options = *mInitialOptions;
@@ -888,8 +903,8 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
}
if (!useOop) {
- notLost.inProcess =
- HostWebGLContext::Create({this, nullptr}, initDesc, ¬Lost.info);
+ notLost->inProcess =
+ HostWebGLContext::Create({this, nullptr}, initDesc, ¬Lost->info);
return Ok();
}
@@ -916,11 +931,11 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
mFwdTransactionTracker = nullptr;
}
- if (!outOfProcess->SendInitialize(initDesc, ¬Lost.info)) {
+ if (!outOfProcess->SendInitialize(initDesc, ¬Lost->info)) {
return Err("WebGL actor Initialize failed");
}
- notLost.outOfProcess = outOfProcess;
+ notLost->outOfProcess = outOfProcess;
reporter.SetSuccessful();
return Ok();
}();
@@ -931,13 +946,12 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) {
" (about:config override available:"
" webgl.disable-fail-if-major-performance-caveat)";
}
- notLost.info.error = str;
+ notLost->info.error = str;
}
- if (!notLost.info.error->empty()) {
- ThrowEvent_WebGLContextCreationError(notLost.info.error);
+ if (!notLost->info.error->empty()) {
+ ThrowEvent_WebGLContextCreationError(notLost->info.error);
return false;
}
- mNotLost = pNotLost;
UpdateCanvasParameters();
MarkCanvasDirty();
@@ -1011,9 +1025,10 @@ std::unordered_map<GLenum, bool> webgl::MakeIsEnabledMap(const bool webgl2) {
// -------
uvec2 ClientWebGLContext::DrawingBufferSize() {
- if (IsContextLost()) return {};
- RefPtr<webgl::NotLostData> notLost(
- mNotLost); // Hold a strong-ref to prevent LoseContext=>UAF.
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return {};
+ }
auto& state = State();
auto& size = state.mDrawingBufferSize;
@@ -1034,14 +1049,19 @@ uvec2 ClientWebGLContext::DrawingBufferSize() {
}
void ClientWebGLContext::OnMemoryPressure() {
- if (IsContextLost()) return;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->OnMemoryPressure();
}
- const auto& child = mNotLost->outOfProcess;
- (void)child->SendOnMemoryPressure();
+ const auto& child = notLost->outOfProcess;
+ if (child) {
+ (void)child->SendOnMemoryPressure();
+ }
}
NS_IMETHODIMP
@@ -1104,9 +1124,10 @@ void ClientWebGLContext::DidRefresh() { Run<RPROC(DidRefresh)>(); }
already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
gfxAlphaType* const out_alphaType) {
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
- if (IsContextLost()) return nullptr;
- RefPtr<webgl::NotLostData> notLost(
- mNotLost); // Hold a strong-ref to prevent LoseContext=>UAF.
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return nullptr;
+ }
auto ret = BackBufferSnapshot();
if (!ret) return nullptr;
@@ -1153,9 +1174,10 @@ mozilla::ipc::IProtocol* ClientWebGLContext::SupportsSnapshotExternalCanvas()
RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
const bool requireAlphaPremult) {
const FuncScope funcScope(*this, "<GetSurfaceSnapshot>");
- if (IsContextLost()) return nullptr;
- RefPtr<webgl::NotLostData> notLost(
- mNotLost); // Hold a strong-ref to prevent LoseContext=>UAF.
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return nullptr;
+ }
const auto& options = notLost->info.options;
@@ -1170,7 +1192,7 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
/*zero=*/true));
};
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
const auto maybeSize = inProcess->FrontBufferSnapshotInto({});
if (!maybeSize) return nullptr;
@@ -1210,7 +1232,7 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
}
return surf;
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
webgl::FrontBufferSnapshotIpc res;
if (!child->SendGetFrontBufferSnapshot(&res)) {
@@ -1256,9 +1278,10 @@ RefPtr<gfx::SourceSurface> ClientWebGLContext::GetFrontBufferSnapshot(
}
RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {
- if (IsContextLost()) return nullptr;
- RefPtr<webgl::NotLostData> notLost(
- mNotLost); // Hold a strong-ref to prevent LoseContext=>UAF.
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return nullptr;
+ }
const auto& options = notLost->info.options;
const auto& state = State();
@@ -1333,6 +1356,11 @@ RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {
UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(
mozilla::CanvasUtils::ImageExtraction aExtractionBehavior,
int32_t* out_format, gfx::IntSize* out_imageSize) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return nullptr;
+ }
+
*out_format = 0;
*out_imageSize = {};
@@ -1343,7 +1371,7 @@ UniquePtr<uint8_t[]> ClientWebGLContext::GetImageBuffer(
RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
- const auto& premultAlpha = mNotLost->info.options.premultipliedAlpha;
+ const auto& premultAlpha = notLost->info.options.premultipliedAlpha;
*out_imageSize = dataSurface->GetSize();
if (aExtractionBehavior == CanvasUtils::ImageExtraction::Randomize) {
@@ -1360,13 +1388,18 @@ ClientWebGLContext::GetInputStream(
const char* mimeType, const nsAString& encoderOptions,
mozilla::CanvasUtils::ImageExtraction extractionBehavior,
const nsACString& randomizationKey, nsIInputStream** out_stream) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return NS_ERROR_FAILURE;
+ }
+
// Use GetSurfaceSnapshot() to make sure that appropriate y-flip gets applied
gfxAlphaType any;
RefPtr<gfx::SourceSurface> snapshot = GetSurfaceSnapshot(&any);
if (!snapshot) return NS_ERROR_FAILURE;
RefPtr<gfx::DataSourceSurface> dataSurface = snapshot->GetDataSurface();
- const auto& premultAlpha = mNotLost->info.options.premultipliedAlpha;
+ const auto& premultAlpha = notLost->info.options.premultipliedAlpha;
if (ShouldResistFingerprinting(RFPTarget::CanvasRandomization)) {
return gfxUtils::GetInputStreamWithRandomNoise(
@@ -1416,21 +1449,24 @@ ClientWebGLContext::CreateOpaqueFramebuffer(
auto ret = AsRefPtr(new WebGLFramebufferJS(*this, true));
- if (mNotLost) {
- const auto& inProcess = mNotLost->inProcess;
- if (inProcess) {
- if (!inProcess->CreateOpaqueFramebuffer(ret->mId, options)) {
- ret = nullptr;
- }
- return ret.forget();
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return ret.forget();
+ }
+
+ const auto& inProcess = notLost->inProcess;
+ if (inProcess) {
+ if (!inProcess->CreateOpaqueFramebuffer(ret->mId, options)) {
+ ret = nullptr;
}
- const auto& child = mNotLost->outOfProcess;
- child->FlushPendingCmds();
- bool ok = false;
- if (!child->SendCreateOpaqueFramebuffer(ret->mId, options, &ok))
- return nullptr;
- if (!ok) return nullptr;
+ return ret.forget();
}
+ const auto& child = notLost->outOfProcess;
+ child->FlushPendingCmds();
+ bool ok = false;
+ if (!child->SendCreateOpaqueFramebuffer(ret->mId, options, &ok))
+ return nullptr;
+ if (!ok) return nullptr;
return ret.forget();
}
@@ -1943,9 +1979,12 @@ bool ClientWebGLContext::IsVertexArray(
void ClientWebGLContext::SetEnabledI(const GLenum cap, const Maybe<GLuint> i,
const bool val) const {
const FuncScope funcScope(*this, "enable/disable");
- if (IsContextLost()) return;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
- auto& map = mNotLost->state.mIsEnabledMap;
+ auto& map = notLost->state.mIsEnabledMap;
auto slot = MaybeFind(map, cap);
if (i && cap != LOCAL_GL_BLEND) {
slot = nullptr;
@@ -1964,9 +2003,12 @@ void ClientWebGLContext::SetEnabledI(const GLenum cap, const Maybe<GLuint> i,
bool ClientWebGLContext::IsEnabled(const GLenum cap) const {
const FuncScope funcScope(*this, "isEnabled");
- if (IsContextLost()) return false;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return false;
+ }
- const auto& map = mNotLost->state.mIsEnabledMap;
+ const auto& map = notLost->state.mIsEnabledMap;
const auto slot = MaybeFind(map, cap);
if (!slot) {
EnqueueError_ArgEnum("cap", cap);
@@ -1987,9 +2029,10 @@ void ClientWebGLContext::GetInternalformatParameter(
JS::MutableHandle<JS::Value> retval, ErrorResult& rv) {
const FuncScope funcScope(*this, "getInternalformatParameter");
retval.set(JS::NullValue());
- const auto notLost =
- mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
- if (IsContextLost()) return;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
const auto& inProcessContext = notLost->inProcess;
Maybe<std::vector<int32_t>> maybe;
@@ -2034,14 +2077,17 @@ bool ToJSValueOrNull(JSContext* const cx, const RefPtr<T>& ptr,
}
Maybe<double> ClientWebGLContext::GetNumber(const GLenum pname) {
- MOZ_ASSERT(!IsContextLost());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return Nothing();
+ }
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetNumber(pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
@@ -2052,14 +2098,17 @@ Maybe<double> ClientWebGLContext::GetNumber(const GLenum pname) {
}
Maybe<std::string> ClientWebGLContext::GetString(const GLenum pname) {
- MOZ_ASSERT(!IsContextLost());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return Nothing();
+ }
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetString(pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<std::string> ret;
@@ -2073,6 +2122,11 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
JS::MutableHandle<JS::Value> retval,
ErrorResult& rv, const bool debug) {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getParameter");
if (IsContextLost()) return;
const auto& limits = Limits();
@@ -2474,8 +2528,8 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
if (maybe) {
auto str = std::string{};
if (pname == dom::MOZ_debug_Binding::WSI_INFO) {
- const auto& outOfProcess = mNotLost->outOfProcess;
- const auto& inProcess = mNotLost->inProcess;
+ const auto& outOfProcess = notLost->outOfProcess;
+ const auto& inProcess = notLost->inProcess;
str += PrintfStdString("outOfProcess: %s\ninProcess: %s\n",
ToChars(bool(outOfProcess)),
ToChars(bool(inProcess)));
@@ -2541,14 +2595,17 @@ void ClientWebGLContext::GetBufferParameter(
JSContext* cx, GLenum target, GLenum pname,
JS::MutableHandle<JS::Value> retval) const {
retval.set(JS::NullValue());
- if (IsContextLost()) return;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
const auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetBufferParameter(target, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetBufferParameter(target, pname, &ret)) {
@@ -2580,8 +2637,12 @@ void ClientWebGLContext::GetFramebufferAttachmentParameter(
const GLenum pname, JS::MutableHandle<JS::Value> retval,
ErrorResult& rv) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getFramebufferAttachmentParameter");
- if (IsContextLost()) return;
const auto& state = State();
@@ -2597,12 +2658,12 @@ void ClientWebGLContext::GetFramebufferAttachmentParameter(
const auto fnGet = [&](const GLenum pname) {
const auto fbId = fb ? fb->mId : 0;
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetFramebufferAttachmentParameter(fbId, attachment,
pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetFramebufferAttachmentParameter(fbId, attachment, pname,
@@ -2661,8 +2722,12 @@ void ClientWebGLContext::GetRenderbufferParameter(
JSContext* cx, GLenum target, GLenum pname,
JS::MutableHandle<JS::Value> retval) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getRenderbufferParameter");
- if (IsContextLost()) return;
if (target != LOCAL_GL_RENDERBUFFER) {
EnqueueError_ArgEnum("target", target);
@@ -2673,11 +2738,11 @@ void ClientWebGLContext::GetRenderbufferParameter(
const auto& rb = state.mBoundRb;
const auto rbId = rb ? rb->mId : 0;
const auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetRenderbufferParameter(rbId, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetRenderbufferParameter(rbId, pname, &ret)) {
@@ -2694,8 +2759,12 @@ void ClientWebGLContext::GetIndexedParameter(
JSContext* cx, GLenum target, GLuint index,
JS::MutableHandle<JS::Value> retval, ErrorResult& rv) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getIndexedParameter");
- if (IsContextLost()) return;
const auto& state = State();
@@ -2725,11 +2794,11 @@ void ClientWebGLContext::GetIndexedParameter(
}
const auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetIndexedParameter(target, index);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetIndexedParameter(target, index, &ret)) {
@@ -2762,8 +2831,12 @@ void ClientWebGLContext::GetUniform(JSContext* const cx,
const WebGLUniformLocationJS& loc,
JS::MutableHandle<JS::Value> retval) {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getUniform");
- if (IsContextLost()) return;
if (!prog.ValidateUsable(*this, "prog")) return;
if (!loc.ValidateUsable(*this, "loc")) return;
@@ -2781,11 +2854,11 @@ void ClientWebGLContext::GetUniform(JSContext* const cx,
}
const auto res = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetUniform(prog.mId, loc.mLocation);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
webgl::GetUniformData ret;
if (!child->SendGetUniform(prog.mId, loc.mLocation, &ret)) {
@@ -2901,10 +2974,14 @@ void ClientWebGLContext::GetUniform(JSContext* const cx,
already_AddRefed<WebGLShaderPrecisionFormatJS>
ClientWebGLContext::GetShaderPrecisionFormat(const GLenum shadertype,
const GLenum precisiontype) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return nullptr;
+ }
+
const FuncScope funcScope(*this, "getShaderPrecisionFormat");
- if (IsContextLost()) return nullptr;
- const auto& shaderPrecisions = *mNotLost->info.shaderPrecisions;
+ const auto& shaderPrecisions = *notLost->info.shaderPrecisions;
const auto args =
webgl::GetShaderPrecisionFormatArgs{shadertype, precisiontype};
const auto found = MaybeFind(shaderPrecisions, args);
@@ -2956,13 +3033,16 @@ void ClientWebGLContext::BlendFuncSeparateI(Maybe<GLuint> i, GLenum srcRGB,
}
GLenum ClientWebGLContext::CheckFramebufferStatus(GLenum target) {
- if (IsContextLost()) return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED;
+ }
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->CheckFramebufferStatus(target);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
GLenum ret = 0;
if (!child->SendCheckFramebufferStatus(target, &ret)) {
@@ -3084,27 +3164,34 @@ void ClientWebGLContext::DepthRange(GLclampf zNear, GLclampf zFar) {
}
void ClientWebGLContext::Flush(const bool flushGl) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "flush");
- if (IsContextLost()) return;
if (flushGl) {
Run<RPROC(Flush)>();
}
- if (mNotLost->inProcess) return;
- const auto& child = mNotLost->outOfProcess;
+ if (notLost->inProcess) return;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
}
void ClientWebGLContext::Finish() {
- if (IsContextLost()) return;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
inProcess->Finish();
return;
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
(void)child->SendFinish();
}
@@ -3112,19 +3199,23 @@ void ClientWebGLContext::Finish() {
void ClientWebGLContext::FrontFace(GLenum mode) { Run<RPROC(FrontFace)>(mode); }
GLenum ClientWebGLContext::GetError() {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return 0;
+ }
+
const FuncScope funcScope(*this, "getError");
if (mNextError) {
const auto ret = mNextError;
mNextError = 0;
return ret;
}
- if (IsContextLost()) return 0;
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetError();
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
GLenum ret = 0;
if (!child->SendGetError(&ret)) {
@@ -3501,10 +3592,13 @@ void ClientWebGLContext::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
const dom::ArrayBufferView& dstData,
GLuint dstElemOffset,
GLuint dstElemCountOverride) {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getBufferSubData");
- if (IsContextLost()) return;
- const auto notLost =
- mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
+
if (!ValidateNonNegative("srcByteOffset", srcByteOffset)) return;
size_t elemSize = SizeOfViewElem(dstData);
@@ -4114,8 +4208,12 @@ void ClientWebGLContext::GetTexParameter(
JSContext* cx, GLenum texTarget, GLenum pname,
JS::MutableHandle<JS::Value> retval) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "getTexParameter");
- if (IsContextLost()) return;
auto& state = State();
auto& texUnit = state.mTexUnits[state.mActiveTexUnit];
@@ -4132,11 +4230,11 @@ void ClientWebGLContext::GetTexParameter(
}
const auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetTexParameter(tex->mId, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetTexParameter(tex->mId, pname, &ret)) {
@@ -4315,8 +4413,12 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
const Maybe<ivec3>& isize, GLint border,
const webgl::PackingInfo& pi,
const TexImageSource& src) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
+
const FuncScope funcScope(*this, "tex(Sub)Image[23]D");
- if (IsContextLost()) return;
if (!IsTexTargetForDims(ImageToTexTarget(imageTarget), mIsWebGL2, funcDims)) {
EnqueueError_ArgEnum("imageTarget", imageTarget);
return;
@@ -4513,7 +4615,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
if (desc->sd) {
const auto& sd = *(desc->sd);
const auto sdType = sd.type();
- const auto& contextInfo = mNotLost->info;
+ const auto& contextInfo = notLost->info;
// TODO (Bug 754256): Figure out the source colorSpace.
const auto& webgl = this;
@@ -4560,7 +4662,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
} break;
case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10: {
const auto& sdD3D = sd.get_SurfaceDescriptorD3D10();
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
MOZ_ASSERT(desc->image);
keepAliveImage = desc->image;
@@ -4570,7 +4672,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
}
} break;
case layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
MOZ_ASSERT(desc->image);
keepAliveImage = desc->image;
if (inProcess) {
@@ -4593,7 +4695,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
}
} break;
case layers::SurfaceDescriptor::TSurfaceDescriptorExternalImage: {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
MOZ_ASSERT(desc->sourceSurf);
keepAliveSurf = desc->sourceSurf;
if (inProcess) {
@@ -4602,7 +4704,7 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
}
} break;
case layers::SurfaceDescriptor::TSurfaceDescriptorCanvasSurface: {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
MOZ_ASSERT(desc->sourceSurf);
keepAliveSurf = desc->sourceSurf;
if (inProcess) {
@@ -4670,12 +4772,12 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
CastUvec3(offset), pi, std::move(*desc));
} else {
// We can't handle shmems like SurfaceDescriptorBuffer inline, so use ipdl.
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->TexImage(static_cast<uint32_t>(level), respecFormat,
CastUvec3(offset), pi, *desc);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
// The shmem we're handling was only shared from RDD to Content, and
@@ -4829,16 +4931,19 @@ void ClientWebGLContext::UseProgram(WebGLProgramJS* const prog) {
}
void ClientWebGLContext::ValidateProgram(WebGLProgramJS& prog) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
const FuncScope funcScope(*this, "validateProgram");
- if (IsContextLost()) return;
if (!prog.ValidateUsable(*this, "prog")) return;
prog.mLastValidate = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->ValidateProgram(prog.mId);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
bool ret = {};
if (!child->SendValidateProgram(prog.mId, &ret)) {
@@ -4852,11 +4957,15 @@ void ClientWebGLContext::ValidateProgram(WebGLProgramJS& prog) const {
Maybe<double> ClientWebGLContext::GetVertexAttribPriv(const GLuint index,
const GLenum pname) {
- const auto& inProcess = mNotLost->inProcess;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return Nothing();
+ }
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetVertexAttrib(index, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetVertexAttrib(index, pname, &ret)) {
@@ -5289,9 +5398,10 @@ void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
bool ClientWebGLContext::DoReadPixels(const webgl::ReadPixelsDesc& desc,
const Span<uint8_t> dest) const {
- const auto notLost =
- mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
- if (!notLost) return false;
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return false;
+ }
const auto& inProcess = notLost->inProcess;
if (inProcess) {
inProcess->ReadPixelsInto(desc, dest);
@@ -5434,16 +5544,19 @@ void ClientWebGLContext::GetQueryParameter(
JSContext*, WebGLQueryJS& query, const GLenum pname,
JS::MutableHandle<JS::Value> retval) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
const FuncScope funcScope(*this, "getQueryParameter");
- if (IsContextLost()) return;
if (!query.ValidateUsable(*this, "query")) return;
auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetQueryParameter(query.mId, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetQueryParameter(query.mId, pname, &ret)) {
@@ -5567,16 +5680,19 @@ void ClientWebGLContext::GetSamplerParameter(
JSContext* cx, const WebGLSamplerJS& sampler, const GLenum pname,
JS::MutableHandle<JS::Value> retval) const {
retval.set(JS::NullValue());
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return;
+ }
const FuncScope funcScope(*this, "getSamplerParameter");
- if (IsContextLost()) return;
if (!sampler.ValidateUsable(*this, "sampler")) return;
const auto maybe = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetSamplerParameter(sampler.mId, pname);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
Maybe<double> ret;
if (!child->SendGetSamplerParameter(sampler.mId, pname, &ret)) {
@@ -5667,8 +5783,11 @@ void ClientWebGLContext::GetSyncParameter(
GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync,
const GLbitfield flags,
const GLuint64 timeout) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return LOCAL_GL_WAIT_FAILED;
+ }
const FuncScope funcScope(*this, "clientWaitSync");
- if (IsContextLost()) return LOCAL_GL_WAIT_FAILED;
if (!sync.ValidateUsable(*this, "sync")) return LOCAL_GL_WAIT_FAILED;
static constexpr auto VALID_BITS = LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT;
@@ -5729,11 +5848,11 @@ GLenum ClientWebGLContext::ClientWaitSync(WebGLSyncJS& sync,
// Fine, time to block:
const auto ret = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->ClientWaitSync(sync.mId, flags, timeout);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
GLenum ret = {};
if (!child->SendClientWaitSync(sync.mId, flags, timeout, &ret)) {
@@ -5951,7 +6070,7 @@ void ClientWebGLContext::DrawBuffers(const dom::Sequence<GLenum>& buffers) {
void ClientWebGLContext::EnqueueErrorImpl(const GLenum error,
const nsACString& text) const {
- if (!mNotLost) return; // Ignored if context is lost.
+ if (IsContextLost()) return;
AutoEnqueueFlush();
Run<RPROC(GenerateError)>(error, ToString(text));
}
@@ -6001,7 +6120,7 @@ void ClientWebGLContext::GetSupportedExtensions(
dom::Nullable<nsTArray<nsString>>& retval,
const dom::CallerType callerType) const {
retval.SetNull();
- if (!mNotLost) return;
+ if (IsContextLost()) return;
auto& retarr = retval.SetValue();
for (const auto i : MakeEnumeratedRange(WebGLExtensionID::Max)) {
@@ -6017,7 +6136,7 @@ void ClientWebGLContext::GetSupportedExtensions(
void ClientWebGLContext::GetSupportedProfilesASTC(
dom::Nullable<nsTArray<nsString>>& retval) const {
retval.SetNull();
- if (!mNotLost) return;
+ if (IsContextLost()) return;
const auto& limits = Limits();
auto& retarr = retval.SetValue();
@@ -6410,8 +6529,11 @@ GLint ClientWebGLContext::GetAttribLocation(const WebGLProgramJS& prog,
GLint ClientWebGLContext::GetFragDataLocation(const WebGLProgramJS& prog,
const nsAString& name) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return -1;
+ }
const FuncScope funcScope(*this, "getFragDataLocation");
- if (IsContextLost()) return -1;
if (!prog.ValidateUsable(*this, "program")) return -1;
const auto nameU8 = ToString(NS_ConvertUTF16toUTF8(name));
@@ -6423,11 +6545,11 @@ GLint ClientWebGLContext::GetFragDataLocation(const WebGLProgramJS& prog,
}
return [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetFragDataLocation(prog.mId, nameU8);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
GLint ret = {};
if (!child->SendGetFragDataLocation(prog.mId, nameU8, &ret)) {
@@ -6756,13 +6878,17 @@ void ClientWebGLContext::ShaderSource(WebGLShaderJS& shader,
const webgl::CompileResult& ClientWebGLContext::GetCompileResult(
const WebGLShaderJS& shader) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return shader.mResult;
+ }
if (shader.mResult.pending) {
shader.mResult = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetCompileResult(shader.mId);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
webgl::CompileResult ret = {};
if (!child->SendGetCompileResult(shader.mId, &ret)) {
@@ -6776,17 +6902,17 @@ const webgl::CompileResult& ClientWebGLContext::GetCompileResult(
const webgl::LinkResult& ClientWebGLContext::GetLinkResult(
const WebGLProgramJS& prog) const {
+ RefPtr<webgl::NotLostData> notLost(mNotLost);
+ if (!notLost) {
+ return *(prog.mResult);
+ }
if (prog.mResult->pending) {
- const auto notLost =
- mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF.
- if (!notLost) return *(prog.mResult);
-
*(prog.mResult) = [&]() {
- const auto& inProcess = mNotLost->inProcess;
+ const auto& inProcess = notLost->inProcess;
if (inProcess) {
return inProcess->GetLinkResult(prog.mId);
}
- const auto& child = mNotLost->outOfProcess;
+ const auto& child = notLost->outOfProcess;
child->FlushPendingCmds();
webgl::LinkResult ret;
if (!child->SendGetLinkResult(prog.mId, &ret)) {