interp: report 'unreachable' instruction as an error

This instruction should never be hit in real programs, but the
interpreter may hit it after a call to panic(). This would always be a
runtime error.
Этот коммит содержится в:
Ayke van Laethem 2018-12-01 16:16:11 +01:00
родитель cea0a5977a
коммит 469193735a
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E97FF5335DFDFDED
2 изменённых файлов: 12 добавлений и 5 удалений

Просмотреть файл

@ -17,6 +17,8 @@ type frame struct {
locals map[llvm.Value]Value
}
var ErrUnreachable = errors.New("interp: unreachable executed")
// evalBasicBlock evaluates a single basic block, returning the return value (if
// ending with a ret instruction), a list of outgoing basic blocks (if not
// ending with a ret instruction), or an error on failure.
@ -303,8 +305,10 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
case callee.Name() == "runtime.makeInterface":
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstPtrToInt(inst.Operand(0), fr.TargetData.IntPtrType())}
case strings.HasPrefix(callee.Name(), "runtime.print") || callee.Name() == "runtime._panic":
// all print instructions, which necessarily have side
// effects but no results
// This are all print instructions, which necessarily have side
// effects but no results.
// TODO: print an error when executing runtime._panic (with the
// exact error message it would print at runtime).
var params []llvm.Value
for i := 0; i < inst.OperandsCount()-1; i++ {
operand := fr.getLocal(inst.Operand(i)).Value()
@ -428,9 +432,9 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
// unconditional branch (goto)
return nil, []llvm.Value{inst.Operand(0)}, nil
case !inst.IsAUnreachableInst().IsNil():
// unreachable was reached (e.g. after a call to panic())
// assume this is actually unreachable when running
return &LocalValue{fr.Eval, llvm.Undef(fr.fn.Type())}, nil, nil
// Unreachable was reached (e.g. after a call to panic()).
// Report this as an error, as it is not supposed to happen.
return nil, nil, ErrUnreachable
default:
return nil, nil, &Unsupported{inst}

Просмотреть файл

@ -63,6 +63,9 @@ func Run(mod llvm.Module, targetData llvm.TargetData, debug bool) error {
}
pkgName := initName[:len(initName)-5]
_, err := e.Function(call.CalledValue(), nil, pkgName)
if err == ErrUnreachable {
break
}
if err != nil {
return err
}