tor-browser

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

commit ad7fddd733cd01f63f5acd0242d2875ab52aac93
parent d37ee8db0680366dde81a6a6be186ab7a1c2fcd2
Author: Brad Werth <werth@efn.org>
Date:   Fri, 17 Oct 2025 18:18:12 +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 | 425+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
1 file changed, 275 insertions(+), 150 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; } @@ -802,7 +801,8 @@ ClientWebGLContext::SetDimensions(const int32_t signedWidth, mResetLayer = true; // Always treat this as resize. - if (mNotLost) { + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (notLost) { auto& state = State(); auto curSize = prevRequestedSize; @@ -1012,8 +1012,7 @@ 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); auto& state = State(); auto& size = state.mDrawingBufferSize; @@ -1034,14 +1033,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 +1108,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 +1158,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 +1176,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 +1216,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 +1262,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 +1340,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 +1355,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 +1372,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 +1433,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 +1963,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 +1987,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,10 +2013,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; if (inProcessContext) { @@ -2034,14 +2060,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 +2081,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; @@ -2072,9 +2104,12 @@ Maybe<std::string> ClientWebGLContext::GetString(const GLenum pname) { void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname, JS::MutableHandle<JS::Value> retval, ErrorResult& rv, const bool debug) { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } const auto& limits = Limits(); const auto& state = State(); @@ -2474,8 +2509,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 +2576,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)) { @@ -2579,9 +2617,12 @@ void ClientWebGLContext::GetFramebufferAttachmentParameter( JSContext* const cx, const GLenum target, const GLenum attachment, const GLenum pname, JS::MutableHandle<JS::Value> retval, ErrorResult& rv) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getFramebufferAttachmentParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } const auto& state = State(); @@ -2597,12 +2638,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, @@ -2660,9 +2701,12 @@ void ClientWebGLContext::GetFramebufferAttachmentParameter( void ClientWebGLContext::GetRenderbufferParameter( JSContext* cx, GLenum target, GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getRenderbufferParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (target != LOCAL_GL_RENDERBUFFER) { EnqueueError_ArgEnum("target", target); @@ -2673,11 +2717,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)) { @@ -2693,9 +2737,12 @@ void ClientWebGLContext::GetRenderbufferParameter( void ClientWebGLContext::GetIndexedParameter( JSContext* cx, GLenum target, GLuint index, JS::MutableHandle<JS::Value> retval, ErrorResult& rv) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getIndexedParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } const auto& state = State(); @@ -2725,11 +2772,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)) { @@ -2761,9 +2808,13 @@ void ClientWebGLContext::GetUniform(JSContext* const cx, const WebGLProgramJS& prog, const WebGLUniformLocationJS& loc, JS::MutableHandle<JS::Value> retval) { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getUniform"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } + if (!prog.ValidateUsable(*this, "prog")) return; if (!loc.ValidateUsable(*this, "loc")) return; @@ -2781,11 +2832,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 +2952,15 @@ 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 +3012,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 +3143,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(); } @@ -3118,13 +3184,17 @@ GLenum ClientWebGLContext::GetError() { mNextError = 0; return ret; } - if (IsContextLost()) return 0; - const auto& inProcess = mNotLost->inProcess; + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return 0; + } + + 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)) { @@ -3503,8 +3573,10 @@ void ClientWebGLContext::GetBufferSubData(GLenum target, GLintptr srcByteOffset, GLuint dstElemCountOverride) { const FuncScope funcScope(*this, "getBufferSubData"); if (IsContextLost()) return; - const auto notLost = - mNotLost; // Hold a strong-ref to prevent LoseContext=>UAF. + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!ValidateNonNegative("srcByteOffset", srcByteOffset)) return; size_t elemSize = SizeOfViewElem(dstData); @@ -4113,9 +4185,13 @@ void ClientWebGLContext::GenerateMipmap(GLenum texTarget) const { void ClientWebGLContext::GetTexParameter( JSContext* cx, GLenum texTarget, GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getTexParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } + auto& state = State(); auto& texUnit = state.mTexUnits[state.mActiveTexUnit]; @@ -4132,11 +4208,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 +4391,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 +4593,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 +4640,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 +4650,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 +4673,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 +4682,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 +4750,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 +4909,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 +4935,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)) { @@ -4869,9 +4956,12 @@ void ClientWebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname, JS::MutableHandle<JS::Value> retval, ErrorResult& rv) { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getVertexAttrib"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } const auto& state = State(); const auto& genericAttribs = state.mGenericVertexAttribs; @@ -5289,9 +5379,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); @@ -5386,9 +5477,12 @@ static inline GLenum QuerySlotTarget(const GLenum specificTarget) { void ClientWebGLContext::GetQuery(JSContext* cx, GLenum specificTarget, GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getQuery"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } const auto& limits = Limits(); auto& state = State(); @@ -5433,17 +5527,20 @@ void ClientWebGLContext::GetQuery(JSContext* cx, GLenum specificTarget, void ClientWebGLContext::GetQueryParameter( JSContext*, WebGLQueryJS& query, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getQueryParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + 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)) { @@ -5566,17 +5663,20 @@ void ClientWebGLContext::QueryCounter(WebGLQueryJS& query, void ClientWebGLContext::GetSamplerParameter( JSContext* cx, const WebGLSamplerJS& sampler, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getSamplerParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + 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)) { @@ -5635,9 +5735,12 @@ void ClientWebGLContext::SamplerParameterf(WebGLSamplerJS& sampler, void ClientWebGLContext::GetSyncParameter( JSContext* const cx, WebGLSyncJS& sync, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getSyncParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!sync.ValidateUsable(*this, "sync")) return; retval.set([&]() -> JS::Value { @@ -5667,8 +5770,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 +5835,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 +6057,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 +6107,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 +6123,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(); @@ -6264,9 +6370,12 @@ void ClientWebGLContext::GetActiveUniformBlockName(const WebGLProgramJS& prog, void ClientWebGLContext::GetActiveUniformBlockParameter( JSContext* const cx, const WebGLProgramJS& prog, const GLuint index, const GLenum pname, JS::MutableHandle<JS::Value> retval, ErrorResult& rv) { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getActiveUniformBlockParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!prog.ValidateUsable(*this, "program")) return; const auto& res = GetLinkResult(prog); @@ -6310,9 +6419,12 @@ void ClientWebGLContext::GetActiveUniforms( JSContext* const cx, const WebGLProgramJS& prog, const dom::Sequence<GLuint>& uniformIndices, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getActiveUniforms"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!prog.ValidateUsable(*this, "program")) return; const auto& res = GetLinkResult(prog); @@ -6410,8 +6522,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 +6538,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)) { @@ -6612,9 +6727,12 @@ void ClientWebGLContext::GetProgramInfoLog(const WebGLProgramJS& prog, void ClientWebGLContext::GetProgramParameter( JSContext* const js, const WebGLProgramJS& prog, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getProgramParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!prog.ValidateUsable(*this, "program")) return; retval.set([&]() -> JS::Value { @@ -6696,9 +6814,12 @@ void ClientWebGLContext::GetShaderInfoLog(const WebGLShaderJS& shader, void ClientWebGLContext::GetShaderParameter( JSContext* const cx, const WebGLShaderJS& shader, const GLenum pname, JS::MutableHandle<JS::Value> retval) const { - retval.set(JS::NullValue()); const FuncScope funcScope(*this, "getShaderParameter"); - if (IsContextLost()) return; + retval.set(JS::NullValue()); + RefPtr<webgl::NotLostData> notLost(mNotLost); + if (!notLost) { + return; + } if (!shader.ValidateUsable(*this, "shader")) return; retval.set([&]() -> JS::Value { @@ -6756,13 +6877,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 +6901,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)) {