Releases: sanko/Affix.pm
Releases · sanko/Affix.pm
v1.0.6
[v1.0.6] - 2026-01-22
Most of this version's work went into threading stability, ABI correctness, and security within the JIT engine.
Changed
- [infix] The JIT memory allocator on Linux now uses
memfd_create(on kernels 3.17+) to create anonymous file descriptors for dual-mapped W^X memory. This avoids creating visible temporary files in/dev/shmand improves hygiene and security. On FreeBSD,SHM_ANONis now used. - [infix] On dual-mapped platforms (Linux/BSD), the Read-Write view of the JIT memory is now unmapped immediately after code generation. This closes a security window where an attacker with a heap read/write primitive could potentially modify executable code by finding the stale RW pointer.
- [infix]
infix_library_opennow usesRTLD_LOCALinstead ofRTLD_GLOBALon POSIX systems. This prevents symbols from loaded libraries from polluting the global namespace and causing conflicts with other plugins or the host application.
Fixed
- Fixed
CLONEto correctly copy user-defined types (typedefs, structs) to new threads. Previously, child threads started with an empty registry, causing lookup failures for types defined in the parent. - Thread safety: Fixed a crash when callbacks are invoked from foreign threads. Affix now correctly injects the Perl interpreter context into the TLS before executing the callback.
- Added stack overflow protection to the FFI trigger. Argument marshalling buffers larger than 2KB are now allocated on the heap (arena) instead of the stack, preventing crashes on Windows and other platforms with limited stack sizes.
- Type resolution: Fixed a logic bug where
Pointer[SV]types were incorrectly treated as generic pointers iftypedef'd. They are now correctly unwrapped into Perl CODE refs or blessed objects. - Process exit: Disabled explicit library unloading (
dlclose/FreeLibrary) during global destruction. This prevents segmentation faults when background threads from loaded libraries try to execute code that has been unmapped from memory during shutdown.
I tried to just limit it to Go lang libs but it's just more trouble than it's worth until I resolve a few more things. - [infix] Fixed stack corruption on macOS ARM64 (Apple Silicon).
long doubleon this platform is 8 bytes (an alias fordouble), unlike standard AAPCS64 where it is 16 bytes. The JIT previously emitted 16-byte stores (STR Qn) for these types, overwriting adjacent stack memory. - [infix] Fixed
long doublehandling on macOS Intel (Darwin). Verified that Apple adheres to the System V ABI for this type: it requires 16-byte stack alignment and returns values on the x87 FPU stack (ST(0)). - [infix] Fixed a generic System V ABI bug where 128-bit types (vectors,
__int128) were not correctly aligned to 16 bytes on the stack relative to the return address, causing data corruption when mixed with odd numbers of 8-byte arguments. - [infix] Enforced natural alignment for stack arguments in the AAPCS64 implementation. Previously, arguments were packed to 8-byte boundaries, which violated alignment requirements for 128-bit types.
- [infix] Fixed a critical deployment issue where the public
infix.hheader included an internal file (common/compat_c23.h). The header is now fully self-contained and definesINFIX_NODISCARDfor attribute compatibility. - [infix] Fixed 128-bit vector truncation on System V x64 (Linux/macOS). Reverse trampolines previously used 64-bit moves (
MOVSD) for all SSE arguments, corrupting the upper half of vector arguments. They now correctly useMOVUPS. - [infix] Fixed vector argument corruption on AArch64. The reverse trampoline generator now correctly identifies vector types and uses 128-bit stores (
STR Qn) instead of falling back to 64-bit/32-bit stores or GPRs. - [infix] Fixed floating-point corruption on Windows on ARM64. Reverse trampolines now force full 128-bit register saves for all floating-point arguments to ensure robust handling of volatile register states.
- [infix] Fixed a logic error in the System V reverse argument classifier where vectors were defaulting to
INTEGERclass, causing the trampoline to look inRDI/RSIinstead ofXMMregisters. - [infix] Fixed potential cache coherency issues on Windows x64. The library now unconditionally calls
FlushInstructionCacheafter JIT compilation. - [infix] Capped the maximum alignment in
infix_type_create_packed_structto 1MB to prevent integer wrap-around bugs in layout calculation. - [infix] Fixed a buffer overread on macOS ARM64 where small signed integers were loaded using 32-bit
LDRSW. ImplementedLDRSHandLDRSB. - [infix] Added native support for Apple's Hardened Runtime security policy.
- The JIT engine now utilizes
MAP_JITwhen thecom.apple.security.cs.allow-jitentitlement is detected. - Implemented thread-local permission toggling via
pthread_jit_write_protect_npto maintain W^X compliance.
- The JIT engine now utilizes
Full Changelog: v1.0.5...v1.0.6
v1.0.5
Allow users to define types in Affix::Wrap
Full Changelog: v1.0.4...v1.0.5
v1.0.4
Minor documentation tweaks
Full Changelog: v1.0.3...v1.0.4
Affix::Build and Affix::Wrap
Based on infix v0.1.3
Added
- Support for Variadic Functions (varargs):
- Implemented dynamic JIT compilation for C functions with variable arguments (e.g.,
printf). - Added
variadic_cacheto cache trampolines for repeated calls, ensuring high performance. - Implemented runtime type inference: Perl integers promote to
sint64, floats todouble, and strings to*char.
- Implemented dynamic JIT compilation for C functions with variable arguments (e.g.,
- Added
Affix::coerce($type, $value)to explicitly hint types for variadic arguments. This allows passing structs by value or forcing specific integer widths where inference is insufficient. - Cookbook: I'm putting together chapters on a wide range of topics at https://github.com/sanko/Affix.pm/discussions/categories/recipes
affixandwrapfunctions now accept an address to bind to. This expects the library to beundefand jumps past the lib location and loading steps.- Added
FileandPerlIOtypes.- Allows passing Perl filehandles to C functions expecting standard C streams (
PerlIO*=>Pointer[PerlIO]). - Allows receiving
FILE*from C and using them as standard Perl filehandles (FILE*=>Pointer[File]).
- Allows passing Perl filehandles to C functions expecting standard C streams (
- A few new specialized pointer types:
StringList: Automatically marshals an array ref of strings to a null-terminatedchar**array (and back). This is useful in instances whereargvor a similar list is expected.Buffer: Allows passing a pre-allocated scalar as a mutablechar*buffer to C (zero-copy write).SockAddr: Safe marshalling of Perl packed socket addresses tostruct sockaddr*.
- Affix::Build: A polyglot shared library builder. Currently supports Ada, Assembly, C, C#, C++, Cobol, Crystal, Dlang, Eiffel, F#, Fortran, Futhark, Go, Haskell, Nim, OCaml, Odin, Pascal, Rust, Swift, Vlang, and Zig.
- Affix::Wrap: An experimental tool to introspect C header files and generate Affix bindings and documentation.
- Dual-Driver Architecture:
Affix::Wrap::Driver::Clang: Uses the systemclangexecutable to parse the AST for high-fidelity extraction of types, macros, and comments.Affix::Wrap::Driver::Regex: A zero-dependency fallback driver that parses headers using heuristics.
- Dual-Driver Architecture:
Changed
Array[Char]function arguments now accept Perl strings directly, copying the string data into the temporary C array.Affix::errno()now returns a dualvar containing both the numeric error code (errno/GetLastError) and the system error string (strerror/FormatMessage).
Fixed
- Correctly implemented array decay for function arguments on ARM and Win64.
Array[...]types are now marshalled into temporary C arrays and passed as pointers, matching standard C behavior. Previously, they were incorrectly passed by value, causing stack corruption. - Fixed binary safety for
Array[Char/UChar]. Reading these arrays now respects the explicit length rather than stopping at the first null byte. - The write-back mechanism no longer attempts to overwrite the read-only ArrayRef scalar with the pointer address.
Pointer[SV]is now handled properly as args, return values, and in callbacks. Reference counting is automatic to prevent premature garbage collection of passed scalars.- Shared libs written in Go spin up background threads (for GC and scheduling) that do not shut down cleanly when a shared library is unloaded. This often causes access violations on Windows during program exit. We attempt to work around this by detecting libs with the Go runtime and just... not unloading them.
What's Changed
- VarArgs, PerlIO and File handles, locate_lib fix, Enum enhancement, errno fix, etc. by @sanko in #73
- Work around segfaults caused by unloading shared libs written in Go by @sanko in #82
- Runtime bindings from C/C++ headers by @sanko in #83
- Allow passing Perl strings to char*, uchar*, and void* arguments by @sanko in #92
Full Changelog: v1.0.2...v1.0.3
Union and lvalue pointer fixes
Full Changelog: v1.0.0...v1.0.1
Stable enough
Full Changelog: v0.12.0...v1.0.0
Unstable total rewrite
First version based on infix. This will eventually be 1.0.x.
Full Changelog: https://github.com/sanko/Affix.pm/commits/v0.12.0
0.11
Itanium and Rust (legacy) mangling
Full Changelog: 0.10...0.11