Added missing guard to DevTools for Objects with null proto (#17757)
This prevents a runtime error from occurring when these objects are inspected.
Brian Vaughn committed
Jan 2, 2020 at 08:27 UTC
195b3db61885552b84eacb2ab51502b342d0fa8a
6 files changed
+44
-6
packages/react-devtools-shared/src/__tests__/__snapshots__/inspectedElementContext-test.js.snap
+5
@@ -510,6 +510,11 @@ exports[`InspectedElementContext should support complex data types: 1: Inspected
510
"object_of_objects": {
511
"inner": {}
512
},
513
+ "object_with_null_proto": {
514
+ "string": "abc",
515
+ "number": 123,
516
+ "boolean": true
517
+ },
518
"react_element": {},
519
"regexp": {},
520
"set": {
packages/react-devtools-shared/src/__tests__/inspectedElementContext-test.js
+14
-2
@@ -524,7 +524,7 @@ describe('InspectedElementContext', () => {
524
const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
525
const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
526
const objectOfObjects = {
527
- inner: {string: 'abc', number: 213, boolean: true},
527
+ inner: {string: 'abc', number: 123, boolean: true},
528
};
529
const typedArray = Int8Array.from([100, -100, 0]);
530
const arrayBuffer = typedArray.buffer;
@@ -537,6 +537,10 @@ describe('InspectedElementContext', () => {
537
xyz: 1,
538
},
539
});
540
+ const objectWithNullProto = Object.create(null);
541
+ objectWithNullProto.string = 'abc';
542
+ objectWithNullProto.number = 123;
543
+ objectWithNullProto.boolean = true;
544
545
const container = document.createElement('div');
546
await utils.actAsync(() =>
@@ -554,6 +558,7 @@ describe('InspectedElementContext', () => {
558
map={mapShallow}
559
map_of_maps={mapOfMaps}
560
object_of_objects={objectOfObjects}
561
+ object_with_null_proto={objectWithNullProto}
562
react_element={<span />}
563
regexp={/abc/giu}
564
set={setShallow}
@@ -604,6 +609,7 @@ describe('InspectedElementContext', () => {
609
map,
610
map_of_maps,
611
object_of_objects,
612
+ object_with_null_proto,
613
react_element,
614
regexp,
615
set,
@@ -691,10 +697,16 @@ describe('InspectedElementContext', () => {
697
expect(object_of_objects.inner[meta.name]).toBe('');
698
expect(object_of_objects.inner[meta.type]).toBe('object');
699
expect(object_of_objects.inner[meta.preview_long]).toBe(
694
- '{boolean: true, number: 213, string: "abc"}',
700
+ '{boolean: true, number: 123, string: "abc"}',
701
);
702
expect(object_of_objects.inner[meta.preview_short]).toBe('{…}');
703
704
+ expect(object_with_null_proto).toEqual({
705
+ boolean: true,
706
+ number: 123,
707
+ string: 'abc',
708
+ });
709
+
710
expect(react_element[meta.inspectable]).toBe(false);
711
expect(react_element[meta.name]).toBe('span');
712
expect(react_element[meta.type]).toBe('react_element');
packages/react-devtools-shared/src/__tests__/legacy/__snapshots__/inspectElement-test.js.snap
+5
@@ -151,6 +151,11 @@ Object {
151
"object_of_objects": {
152
"inner": {}
153
},
154
+ "object_with_null_proto": {
155
+ "string": "abc",
156
+ "number": 123,
157
+ "boolean": true
158
+ },
159
"react_element": {},
160
"regexp": {},
161
"set": {
packages/react-devtools-shared/src/__tests__/legacy/inspectElement-test.js
+14
-2
@@ -155,7 +155,7 @@ describe('InspectedElementContext', () => {
155
const setOfSets = new Set([new Set(['a', 'b', 'c']), new Set([1, 2, 3])]);
156
const mapOfMaps = new Map([['first', mapShallow], ['second', mapShallow]]);
157
const objectOfObjects = {
158
- inner: {string: 'abc', number: 213, boolean: true},
158
+ inner: {string: 'abc', number: 123, boolean: true},
159
};
160
const typedArray = Int8Array.from([100, -100, 0]);
161
const arrayBuffer = typedArray.buffer;
@@ -168,6 +168,10 @@ describe('InspectedElementContext', () => {
168
xyz: 1,
169
},
170
});
171
+ const objectWithNullProto = Object.create(null);
172
+ objectWithNullProto.string = 'abc';
173
+ objectWithNullProto.number = 123;
174
+ objectWithNullProto.boolean = true;
175
176
act(() =>
177
ReactDOM.render(
@@ -184,6 +188,7 @@ describe('InspectedElementContext', () => {
188
map={mapShallow}
189
map_of_maps={mapOfMaps}
190
object_of_objects={objectOfObjects}
191
+ object_with_null_proto={objectWithNullProto}
192
react_element={<span />}
193
regexp={/abc/giu}
194
set={setShallow}
@@ -212,6 +217,7 @@ describe('InspectedElementContext', () => {
217
map,
218
map_of_maps,
219
object_of_objects,
220
+ object_with_null_proto,
221
react_element,
222
regexp,
223
set,
@@ -273,10 +279,16 @@ describe('InspectedElementContext', () => {
279
expect(object_of_objects.inner[meta.name]).toBe('');
280
expect(object_of_objects.inner[meta.type]).toBe('object');
281
expect(object_of_objects.inner[meta.preview_long]).toBe(
276
- '{boolean: true, number: 213, string: "abc"}',
282
+ '{boolean: true, number: 123, string: "abc"}',
283
);
284
expect(object_of_objects.inner[meta.preview_short]).toBe('{…}');
285
286
+ expect(object_with_null_proto).toEqual({
287
+ boolean: true,
288
+ number: 123,
289
+ string: 'abc',
290
+ });
291
+
292
expect(react_element[meta.inspectable]).toBe(false);
293
expect(react_element[meta.name]).toBe('span');
294
expect(react_element[meta.type]).toBe('react_element');
packages/react-devtools-shared/src/utils.js
+2
-2
@@ -388,7 +388,7 @@ export function getDataType(data: Object): DataType {
388
return data.constructor.hasOwnProperty('BYTES_PER_ELEMENT')
389
? 'typed_array'
390
: 'data_view';
391
- } else if (data.constructor.name === 'ArrayBuffer') {
391
+ } else if (data.constructor && data.constructor.name === 'ArrayBuffer') {
392
// HACK This ArrayBuffer check is gross; is there a better way?
393
// We could try to create a new DataView with the value.
394
// If it doesn't error, we know it's an ArrayBuffer,
@@ -396,7 +396,7 @@ export function getDataType(data: Object): DataType {
396
return 'array_buffer';
397
} else if (typeof data[Symbol.iterator] === 'function') {
398
return 'iterator';
399
- } else if (data.constructor.name === 'RegExp') {
399
+ } else if (data.constructor && data.constructor.name === 'RegExp') {
400
return 'regexp';
401
} else if (Object.prototype.toString.call(data) === '[object Date]') {
402
return 'date';
packages/react-devtools-shell/src/app/InspectableElements/UnserializableProps.js
+4
@@ -25,6 +25,9 @@ const immutable = Immutable.fromJS({
25
xyz: 1,
26
},
27
});
28
+const objectWithNullProto = Object.create(null);
29
+objectWithNullProto.foo = 'abc';
30
+objectWithNullProto.bar = 123;
31
32
export default function UnserializableProps() {
33
return (
@@ -37,6 +40,7 @@ export default function UnserializableProps() {
40
setOfSets={setOfSets}
41
typedArray={typedArray}
42
immutable={immutable}
43
+ objectWithNullProto={objectWithNullProto}
44
/>
45
);
46
}