You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix memory leak when a behavior parameter has a different capability than the trait it implements
When a behavior is called through a trait and the concrete actor's parameter
has a different trace-significant capability (e.g., trait has iso, concrete
has val), the sender traces with one trace kind and the receiver traces with
another. This ORCA GC mismatch causes field reference counts to never reach
zero, leaking objects reachable from the parameter.
The fix includes trace-kind characters in mangled names for behaviors and
constructors, so methods whose parameters differ in trace-significant ways
get distinct vtable indices. When a forwarding method is created due to a
cap mismatch, genfun_forward now adds a dispatch case that traces with the
forwarding method's params (the trait's capabilities) but calls the concrete
method's handler. A two-pass ordering in genfun_method_bodies ensures
concrete handlers are generated before forwarding dispatch cases that
reference them.
The leak isn't currently active because make_might_reference_actor forces
full tracing of immutable objects. Without this fix, re-enabling that
optimization would expose the leak.
Design: #4943Closes#4102
ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make configure arch=x86-64 config=debug use=${{ matrix.directives }}
504
+
ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make build config=debug
505
+
- name: Test with Debug Runtime
506
+
run: ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make test-ci-core config=debug test_full_program_timeout=300
507
+
- name: Build Release Runtime
508
+
run: |
509
+
ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make configure arch=x86-64 config=release use=${{ matrix.directives }}
510
+
ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make build config=release
511
+
- name: Test with Release Runtime
512
+
run: ASAN_OPTIONS=detect_leaks=0:external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer UBSAN_OPTIONS=external_symbolizer_path=$PWD/build/libs/bin/llvm-symbolizer make test-ci-core config=release test_full_program_timeout=300
When a behavior was called through a trait reference and the concrete actor's parameter had a different trace-significant capability (e.g., the trait declared `iso` but the actor declared `val`), the ORCA garbage collector's reference counting was broken. The sender traced the parameter with one trace kind and the receiver traced with another, causing field reference counts to never reach zero. Objects reachable from the parameter were leaked.
4
+
5
+
```pony
6
+
trait tag Receiver
7
+
be receive(b: SomeClass iso)
8
+
9
+
actor MyActor is Receiver
10
+
be receive(b: SomeClass val) =>
11
+
// b's fields were leaked when called through a Receiver reference
12
+
None
13
+
```
14
+
15
+
The leak is not currently active because `make_might_reference_actor` — an optimization that was disabled as a safety net — masks it by forcing full tracing of all immutable objects. Without this fix, the leak would have become active as we started re-enabling that optimization.
16
+
17
+
The sender and receiver now use consistent tracing for each parameter, regardless of capability differences between the trait and concrete method.
Copy file name to clipboardExpand all lines: .release-notes/next-release.md
-31Lines changed: 0 additions & 31 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -69,34 +69,3 @@ The FFI declaration now correctly uses `I32`, and the accept loop bails out on `
69
69
70
70
We've updated the LLVM version used to build Pony from 18.1.8 to 21.1.8.
71
71
72
-
## Compile-time string literal concatenation
73
-
74
-
The compiler now folds adjacent string literal concatenation at compile time, avoiding runtime allocation and copying. This works across chains that mix literals and variables — adjacent literals are merged while non-literal operands are left as runtime `.add()` calls. For example, `"a" + "b" + x + "c" + "d"` is folded to the equivalent of `"ab".add(x).add("cd")`, reducing four runtime concatenations down to two.
75
-
76
-
## Exempt unsplittable string literals from line length rule
77
-
78
-
The `style/line-length` lint rule no longer flags lines where the only reason for exceeding 80 columns is a string literal that contains no spaces. Strings without spaces — URLs, file paths, qualified identifiers — cannot be meaningfully split across lines, so flagging them produced noise with no actionable fix.
79
-
80
-
Strings that contain spaces are still flagged because they can be split at space boundaries using compile-time string concatenation at zero runtime cost:
81
-
82
-
```pony
83
-
// Before: flagged, and splitting is awkward
84
-
let url = "https://github.com/ponylang/ponyc/blob/main/packages/builtin/string.pony"
85
-
86
-
// After: no longer flagged — the string has no spaces and can't be split
87
-
88
-
// Strings with spaces can still be split, so they remain flagged:
89
-
let msg = "This is a very long error message that should be split across multiple lines"
90
-
91
-
// Fix by splitting at spaces:
92
-
let msg =
93
-
"This is a very long error message that should be split "
94
-
+ "across multiple lines"
95
-
```
96
-
97
-
Lines inside triple-quoted strings (docstrings) and lines containing `"""` delimiters are not eligible for this exemption — docstring content should be wrapped regardless of whether it contains spaces.
98
-
99
-
## Fix compiler crash on `return error`
100
-
101
-
Previously, writing `return error` in a function body would crash the compiler with an assertion failure instead of producing a diagnostic error. The compiler now correctly reports that a return value cannot be a control statement.
0 commit comments