internal/gamepaddb: bug fix: don't panic with invalid inputs

Closes #2218
This commit is contained in:
Hajime Hoshi 2022-07-29 12:13:01 +09:00
parent 10d50b885f
commit bacb630c5b
3 changed files with 84 additions and 7 deletions

View File

@ -335,7 +335,10 @@ func IsStandardGamepadLayoutAvailable(id GamepadID) bool {
// //
// UpdateStandardGamepadLayoutMappings works atomically. If an error happens, nothing is updated. // UpdateStandardGamepadLayoutMappings works atomically. If an error happens, nothing is updated.
func UpdateStandardGamepadLayoutMappings(mappings string) (bool, error) { func UpdateStandardGamepadLayoutMappings(mappings string) (bool, error) {
return gamepaddb.Update([]byte(mappings)) if err := gamepaddb.Update([]byte(mappings)); err != nil {
return false, err
}
return true, nil
} }
// TouchID represents a touch's identifier. // TouchID represents a touch's identifier.

View File

@ -92,10 +92,10 @@ var additionalGLFWGamepads = []byte(`
`) `)
func init() { func init() {
if _, err := Update(gamecontrollerdbTxt); err != nil { if err := Update(gamecontrollerdbTxt); err != nil {
panic(err) panic(err)
} }
if _, err := Update(additionalGLFWGamepads); err != nil { if err := Update(additionalGLFWGamepads); err != nil {
panic(err) panic(err)
} }
} }
@ -139,11 +139,18 @@ func parseLine(line string, platform platform) (id string, name string, buttons
return "", "", nil, nil, nil return "", "", nil, nil, nil
} }
tokens := strings.Split(line, ",") tokens := strings.Split(line, ",")
if len(tokens) < 2 {
return "", "", nil, nil, fmt.Errorf("gamepaddb: syntax error")
}
for _, token := range tokens[2:] { for _, token := range tokens[2:] {
if len(token) == 0 { if len(token) == 0 {
continue continue
} }
tks := strings.Split(token, ":") tks := strings.Split(token, ":")
if len(tks) < 2 {
return "", "", nil, nil, fmt.Errorf("gamepaddb: syntax error")
}
// Note that the platform part is listed in the definition of SDL_GetPlatform. // Note that the platform part is listed in the definition of SDL_GetPlatform.
if tks[0] == "platform" { if tks[0] == "platform" {
@ -501,7 +508,7 @@ func IsButtonPressed(id string, button StandardButton, state GamepadState) bool
// The string must be in the format of SDL_GameControllerDB. // The string must be in the format of SDL_GameControllerDB.
// //
// Update works atomically. If an error happens, nothing is updated. // Update works atomically. If an error happens, nothing is updated.
func Update(mappingData []byte) (bool, error) { func Update(mappingData []byte) error {
mappingsM.Lock() mappingsM.Lock()
defer mappingsM.Unlock() defer mappingsM.Unlock()
@ -519,11 +526,11 @@ func Update(mappingData []byte) (bool, error) {
for { for {
line, err := r.ReadString('\n') line, err := r.ReadString('\n')
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return false, err return err
} }
id, name, buttons, axes, err1 := parseLine(line, currentPlatform) id, name, buttons, axes, err1 := parseLine(line, currentPlatform)
if err1 != nil { if err1 != nil {
return false, err1 return err1
} }
if id != "" { if id != "" {
lines = append(lines, parsedLine{ lines = append(lines, parsedLine{
@ -544,7 +551,7 @@ func Update(mappingData []byte) (bool, error) {
gamepadAxisMappings[l.id] = l.axes gamepadAxisMappings[l.id] = l.axes
} }
return true, nil return nil
} }
func addAndroidDefaultMappings(id string) bool { func addAndroidDefaultMappings(id string) bool {

View File

@ -0,0 +1,67 @@
// Copyright 2022 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gamepaddb_test
import (
"testing"
"github.com/hajimehoshi/ebiten/v2/internal/gamepaddb"
)
func TestUpdate(t *testing.T) {
cases := []struct {
Input string
Err bool
}{
{
Input: "",
Err: false,
},
{
Input: "{}",
Err: true,
},
{
Input: "00000000000000000000000000000000",
Err: true,
},
{
Input: "00000000000000000000000000000000,foo",
Err: false,
},
{
Input: "00000000000000000000000000000000,foo,platform",
Err: true,
},
{
Input: "00000000000000000000000000000000,foo,pltform:Foo",
Err: true,
},
{
Input: "00000000000000000000000000000000,foo,platform:Windows",
Err: false,
},
}
for _, c := range cases {
err := gamepaddb.Update([]byte(c.Input))
if err == nil && c.Err {
t.Errorf("Update(%q) should return an error but not", c.Input)
}
if err != nil && !c.Err {
t.Errorf("Update(%q) should not return an error but returned %v", c.Input, err)
}
}
}