Affix

 view release on metacpan or  search on metacpan

Changes.md  view on Meta::CPAN

# Changelog

All notable changes to Affix.pm will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v1.2.5] - 2026-08-17

### Fixed

- `SAVEVPTR`/`SAVEDESTRUCTOR_X` 'fix' broke thread safety. When a second thread or fiber entered the same Affix-generated XSUB, its `SAVEVPTR` captured the first fiber's temp arena as "old", so on scope exit the second fiber restored a dangling point...

## [v1.2.4] - 2026-08-15

Plugging leaks...

### Fixed

- Use `SAVEVPTR` and `SAVEDESTRUCTOR_X` to swap out arenas to fix leaky allocator in situations where tons of structs are passed in a list and need to be marshalled in only one direction
- Casting or binding an aggregate (`Affix::cast`, member pins) no longer leaks: member pins borrowed the freshly created parent hash/array as their lifeline, forming a strong reference cycle that Perl's refcounting cannot collect, so the whole pin tr...
- Passing a union to a wrapped call no longer segfaults: the argument sync read back *every* union member, and reading an inactive pointer/string member dereferenced the active member's float bytes as a C string pointer. Deep writes now skip members ...
- The library probe in `Affix::Platform::Unix` (`_findLib_gcc`) no longer prints linker errors (`undefined reference to WinMain`/`main`) while searching: it probes with `-shared`, which needs no entry point.
- Bitfields inside `Struct[...]` are no longer read or written out of bounds: `member->offset` now points at the storage unit base (with `bit_offset` relative to the unit) instead of the bitfield's own byte, so the unit-sized load/store in `push_stru...
- Reading and writing packed struct members (and pinned primitives) no longer uses unaligned native loads/stores: the dispatch vtables, bitfield vtables, pull handlers, and push handlers now round-trip through `memcpy`, which is safe on strict-alignm...
- Passing a wide string (`WString()`, i.e. `*wchar_t`) to a wrapped function now works on all platforms instead of croaking `Don't know how to handle this type of scalar as a pointer argument yet` on non-Windows systems, where the wide-string push op...
- Returning a `WString` no longer crashes: the wide-string pull handler called `SvGROW` on an uninitialized target SV, faulting before any buffer was allocated.
- [infix] Passing a 5-7 byte `Struct[...]` by value to a wrapped function no longer drops the trailing members on ARM64. The forward trampoline emitted a 32-bit register load unless the struct was exactly 8 bytes, so a `Struct[ arr => Array[2, UInt16...

## [v1.2.3] - 2026-08-08

### Fixed

- `Struct[...]` fields of type `WString` can now be assigned to (or as?) Perl strings (`SvPV`) rather than falling through and becoming null pointers

## [v1.2.2] - 2026-08-05

The headline is support for RISC-V!

### Fixed

- `malloc()`/`calloc()` pins no longer lose their `Affix::Memory` lifeline: the memory is kept alive for as long as any derived pin exists (fixes a use-after-free where the block could be handed out to a later allocation), and `free()` now works on p...
- `realloc()` no longer corrupts the `Affix::Memory` reference header when updating the stored address.
- [infix] Layout recalculation now descends into reverse trampolines, so a `Struct[...]` declared inline in a signature whose members referenced named types no longer has corrupted offsets.

### Added
- [infix] Support for RISC-V (rv64)

## [v1.2.1] - 2026-08-02

### Fixed

- Fixed `panic: free ... from wrong pool` crash at process exit on perls built with both debugging and threads enabled.

## [v1.2.0] - 2026-07-29

### Changed
- Affix::Build tests have been fenced off as author tests.

## [v1.1.0] - 2026-07-25

### Added

- V2 Pin System: Replaced the old `Affix_Pin` struct with `Affix_Pin_2_Point_Oh` backed by Perl Magic VTables, eliminating tied-variable overhead for all memory access.
- Reworked `Affix::Wrap` type parser to handle `const`, `restrict`, and `volatile` qualifiers, improved function pointer matching, and refactored the type map for cleaner code generation.
- Generated `Affix::Wrap` bindings now emit `Const[...]` for C `const`-qualified types, enabling compile-time safety in wrapper output.
- Added `Const[...]` type wrapper that prevents Perl-side mutation of C memory marked `const`. Replaces the old `Live` helper.
- Added struct bitfield array syntax so members can be declared as `[$name, $type, $width]`.
- Enum definitions now accept explicit integer values and arithmetic expressions (`FOO => BAR | 0x8`) in addition to sequential auto-increment.
- [infix] Added support for preserving character-specific primitive names (`wchar_t`, `char16_t`, `char32_t`, `char8_t`), enabling correct identification of string buffers via `infix_type_get_name()`.

### Changed

- WChar now maps to the platform-correct `wchar_t` type (uint16 on Windows, uint32 elsewhere) instead of hardcoded `uint16`.
- WString now platform-dependent (`*uint16` on Windows, `*uint32` elsewhere).
- StringList redefined as `Pointer[Pointer[Char]]` instead of the `@StringList` alias.
- Extended `_is_signature_string` to recognize `+`, `c[...]`, `v[...]`, and `e:` prefixed type strings.
- Do not rewind `args_arena` so pointers survive XSUB return (hopefully callee stored them).

### Fixed

- Fixed struct member callback assignment where `$pin->{fn} = sub { ... }` silently created a trampoline with 0 arguments, causing "Too few arguments" errors or crashes when C called through the function pointer. `Pointer[Callback[...]]` creates a do...
- `set_ptr` now croaks when a coderef is assigned to a non-callback pointer type instead of silently creating a broken 0-argument trampoline.
- Fixed fuzzer `struct_callback` variant's verify function to truncate expected values to the callback return type's width.
- Fixed packed struct layout where `Packed(Struct[...])` returned sizeof values matching unpacked structs.
- Replaced silent fallbacks with proper errors: unknown primitive type IDs in opcode dispatch and enum size handling now croak instead of silently misinterpreting memory.
- Added warning when callback type signature serialization fails instead of silently returning a raw pointer value.
- Fixed a sign-extension bug in 128-bit integer parsing.
- Fixed bitfield write-back logic to use proper bitmasking, preventing neighboring bit corruption.
- Corrected `wstring` (UTF-16/32) conversion to handle null-terminators properly in fixed-size arrays.
- Fixed `Affix::Wrap` eval-generated bindings on macOS where Clang emits Mach-O underscore-prefixed `mangledName` (`_return_six`), but `dlsym` expects the source-level name (`return_six`).
- [infix] Fixed RAX register preservation in Windows x64 reverse trampoline epilogue for void functions, preventing clobber of the return value register.
- [infix] Fixed SysV x64 reverse trampoline handling of `ARG_LOCATION_GPR_REFERENCE` for aggregates >16 bytes passed by reference.
- [infix] Corrected handling of aggregates classified as `MEMORY` during reverse trampoline calls in SysV.

## [v1.0.9] - 2026-03-05

This release focuses on refining the "Live" zero-copy system (ugh) and fixing bitfield write-back support (yay).

### Breaking Changes
- Replaced `LiveStruct`, `LiveArray`, and `LiveUnion` with a single `Live` wrapper. It now accepts any type object or signature (`Live[Struct[...]]`, `Live[Array[Int, 10]]`) and returns a live, zero-copy view. I hate this too but I'm workin' on it.

### Added
- Fully implemented write support for bitfields in live views. Modifying a bitfield member in an `Affix::Live` hash now correctly performs bit-masked writes to the underlying C memory.
- Added `LiveUnion` as a deprecated alias for the unified `Live()` classifier.

### Fixed

- Fixed an inconsistency where `Affix::Type::Array` objects were stringifying in a format incompatible with `cast`. They now correctly use the `$type[$count]` syntax.
- Updated the internal type stringifier to correctly resolve and prefer the `signature` method over `stringify`, ensuring consistent behavior across all `Affix::Type` objects.
- Fixed a bug in `Affix_cast` where the `live_hint` (`+`) was ignored for Arrays and Unions.

## [v1.0.8] - 2026-03-02

This release introduces a modernization of pointer handling, turning pins into first-class objects with native indexing support. In other words, you can now use `$ptr->[$n]` to access the nth element.

Support for passing 128bit integers around is now complete. Additionally, functions expecting an enumeration now accept the string name of a constant; `state('PLASMA')` is the same as `state(PLASMA)` where `state` expects values defined like this: `t...

### Added

- Added support for native Perl array indexing on pointers and arrays. You can now use `$ptr->[$i]` to read or write memory at an offset without manual casting.
- New `Affix::Pointer` objects for structs and unions now allow direct field access like `$ptr->{field}` without explicit casting to `LiveStruct`.
- Recursive Liveness: Unified access and `LiveStruct` now work recursively. Accessing a nested struct member returns a live view or pointer tied to the original memory block.
- All pointers returned by `malloc`, `calloc`, `cast`, etc., are now blessed into the `Affix::Pointer` class, which provides several new methods:
    - `address()`: Returns the virtual memory address.
    - `type()`: Returns the L<infix> signature of the pointer.
    - `element_type()`: Returns the signature of the pointed-to elements.
    - `count()`: Returns the element count for Arrays, or byte size for Void pointers.
    - `size()`: Returns the total allocated size for managed pointers.
    - `cast($type)`: Reinterprets the pointer.
    - `attach_destructor($destructor, [$lib])`: Attaches a custom C cleanup routine to the pointer.
- Added `attach_destructor( $pin, $destructor, [$lib] )` to allow attaching custom C cleanup routines to managed pointers.
- Improved `VarArgs` support to automatically promote Perl strings to `char*`.
- Experimental Zero-Copy 'Live' Aggregates:
    - `LiveStruct`: A new helper to return zero-copy, live views of C structs. Modifications to the returned blessed hash reflect immediately in C memory.
    - `LiveArray`: A new helper to return live `Affix::Pointer` objects instead of deeply copied array references.
    - Implemented the `TIEHASH` interface for `Affix::Live` so perl can treat them as standard Perl hashes (`keys %$live`, `each %$live`, etc.).
- Fully implemented marshalling for `Int128` and `UInt128` (sint128/uint128) primitive types.
- Added `Affix::Wrap->generate( $lib, $pkg, $file )` for static binding generation. This emits standalone Perl modules that depend only on `Affix`, eliminating the need for `Clang` or header files at runtime.
- Recursive macro resolution support in `Affix::Wrap` for bitwise OR expressions like `(FLAG_A | FLAG_B)`.
- Support for passing string names of enum constants directly to functions.
- Added `params()` method to `Affix::Type::Callback` to allow inspecting and modifying callback parameters.
- Added string-to-integer conversion when passing Perl strings to C functions expecting enums.

### Fixed

- Optimized `Pointer` returns in the XSUB dispatcher for performance by inlining the marshalling path and caching the stash.
- Fixed several issues in `CLONE` where metadata, managed memory, and enum registries were not correctly duplicated across perl's ithreads.
- Improved `_get_pin_from_sv` and `is_pin` to safely handle both references to pins and direct magical scalars like those found in Unions.
- Fixed potential double-frees and leaks in `Affix_Lib_DESTROY` and `Affix_free_pin` by improving reference counting and ownership tracking.
- Symbols found via `find_symbol` now correctly track the parent `Affix::Lib` object to prevent the library from being unloaded while symbols are still in use.
- Corrected a memory corruption bug in `Affix_malloc` and `Affix_strdup` caused by uninitialized internal `Affix_Pin` structures.
- Fixed `dualvar` behavior for enums returned from C, ensuring they correctly function as both strings and integers in Perl.
- Fixed the `clean` action in `Affix::Builder` which was failing due to an undefined `rmtree` call.
- Fixed an issue where blessing a return value could prematurely trigger 'set' magic on the underlying SV.
- Fixed `typedef` parsing: Named types now return proper `Affix::Type::Reference` objects instead of strings, ensuring they are correctly resolved when nested in other aggregates.
- Fixed `cast` to correctly return blessed `Affix::Live` objects when the `+` hint is used for live struct views.
- Hardened pointer indexing: Added strict type checks to `$ptr->[$i]` to ensure indexing is only performed on `Array` types or `Void*` (byte-indexed).

## [v1.0.7] - 2026-02-15

Valgrind directed the work in Affix itself but infix got a lot of platform stability fixes which found their way into Affix by way of new Float16 support, bitfield width support, and SIMD improvements.

### Fixed

- Anonymous wrapper functions created via wrap() were leaking because of a redundant SvREFCNT_inc call and the use of newRV_inc instead of newRV_noinc. This prevented the underlying CV and its associated Affix struct (including its memory arenas) fro...
- Implicitly loaded libraries (by path) were not having their reference counts decremented because the handle was not stored in the Affix struct. Additionally, using Affix::Lib objects did not increment the registry reference count, potentially leadi...
- Passing Pointer[SV] arguments to C functions caused a reference count leak of 1 per call because SvREFCNT_inc was called without a corresponding decrement.
- The library registry cleanup logic was missing from the main CV destructor and had a potential crash-inducing bug in the bundled destructor.
- [infix] Corrected an ARM64 bug in `emit_arm64_ldr_vpr` and `emit_arm64_str_vpr` where boolean conditions were being passed instead of actual byte sizes, causing data truncation for floating-point values in the direct marshalling path.
- [infix] Fixed MSVC ARM: SEH XDATA layout to follow the architecture's specification exactly, enabling reliable exception handling on Windows on ARM.
- [infix] Hardened instruction cache invalidation on ARM64 Linux/BSD with a robust manual fallback using assembly (`dc cvau`, `ic ivau`, etc.), ensuring generated code is immediately visible to the CPU.
- [infix] Fixed the DWARF `.eh_frame` generation for ARM64 Linux `FORWARD` trampolines, correcting the instruction sequence and offsets to enable reliable C++ exception propagation.
- [infix] Corrected a performance issue on x64 by adding `vzeroupper` calls in epilogues when AVX instructions are potentially used, avoiding transition penalties.
- [infix] Fixed bitfield parsing logic to correctly handle colons in namespaces vs bitfield widths.
- [infix] Fixed missing support for 256-bit and 512-bit vectors in SysV reverse trampolines.
- [infix] Rewrote `_layout_struct` in `src/core/types.c` to correctly handle bitfields larger than 8 bits and ensures `bit_offset` is always within the correct byte, matching standard C (well, GNU) compiler packing behavior.
- [infix] Fixed a bug in the SysV recursive classifier that was incorrectly applying strict natural alignment checks to bitfield members. This was causing structs containing bitfields to be unnecessarily passed on the stack instead of in registers.
- [infix] Trampolines allocated in a user-managed "shared arena" were being added to the internal global cache. When the user destroyed the arena, the cache retained dangling pointers to the trampoline signatures.

### Added

- Float16 support



( run in 0.601 second using v1.01-cache-2.11-cpan-5c0b1e786e0 )