Skip to content

Breaking-Change-Request: Fix StreamIterator accepting null as stream. #36382

Closed
@lrhn

Description

The StreamIterator class in dart:async accepts null as a constructor argument. This acts the same as an empty stream.
The constructor is not documented as accepting null, it was not intended and may be hiding bugs.

The scope of the bug is increased by the StreamIterator class being used internally by some platforms as part of the implementation of await for loops. This means that await for (var x in null) ... is accepted without error. Again, this was not intended, and may be hiding actual bugs.

When we introduce non-nullable types, the StreamIterator constructor will be changed to requiring a non-nullable argument, and await for will require a non-nullable type for its stream operand. That will turn the current (missing) run-time error into a compile-time error.
This also means that the current behavior cannot be retained in the longer term, even if we wanted to avoid changing the behavior right now. So, we choose to fix the bug as soon as possible.

We can delay the change until the launch of non-nullable types, but that would introduce one more thing to check as part of the non-null migration, a subtle problem that might drown in other migration issues.
We think it will be better to fix this up-front while the problem is easily detectable independently of other changes.

Planned Change

See planned fix CL: https://dart-review.googlesource.com/c/sdk/+/98001

The StreamIterator constructor will check its argument for being null, and throw an ArgumentError if it receives a null. This will turn the current behavior on a null stream into a run-time error.
This will also propagate to the language implementation uses, so await for with a null stream will also throw at run-time.

Expected Impact

It is not expected that there is any code deliberately depending on the incorrect behavior.
There is a CL ready to land which will fix the problem. We will run this against available source to see how much breakage it will cause.

Mitigation

Any place where a null value can be the argument to the StreamIterator constructor or the stream operand of an await for loop, just add ?? Stream.empty() to the expression.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

area-core-librarySDK core library issues (core, async, ...); use area-vm or area-web for platform specific libraries.area-languageDart language related items (some items might be better tracked at github.com/dart-lang/language).breaking-change-requestThis tracks requests for feedback on breaking changeslibrary-async

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions