Skip to content

Commit 790289c

Browse files
OskarEichlermeta-codesync[bot]
authored andcommitted
Fix EventEmitter prototype-key event types (#58229)
Summary: The shared EventEmitter uses an ordinary object registry, so event types such as `constructor` and `__proto__` resolve inherited values and throw during registration. Initialize and reset the internal registry without a prototype, and cover registration, emission, counting, and full reset for both keys. Fixes #58228. ## Changelog: [GENERAL] [FIXED] - Support EventEmitter event names that overlap Object prototype properties. Pull Request resolved: #58229 Test Plan: - Exact upstream regression: 20 passed / 1 failed at `registrations.add`. - Fixed Fantom suite: 21/21 passed. - Fresh `yarn flow-check`: 0 errors. - Targeted no-ignore ESLint, Prettier, and `git diff --check` passed. No UI change; screenshots are not applicable. Reviewed By: cortinico Differential Revision: D118267117 Pulled By: javache fbshipit-source-id: 12c3aab577ec13dabe475409ae6e21f5e6853135
1 parent 621ced7 commit 790289c

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

‎packages/react-native/Libraries/vendor/emitter/EventEmitter.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default class EventEmitter<
8484

8585
constructor() {
8686
// $FlowFixMe[incompatible-type]
87-
this.#registry = {};
87+
this.#registry = Object.create(null);
8888
}
8989

9090
/**
@@ -147,7 +147,7 @@ export default class EventEmitter<
147147
): void {
148148
if (eventType == null) {
149149
// $FlowFixMe[incompatible-type]
150-
this.#registry = {};
150+
this.#registry = Object.create(null);
151151
} else {
152152
// $FlowFixMe[cannot-write]
153153
delete this.#registry[eventType];

‎packages/react-native/Libraries/vendor/emitter/__tests__/EventEmitter-itest.js‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,27 @@ describe('listeners', () => {
5757
expect(listenerB).toHaveBeenCalledTimes(1);
5858
});
5959

60+
it('supports event types that match Object prototype keys', () => {
61+
const emitter = new EventEmitter<Readonly<Record<string, []>>>();
62+
63+
const constructorListener = jest.fn();
64+
const protoListener = jest.fn();
65+
emitter.addListener('constructor', constructorListener);
66+
emitter.addListener('__proto__', protoListener);
67+
68+
emitter.emit('constructor');
69+
emitter.emit('__proto__');
70+
71+
expect(constructorListener).toHaveBeenCalledTimes(1);
72+
expect(protoListener).toHaveBeenCalledTimes(1);
73+
expect(emitter.listenerCount('constructor')).toBe(1);
74+
expect(emitter.listenerCount('__proto__')).toBe(1);
75+
76+
emitter.removeAllListeners();
77+
expect(emitter.listenerCount('constructor')).toBe(0);
78+
expect(emitter.listenerCount('__proto__')).toBe(0);
79+
});
80+
6081
it('invokes listeners in registration order', () => {
6182
const emitter = new EventEmitter<{A: []}>();
6283

0 commit comments

Comments
 (0)