Skip to content

Commit f9413ab

Browse files
committed
Do not allow to override builtin function
1 parent d6ddf08 commit f9413ab

File tree

4 files changed

+68
-3
lines changed

4 files changed

+68
-3
lines changed

builtin/builtin.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,19 @@ import (
1212
)
1313

1414
type Function struct {
15-
Name string
16-
Func func(args ...interface{}) (interface{}, error)
15+
Name string
16+
Func func(args ...interface{}) (interface{}, error)
17+
Types []reflect.Type
18+
19+
builtin bool // true if function is builtin
1720
Builtin1 func(arg interface{}) interface{}
18-
Types []reflect.Type
1921
Validate func(args []reflect.Type) (reflect.Type, error)
2022
}
2123

24+
func (f Function) Builtin() bool {
25+
return f.builtin
26+
}
27+
2228
var (
2329
Index map[string]int
2430
Names []string
@@ -28,6 +34,7 @@ func init() {
2834
Index = make(map[string]int)
2935
Names = make([]string, len(Functions))
3036
for i, fn := range Functions {
37+
fn.builtin = true
3138
Index[fn.Name] = i
3239
Names[i] = fn.Name
3340
}

builtin/builtin_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,34 @@ func TestBuiltin_memory_limits(t *testing.T) {
187187
})
188188
}
189189
}
190+
191+
func TestBuiltin_disallow_builtins_override(t *testing.T) {
192+
t.Run("via env", func(t *testing.T) {
193+
env := map[string]interface{}{
194+
"len": func() int { return 42 },
195+
"repeat": func(a string) string {
196+
return a
197+
},
198+
}
199+
assert.Panics(t, func() {
200+
_, _ = expr.Compile(`string(len("foo")) + repeat("0", 2)`, expr.Env(env))
201+
})
202+
})
203+
t.Run("via expr.Function", func(t *testing.T) {
204+
length := expr.Function("len",
205+
func(params ...interface{}) (interface{}, error) {
206+
return 42, nil
207+
},
208+
new(func() int),
209+
)
210+
repeat := expr.Function("repeat",
211+
func(params ...interface{}) (interface{}, error) {
212+
return params[0], nil
213+
},
214+
new(func(string) string),
215+
)
216+
assert.Panics(t, func() {
217+
_, _ = expr.Compile(`string(len("foo")) + repeat("0", 2)`, length, repeat)
218+
})
219+
})
220+
}

conf/config.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,24 @@ func (c *Config) Check() {
9595
}
9696
}
9797
}
98+
for name, t := range c.Types {
99+
if kind(t.Type) != reflect.Func {
100+
continue
101+
}
102+
for _, b := range builtin.Names {
103+
if b == name {
104+
panic(fmt.Errorf(`cannot override builtin %s(); it is already defined in expr`, name))
105+
}
106+
}
107+
}
108+
for _, f := range c.Functions {
109+
if f.Builtin() {
110+
continue
111+
}
112+
for _, b := range builtin.Names {
113+
if b == f.Name {
114+
panic(fmt.Errorf(`cannot override builtin %s(); it is already defined in expr`, f.Name))
115+
}
116+
}
117+
}
98118
}

conf/types_table.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ func dereference(t reflect.Type) reflect.Type {
121121
return t
122122
}
123123

124+
func kind(t reflect.Type) reflect.Kind {
125+
if t == nil {
126+
return reflect.Invalid
127+
}
128+
return t.Kind()
129+
}
130+
124131
func FieldName(field reflect.StructField) string {
125132
if taggedName := field.Tag.Get("expr"); taggedName != "" {
126133
return taggedName

0 commit comments

Comments
 (0)