From a5aa5baeb50ba5ce590ba913a1c5066df285352c Mon Sep 17 00:00:00 2001 From: Oleg Pulatov <242408046+olegpulatov@users.noreply.github.com> Date: Fri, 31 Jul 2026 03:14:46 +0200 Subject: [PATCH] test(natives): validate cross-target maudio layouts --- .../patches/maudio-sys-target-bindings.patch | 77 +++++++++++++------ crates/pi-voice/BUILD.bazel | 5 +- packages/natives/CHANGELOG.md | 3 +- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/bazel/patches/maudio-sys-target-bindings.patch b/bazel/patches/maudio-sys-target-bindings.patch index 398ccbb27..db1ff6207 100644 --- a/bazel/patches/maudio-sys-target-bindings.patch +++ b/bazel/patches/maudio-sys-target-bindings.patch @@ -2,9 +2,7 @@ diff --git a/build.rs b/build.rs index 419076b76e63bf1acbf92d0c7ffebfbe00fcebed..6abe69957113d92429b395e9d4b5cbc6a140a7c4 100644 --- a/build.rs +++ b/build.rs -@@ -5,6 +5,12 @@ use cc::Build; - - #[cfg(feature = "generate-bindings")] +@@ -7,2 +7,8 @@ use cc::Build; fn write_bindings(out_bindings: &std::path::Path) { + let target = env::var("TARGET").expect("TARGET must be set by Cargo"); + if !target.contains("apple-darwin") { @@ -13,11 +11,7 @@ index 419076b76e63bf1acbf92d0c7ffebfbe00fcebed..6abe69957113d92429b395e9d4b5cbc6 + } + let mut builder = bindgen::Builder::default() - .header("native/miniaudio/miniaudio.h") - .clang_arg("-Inative") -@@ -25,12 +31,20 @@ fn write_bindings(out_bindings: &std::path::Path) { - - #[cfg(not(feature = "generate-bindings"))] +@@ -27,8 +33,16 @@ fn write_bindings(out_bindings: &std::path::Path) { fn write_bindings(out_bindings: &std::path::Path) { + let target = env::var("TARGET").expect("TARGET must be set by Cargo"); + copy_bindings(&target, out_bindings); @@ -39,18 +33,33 @@ index 419076b76e63bf1acbf92d0c7ffebfbe00fcebed..6abe69957113d92429b395e9d4b5cbc6 + }; + std::fs::copy(source, out_bindings) .expect("Failed to copy pre-generated bindings to OUT_DIR"); - } - diff --git a/native/miniaudio_version_check.c b/native/miniaudio_version_check.c -index 58b5fee15748c92f21825948907b3535cb68bac9..b943c65b3e0c03f4442ba9569deaf27972853a73 100644 +index 58b5fee15748c92f21825948907b3535cb68bac9..d257fa23d945ad44f8a5e0956f6d8fd6d2a6fdf7 100644 --- a/native/miniaudio_version_check.c +++ b/native/miniaudio_version_check.c -@@ -4,4 +4,11 @@ - #error "Unsupported miniaudio version. Expected 0.11.23." - #endif - +@@ -7 +7,28 @@ -int miniaudio_version_check(void) { return 0; } +int miniaudio_version_check(void) { return 0; } ++ ++/* Cross-build baseline: validate the C target without executing its binary. */ ++#if defined(__linux__) ++#if defined(__aarch64__) && defined(__GLIBC__) ++#define OMP_MAUDIO_MUTEX_SIZE 48 ++#define OMP_MAUDIO_CONTEXT_SIZE 1056 ++#define OMP_MAUDIO_DEVICE_SIZE 3832 ++#else ++#define OMP_MAUDIO_MUTEX_SIZE 40 ++#define OMP_MAUDIO_CONTEXT_SIZE 1024 ++#define OMP_MAUDIO_DEVICE_SIZE 3776 ++#endif ++_Static_assert(sizeof(ma_mutex) == OMP_MAUDIO_MUTEX_SIZE, "unexpected ma_mutex size"); ++_Static_assert(_Alignof(ma_mutex) == 8, "unexpected ma_mutex alignment"); ++_Static_assert(sizeof(ma_context) == OMP_MAUDIO_CONTEXT_SIZE, "unexpected ma_context size"); ++_Static_assert(_Alignof(ma_context) == 8, "unexpected ma_context alignment"); ++_Static_assert(sizeof(ma_device) == OMP_MAUDIO_DEVICE_SIZE, "unexpected ma_device size"); ++_Static_assert(_Alignof(ma_device) == 8, "unexpected ma_device alignment"); ++#endif ++ +/* Hardware-independent ABI probe used by OMP's Rust layout regression test. */ +size_t omp_maudio_sizeof_mutex(void) { return sizeof(ma_mutex); } +size_t omp_maudio_alignof_mutex(void) { return _Alignof(ma_mutex); } @@ -59,29 +68,53 @@ index 58b5fee15748c92f21825948907b3535cb68bac9..b943c65b3e0c03f4442ba9569deaf279 +size_t omp_maudio_sizeof_device(void) { return sizeof(ma_device); } +size_t omp_maudio_alignof_device(void) { return _Alignof(ma_device); } diff --git a/src/lib.rs b/src/lib.rs -index af13b9ceb9f0816bc71ba9aebdc601047a77feae..479fc9172f91f475d5c89ce31bad5c4bd5ec9bf6 100644 +index af13b9ceb9f0816bc71ba9aebdc601047a77feae..04c3b659bc537980062076c5c553b2c191a3ef6c 100644 --- a/src/lib.rs +++ b/src/lib.rs -@@ -4,19 +4,7 @@ - #![allow(dead_code)] - #![no_std] - +@@ -7,5 +7,3 @@ -#[cfg(feature = "generate-bindings")] #[doc(hidden)] pub mod ffi { - // Check if the version is at least 1.70 include!(concat!(env!("OUT_DIR"), "/bindings.rs")); - } -- +@@ -14,9 +12,28 @@ pub mod ffi { -#[cfg(not(feature = "generate-bindings"))] -#[doc(hidden)] -pub mod ffi { - #[cfg(unix)] - include!("pregen_bindings/unix.rs"); ++// These target-gated checks pair with the C static assertions in ++// miniaudio_version_check.c, so cross-builds validate both sides without ++// executing a target binary. ++#[cfg(all(target_os = "linux", target_arch = "aarch64", target_env = "gnu"))] ++const _: () = { ++ assert!(core::mem::size_of::() == 48); ++ assert!(core::mem::align_of::() == 8); ++ assert!(core::mem::size_of::() == 1056); ++ assert!(core::mem::align_of::() == 8); ++ assert!(core::mem::size_of::() == 3832); ++ assert!(core::mem::align_of::() == 8); ++}; - ++ - #[cfg(windows)] - include!("pregen_bindings/windows.rs"); -} ++#[cfg(all( ++ target_os = "linux", ++ any( ++ target_env = "musl", ++ all(target_arch = "x86_64", target_env = "gnu") ++ ) ++))] ++const _: () = { ++ assert!(core::mem::size_of::() == 40); ++ assert!(core::mem::align_of::() == 8); ++ assert!(core::mem::size_of::() == 1024); ++ assert!(core::mem::align_of::() == 8); ++ assert!(core::mem::size_of::() == 3776); ++ assert!(core::mem::align_of::() == 8); ++}; diff --git a/src/pregen_bindings/linux-aarch64-gnu.rs b/src/pregen_bindings/linux-aarch64-gnu.rs new file mode 100644 index 0000000000000000000000000000000000000000..1a810aa6dfb98dda7de868d0ab13d2660911bcde diff --git a/crates/pi-voice/BUILD.bazel b/crates/pi-voice/BUILD.bazel index dd0033f88..d17e9f6d4 100644 --- a/crates/pi-voice/BUILD.bazel +++ b/crates/pi-voice/BUILD.bazel @@ -28,8 +28,9 @@ rust_test( deps = all_crate_deps(normal_dev = True), ) -# Direct C/Rust ABI comparison for miniaudio's opaque device state. This test -# needs the patched maudio-sys C probe, so it is intentionally Bazel-only. +# Direct C/Rust ABI comparison for miniaudio's opaque device state on the host. +# The patched crate also carries paired target-gated C and Rust static assertions +# so every cross-built Linux binding gets equivalent compile-time validation. rust_test( name = "maudio_layout_test", srcs = ["bazel/maudio_layout.rs"], diff --git a/packages/natives/CHANGELOG.md b/packages/natives/CHANGELOG.md index 550b7f234..2ba957340 100644 --- a/packages/natives/CHANGELOG.md +++ b/packages/natives/CHANGELOG.md @@ -4,8 +4,7 @@ ### Fixed -- Fixed `/live` corrupting the heap when opening PulseAudio on Linux ARM64 by shipping target-specific miniaudio Rust layouts for GNU and musl native addons. -- Fixed local Bazel addon builds on NixOS by exposing system CMake tools to sandboxed build scripts and forcing bundled Opus into the library directory expected by `audiopus_sys`. +- Fixed `/live` corrupting the heap when opening PulseAudio on Linux ARM64 by shipping target-specific miniaudio Rust layouts for GNU and musl native addons ([#7138](https://github.com/can1357/oh-my-pi/pull/7138) by [@olegpulatov](https://github.com/olegpulatov)). ## [17.2.1] - 2026-07-30