Commit e97a8ec0 authored by Dylan Trotter's avatar Dylan Trotter

Make map() and zip() clean up after StopIteration

This came to light because of this issue report:
https://github.com/google/grumpy/issues/305

Basically, map() and zip() were detecting StopIteration but were calling
ExcRestore(nil, nil) in the wrong place, so under normal circumstances,
exc info would be set to StopIteration after they returned.

Normally this would not cause a problem, but the code in the bug report
was calling a native function (time.Now()) subsequent to a map() and
nativeInvoke checks ExcInfo() to determine whether the Go function
manually triggered an exception. See:

https://github.com/google/grumpy/blob/master/runtime/native.go#L572

In this case, nativeInvoke was being fooled because exc info had been
set previously. nativeInvoke should probably be smarter about this by
resetting the exception before the native call.
parent 400ecd24
......@@ -732,9 +732,9 @@ Outer:
elem, raised := Next(f, iter)
if raised != nil {
if raised.isInstance(StopIterationType) {
f.RestoreExc(nil, nil)
break Outer
}
f.RestoreExc(nil, nil)
return nil, raised
}
elems[i] = elem
......@@ -929,9 +929,9 @@ func zipLongest(f *Frame, args Args) ([][]*Object, *BaseException) {
if raised.isInstance(StopIterationType) {
iters[i] = nil
elems[i] = None
f.RestoreExc(nil, nil)
continue
}
f.RestoreExc(nil, nil)
return nil, raised
}
noItems = false
......
......@@ -385,3 +385,12 @@ except TypeError as e:
assert str(e) == "unsupported operand type(s) for divmod(): 'str' and 'str'"
else:
assert AssertionError
# Check for a bug where zip() and map() were not properly cleaning their
# internal exception state. See:
# https://github.com/google/grumpy/issues/305
sys.exc_clear()
zip((1, 3), (2, 4))
assert not any(sys.exc_info())
map(int, (1, 2, 3))
assert not any(sys.exc_info())
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment