Skip to content

[framework] load files through ImmutableBuffer.fromFilePath (if exact file type)#112892

Merged
cbracken merged 7 commits intoflutter:masterfrom
jonahwilliams:fix_file_image_win
Oct 6, 2022
Merged

[framework] load files through ImmutableBuffer.fromFilePath (if exact file type)#112892
cbracken merged 7 commits intoflutter:masterfrom
jonahwilliams:fix_file_image_win

Conversation

@jonahwilliams
Copy link
Contributor

@jonahwilliams jonahwilliams commented Oct 4, 2022

Update FileImage to use the new ImmutableBuffer.fromFilePath constructor to avoid loading bytes through the Dart heap. As a side effect, tis fixes #112881 which prevents dart:io from opening a file larger than INT_MAX bytes on windows.

For files that are not exactly a dart:io file, we still use the old method of calling loadBytes() in order to not make this a breaking change.

@flutter-dashboard flutter-dashboard bot added the framework flutter/packages/flutter repository. See also f: labels. label Oct 4, 2022
@jonahwilliams jonahwilliams marked this pull request as ready for review October 5, 2022 00:02
@jonahwilliams
Copy link
Contributor Author

Even when we fix the linked issue, we won't be able to open files greater than INT_MAX on windows- it will just fail with an exception instead of crashing. This change is required to be able to load images this big at all

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is different than the behavior of readAsBytes(), and so may have different performance.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, this approach might have two additional copies since readInto doesn't work exactly as advertised. See the allocation of an intermediate buffer in the the implementation here https://github.com/dart-lang/sdk/blob/main/runtime/bin/file.cc#L249

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, there is really no winning here 😆 . Something that returns already sized chunks then requires us to write them into a new buffer anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is, I don't see a way to do this using the dart:io APIs that doesn't involve two copies. Maybe I should apply this strategy only after a certain file size threshold?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have an issue filed for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@jonahwilliams
Copy link
Contributor Author

Maybe lets just see if we can land flutter/engine#36623 first. Then use that new API instead, which doesn't have the problem dart:io does

@jonahwilliams jonahwilliams marked this pull request as draft October 5, 2022 18:31
@jonahwilliams jonahwilliams changed the title [framework] dont load file bytes all at once in FileImage [framework] load files through ImmutableBuffer.fromFilePath (if exact file type) Oct 6, 2022
@jonahwilliams jonahwilliams marked this pull request as ready for review October 6, 2022 07:12
Copy link
Member

@zanderso zanderso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm but wondering if it's easy to expand test coverage.

final Uint8List bytes = await file.readAsBytes();
if (bytes.lengthInBytes == 0) {
final int lengthInBytes = file.lengthSync();
if (lengthInBytes == 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there test coverage of the == 0 case?

Copy link
Member

@cbracken cbracken Oct 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the test failure title, it appears that one of the failures is from such a case:

03:52 +6199 ~13 -1: /b/s/w/ir/x/w/flutter/packages/flutter/test/painting/image_provider_test.dart: File image with empty file throws expected error and evicts from cache [E]                          
  Expected: <true>
    Actual: <false>
  
  package:test_api                                    expect
  package:flutter_test/src/widget_tester.dart 460:16  expect
  test/painting/image_provider_test.dart 77:5         main.<fn>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we have a test that covers this. Interestingly if fails if I use the sync length method: #113044


if (decode != null) {
return decode(await ui.ImmutableBuffer.fromUint8List(bytes));
if (file.runtimeType == File) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to have test coverage of the != File case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of the existing tests use a MemoryFileSystem entity, so they would break without this change

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall lgtm for the approach; looks like there's a test failure related to empty files that needs dealing with.

@jonahwilliams jonahwilliams added the autosubmit Merge PR when tree becomes green via auto submit App label Oct 6, 2022
@dnfield
Copy link
Contributor

dnfield commented Oct 6, 2022

The next magic trick should be ImmutableBuffer.fromNetwork that somehow returns chunk events.

Copy link
Member

@cbracken cbracken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM stamp from a Japanese personal seal

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Oct 7, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Oct 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Flutter crashes when loading very large files with Image.file widget on Windows

4 participants