Skip to content

v5.17.0#379

Merged
szegedi merged 8 commits into
v5.xfrom
v5.17.0-proposal
Jul 23, 2026
Merged

v5.17.0#379
szegedi merged 8 commits into
v5.xfrom
v5.17.0-proposal

Conversation

dependabot Bot and others added 6 commits July 22, 2026 14:14
Bumps the patch-updates group with 2 updates: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) and [eslint-plugin-n](https://github.com/eslint-community/eslint-plugin-n).


Updates `@types/node` from 26.1.0 to 26.1.1
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `eslint-plugin-n` from 18.2.1 to 18.2.2
- [Release notes](https://github.com/eslint-community/eslint-plugin-n/releases)
- [Changelog](https://github.com/eslint-community/eslint-plugin-n/blob/master/CHANGELOG.md)
- [Commits](eslint-community/eslint-plugin-n@v18.2.1...v18.2.2)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 26.1.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch-updates
- dependency-name: eslint-plugin-n
  dependency-version: 18.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: patch-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…#375)

* otel-thread-ctx: publish V8 + ObjectWrap layout constants for readers

Extends the OTEP-4719 process-context attributes emitted by
getProcessContextAttributes with three new entries an out-of-process
eBPF reader needs to walk from our TLS discovery struct to the actual
OTEP-4947 record:

- threadlocal.native_wrap_fields_offset — sizeof(node::ObjectWrap).
  Given a pointer to a CtxWrap fetched via wrapped_object_offset, add
  this to reach CtxWrap::record_.

- threadlocal.js_map_table_offset — offset within a V8 JSMap object of
  the tagged pointer to its backing OrderedHashMap table
  (JSCollection::kTableOffset in V8, 0x18).

- threadlocal.ordered_hash_map_header_size — size of the header
  preceding the element_count / deleted_element_count / n_buckets
  fields inside an OrderedHashMap (0x10).

Without these, a reader implementing the Node.js schema would have to
hardcode them itself and re-verify them per V8 version. Keeping the
constants in the addon puts one source of truth close to V8. The two
V8 internal offsets are not exposed in V8's public headers
(v8-internal.h); they live in Node's private V8 tree
(deps/v8/src/objects/{js-collection,ordered-hash-table}.h) — we cite
those paths in the code comments so a future V8 layout change has a
clear pointer to what to re-check.

New non-Linux fallback values match the Linux ones (24 / 0x18 / 0x10);
the reader contract is Linux-only per the OTEP anyway, so this just
keeps the exported surface consistent in shape across platforms.
Bumps the minor-updates group with 3 updates: [source-map](https://github.com/mozilla/source-map), [sinon](https://github.com/sinonjs/sinon) and [@types/sinon](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/sinon).


Updates `source-map` from 0.7.6 to 0.8.0
- [Release notes](https://github.com/mozilla/source-map/releases)
- [Changelog](https://github.com/mozilla/source-map/blob/master/CHANGELOG.md)
- [Commits](mozilla/source-map@0.7.6...v0.8.0)

Updates `sinon` from 22.0.0 to 22.1.0
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/main/CHANGES.md)
- [Commits](sinonjs/sinon@v22.0.0...v22.1.0)

Updates `@types/sinon` from 21.0.1 to 22.0.0
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/sinon)

---
updated-dependencies:
- dependency-name: source-map
  dependency-version: 0.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: sinon
  dependency-version: 22.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: minor-updates
- dependency-name: "@types/sinon"
  dependency-version: 22.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
  dependency-group: minor-updates
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* test: document webpack source map behaviour for column=0 lookups (#248)

Add tests for SourceMapper.mappingInfo with a synthetic webpack-style
single-line bundle to document the known limitation introduced by #248.

Background
----------
PR #81 changed originalPositionFor to always try LEAST_UPPER_BOUND
first (then fall back to GREATEST_LOWER_BOUND). This was reverted in
#106 because it broke webpack source maps: for real non-zero columns
LEAST_UPPER_BOUND finds the *next* mapping (≥ column) rather than the
one at the column, returning wrong function names.

PR #248 fixed that regression by using LEAST_UPPER_BOUND only when
column === 0, and GREATEST_LOWER_BOUND otherwise. This correctly
handles Node.js ≥ 25 where V8's LineTick struct carries real column
numbers.

Residual limitation (Node.js < 25)
-----------------------------------
On Node.js < 25, the LineTick struct has no column field. The C++ layer
therefore always emits column=0 for every LineTick sample. With
column=0, the sourcemapper uses LEAST_UPPER_BOUND, which finds the
*first* mapping on the line. In a webpack bundle (all output on one
line) every function maps to the same first source function in the map.

This is not a regression vs. the pre-#248 state: before #248, those
functions were simply unmapped (column=0 + GREATEST_LOWER_BOUND →
nothing ≤ 0 → null → falls back to generated name/file). Both outcomes
are imperfect; #248 trades "unmapped" for "mapped to first function",
which may or may not be preferable depending on the use case.

The two new tests pin both behaviours explicitly so any future change
to this logic is immediately visible.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: apply prettier formatting to test-sourcemapper.ts

* Fix source mapping of zero-column locations (#248)

When lineNumbers is enabled, the column is always zero. If only one
occurence of a call occurs on one line then that is correctly selected.
However, in cases where the same function is called multiple times in
the same line it will be unable to differentiate them and would use
the unmapped value. This now makes it select the first call in the line
as a best-guess for the match, and in Node.js v25 will use the new
column field in LineTick to select the correct column where possible.

* fix: use path.resolve/join for platform-portable bundle path in test

---------

Co-authored-by: Stephen Belanger <admin@stephenbelanger.com>
* feat: add columnNumbers option to control frame column encoding

pprof's Line message historically had no column field, so a frame's column was
dropped from the serialized profile. Add a columnNumbers option controlling how
the column is represented:
  - 'drop' (default): omit the column, emit the plain line — preserves the
    historical behavior, so existing pprof-nodejs consumers are unaffected.
  - 'pack': pack the column into the high 32 bits of the line field
    (column << 32 | line) — the encoding the Datadog deobfuscation backend
    decodes (matching the Chrome profile intake).

This lets Node.js profiles of bundled/minified single-line server code (e.g.
Next.js server chunks) be deobfuscated — the column is the only discriminator
between functions on a single generated line. The enum leaves room for a future
'emit' mode using a real pprof Line.column field.

Threaded through serializeTimeProfile/serializeHeapProfile and the time profiler
start options (default 'drop'); dd-trace-js opts in with columnNumbers: 'pack'.

* fix: thread columnNumbers through the heap profiler; clarify BigInt comment

Address review feedback on #377:
- serializeHeapProfile accepted the columnNumbers option but nothing passed it;
  thread it through heap.profile / heap.profileV2 / convertProfile so heap
  profiles can opt into packing too (default 'drop'). Add a heap 'pack' test.
- Fix the misleading packLineAndColumn comment: `column << 32` on a plain
  number is a no-op (32-bit shift) returning `column`; BigInt is needed because
  the arithmetic form loses precision past 2**53.
* fix: scope column packing to frames with a missing source map

columnNumbers: 'pack' previously packed the column into the line for every
frame. That leaked the packed value into profiles that skip server-side
unminification (e.g. Node.js profiles whose maps resolved locally, or that
never had missing maps), which in turn forced the backend to strip it back out
of every parse-time structure.

Pack only frames whose source map was declared but missing (loc.missingMapFile)
— exactly the frames that set dd:has-missing-map-files and are sent for
server-side unminification. Locally-resolved and no-map frames keep their plain
line, so profiles that skip unminification never carry packed line numbers and
the backend needs no stripping. This mirrors how the Chrome path already works.
@datadog-datadog-prod-us1

This comment has been minimized.

szegedi and others added 2 commits July 23, 2026 09:52
The test was intermittently failing across platforms (e.g. centos-test-26,
darwin-arm builds) with either "No context found" or "Unexpected context".

Two compounding causes:

1. It established the sampling context with a bare setContext(). Under
   useCPED that only takes effect when the current continuation already has
   an AsyncContextFrame; otherwise it silently no-ops. Whether one existed
   depended on what ran before, so the context was often never stored and
   samples came back with an undefined context.

2. It stopped after a single sample. The first sample is taken at profiler
   start (before any context is set) and is skipped during context
   association, so one sample left nothing reliable to attach the context to.

Establish the context the way production code does — runWithContext when
useCPED is enabled, setContext otherwise — and wait for several samples
before stopping. Reproduced on Node 26: the test failed 30/30 runs in
isolation before, and passes 30/30 in isolation and 25/25 in the full file
after.
@szegedi
szegedi force-pushed the v5.17.0-proposal branch from c4f5f03 to 8cac039 Compare July 23, 2026 07:52
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Overall package size

Self size: 2.45 MB
Deduped: 3.15 MB
No deduping: 3.15 MB

Dependency sizes | name | version | self size | total size | |------|---------|-----------|------------| | pprof-format | 2.2.3 | 500.55 kB | 500.55 kB | | source-map | 0.8.0 | 185.66 kB | 185.66 kB | | node-gyp-build | 4.8.4 | 13.86 kB | 13.86 kB |

🤖 This report was automatically generated by heaviest-objects-in-the-universe

@szegedi
szegedi merged commit cdf8bbc into v5.x Jul 23, 2026
68 checks passed
@szegedi
szegedi deleted the v5.17.0-proposal branch July 23, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants