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:
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)) {