Skip to content

Commit 6cbdf38

Browse files
authored
fixes panic on GetArrayValueAt when OOB (#329)
1 parent af7f088 commit 6cbdf38

File tree

2 files changed

+64
-4
lines changed

2 files changed

+64
-4
lines changed

examples/Issue328_test.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package examples
2+
3+
import (
4+
"testing"
5+
6+
"github.com/hyperjumptech/grule-rule-engine/ast"
7+
"github.com/hyperjumptech/grule-rule-engine/builder"
8+
"github.com/hyperjumptech/grule-rule-engine/engine"
9+
"github.com/hyperjumptech/grule-rule-engine/pkg"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
const (
14+
SliceOORRule = `
15+
rule SliceOORRule {
16+
when
17+
PriceSlice.Prices[4] > 10 // will cause panic
18+
then
19+
Log("Price number 4 is greater than 10");
20+
Retract("SliceOORRule");
21+
}`
22+
)
23+
24+
type AUserSliceIssue struct {
25+
Prices []int
26+
}
27+
28+
func TestMethodCall_SliceOOR(t *testing.T) {
29+
ps := &AUserSliceIssue{
30+
Prices: []int{1, 2, 3},
31+
}
32+
33+
dataContext := ast.NewDataContext()
34+
err := dataContext.Add("PriceSlice", ps)
35+
assert.NoError(t, err)
36+
37+
// Prepare knowledgebase library and load it with our rule.
38+
lib := ast.NewKnowledgeLibrary()
39+
rb := builder.NewRuleBuilder(lib)
40+
err = rb.BuildRuleFromResource("Test", "0.1.1", pkg.NewBytesResource([]byte(SliceOORRule)))
41+
assert.NoError(t, err)
42+
43+
// expect no panic and no error (ReturnErrOnFailedRuleEvaluation = false)
44+
eng1 := &engine.GruleEngine{MaxCycle: 5}
45+
kb := lib.NewKnowledgeBaseInstance("Test", "0.1.1")
46+
err = eng1.Execute(dataContext, kb)
47+
assert.NoError(t, err)
48+
49+
// expect no panic and execute to return an error here
50+
eng1 = &engine.GruleEngine{MaxCycle: 5, ReturnErrOnFailedRuleEvaluation: true}
51+
kb = lib.NewKnowledgeBaseInstance("Test", "0.1.1")
52+
err = eng1.Execute(dataContext, kb)
53+
assert.Error(t, err)
54+
}

model/GoDataAccessLayer.go

+10-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ package model
1616

1717
import (
1818
"fmt"
19-
"github.com/hyperjumptech/grule-rule-engine/pkg"
2019
"reflect"
20+
21+
"github.com/hyperjumptech/grule-rule-engine/pkg"
2122
)
2223

2324
// NewGoValueNode creates new instance of ValueNode backed by golang reflection
@@ -96,9 +97,14 @@ func (node *GoValueNode) GetArrayType() (reflect.Type, error) {
9697
}
9798

9899
// GetArrayValueAt to get the value of an array element if the current underlying value is an array
99-
func (node *GoValueNode) GetArrayValueAt(index int) (reflect.Value, error) {
100+
func (node *GoValueNode) GetArrayValueAt(index int) (val reflect.Value, err error) {
100101
if node.IsArray() {
101-
return node.thisValue.Index(index), nil
102+
defer func() {
103+
if r := recover(); r != nil {
104+
err = fmt.Errorf("recovered : %v", r)
105+
}
106+
}()
107+
return node.thisValue.Index(index), err
102108
}
103109
return reflect.Value{}, fmt.Errorf("this node identified as \"%s\" is not referring to an array or slice", node.IdentifiedAs())
104110
}
@@ -350,7 +356,7 @@ func (node *GoValueNode) CallFunction(funcName string, args ...reflect.Value) (r
350356
case "Len":
351357
strfunc = StrLen
352358
case "MatchString":
353-
strfunc = StrMatchRegexPattern
359+
strfunc = StrMatchRegexPattern
354360
}
355361
if strfunc != nil {
356362
val, err := strfunc(node.thisValue.String(), args)

0 commit comments

Comments
 (0)