From e1386e2032debfd0a57af425afa8bb5fbfe29404 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Thu, 23 Mar 2023 21:03:16 +0900 Subject: [PATCH] ebiten: add restrictions for values in indices at DrawTriangles* Closes #2611 --- image.go | 25 +++++++++++++-- image_test.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) diff --git a/image.go b/image.go index e1ded5bba..ae11f8601 100644 --- a/image.go +++ b/image.go @@ -400,6 +400,9 @@ const MaxIndicesCount = (1 << 16) / 3 * 3 // Deprecated: as of v2.4. This constant is no longer used. const MaxIndicesNum = MaxIndicesCount +// MaxVerticesCount is the maximum number of vertices for DrawTriangles and DrawTrianglesShader. +const MaxVerticesCount = graphics.MaxVerticesCount + // DrawTriangles draws triangles with the specified vertices and their indices. // // img is used as a source image. img cannot be nil. @@ -412,6 +415,8 @@ const MaxIndicesNum = MaxIndicesCount // // If len(indices) is not multiple of 3, DrawTriangles panics. // +// If a value in indices is out of range of vertices, or not less than MaxVerticesCount, DrawTriangles panics. +// // The rule in which DrawTriangles works effectively is same as DrawImage's. // // When the given image is disposed, DrawTriangles panics. @@ -430,7 +435,14 @@ func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, o if len(indices)%3 != 0 { panic("ebiten: len(indices) % 3 must be 0") } - // TODO: Check the maximum value of indices and len(vertices)? + for _, idx := range indices { + if int(idx) >= len(vertices) { + panic(fmt.Sprintf("ebiten: a value in indices must be less than len(vertices) (%d) but was %d", len(vertices), idx)) + } + if idx >= MaxVerticesCount { + panic(fmt.Sprintf("ebiten: a value in indices must be less than MaxVerticesCount %d but was %d", MaxVerticesCount, idx)) + } + } if options == nil { options = &DrawTrianglesOptions{} @@ -553,6 +565,8 @@ var _ [len(DrawTrianglesShaderOptions{}.Images) - graphics.ShaderImageCount]stru // // If len(indices) is not multiple of 3, DrawTrianglesShader panics. // +// If a value in indices is out of range of vertices, or not less than MaxVerticesCount, DrawTrianglesShader panics. +// // When a specified image is non-nil and is disposed, DrawTrianglesShader panics. // // When the image i is disposed, DrawTrianglesShader does nothing. @@ -566,7 +580,14 @@ func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader if len(indices)%3 != 0 { panic("ebiten: len(indices) % 3 must be 0") } - // TODO: Check the maximum value of indices and len(vertices)? + for _, idx := range indices { + if int(idx) >= len(vertices) { + panic(fmt.Sprintf("ebiten: a value in indices must be less than len(vertices) (%d) but was %d", len(vertices), idx)) + } + if idx >= MaxVerticesCount { + panic(fmt.Sprintf("ebiten: a value in indices must be less than MaxVerticesCount %d but was %d", MaxVerticesCount, idx)) + } + } if options == nil { options = &DrawTrianglesShaderOptions{} diff --git a/image_test.go b/image_test.go index efac6fa77..1755bcbba 100644 --- a/image_test.go +++ b/image_test.go @@ -4119,3 +4119,87 @@ func TestImageSetAndSubImage(t *testing.T) { t.Errorf("got: %v, want: %v", got, want) } } + +// Issue #2611 +func TestImageDrawTrianglesWithGreaterIndexThanVerticesCount(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("DrawTriangles must panic but not") + } + }() + + const w, h = 16, 16 + dst := ebiten.NewImage(w, h) + src := ebiten.NewImage(w, h) + + vs := make([]ebiten.Vertex, 4) + is := []uint16{0, 1, 2, 1, 2, 4} + dst.DrawTriangles(vs, is, src, nil) +} + +// Issue #2611 +func TestImageDrawTrianglesShaderWithGreaterIndexThanVerticesCount(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("DrawTrianglesShader must panic but not") + } + }() + + const w, h = 16, 16 + dst := ebiten.NewImage(w, h) + + vs := make([]ebiten.Vertex, 4) + is := []uint16{0, 1, 2, 1, 2, 4} + shader, err := ebiten.NewShader([]byte(` + package main + func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return color + } + `)) + if err != nil { + t.Fatalf("could not compile shader: %v", err) + } + dst.DrawTrianglesShader(vs, is, shader, nil) +} + +// Issue #2611 +func TestImageDrawTrianglesWithTooBigIndex(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("DrawTriangles must panic but not") + } + }() + + const w, h = 16, 16 + dst := ebiten.NewImage(w, h) + src := ebiten.NewImage(w, h) + + vs := make([]ebiten.Vertex, ebiten.MaxVerticesCount+1) + is := []uint16{0, 1, 2, 1, 2, ebiten.MaxVerticesCount} + dst.DrawTriangles(vs, is, src, nil) +} + +// Issue #2611 +func TestImageDrawTrianglesShaderWithTooBigIndex(t *testing.T) { + defer func() { + if r := recover(); r == nil { + t.Errorf("DrawTrianglesShader must panic but not") + } + }() + + const w, h = 16, 16 + dst := ebiten.NewImage(w, h) + + vs := make([]ebiten.Vertex, ebiten.MaxVerticesCount+1) + is := []uint16{0, 1, 2, 1, 2, ebiten.MaxVerticesCount} + shader, err := ebiten.NewShader([]byte(` + package main + func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + return color + } + `)) + if err != nil { + t.Fatalf("could not compile shader: %v", err) + } + dst.DrawTrianglesShader(vs, is, shader, nil) +}