diff --git a/src/intrinsics/ecma262/JSON.js b/src/intrinsics/ecma262/JSON.js index 3ba8d56256..631db800cc 100644 --- a/src/intrinsics/ecma262/JSON.js +++ b/src/intrinsics/ecma262/JSON.js @@ -478,8 +478,16 @@ export default function(realm: Realm): ObjectValue { // 9. Let wrapper be ObjectCreate(%ObjectPrototype%). let wrapper = Create.ObjectCreate(realm, realm.intrinsics.ObjectPrototype); + let isAbstract = value instanceof AbstractValue; + + // #2411 + if (isAbstract && value.values.isTop()) { + AbstractValue.reportIntrospectionError(value); + throw new FatalError(); + } + // TODO #1012: Make result abstract if any nested element is an abstract value. - if (value instanceof AbstractValue || (value instanceof ObjectValue && value.isPartialObject())) { + if (isAbstract || (value instanceof ObjectValue && value.isPartialObject())) { // Return abstract result. This enables cloning via JSON.parse(JSON.stringify(...)). let clonedValue = InternalJSONClone(realm, value); let result = AbstractValue.createTemporalFromTemplate(realm, JSONStringify, StringValue, [clonedValue], { diff --git a/test/serializer/abstract/JSONStringifyOnAbstract2411.js b/test/serializer/abstract/JSONStringifyOnAbstract2411.js new file mode 100644 index 0000000000..70308eb888 --- /dev/null +++ b/test/serializer/abstract/JSONStringifyOnAbstract2411.js @@ -0,0 +1,9 @@ +// throws introspection error +// +(function() { + let o = __abstract("object", "(o)"); + let s; + s = "A" + JSON.stringify(o); + + global.s = s; +})();