Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent native blob resource from being de-allocated prematurely #31392

Closed
wants to merge 2 commits into from
Closed

Prevent native blob resource from being de-allocated prematurely #31392

wants to merge 2 commits into from

Conversation

awinograd
Copy link
Contributor

Summary

This PR prevents blob data from being prematurely de-allocated in native code when using slice to create views into an existing blob. Currently, whenever a new blob is created via createFromOptions, BlobManager.js creates a new blobCollector object since options.__collector is never provided.

// Reuse the collector instance when creating from an existing blob.
// This will make sure that the underlying resource is only deallocated
// when all blobs that refer to it are deallocated.
options.__collector == null
? {
...options,
__collector: createBlobCollector(options.blobId),
}
: options,

When the reference to a blobCollector is garbage collected, the corresponding native memory for the blob data is de-allocated.

RCTBlobCollector::~RCTBlobCollector() {
RCTBlobManager *blobManager = blobManager_;
NSString *blobId = [NSString stringWithUTF8String:blobId_.c_str()];
dispatch_async([blobManager_ methodQueue], ^{
[blobManager remove:blobId];
});
}

Since, blob.slice() is supposed to create a new view onto the same binary data as the original blob, we need to re-use the same collector object when slicing so that it is not GC'd until the last reference to the binary data is no longer reachable. Currently, since each blob slice gets a new blobCollector object, the memory is de-allocated when the first blob is GC'd.

Fixes #29970
Fixes #27857

Changelog

[iOS] [Fixed] - Blob data is no longer prematurely deallocated when using blob.slice

Test Plan

I could use help coming up with a test plan here. I could add a referential equality check for the blob.data.__collector in Blob-test but it doesn't seem quite right to be testing the implementation detail there.

@facebook-github-bot facebook-github-bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Apr 20, 2021
Copy link

@analysis-bot analysis-bot left a comment

Choose a reason for hiding this comment

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

Code analysis results:

  • eslint found some issues. Run yarn lint --fix to automatically fix problems.

Libraries/Blob/Blob.js Outdated Show resolved Hide resolved
Libraries/Blob/Blob.js Outdated Show resolved Hide resolved
@analysis-bot
Copy link

analysis-bot commented Apr 20, 2021

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 7,104,346 +41
android hermes armeabi-v7a 6,473,107 +40
android hermes x86 7,522,621 +40
android hermes x86_64 7,381,045 +37
android jsc arm64-v8a 8,971,785 +7
android jsc armeabi-v7a 7,703,213 +5
android jsc x86 9,034,393 +6
android jsc x86_64 9,511,776 -3

Base commit: e509007
Branch: main

@analysis-bot
Copy link

analysis-bot commented Apr 20, 2021

Platform Engine Arch Size (bytes) Diff
ios - universal n/a --

Base commit: 322a796
Branch: main

@react-native-bot react-native-bot added Bug Platform: iOS iOS applications. labels Oct 1, 2021
@facebook-github-bot facebook-github-bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Mar 28, 2022
@lachenmayer
Copy link

Hi there, we have been facing this issue for quite a while. We are using a resumable/chunked upload client called tus which uses Blob#slice() under the hood (see tus/tus-js-client#326 for a detailed bug report).

We have been applying this patch (using patch-package) for several months now, and we can confirm that it works. Also a bit unclear how you would test something like this other than saying it has massively reduced our crash rate :)

Without the patch we consistently see crashes with a *** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0] exception.

One of my team members implemented a repro here if anyone is interested: samal-rasmussen/tus-js-client-slice-bug@112843b

@awinograd
Copy link
Contributor Author

@kelset sorry to bother you with a ping, but would be great to get some 👁️ on this PR. Is there anything I can do to entice a maintainer to take a look?

Since `blob.slice()` creates a new view onto the same binary
data as the original blob, we should re-use the same collector
object so that the underlying resource gets deallocated when
the last view into the data is released, not the first.
@facebook-github-bot
Copy link
Contributor

@cortinico has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator.

@pull-bot
Copy link

pull-bot commented Dec 5, 2022

PR build artifact for d064dfe is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@pull-bot
Copy link

pull-bot commented Dec 5, 2022

PR build artifact for d064dfe is ready.
To use, download tarball from "Artifacts" tab in this CircleCI job then run yarn add <path to tarball> in your React Native project.

@github-actions
Copy link

github-actions bot commented Dec 5, 2022

This pull request was successfully merged by @awinograd in 36cc71a.

When will my fix make it into a release? | Upcoming Releases

@github-actions github-actions bot added the Merged This PR has been merged. label Dec 5, 2022
@awinograd
Copy link
Contributor Author

Thank you @kelset @cortinico for pushing this PR forward and getting it merged. Much appreciated!

@awinograd awinograd deleted the patch-1 branch December 5, 2022 15:47
kelset pushed a commit that referenced this pull request Mar 28, 2023
)

Summary:
This PR prevents blob data from being prematurely de-allocated in native code when using slice to create views into an existing blob. Currently, whenever a new blob is created via createFromOptions, BlobManager.js creates a new blobCollector object since options.__collector is never provided.

https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/Libraries/Blob/BlobManager.js#L115-L123

When the reference to a blobCollector is garbage collected, the corresponding native memory for the blob data is de-allocated.

https://github.com/facebook/react-native/blob/27651720b40cab564a0cbd41be56a02584e0c73a/Libraries/Blob/RCTBlobCollector.mm#L19-L25

Since, `blob.slice()` is supposed to create a new view onto the same binary data as the original blob, we need to re-use the same collector object when slicing so that it is not GC'd until the last reference to the binary data is no longer reachable. Currently, since each blob slice gets a new blobCollector object, the memory is de-allocated when the first blob is GC'd.

Fixes #29970
Fixes #27857

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Blob data is no longer prematurely deallocated when using blob.slice

Pull Request resolved: #31392

Test Plan: I could use help coming up with a test plan here. I could add a referential equality check for the blob.data.__collector in `Blob-test` but it doesn't seem quite right to be testing the implementation detail there.

Reviewed By: javache

Differential Revision: D41730782

Pulled By: cortinico

fbshipit-source-id: 5671ae2c69908f4c9acb5d203ba198b41b421294
kelset pushed a commit that referenced this pull request Apr 3, 2023
)

Summary:
This PR prevents blob data from being prematurely de-allocated in native code when using slice to create views into an existing blob. Currently, whenever a new blob is created via createFromOptions, BlobManager.js creates a new blobCollector object since options.__collector is never provided.

https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/Libraries/Blob/BlobManager.js#L115-L123

When the reference to a blobCollector is garbage collected, the corresponding native memory for the blob data is de-allocated.

https://github.com/facebook/react-native/blob/27651720b40cab564a0cbd41be56a02584e0c73a/Libraries/Blob/RCTBlobCollector.mm#L19-L25

Since, `blob.slice()` is supposed to create a new view onto the same binary data as the original blob, we need to re-use the same collector object when slicing so that it is not GC'd until the last reference to the binary data is no longer reachable. Currently, since each blob slice gets a new blobCollector object, the memory is de-allocated when the first blob is GC'd.

Fixes #29970
Fixes #27857

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Blob data is no longer prematurely deallocated when using blob.slice

Pull Request resolved: #31392

Test Plan: I could use help coming up with a test plan here. I could add a referential equality check for the blob.data.__collector in `Blob-test` but it doesn't seem quite right to be testing the implementation detail there.

Reviewed By: javache

Differential Revision: D41730782

Pulled By: cortinico

fbshipit-source-id: 5671ae2c69908f4c9acb5d203ba198b41b421294
kelset pushed a commit that referenced this pull request Apr 3, 2023
)

Summary:
This PR prevents blob data from being prematurely de-allocated in native code when using slice to create views into an existing blob. Currently, whenever a new blob is created via createFromOptions, BlobManager.js creates a new blobCollector object since options.__collector is never provided.

https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/Libraries/Blob/BlobManager.js#L115-L123

When the reference to a blobCollector is garbage collected, the corresponding native memory for the blob data is de-allocated.

https://github.com/facebook/react-native/blob/27651720b40cab564a0cbd41be56a02584e0c73a/Libraries/Blob/RCTBlobCollector.mm#L19-L25

Since, `blob.slice()` is supposed to create a new view onto the same binary data as the original blob, we need to re-use the same collector object when slicing so that it is not GC'd until the last reference to the binary data is no longer reachable. Currently, since each blob slice gets a new blobCollector object, the memory is de-allocated when the first blob is GC'd.

Fixes #29970
Fixes #27857

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Blob data is no longer prematurely deallocated when using blob.slice

Pull Request resolved: #31392

Test Plan: I could use help coming up with a test plan here. I could add a referential equality check for the blob.data.__collector in `Blob-test` but it doesn't seem quite right to be testing the implementation detail there.

Reviewed By: javache

Differential Revision: D41730782

Pulled By: cortinico

fbshipit-source-id: 5671ae2c69908f4c9acb5d203ba198b41b421294
OlimpiaZurek pushed a commit to OlimpiaZurek/react-native that referenced this pull request May 22, 2023
…ebook#31392)

Summary:
This PR prevents blob data from being prematurely de-allocated in native code when using slice to create views into an existing blob. Currently, whenever a new blob is created via createFromOptions, BlobManager.js creates a new blobCollector object since options.__collector is never provided.

https://github.com/facebook/react-native/blob/dc80b2dcb52fadec6a573a9dd1824393f8c29fdc/Libraries/Blob/BlobManager.js#L115-L123

When the reference to a blobCollector is garbage collected, the corresponding native memory for the blob data is de-allocated.

https://github.com/facebook/react-native/blob/27651720b40cab564a0cbd41be56a02584e0c73a/Libraries/Blob/RCTBlobCollector.mm#L19-L25

Since, `blob.slice()` is supposed to create a new view onto the same binary data as the original blob, we need to re-use the same collector object when slicing so that it is not GC'd until the last reference to the binary data is no longer reachable. Currently, since each blob slice gets a new blobCollector object, the memory is de-allocated when the first blob is GC'd.

Fixes facebook#29970
Fixes facebook#27857

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[iOS] [Fixed] - Blob data is no longer prematurely deallocated when using blob.slice

Pull Request resolved: facebook#31392

Test Plan: I could use help coming up with a test plan here. I could add a referential equality check for the blob.data.__collector in `Blob-test` but it doesn't seem quite right to be testing the implementation detail there.

Reviewed By: javache

Differential Revision: D41730782

Pulled By: cortinico

fbshipit-source-id: 5671ae2c69908f4c9acb5d203ba198b41b421294
@cipolleschi cipolleschi mentioned this pull request Oct 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Needs: React Native Team Attention Platform: iOS iOS applications. Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

iOS 14 Only attempt to insert nil object from objects[0] iOS Native Crash when uploading blobs using aws-sdk
7 participants