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 <nigeltao@golang.org>
Run-TryBot: Nigel Tao <nigeltao@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Jiulong Wang 2017-12-12 11:22:48 -08:00 committed by Nigel Tao
parent e5db4c4663
commit 12117c17ca
3 changed files with 20 additions and 6 deletions

View File

@ -877,8 +877,9 @@ func relName(s string) string {
const ( const (
codeRoot = ` codeRoot = `
func (z $receiver) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) { 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. // Try to simplify a Scale to a Copy when DstMask is not specified.
if dr.Size() == sr.Size() { // 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) Copy(dst, dr.Min, src, sr, op, opts)
return return
} }

View File

@ -11,8 +11,9 @@ import (
) )
func (z nnInterpolator) Scale(dst Image, dr image.Rectangle, src image.Image, sr image.Rectangle, op Op, opts *Options) { 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. // Try to simplify a Scale to a Copy when DstMask is not specified.
if dr.Size() == sr.Size() { // 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) Copy(dst, dr.Min, src, sr, op, opts)
return 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) { 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. // Try to simplify a Scale to a Copy when DstMask is not specified.
if dr.Size() == sr.Size() { // 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) Copy(dst, dr.Min, src, sr, op, opts)
return return
} }

View File

@ -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 // TODO: delete this wrapper type once Go 1.5 is released, where an
// image.Rectangle implements image.Image. // image.Rectangle implements image.Image.
type rectImage image.Rectangle type rectImage image.Rectangle