Fix memory leak in JfrMetadata::reset() - #694
Conversation
reset() cleared _root._children/_attributes without deleting the heap-allocated Element/NoField objects initialize() had allocated. Only reachable via a Profiler restart (reset() -> initialize() a second time in the same process); unrelated to PROF-15075, which crashes on a plain chunk dump with no restart involved (split out of #692 per https://datadoghq.atlassian.net/browse/PROF-15075).
CI Test ResultsRun: #30900616939 | Commit:
Status Overview
Legend: ✅ passed | ❌ failed | ⚪ skipped | 🚫 cancelled Summary: Total: 32 | Passed: 32 | Failed: 0 Updated: 2026-08-04 10:42:49 UTC |
Benchmark Results (commit 008d688)Pipeline: https://gitlab.ddbuild.io/DataDog/apm-reliability/benchmarking-platform/-/pipelines/127401287 Commit:
|
| Benchmark | JDK | Latest | Dev | Δ (dev vs latest) | Issues L/D |
|---|---|---|---|---|---|
| akka-uct | 21 | ✅ 10193 ms (21 iters) | ✅ 10416 ms (21 iters) | ≈ +2.2% (±11.2%) | — / — |
| akka-uct | 25 | ✅ 8880 ms (24 iters) | ✅ 8743 ms (24 iters) | ≈ -1.5% (±10%) | — / — |
| finagle-chirper | 21 | ✅ 6002 ms (33 iters) | ✅ 5929 ms (33 iters) | ≈ -1.2% (±24.7%) | |
| finagle-chirper | 25 | ✅ 5437 ms (36 iters) | ✅ 5445 ms (36 iters) | ≈ +0.1% (±24.3%) | |
| fj-kmeans | 21 | ✅ 2745 ms (68 iters) | ✅ 2638 ms (72 iters) | 🟢 -3.9% | — / — |
| fj-kmeans | 25 | ✅ 2832 ms (66 iters) | ✅ 2832 ms (66 iters) | ≈ 0% (±2.6%) | — / — |
| future-genetic | 21 | ✅ 2122 ms (87 iters) | ✅ 2058 ms (90 iters) | 🟢 -3% | — / — |
| future-genetic | 25 | ✅ 2059 ms (90 iters) | ✅ 2049 ms (90 iters) | ≈ -0.5% (±2.6%) | — / — |
| naive-bayes | 21 | ✅ 1257 ms (136 iters) | ✅ 1304 ms (132 iters) | ≈ +3.7% (±33.1%) | — / — |
| naive-bayes | 25 | ✅ 1028 ms (167 iters) | ✅ 1014 ms (169 iters) | ≈ -1.4% (±31.8%) | — / — |
| reactors | 21 | ✅ 16668 ms (15 iters) | ✅ 15846 ms (15 iters) | ≈ -4.9% (±7.4%) | — / — |
| reactors | 25 | ✅ 18281 ms (15 iters) | ✅ 18391 ms (15 iters) | ≈ +0.6% (±5%) | — / — |
Internal counter details (ddprof)
ddprof internal counters, latest / dev (✅ = 0, · = unavailable):
| Benchmark | JDK | Dropped rec | Dropped jvmti | Dropped trace | Skipped WC | AGCT fail | Unwind fail |
|---|---|---|---|---|---|---|---|
| akka-uct | 21 | ✅ / ✅ | ✅ / ✅ | 4 / 2 | 1961 / 1939 | ✅ / ✅ | ✅ / ✅ |
| akka-uct | 25 | ✅ / ✅ | ✅ / ✅ | 6 / 1 | 2369 / 2031 | ✅ / ✅ | ✅ / ✅ |
| finagle-chirper | 21 | ✅ / ✅ | ✅ / ✅ | 4 / 1 | 8227 / 8628 | ✅ / ✅ | ✅ / ✅ |
| finagle-chirper | 25 | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | 8367 / 8248 | ✅ / ✅ | ✅ / ✅ |
| fj-kmeans | 21 | ✅ / ✅ | ✅ / ✅ | 2 / 1 | 1267 / 1276 | ✅ / ✅ | ✅ / ✅ |
| fj-kmeans | 25 | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | 1287 / 1259 | ✅ / ✅ | ✅ / ✅ |
| future-genetic | 21 | ✅ / ✅ | ✅ / ✅ | 2 / 1 | 2932 / 3002 | ✅ / ✅ | ✅ / ✅ |
| future-genetic | 25 | ✅ / ✅ | ✅ / ✅ | 2 / 2 | 2843 / 2845 | ✅ / ✅ | ✅ / ✅ |
| naive-bayes | 21 | ✅ / ✅ | ✅ / ✅ | 2 / 4 | 3484 / 3550 | ✅ / ✅ | ✅ / ✅ |
| naive-bayes | 25 | ✅ / ✅ | ✅ / ✅ | 2 / 4 | 3492 / 3488 | ✅ / ✅ | ✅ / ✅ |
| reactors | 21 | ✅ / ✅ | ✅ / ✅ | 1 / 2 | 1638 / 1621 | ✅ / ✅ | ✅ / ✅ |
| reactors | 25 | ✅ / ✅ | ✅ / ✅ | 1 / 1 | 1843 / 1824 | ✅ / ✅ | ✅ / ✅ |
|
@codex review |
Scan-Build Report
Bug Summary
Reports
|
||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 64c7b4423d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Benchmark Results (commit 64c7b44)Pipeline: https://gitlab.ddbuild.io/DataDog/apm-reliability/benchmarking-platform/-/pipelines/128804523 Commit:
|
| Benchmark | JDK | Latest | Dev | Δ (dev vs latest) | Issues L/D |
|---|---|---|---|---|---|
| akka-uct | 21 | ✅ 10336 ms (21 iters) | ✅ 10225 ms (21 iters) | ≈ -1.1% (±11.2%) | — / — |
| akka-uct | 25 | ✅ 8844 ms (24 iters) | ✅ 8823 ms (24 iters) | ≈ -0.2% (±9.5%) | — / — |
| finagle-chirper | 21 | ✅ 5987 ms (33 iters) | ✅ 5912 ms (33 iters) | ≈ -1.3% (±25.2%) | |
| finagle-chirper | 25 | ✅ 5454 ms (36 iters) | ✅ 5458 ms (36 iters) | ≈ +0.1% (±24.1%) | |
| fj-kmeans | 21 | ✅ 2712 ms (68 iters) | ✅ 2695 ms (70 iters) | ≈ -0.6% (±2.8%) | — / — |
| fj-kmeans | 25 | ✅ 2828 ms (66 iters) | ✅ 2822 ms (66 iters) | ≈ -0.2% (±2.6%) | — / — |
| future-genetic | 21 | ✅ 2037 ms (91 iters) | ✅ 2090 ms (89 iters) | 🔴 +2.6% | — / — |
| future-genetic | 25 | ✅ 2038 ms (91 iters) | ✅ 2027 ms (92 iters) | ≈ -0.5% (±2.6%) | — / — |
| naive-bayes | 21 | ✅ 1264 ms (135 iters) | ✅ 1273 ms (134 iters) | ≈ +0.7% (±32.6%) | — / — |
| naive-bayes | 25 | ✅ 975 ms (175 iters) | ✅ 984 ms (173 iters) | ≈ +0.9% (±31.8%) | — / — |
| reactors | 21 | ✅ 16879 ms (15 iters) | ✅ 16257 ms (15 iters) | ≈ -3.7% (±6.4%) | — / — |
| reactors | 25 | ✅ 18594 ms (15 iters) | ✅ 18489 ms (15 iters) | ≈ -0.6% (±5.2%) | — / — |
Internal counter details (ddprof)
ddprof internal counters, latest / dev (✅ = 0, · = unavailable):
| Benchmark | JDK | Dropped rec | Dropped jvmti | Dropped trace | Skipped WC | AGCT fail | Unwind fail |
|---|---|---|---|---|---|---|---|
| akka-uct | 21 | ✅ / ✅ | ✅ / ✅ | 5 / ✅ | 1958 / 2013 | ✅ / ✅ | ✅ / ✅ |
| akka-uct | 25 | ✅ / ✅ | ✅ / ✅ | 1 / 2 | 2362 / 2213 | ✅ / ✅ | ✅ / ✅ |
| finagle-chirper | 21 | ✅ / ✅ | ✅ / ✅ | 1 / 4 | 8457 / 8027 | ✅ / ✅ | ✅ / ✅ |
| finagle-chirper | 25 | ✅ / ✅ | ✅ / ✅ | 2 / ✅ | 8212 / 8454 | ✅ / ✅ | ✅ / ✅ |
| fj-kmeans | 21 | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ |
| fj-kmeans | 25 | ✅ / ✅ | ✅ / ✅ | 3 / 2 | 1255 / 1238 | ✅ / ✅ | ✅ / ✅ |
| future-genetic | 21 | ✅ / ✅ | ✅ / ✅ | 2 / ✅ | 3008 / 2999 | ✅ / ✅ | ✅ / ✅ |
| future-genetic | 25 | ✅ / ✅ | ✅ / ✅ | 6 / 3 | 2856 / 2871 | ✅ / ✅ | ✅ / ✅ |
| naive-bayes | 21 | ✅ / ✅ | ✅ / ✅ | 8 / 7 | 3501 / 3494 | ✅ / ✅ | ✅ / ✅ |
| naive-bayes | 25 | ✅ / ✅ | ✅ / ✅ | 3 / 6 | 3478 / 3462 | ✅ / ✅ | ✅ / ✅ |
| reactors | 21 | ✅ / ✅ | ✅ / ✅ | ✅ / ✅ | 1843 / 1642 | ✅ / ✅ | ✅ / ✅ |
| reactors | 25 | ✅ / ✅ | ✅ / ✅ | 1 / ✅ | 1897 / 1838 | ✅ / ✅ | ✅ / ✅ |
What does this PR do?:
JfrMetadata::reset()cleared_root._children/_root._attributeswithout deleting the heap-allocatedElement/NoFieldobjectsinitialize()had allocated, leaking them and leaving the tree vulnerable to use-after-free if the allocator later reused a freed address. Adds recursive deletion of theElementtree and the tracked_nofieldslist before clearing.Motivation:
Only reachable via a profiler restart (
reset()followed byinitialize()a second time in the same process). Found while investigating PROF-15075 (SIGSEGV inRecording::writeElement) but not its cause — that crash trace shows a plain chunk dump with no restart involved. Closing this separately since it's a real leak/UAF risk on its own.How to test the change?:
ddprof-lib/src/test/cpp/jfrMetadata_ut.cppexercisesinitialize()/reset()cycles, including with context attributes, and asserts no leaked/danglingElements.For Datadog employees:
credentials of any kind, I've requested a security review (run the
dd:platform-security-reviewskill, or file a request via the PSEC review form).
bewairealso runs automatically on every PR.Unsure? Have a question? Request a review!