Skip to content

Commit a769291

Browse files
laplace youngfatso83
authored andcommitted
fix: isolate walk state from Object prototype
1 parent 66df977 commit a769291

3 files changed

Lines changed: 58 additions & 1 deletion

File tree

src/sinon/util/core/walk.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function walkInternal(obj, iterator, context, originalObj, seen) {
6363
* @returns {void} nothing
6464
*/
6565
const walk = function (obj, iterator, context) {
66-
return walkInternal(obj, iterator, context, obj, {});
66+
return walkInternal(obj, iterator, context, obj, Object.create(null));
6767
};
6868

6969
export default walk;

test/issues/issues-test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,4 +860,29 @@ describe("issues", function () {
860860
assert(cb.calledOnce);
861861
assert.equals(cb.firstCall.args, ["Hello"]);
862862
});
863+
864+
it("#2702 - stub creation should ignore inherited non-writable Object prototype properties", function () {
865+
const descriptor = Object.getOwnPropertyDescriptor(
866+
Object.prototype,
867+
"someFlag",
868+
);
869+
870+
Object.defineProperty(Object.prototype, "someFlag", {
871+
value: "x",
872+
writable: false,
873+
configurable: true,
874+
});
875+
876+
try {
877+
refute.exception(function () {
878+
sinon.stub();
879+
});
880+
} finally {
881+
if (descriptor) {
882+
Object.defineProperty(Object.prototype, "someFlag", descriptor);
883+
} else {
884+
delete Object.prototype.someFlag;
885+
}
886+
}
887+
});
863888
});

test/src/util/core/walk-test.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import referee from "@sinonjs/referee";
22
import walk from "../../../../src/sinon/util/core/walk.js";
33
import createSpy from "../../../../src/sinon/spy.js";
44
const assert = referee.assert;
5+
const refute = referee.refute;
56

67
describe("util/core/walk", function () {
78
it("should call iterator with value, key, and obj, with context as the receiver", function () {
@@ -163,4 +164,35 @@ describe("util/core/walk", function () {
163164
assert.equals(index, propertyNames.lastIndexOf(name));
164165
});
165166
});
167+
168+
it("tracks visited names without inheriting Object.prototype properties", function () {
169+
const target = {};
170+
const iterator = createSpy();
171+
const descriptor = Object.getOwnPropertyDescriptor(
172+
Object.prototype,
173+
"someFlag",
174+
);
175+
176+
// eslint-disable-next-line no-extend-native
177+
Object.defineProperty(Object.prototype, "someFlag", {
178+
value: "x",
179+
writable: false,
180+
configurable: true,
181+
});
182+
183+
try {
184+
refute.exception(function () {
185+
walk(target, iterator);
186+
});
187+
188+
assert(iterator.calledWith("someFlag", Object.prototype));
189+
} finally {
190+
if (descriptor) {
191+
// eslint-disable-next-line no-extend-native
192+
Object.defineProperty(Object.prototype, "someFlag", descriptor);
193+
} else {
194+
delete Object.prototype.someFlag;
195+
}
196+
}
197+
});
166198
});

0 commit comments

Comments
 (0)