mirror of
https://github.com/status-im/react-native.git
synced 2025-01-09 17:15:54 +00:00
d2de604721
Summary: On Android with dev mode on, we're seeing a regular SIGSEGV when pushing a lot of animation declarations over the bridge. We tracked this down to being not specific to animations, but the crash is caused in `deepFreezeAndThrowOnMutationInDev`. Specifically: the provided object to freeze is modified while looping, replacing the current key access to a getter/setter. After the modification, JSC crashes during retrieval of the next key - but only when there are a lot of events passing over the bridge. We have a hunch that this is due to a bug in JSC object enumeration but did we not look into it further yet. Any help here is welcome. The JS code seems all right at first sight and shouldn't cause a segmentation crash. The workaround in this PR is to retrieve the keys first from the object and then looping over that array. In our app and in a reduced app test case this fixes the crash. If needed I can provide the reduced app test case. It's really tricky to make a test for this as it requires to be run Closes https://github.com/facebook/react-native/pull/11804 Differential Revision: D4403483 Pulled By: davidaurelio fbshipit-source-id: a31e5cff734e96bfec56e4a39dc1c6854798e245
76 lines
2.3 KiB
JavaScript
76 lines
2.3 KiB
JavaScript
/**
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule deepFreezeAndThrowOnMutationInDev
|
|
* @flow
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
/**
|
|
* If your application is accepting different values for the same field over
|
|
* time and is doing a diff on them, you can either (1) create a copy or
|
|
* (2) ensure that those values are not mutated behind two passes.
|
|
* This function helps you with (2) by freezing the object and throwing if
|
|
* the user subsequently modifies the value.
|
|
*
|
|
* There are two caveats with this function:
|
|
* - If the call site is not in strict mode, it will only throw when
|
|
* mutating existing fields, adding a new one
|
|
* will unfortunately fail silently :(
|
|
* - If the object is already frozen or sealed, it will not continue the
|
|
* deep traversal and will leave leaf nodes unfrozen.
|
|
*
|
|
* Freezing the object and adding the throw mechanism is expensive and will
|
|
* only be used in DEV.
|
|
*/
|
|
function deepFreezeAndThrowOnMutationInDev(object: Object) {
|
|
if (__DEV__) {
|
|
if (typeof object !== 'object' ||
|
|
object === null ||
|
|
Object.isFrozen(object) ||
|
|
Object.isSealed(object)) {
|
|
return;
|
|
}
|
|
|
|
var keys = Object.keys(object);
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
if (object.hasOwnProperty(key)) {
|
|
object.__defineGetter__(key, identity.bind(null, object[key]));
|
|
object.__defineSetter__(key, throwOnImmutableMutation.bind(null, key));
|
|
}
|
|
}
|
|
|
|
Object.freeze(object);
|
|
Object.seal(object);
|
|
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
if (object.hasOwnProperty(key)) {
|
|
deepFreezeAndThrowOnMutationInDev(object[key]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function throwOnImmutableMutation(key, value) {
|
|
throw Error(
|
|
'You attempted to set the key `' + key + '` with the value `' +
|
|
JSON.stringify(value) + '` on an object that is meant to be immutable ' +
|
|
'and has been frozen.'
|
|
);
|
|
}
|
|
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
|
|
module.exports = deepFreezeAndThrowOnMutationInDev;
|