diff options
author | Hiroya Fujinami <[email protected]> | 2023-10-25 16:32:25 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2023-10-25 16:32:25 +0900 |
commit | 3e64cf60b5162bb5dad772f300b7f6346e5f83f9 (patch) | |
tree | cb59d29a745028a5c55f108d665cb93c6585a4ff /enumerator.c | |
parent | a6a67b0524ec3f8da96143cdf5094b5eaf7d820d (diff) |
Fix [Bug #19632]: Disable external iterator for frozen enumerator (#7791)
* Fix [Bug #19632]: Disable external iterator for frozen enumerator
Currently, methods to manipulate an external iterator like `#next`
and `#feed` can be called even if a receiver of an enumerator is
frozen. However, these methods change the state of an external
iterator in an enumerator. Therefore, it seems a BUG to me, and
these methods should raise FrozenError if the receiver is frozen.
This fixed the following methods to raise FrozenError if the receiver is
frozen.
- `Enumerator#next`
- `Enumerator#next_values`
- `Enumerator#peek`
- `Enumerator#peek_values`
- `Enumerator#feed`
- `Enumerator#rewind`
* Fix a typo in the document
Thanks @Maumagnaguagno.
Diffstat (limited to 'enumerator.c')
-rw-r--r-- | enumerator.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/enumerator.c b/enumerator.c index 252333f303..0e010c14c2 100644 --- a/enumerator.c +++ b/enumerator.c @@ -85,12 +85,16 @@ * puts e.next # => 3 * puts e.next # raises StopIteration * - * +next+, +next_values+, +peek+ and +peek_values+ are the only methods - * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+). + * +next+, +next_values+, +peek+, and +peek_values+ are the only methods + * which use external iteration (and Array#zip(Enumerable-not-Array) which uses +next+ internally). * * These methods do not affect other internal enumeration methods, * unless the underlying iteration method itself has side-effect, e.g. IO#each_line. * + * FrozenError will be raised if these methods are called against a frozen enumerator. + * Since +rewind+ and +feed+ also change state for external iteration, + * these methods may raise FrozenError too. + * * External iteration differs *significantly* from internal iteration * due to using a Fiber: * - The Fiber adds some overhead compared to internal enumeration. @@ -869,6 +873,8 @@ enumerator_next_values(VALUE obj) struct enumerator *e = enumerator_ptr(obj); VALUE vs; + rb_check_frozen(obj); + if (!UNDEF_P(e->lookahead)) { vs = e->lookahead; e->lookahead = Qundef; @@ -930,6 +936,8 @@ enumerator_peek_values(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); + rb_check_frozen(obj); + if (UNDEF_P(e->lookahead)) { e->lookahead = get_next_values(obj, e); } @@ -1054,6 +1062,8 @@ enumerator_feed(VALUE obj, VALUE v) { struct enumerator *e = enumerator_ptr(obj); + rb_check_frozen(obj); + if (!UNDEF_P(e->feedvalue)) { rb_raise(rb_eTypeError, "feed value already set"); } @@ -1076,6 +1086,8 @@ enumerator_rewind(VALUE obj) { struct enumerator *e = enumerator_ptr(obj); + rb_check_frozen(obj); + rb_check_funcall(e->obj, id_rewind, 0, 0); e->fib = 0; |