From e47c3bbbfb9d65c251037ccd81932932764f17dc Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 5 Nov 2016 03:06:18 +0900 Subject: [PATCH] graphics: Limit image size strictly --- image_test.go | 77 ++++++++++++++++++++++++++++++++++++++ imageimpl.go | 30 ++++++++++++++- internal/graphics/image.go | 2 + 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/image_test.go b/image_test.go index e2ad53bcd..eb9a7f9bd 100644 --- a/image_test.go +++ b/image_test.go @@ -419,3 +419,80 @@ func TestImageFill(t *testing.T) { } } } + +func TestImageSize(t *testing.T) { + sizes := []struct { + width int + height int + error bool + }{ + { + width: -1, + height: -1, + error: true, + }, + { + width: -1, + height: 1, + error: true, + }, + { + width: 1, + height: -1, + error: true, + }, + { + width: 0, + height: 0, + error: true, + }, + { + width: 0, + height: 1, + error: true, + }, + { + width: 1, + height: 0, + error: true, + }, + { + width: 1, + height: 1, + error: false, + }, + { + width: 4096, + height: 4096, + error: false, + }, + { + width: 4096, + height: 4097, + error: true, + }, + { + width: 4097, + height: 4096, + error: true, + }, + { + width: 4097, + height: 4097, + error: true, + }, + } + for _, size := range sizes { + _, err := NewImage(size.width, size.height, FilterNearest) + if err == nil { + if size.error { + t.Errorf("NewImage(%d, %d, ...) must cause error but not", size.width, size.height) + } + return + } else { + if !size.error { + t.Errorf("NewImage(%d, %d, ...) must not cause error but did: %s", size.width, size.height, err) + } + } + } +} diff --git a/imageimpl.go b/imageimpl.go index c6afef451..9c4fa804f 100644 --- a/imageimpl.go +++ b/imageimpl.go @@ -23,6 +23,7 @@ import ( "runtime" "sync" + "github.com/hajimehoshi/ebiten/internal/graphics" "github.com/hajimehoshi/ebiten/internal/opengl" "github.com/hajimehoshi/ebiten/internal/restorable" ) @@ -32,7 +33,27 @@ type imageImpl struct { m sync.Mutex } +func checkSize(width, height int) error { + if width <= 0 { + return fmt.Errorf("ebiten: width must be more than 0") + } + if height <= 0 { + return fmt.Errorf("ebiten: height must be more than 0") + } + if width > graphics.ImageMaxSize { + return fmt.Errorf("ebiten: width must be less than or equal to %d", graphics.ImageMaxSize) + } + if height > graphics.ImageMaxSize { + return fmt.Errorf("ebiten: height must be less than or equal to %d", graphics.ImageMaxSize) + } + return nil +} + func newImageImpl(width, height int, filter Filter, volatile bool) (*imageImpl, error) { + if err := checkSize(width, height); err != nil { + return nil, err + } + img, err := restorable.NewImage(width, height, glFilter(filter), volatile) if err != nil { return nil, err @@ -47,7 +68,10 @@ func newImageImpl(width, height int, filter Filter, volatile bool) (*imageImpl, func newImageImplFromImage(source image.Image, filter Filter) (*imageImpl, error) { size := source.Bounds().Size() w, h := size.X, size.Y - // TODO: Return error when the image is too big! + if err := checkSize(w, h); err != nil { + return nil, err + } + // Don't lock while manipulating an image.Image interface. // It is necessary to copy the source image since the actual construction of @@ -74,6 +98,10 @@ func newImageImplFromImage(source image.Image, filter Filter) (*imageImpl, error } func newScreenImageImpl(width, height int) (*imageImpl, error) { + if err := checkSize(width, height); err != nil { + return nil, err + } + img, err := restorable.NewScreenFramebufferImage(width, height) if err != nil { return nil, err diff --git a/internal/graphics/image.go b/internal/graphics/image.go index 024eb464f..9379d8a17 100644 --- a/internal/graphics/image.go +++ b/internal/graphics/image.go @@ -29,6 +29,8 @@ type Image struct { height int } +const ImageMaxSize = viewportSize + func NewImage(width, height int, filter opengl.Filter) (*Image, error) { i := &Image{ width: width,