Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
# Changelog

## Unreleased

### Bug Fixes 🐛

- Limit the serialization of `asyncState` and `pollState` (depth, properties
per object, total reads and total string length, with markers such as
`"[Object]"` and `"[MaxProperties ~]"` where data was cut), so capturing a
stack trace no longer freezes, crashes or runs out of memory on large or
deeply linked state. Exceptions thrown while reading the state no longer
reach the captured thread, only own properties are serialized, and `Proxy`
values become `"[Proxy]"`.

## 0.5.2

### Bug Fixes 🐛
Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,37 @@ Sends a heartbeat from the current thread.

Returns the time in milliseconds since each registered thread called
`threadPoll()`.

### State serialization

`asyncState` and `pollState` are best-effort, size-limited snapshots.
`asyncState` is read on the captured thread while its JavaScript is
interrupted, so the serialization is limited whatever the state contains:

- Values are copied like `JSON.stringify` copies them: own enumerable
string-keyed properties only, while functions, symbols, BigInts, `undefined`
and circular references are left out. Shared references that are not circular
are copied each time they appear. Integer-like keys of plain objects (e.g.
`"0"`) are left out, and `toJSON` methods are not called.
- Getters run, as they do with `JSON.stringify`. A property whose getter throws
is left out. Exceptions never reach the code running on the captured thread,
but termination (e.g. `worker.terminate()`) still takes effect. A `Proxy`
becomes `"[Proxy]"` without running its traps.
- Limits, with markers replacing what was cut:
- Depth 10: objects and arrays nested deeper become `"[Object]"` or
`"[Array]"`.
- 1,000 properties or elements per object or array: the rest is replaced by a
single `"[MaxProperties ~]"` entry (the next element of an array, or the
value of the first key left out of an object).
- 20,000 property or element reads in total: after that nothing more is read.
The objects and arrays being copied end with a `"[MaxProperties ~]"` entry,
and later objects and arrays become `"[Object]"` or `"[Array]"`.
- 1,048,576 characters (UTF-16 code units) of strings in total, counting
values and keys: the string that crosses the limit is cut and ends with
`"..."`, and later strings become `"[String]"`. An object whose next key
does not fit ends with a `"...": "[MaxProperties ~]"` entry.
- The limits bound the size of the snapshot and how deep the serialization
recurses. The serialization still reads the full list of own keys of each
object it copies, and still runs getters, so a slow getter or a very wide
object delays the snapshot.
- If the state cannot be read at all, `asyncState` is left out.
Loading
Loading