From 230206abb0ac8937b5c2d25569a0b8fa3732833c Mon Sep 17 00:00:00 2001 From: Iuri de Silvio Date: Tue, 23 Jun 2026 11:20:58 +0200 Subject: [PATCH] Context2d: keep fillStyle/strokeStyle strong; fix resetState and ~Context2d teardown Three Context2d state-handling correctness fixes, independent of the canvas_state_t cairo_pattern_t ownership change in #2582: - Hold a strong reference to the fillStyle/strokeStyle JS object (_fillStyle/_strokeStyle.Reset(obj, 1)). For an image-backed CanvasPattern the cairo pattern's surface points at the Image's pixel buffer, which Image::clearData() frees when the Image is GC'd; keeping the wrapper alive while the state still references its pattern prevents a use-after-free (matches the CanvasPattern source retention in #2583). - resetState(): pop all states and re-point state = &states.top() after emplace(); the original pop()+emplace() left `state` dangling and only cleared one level. - ~Context2d(): pop states before destroying the cairo context. Co-Authored-By: Claude Opus 4.8 --- src/CanvasRenderingContext2d.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 9c5482074..22bb70b31 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -242,6 +242,10 @@ Context2d::Context2d(const Napi::CallbackInfo& info) : Napi::ObjectWrapfontDescription); _resetPersistentHandles(); } @@ -1966,11 +1971,11 @@ Context2d::SetFillStyle(const Napi::CallbackInfo& info, const Napi::Value& value InstanceData *data = env.GetInstanceData(); Napi::Object obj = value.As(); if (obj.InstanceOf(data->CanvasGradientCtor.Value()).UnwrapOr(false)) { - _fillStyle.Reset(obj); + _fillStyle.Reset(obj, 1); Gradient *grad = Gradient::Unwrap(obj); state->fillGradient = grad->pattern(); } else if (obj.InstanceOf(data->CanvasPatternCtor.Value()).UnwrapOr(false)) { - _fillStyle.Reset(obj); + _fillStyle.Reset(obj, 1); Pattern *pattern = Pattern::Unwrap(obj); state->fillPattern = pattern->pattern(); } @@ -2006,11 +2011,11 @@ Context2d::SetStrokeStyle(const Napi::CallbackInfo& info, const Napi::Value& val InstanceData *data = env.GetInstanceData(); Napi::Object obj = value.As(); if (obj.InstanceOf(data->CanvasGradientCtor.Value()).UnwrapOr(false)) { - _strokeStyle.Reset(obj); + _strokeStyle.Reset(obj, 1); Gradient *grad = Gradient::Unwrap(obj); state->strokeGradient = grad->pattern(); } else if (obj.InstanceOf(data->CanvasPatternCtor.Value()).UnwrapOr(false)) { - _strokeStyle.Reset(value); + _strokeStyle.Reset(value, 1); Pattern *pattern = Pattern::Unwrap(obj); state->strokePattern = pattern->pattern(); }