Skip to content

Commit 2ee660c

Browse files
committed
Make map() and zip() clean up after StopIteration
This came to light because of this issue report: google/grumpy#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.
1 parent 06480b5 commit 2ee660c

File tree

2 files changed

+11
-2
lines changed

2 files changed

+11
-2
lines changed

runtime/builtin_types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -732,9 +732,9 @@ Outer:
732732
elem, raised := Next(f, iter)
733733
if raised != nil {
734734
if raised.isInstance(StopIterationType) {
735+
f.RestoreExc(nil, nil)
735736
break Outer
736737
}
737-
f.RestoreExc(nil, nil)
738738
return nil, raised
739739
}
740740
elems[i] = elem
@@ -929,9 +929,9 @@ func zipLongest(f *Frame, args Args) ([][]*Object, *BaseException) {
929929
if raised.isInstance(StopIterationType) {
930930
iters[i] = nil
931931
elems[i] = None
932+
f.RestoreExc(nil, nil)
932933
continue
933934
}
934-
f.RestoreExc(nil, nil)
935935
return nil, raised
936936
}
937937
noItems = false

testing/builtin_test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,3 +385,12 @@ class Foo(object):
385385
assert str(e) == "unsupported operand type(s) for divmod(): 'str' and 'str'"
386386
else:
387387
assert AssertionError
388+
389+
# Check for a bug where zip() and map() were not properly cleaning their
390+
# internal exception state. See:
391+
# https://github.com/google/grumpy/issues/305
392+
sys.exc_clear()
393+
zip((1, 3), (2, 4))
394+
assert not any(sys.exc_info())
395+
map(int, (1, 2, 3))
396+
assert not any(sys.exc_info())

0 commit comments

Comments
 (0)