From 12117c17ca67ffa1ce22e9409f3b0b0a93ac08c7 Mon Sep 17 00:00:00 2001 From: Jiulong Wang Date: Tue, 12 Dec 2017 11:22:48 -0800 Subject: [PATCH] draw: fix crash caused by Scale by Copy shortcut When DstMask is not nil, this shortcut causes stack overflow because Copy function in turn will call Scale with same dr and sr. Fixes golang/go#23107 Change-Id: I8ccadbd9b7f16363ac17b6114308527d6fa9456e Reviewed-on: https://go-review.googlesource.com/83537 Reviewed-by: Nigel Tao Run-TryBot: Nigel Tao TryBot-Result: Gobot Gobot --- draw/gen.go | 5 +++-- draw/impl.go | 10 ++++++---- draw/scale_test.go | 11 +++++++++++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/draw/gen.go b/draw/gen.go index 65a7123..822bb6a 100644 --- a/draw/gen.go +++ b/draw/gen.go @@ -877,8 +877,9 @@ func relName(s string) string { const ( codeRoot = ` func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) { - // Try to simplify a Scale to a Copy. - if dr.Size() == sr.Size() { + // Try to simplify a Scale to a Copy when DstMask is not specified. + // If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow. + if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) { Copy(dst, dr.Min, src, sr, op, opts) return } diff --git a/draw/impl.go b/draw/impl.go index 637887b..75498ad 100644 --- a/draw/impl.go +++ b/draw/impl.go @@ -11,8 +11,9 @@ import ( ) func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) { - // Try to simplify a Scale to a Copy. - if dr.Size() == sr.Size() { + // Try to simplify a Scale to a Copy when DstMask is not specified. + // If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow. + if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) { Copy(dst, dr.Min, src, sr, op, opts) return } @@ -1048,8 +1049,9 @@ func (nnInterpolator) transform_Image_Image_Src(dst Image, dr, adr image.Rectang } func (z ablInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) { - // Try to simplify a Scale to a Copy. - if dr.Size() == sr.Size() { + // Try to simplify a Scale to a Copy when DstMask is not specified. + // If DstMask is not nil, Copy will call Scale back with same dr and sr, and cause stack overflow. + if dr.Size() == sr.Size() && (opts == nil || opts.DstMask == nil) { Copy(dst, dr.Min, src, sr, op, opts) return } diff --git a/draw/scale_test.go b/draw/scale_test.go index 5e184c2..ea41940 100644 --- a/draw/scale_test.go +++ b/draw/scale_test.go @@ -551,6 +551,17 @@ func TestRectDstMask(t *testing.T) { } } +func TestDstMaskSameSizeCopy(t *testing.T) { + bounds := image.Rect(0, 0, 42, 42) + src := image.Opaque + dst := image.NewRGBA(bounds) + mask := image.NewRGBA(bounds) + + Copy(dst, image.ZP, src, bounds, Src, &Options{ + DstMask: mask, + }) +} + // TODO: delete this wrapper type once Go 1.5 is released, where an // image.Rectangle implements image.Image. type rectImage image.Rectangle