Skip to content

Commit

Permalink
[Fix] stringify: actually fix cyclic references
Browse files Browse the repository at this point in the history
Fixes #403.

Co-authored-by: liaokunhua <acutedev@163.com>
Co-authored-by: Jordan Harband <ljharb@gmail.com>
  • Loading branch information
liaokunhua and ljharb committed Dec 4, 2021
1 parent 24c19cc commit e96ec94
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 5 deletions.
24 changes: 21 additions & 3 deletions lib/stringify.js
Expand Up @@ -56,6 +56,8 @@ var isNonNullishPrimitive = function isNonNullishPrimitive(v) {
|| typeof v === 'bigint';
};

var sentinel = {};

var stringify = function stringify(
object,
prefix,
Expand All @@ -75,8 +77,23 @@ var stringify = function stringify(
) {
var obj = object;

if (sideChannel.has(object)) {
throw new RangeError('Cyclic object value');
var tmpSc = sideChannel;
var step = 0;
var findFlag = false;
while ((tmpSc = tmpSc.get(sentinel)) !== undefined && !findFlag) {
// Where object last appeared in the ref tree
var pos = tmpSc.get(object);
step += 1;
if (pos !== undefined) {
if (pos === step) {
throw new RangeError('Cyclic object value');
} else {
findFlag = true; // Break while
}
}
if (tmpSc.get(sentinel) === undefined) {
step = 0;
}
}

if (typeof filter === 'function') {
Expand Down Expand Up @@ -145,8 +162,9 @@ var stringify = function stringify(
? typeof generateArrayPrefix === 'function' ? generateArrayPrefix(prefix, key) : prefix
: prefix + (allowDots ? '.' + key : '[' + key + ']');

sideChannel.set(object, true);
sideChannel.set(object, step);
var valueSideChannel = getSideChannel();
valueSideChannel.set(sentinel, sideChannel);
pushToArray(values, stringify(
value,
keyPrefix,
Expand Down
10 changes: 8 additions & 2 deletions test/stringify.js
Expand Up @@ -454,7 +454,7 @@ test('stringify()', function (t) {

st['throws'](
function () { qs.stringify({ 'foo[bar]': 'baz', 'foo[baz]': a }); },
RangeError,
/RangeError: Cyclic object value/,
'cyclic values throw'
);

Expand All @@ -464,10 +464,16 @@ test('stringify()', function (t) {
circular.a = circular;
st['throws'](
function () { qs.stringify(circular); },
RangeError,
/RangeError: Cyclic object value/,
'cyclic values throw'
);

var a = ['a'];
st.doesNotThrow(
function () { qs.stringify({ x:a, y:a }); },
'non-cyclic values do not throw'
);

st.end();
});

Expand Down

0 comments on commit e96ec94

Please sign in to comment.