| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 6c2e052 commit fe36778
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -346,6 +346,31 @@ def spam(state=[0]): | |||
| 346 | 346 | return i | |
| 347 | 347 | self.check_iterator(iter(spam, 20), list(range(10)), pickle=False) | |
| 348 | 348 | ||
| 349 | + def test_iter_function_concealing_reentrant_exhaustion(self): | ||
| 350 | + # gh-101892: Test two-argument iter() with a function that | ||
| 351 | + # exhausts its associated iterator but forgets to either return | ||
| 352 | + # a sentinel value or raise StopIteration. | ||
| 353 | + HAS_MORE = 1 | ||
| 354 | + NO_MORE = 2 | ||
| 355 | + | ||
| 356 | + def exhaust(iterator): | ||
| 357 | + """Exhaust an iterator without raising StopIteration.""" | ||
| 358 | + list(iterator) | ||
| 359 | + | ||
| 360 | + def spam(): | ||
| 361 | + # Touching the iterator with exhaust() below will call | ||
| 362 | + # spam() once again so protect against recursion. | ||
| 363 | + if spam.is_recursive_call: | ||
| 364 | + return NO_MORE | ||
| 365 | + spam.is_recursive_call = True | ||
| 366 | + exhaust(spam.iterator) | ||
| 367 | + return HAS_MORE | ||
| 368 | + | ||
| 369 | + spam.is_recursive_call = False | ||
| 370 | + spam.iterator = iter(spam, NO_MORE) | ||
| 371 | + with self.assertRaises(StopIteration): | ||
| 372 | + next(spam.iterator) | ||
| 373 | + | ||
| 349 | 374 | # Test exception propagation through function iterator | |
| 350 | 375 | def test_exception_function(self): | |
| 351 | 376 | def spam(state=[0]): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Callable iterators no longer raise :class:`SystemError` when the | ||
| 2 | + callable object exhausts the iterator but forgets to either return a | ||
| 3 | + sentinel value or raise :class:`StopIteration`. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -223,15 +223,14 @@ calliter_iternext(calliterobject *it) | |||
| 223 | 223 | } | |
| 224 | 224 | ||
| 225 | 225 | result = _PyObject_CallNoArg(it->it_callable); | |
| 226 | - if (result != NULL) { | ||
| 226 | + if (result != NULL && it->it_sentinel != NULL){ | ||
| 227 | 227 | int ok; | |
| 228 | 228 | ||
| 229 | 229 | ok = PyObject_RichCompareBool(it->it_sentinel, result, Py_EQ); | |
| 230 | 230 | if (ok == 0) { | |
| 231 | 231 | return result; /* Common case, fast path */ | |
| 232 | 232 | } | |
| 233 | 233 | ||
| 234 | - Py_DECREF(result); | ||
| 235 | 234 | if (ok > 0) { | |
| 236 | 235 | Py_CLEAR(it->it_callable); | |
| 237 | 236 | Py_CLEAR(it->it_sentinel); | |
@@ -242,6 +241,7 @@ calliter_iternext(calliterobject *it) | |||
| 242 | 241 | Py_CLEAR(it->it_callable); | |
| 243 | 242 | Py_CLEAR(it->it_sentinel); | |
| 244 | 243 | } | |
| 244 | + Py_XDECREF(result); | ||
| 245 | 245 | return NULL; | |
| 246 | 246 | } | |
| 247 | 247 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments