Skip to content

Circular references causing browser crash when collecting errors #1707

@dorianrod

Description

@dorianrod

Important Details

How are you running Sentry?

"@sentry/browser": "^4.1.1"

Description

When error happens, the browser crash because Sentry tries to collect errors and there is a loop somewhere.

Steps to Reproduce

Using chrome:

  1. An error happened during the use of my app (a crash happened in a React View, which is catched by ErrorBounding of React => Sentry is creating a report).

  2. The app crash because of lack of memory

I don't really know how to reproduce it with a "normal use" of Sentry because I don't know how is collected "breadthumbs" (cf. following explanations) but you should be able to reproduce the issue with explanations and following code.

What happened ?

Synthesis:

This is caused by circular references in objects captured by Sentry when sending an error report.
When this kind of object is captured if you do JSON.stringify(objectWithCircular), the console will tell you that there are circular methods. But when using JSON.stringify(object, serializer()) (as used in sentry libs), I don't know why but it crashes.

Details:
I've investigated to understand why the crash happened and it's due to the following line :
"return JSON.stringify(object, serializer());" in @senty/browser/dist/index.

The object attribute is an object produced by Sentry to send the report. In "breadcrumbs.data.extra.arguments", you can find some object which are captured by Sentry.

When calling JSON.stringify(object, serializer()), it will progressively call the method "toJSON" of all object contained in the object. Sentry has a mecanism to prevent circular references but this doesn't work in this case.

For instance, in my case the problem was caused by a google map object which was captured inside breadcrumbs[].data.extra.arguments[0].

To reproduce it you can create a google map:

<html>

  <head>
    <meta charset="utf-8" />
    <script src="https://maps.googleapis.com/maps/api/js?callback=initMap"
    async defer></script>
  </head>

  <body>
    <div id="map" ></div>
  </body>
	<script>
			
		function initMap(map) {
			var map;
			map = new google.maps.Map(document.getElementById('map'), {
			  center: {lat: -34.397, lng: 150.644},
			  zoom: 8
			});
			console.log(JSON.stringify(map))
		}
	</script>
</html>

In this code, you can see that "console.log(JSON.stringify({gm: map}))" will write in console "circular references".

If you include the code in "@sentry/browser/dist", and use the function
"JSON.stringify({gm: map}, serializer()) memory will inscrease until the browser crash.

What you expected to happen

A mecanism to prevent circular references to cause the crash.

Possible Solution

?

The workaround I used in my code was to prevent google map object from being stringify like this:

function serializer() {
    var stack = [];
    var keys = [];
    var cycleReplacer = function (_, value) {
        if (stack[0] === value) {
            return '[Circular ~]';
        }
        return "[Circular ~." + keys.slice(0, stack.indexOf(value)).join('.') + "]";
    };
    return function (key, value) {
        if(value && value.gm_bindings_) return "[google map]"; //cause une référence circulaire

This could not be a perennial one because you never know which objects are collected and which ones will cause a crash.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions