Skip to content

Fix segfault when matching tuple elements against unions or interfaces via Any#5134

Open
SeanTAllen wants to merge 1 commit intomainfrom
fix-issue-4507-tuple-match-boxing
Open

Fix segfault when matching tuple elements against unions or interfaces via Any#5134
SeanTAllen wants to merge 1 commit intomainfrom
fix-issue-4507-tuple-match-boxing

Conversation

@SeanTAllen
Copy link
Copy Markdown
Member

When pattern matching a boxed tuple (via Any val), unboxed numeric elements were loaded as pointers when the match pattern expected a union or interface type. The raw byte value got interpreted as a memory address and the program segfaulted.

The codegen for dynamic_capture_ptr and dynamic_value_ptr now checks the runtime type_id to distinguish object pointers (odd type_id, load directly) from raw inline data (even type_id, box into a heap object first). The boxing helper allocates via pony_alloc, stores the descriptor, and memcpys the data at the correct alignment-aware offset. This uses the same type_id encoding that gentrace.c already relies on.

The fix also corrects make_field_offset to return the actual struct offset for boxable numeric types. It was returning 0 for all types with field_count == 0, which would put the value at the wrong offset for types like I128/U128 where alignment padding pushes the value past the pointer-sized offset.

Five regression tests cover: union-typed element, interface-typed element, the no-double-boxing scenario from PR #4787's regression, I128 alignment, and nested inline tuples.

Note: The dynamic_value_ptr fix mirrors dynamic_capture_ptr but has no dedicated test. I think the pointer-type branch there is probably unreachable in practice since value patterns resolve to concrete eq() parameter types rather than unions or interfaces. The code is defensive.

Closes #4507

…s via Any

When pattern matching a boxed tuple (via Any val), unboxed numeric elements
were loaded as pointers when the match pattern expected a union or interface
type, causing a segfault.

The fix adds a runtime type_id parity check in dynamic_capture_ptr and
dynamic_value_ptr: odd type_id means the field is an object pointer (load
directly), even means raw inline data that needs boxing into a heap object.
The boxing helper allocates via pony_alloc, stores the descriptor, and
memcpys the raw data at the correct alignment-aware offset.

Also fixes make_field_offset to return the correct value offset for boxable
numeric types — it was returning 0, which would break types like I128/U128
where alignment padding puts the value past the pointer-sized offset.

Closes #4507
@SeanTAllen SeanTAllen added the changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge label Apr 5, 2026
@ponylang-main ponylang-main added the discuss during sync Should be discussed during an upcoming sync label Apr 5, 2026
@SeanTAllen
Copy link
Copy Markdown
Member Author

@nisanharamati please give this a test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog - fixed Automatically add "Fixed" CHANGELOG entry on merge discuss during sync Should be discussed during an upcoming sync

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Segfault when accessing a union in a tuple via Any

2 participants