Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

recover panics raised by make() #278

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions engine/atom.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ var (
atomMax = NewAtom("max")
atomMaxArity = NewAtom("max_arity")
atomMaxInteger = NewAtom("max_integer")
atomMemory = NewAtom("memory")
atomMin = NewAtom("min")
atomMinInteger = NewAtom("min_integer")
atomMod = NewAtom("mod")
Expand Down
23 changes: 17 additions & 6 deletions engine/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,10 @@ func Functor(vm *VM, t, name, arity Term, k Cont, env *Env) *Promise {
return Error(typeError(validTypeAtom, name, env))
}

vs := make([]Term, arity)
vs, err := makeTermSlice(int(arity))
if err != nil {
return Error(resourceError(resourceMemory, env))
}
for i := range vs {
vs[i] = NewVariable()
}
Expand Down Expand Up @@ -2761,7 +2764,7 @@ func Length(vm *VM, list, length Term, k Cont, env *Env) *Promise {
return Error(resourceError(resourceFiniteMemory, env))
}

return lengthAddendum(vm, atomEmptyList, skipped, suffix, n, k, env)
return lengthAddendum(vm, 0, skipped, suffix, n, k, env)
case Atom: // list or non-list terminated by an atom
if suffix != atomEmptyList {
return Bool(false)
Expand All @@ -2785,23 +2788,31 @@ func Length(vm *VM, list, length Term, k Cont, env *Env) *Promise {
}

func lengthRundown(vm *VM, list Variable, n Integer, k Cont, env *Env) *Promise {
elems := make([]Term, n)
elems, err := makeTermSlice(int(n))
if err != nil {
return Error(resourceError(resourceMemory, env))
}
for i := range elems {
elems[i] = NewVariable()
}
return Unify(vm, list, List(elems...), k, env)
}

func lengthAddendum(vm *VM, suffix Term, offset Integer, list, length Variable, k Cont, env *Env) *Promise {
func lengthAddendum(vm *VM, n, offset Integer, list, length Variable, k Cont, env *Env) *Promise {
suffix, err := freshVarList(int(n))
if err != nil {
return Error(err)
}

return Delay(func(context.Context) *Promise {
return Unify(vm, tuple(list, length), tuple(suffix, offset), k, env)
}, func(context.Context) *Promise {
suffix := atomDot.Apply(NewVariable(), suffix)
n, _ := addI(n, 1)
offset, err := addI(offset, 1)
if err != nil {
return Error(representationError(flagMaxInteger, env))
}
return lengthAddendum(vm, suffix, offset, list, length, k, env)
return lengthAddendum(vm, n, offset, list, length, k, env)
})
}

Expand Down
15 changes: 15 additions & 0 deletions engine/compound.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,21 @@ func List(ts ...Term) Term {
return list(ts)
}

func freshVarList(n int) (Term, error) {
if n == 0 {
return atomEmptyList, nil
}

ts, err := makeTermSlice(n)
if err != nil {
return nil, err
}
for i := range ts {
ts[i] = NewVariable()
}
return list(ts), nil
}

type partial struct {
Compound
tail *Term
Expand Down
3 changes: 3 additions & 0 deletions engine/exception.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,13 @@ type resource uint8
// resource is one of these values.
const (
resourceFiniteMemory resource = iota

resourceMemory
)

var resourceAtoms = [...]Atom{
resourceFiniteMemory: atomFiniteMemory,
resourceMemory: atomMemory,
}

// Term returns an Atom for the resource.
Expand Down
12 changes: 12 additions & 0 deletions engine/term.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package engine

import (
"errors"
"io"
"reflect"
"strconv"
Expand Down Expand Up @@ -485,3 +486,14 @@ func id(t Term) termID {
return t // Assuming it's comparable.
}
}

var errTooLarge = errors.New("too large")

func makeTermSlice(n int) (_ []Term, err error) {
defer func() {
if recover() != nil {
err = errTooLarge
}
}()
return make([]Term, n, n), nil
}