aboutsummaryrefslogtreecommitdiffstats
path: root/enumerator.c
diff options
context:
space:
mode:
authorHiroya Fujinami <make.just.on@gmail.com>2023-10-25 16:32:25 +0900
committerGitHub <noreply@github.com>2023-10-25 16:32:25 +0900
commit3e64cf60b5162bb5dad772f300b7f6346e5f83f9 (patch)
treecb59d29a745028a5c55f108d665cb93c6585a4ff /enumerator.c
parenta6a67b0524ec3f8da96143cdf5094b5eaf7d820d (diff)
downloadruby-3e64cf60b5162bb5dad772f300b7f6346e5f83f9.tar.gz
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.c16
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;