tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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:
Mdom/canvas/ClientWebGLContext.cpp | 466++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
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, &notLost.info); + notLost->inProcess = + HostWebGLContext::Create({this, nullptr}, initDesc, &notLost->info); return Ok(); } @@ -916,11 +931,11 @@ bool ClientWebGLContext::CreateHostContext(const uvec2& requestedSize) { mFwdTransactionTracker = nullptr; } - if (!outOfProcess->SendInitialize(initDesc, &notLost.info)) { + if (!outOfProcess->SendInitialize(initDesc, &notLost->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)) {