Skip to content

Commit af7489c

Browse files
MattiasBuelensruyadorno
authored andcommitted
lib: add brand checks to AbortController and AbortSignal
PR-URL: #37720 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 4700042 commit af7489c

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

lib/internal/abort_controller.js

+29-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ const {
2323
customInspectSymbol,
2424
} = require('internal/util');
2525
const { inspect } = require('internal/util/inspect');
26+
const {
27+
codes: {
28+
ERR_INVALID_THIS,
29+
}
30+
} = require('internal/errors');
2631

2732
const kAborted = Symbol('kAborted');
2833

@@ -37,13 +42,21 @@ function customInspect(self, obj, depth, options) {
3742
return `${self.constructor.name} ${inspect(obj, opts)}`;
3843
}
3944

45+
function validateAbortSignal(obj) {
46+
if (obj?.[kAborted] === undefined)
47+
throw new ERR_INVALID_THIS('AbortSignal');
48+
}
49+
4050
class AbortSignal extends EventTarget {
4151
constructor() {
4252
// eslint-disable-next-line no-restricted-syntax
4353
throw new TypeError('Illegal constructor');
4454
}
4555

46-
get aborted() { return !!this[kAborted]; }
56+
get aborted() {
57+
validateAbortSignal(this);
58+
return !!this[kAborted];
59+
}
4760

4861
[customInspectSymbol](depth, options) {
4962
return customInspect(this, {
@@ -89,13 +102,26 @@ function abortSignal(signal) {
89102
// initializers for now:
90103
// https://bugs.chromium.org/p/v8/issues/detail?id=10704
91104
const kSignal = Symbol('signal');
105+
106+
function validateAbortController(obj) {
107+
if (obj?.[kSignal] === undefined)
108+
throw new ERR_INVALID_THIS('AbortController');
109+
}
110+
92111
class AbortController {
93112
constructor() {
94113
this[kSignal] = createAbortSignal();
95114
}
96115

97-
get signal() { return this[kSignal]; }
98-
abort() { abortSignal(this[kSignal]); }
116+
get signal() {
117+
validateAbortController(this);
118+
return this[kSignal];
119+
}
120+
121+
abort() {
122+
validateAbortController(this);
123+
abortSignal(this[kSignal]);
124+
}
99125

100126
[customInspectSymbol](depth, options) {
101127
return customInspect(this, {

test/parallel/test-abortcontroller.js

+60
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,63 @@ const { ok, strictEqual, throws } = require('assert');
7272
const signal = AbortSignal.abort();
7373
ok(signal.aborted);
7474
}
75+
76+
{
77+
// Test that AbortController properties and methods validate the receiver
78+
const acSignalGet = Object.getOwnPropertyDescriptor(
79+
AbortController.prototype,
80+
'signal'
81+
).get;
82+
const acAbort = AbortController.prototype.abort;
83+
84+
const goodController = new AbortController();
85+
ok(acSignalGet.call(goodController));
86+
acAbort.call(goodController);
87+
88+
const badAbortControllers = [
89+
null,
90+
undefined,
91+
0,
92+
NaN,
93+
true,
94+
'AbortController',
95+
Object.create(AbortController.prototype)
96+
];
97+
for (const badController of badAbortControllers) {
98+
throws(
99+
() => acSignalGet.call(badController),
100+
{ code: 'ERR_INVALID_THIS', name: 'TypeError' }
101+
);
102+
throws(
103+
() => acAbort.call(badController),
104+
{ code: 'ERR_INVALID_THIS', name: 'TypeError' }
105+
);
106+
}
107+
}
108+
109+
{
110+
// Test that AbortSignal properties validate the receiver
111+
const signalAbortedGet = Object.getOwnPropertyDescriptor(
112+
AbortSignal.prototype,
113+
'aborted'
114+
).get;
115+
116+
const goodSignal = new AbortController().signal;
117+
strictEqual(signalAbortedGet.call(goodSignal), false);
118+
119+
const badAbortSignals = [
120+
null,
121+
undefined,
122+
0,
123+
NaN,
124+
true,
125+
'AbortSignal',
126+
Object.create(AbortSignal.prototype)
127+
];
128+
for (const badSignal of badAbortSignals) {
129+
throws(
130+
() => signalAbortedGet.call(badSignal),
131+
{ code: 'ERR_INVALID_THIS', name: 'TypeError' }
132+
);
133+
}
134+
}

0 commit comments

Comments
 (0)