diff --git a/rust/plex-pg-core/src/pms_process_compat.rs b/rust/plex-pg-core/src/pms_process_compat.rs index b619f2a9..279425f1 100644 --- a/rust/plex-pg-core/src/pms_process_compat.rs +++ b/rust/plex-pg-core/src/pms_process_compat.rs @@ -9,6 +9,9 @@ use crate::db_interpose_common; use crate::db_interpose_common::stderr_ptr; use crate::env_utils; +// Do not interpose vfork. Until the child execs, it shares the parent's stack; +// returning through a Rust wrapper can corrupt the suspended caller's frame. + type CloneStartFn = unsafe extern "C" fn(*mut libc::c_void) -> c_int; type CloneFn = unsafe extern "C" fn( Option, @@ -39,7 +42,6 @@ type SyscallFn = unsafe extern "C" fn( libc::c_long, libc::c_long, ) -> libc::c_long; -type VForkFn = unsafe extern "C" fn() -> libc::pid_t; static mut ORIG_DAEMON: Option = None; static mut ORIG_FORK: Option = None; @@ -48,7 +50,6 @@ static mut ORIG_PRCTL: Option = None; static mut ORIG_PTHREAD_SETNAME_NP: Option = None; static mut ORIG_SETSID: Option = None; static mut ORIG_SYSCALL: Option = None; -static mut ORIG_VFORK: Option = None; static PROCESS_COMPAT_LOG_BUDGET: AtomicI32 = AtomicI32::new(0); static SUPPRESS_DAEMON: AtomicI32 = AtomicI32::new(0); @@ -117,10 +118,6 @@ unsafe fn resolve_syscall() -> Option { resolve_symbol(&mut ORIG_SYSCALL, b"syscall\0") } -unsafe fn resolve_vfork() -> Option { - resolve_symbol(&mut ORIG_VFORK, b"vfork\0") -} - unsafe fn set_errno(err: c_int) { *libc::__errno_location() = err; } @@ -370,24 +367,6 @@ pub unsafe extern "C" fn clone( rc } -#[no_mangle] -/// # Safety -/// ABI interposition wrapper for `vfork`. Callers must obey libc preconditions. -pub unsafe extern "C" fn vfork() -> libc::pid_t { - let Some(orig) = resolve_vfork() else { - set_errno(libc::ENOSYS); - return -1; - }; - - let rc = orig(); - if rc > 0 { - maybe_log_event(b"vfork\0", i64::from(rc), 0); - } else if rc < 0 { - maybe_log_event(b"vfork\0", -1, *libc::__errno_location()); - } - rc -} - #[no_mangle] /// # Safety /// ABI interposition wrapper for `prctl`. Callers must obey libc preconditions. diff --git a/rust/plex-pg-core/src/runtime_linux.rs b/rust/plex-pg-core/src/runtime_linux.rs index bc3aa47c..f0de50f2 100644 --- a/rust/plex-pg-core/src/runtime_linux.rs +++ b/rust/plex-pg-core/src/runtime_linux.rs @@ -525,6 +525,43 @@ static INIT: extern "C" fn() = shim_init_wrapper; #[cfg_attr(target_os = "linux", link_section = ".fini_array")] static FINI: extern "C" fn() = shim_cleanup_wrapper; +// ──────────────────────────────────────────────────────────────────────────── +// The bundled x86-64 Boost codecvt also rejects the "ASCII" name. Preserve +// the C++ hidden return pointer in rdi and tail-call the UTF-8 variant with +// its two explicit arguments (locale in rsi, facet moved from ecx to edx). +#[cfg(all(feature = "interpose", target_arch = "x86_64"))] +std::arch::global_asm!( + ".global _ZN5boost6locale4util21create_simple_codecvtERKNSt3__26localeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS0_12char_facet_tE", + ".type _ZN5boost6locale4util21create_simple_codecvtERKNSt3__26localeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS0_12char_facet_tE, @function", + "_ZN5boost6locale4util21create_simple_codecvtERKNSt3__26localeERKNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEENS0_12char_facet_tE:", + "cmp byte ptr [rdx], 65", + "jne .Lshim_x86_csc_orig", + "cmp byte ptr [rdx + 1], 83", + "jne .Lshim_x86_csc_orig", + "cmp byte ptr [rdx + 2], 67", + "jne .Lshim_x86_csc_orig", + "cmp byte ptr [rdx + 3], 73", + "jne .Lshim_x86_csc_orig", + "cmp byte ptr [rdx + 4], 73", + "jne .Lshim_x86_csc_orig", + "cmp byte ptr [rdx + 5], 0", + "jne .Lshim_x86_csc_orig", + "mov r11, qword ptr [rip + SHIM_CREATE_UTF8_CODECVT_PTR@GOTPCREL]", + "mov r11, qword ptr [r11]", + "test r11, r11", + "je .Lshim_x86_csc_orig", + "mov edx, ecx", + "jmp r11", + ".Lshim_x86_csc_orig:", + "mov r11, qword ptr [rip + SHIM_CREATE_SIMPLE_CODECVT_PTR@GOTPCREL]", + "mov r11, qword ptr [r11]", + "test r11, r11", + "je .Lshim_x86_csc_abort", + "jmp r11", + ".Lshim_x86_csc_abort:", + "jmp abort@PLT", +); + // ──────────────────────────────────────────────────────────────────────────── // ──────────────────────────────────────────────────────────────────────────── // AArch64 assembly hook for boost::locale::util::create_simple_codecvt. diff --git a/scripts/migrate_lib.sh b/scripts/migrate_lib.sh index e4cf282e..8bf722b1 100644 --- a/scripts/migrate_lib.sh +++ b/scripts/migrate_lib.sh @@ -199,7 +199,8 @@ migrate_sqlite_to_pg() { if [[ -z "$pg_cols" ]]; then echo -e "${YELLOW}SKIP (no PG table)${NC}" - ((skipped++)) + # Prefix increment succeeds when this script runs under set -e. + ((++skipped)) continue fi @@ -276,10 +277,10 @@ migrate_sqlite_to_pg() { if python3 "$migrate_py" \ "$SQLITE_DB" "$table" "$sqlite_select" "$pg_cols_list" "$schema" 2>>"$log_dir/migration_errors.log"; then echo -e "${GREEN}OK${NC}" - ((migrated++)) + ((++migrated)) else echo -e "${RED}FAIL${NC}" - ((failed++)) + ((++failed)) fi # Restore check constraints and triggers