Skip to content

Commit 3f6c14d

Browse files
fangerertimfel
authored andcommitted
Fix: use fresh copy of generator arguments on every invocation.
1 parent fd1f8eb commit 3f6c14d

File tree

1 file changed

+34
-5
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator

1 file changed

+34
-5
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/generator/GeneratorBuiltins.java

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,40 @@
8282
@CoreFunctions(extendClasses = PythonBuiltinClassType.PGenerator)
8383
public class GeneratorBuiltins extends PythonBuiltins {
8484

85+
/**
86+
* Creates a fresh copy of the generator arguments to be used for the next invocation of the
87+
* generator. This is necessary to avoid persisting caller state. For example: If the generator
88+
* is invoked using {@code next(g)} outside of any {@code except} handler but the generator
89+
* requests the exception state, then the exception state will be written into the arguments. If
90+
* we now use the same arguments array every time, the next invocation would think that there is
91+
* not excepion but in fact, the a subsequent call ot {@code next} may have a different
92+
* exception state.
93+
*
94+
* <pre>
95+
* g = my_generator()
96+
*
97+
* # invoke without any exception context
98+
* next(g)
99+
*
100+
* try:
101+
* raise ValueError
102+
* except ValueError:
103+
* # invoke with exception context
104+
* next(g)
105+
* </pre>
106+
*
107+
* This is necessary for correct chaining of exceptions.
108+
*/
109+
private static Object[] prepareArguments(PGenerator self) {
110+
Object[] generatorArguments = self.getArguments();
111+
Object[] arguments = new Object[generatorArguments.length];
112+
PythonUtils.arraycopy(generatorArguments, 0, arguments, 0, arguments.length);
113+
return arguments;
114+
}
115+
85116
private static Object resumeGenerator(PGenerator self) {
86117
try {
87-
return self.getCurrentCallTarget().call(self.getArguments());
118+
return self.getCurrentCallTarget().call(prepareArguments(self));
88119
} catch (PException e) {
89120
self.markAsFinished();
90121
throw e;
@@ -133,8 +164,7 @@ public Object nextCached(VirtualFrame frame, PGenerator self,
133164
throw raise(StopIteration);
134165
}
135166
try {
136-
Object[] arguments = self.getArguments();
137-
return call.execute(frame, null, null, arguments);
167+
return call.execute(frame, null, null, prepareArguments(self));
138168
} catch (PException e) {
139169
self.markAsFinished();
140170
throw e;
@@ -150,8 +180,7 @@ public Object next(VirtualFrame frame, PGenerator self,
150180
throw raise(StopIteration);
151181
}
152182
try {
153-
Object[] arguments = self.getArguments();
154-
return call.execute(frame, self.getCurrentCallTarget(), arguments);
183+
return call.execute(frame, self.getCurrentCallTarget(), prepareArguments(self));
155184
} catch (PException e) {
156185
self.markAsFinished();
157186
throw e;

0 commit comments

Comments
 (0)