[PATCH] Fix 128-bit alien value truncation on x86-64
Andreas Franke via Sbcl-devel <[email protected]> Fri, 27 Feb 2026 00:23:58 +0000
| Newsgroups | gmane.lisp.steel-bank.devel |
|---|---|
| Message-ID | <trinity-b649d32a-2bd5-489c-97fa-4bbedbd695af-1772151838646@trinity-msg-rest-gmx-gmx-live-756cfcdf5c-tbvpt> |
Here's another one (co-authored by Claude). Validated on sbcl-2.6.1-233-g122d48ff6 master. _______________________________________________ Sbcl-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/sbcl-devel
0001-Fix-128-bit-alien-value-truncation-on-x86-64.patch
(text/x-patch, 3.2 KB)
From 2074ae00c19007b862e0e03001defc059e9e6c77 Mon Sep 17 00:00:00 2001 From: Andreas Franke <[email protected]> Date: Thu, 26 Feb 2026 21:05:12 +0000 Subject: [PATCH] Fix 128-bit alien value truncation on x86-64 --- src/compiler/x86-64/c-call.lisp | 6 +----- tests/alien-128.c | 6 ++++++ tests/alien.impure.lisp | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/alien-128.c diff --git a/src/compiler/x86-64/c-call.lisp b/src/compiler/x86-64/c-call.lisp index bf89c8d1d..22b400876 100644 --- a/src/compiler/x86-64/c-call.lisp +++ b/src/compiler/x86-64/c-call.lisp @@ -512,11 +512,7 @@ Floats are passed in integer registers." (lambda-vars arg) (cond ((and (alien-integer-type-p type) (> (sb-alien::alien-integer-type-bits type) 64)) - ;; CLH: FIXME! This should really be - ;; #xffffffffffffffff. nyef says: "Passing - ;; 128-bit integers to ALIEN functions on x86-64 - ;; believed to be broken." - (new-args `(logand ,arg #xffffffff)) + (new-args `(logand ,arg #xffffffffffffffff)) (new-args `(ash ,arg -64)) (new-arg-types (parse-alien-type '(unsigned 64) env)) (if (alien-integer-type-signed type) diff --git a/tests/alien-128.c b/tests/alien-128.c new file mode 100644 index 000000000..45804ad55 --- /dev/null +++ b/tests/alien-128.c @@ -0,0 +1,6 @@ +#include <stdint.h> + +typedef unsigned __int128 uint128; + +uint64_t echo_low_64(uint128 x) { return (uint64_t)x; } +uint64_t echo_high_64(uint128 x) { return (uint64_t)(x >> 64); } diff --git a/tests/alien.impure.lisp b/tests/alien.impure.lisp index 1ba7e58ab..c73d88017 100644 --- a/tests/alien.impure.lisp +++ b/tests/alien.impure.lisp @@ -585,6 +585,29 @@ (alien-funcall (extern-alien (something) (function c-string c-string)) s)))))) (assert (string= (funcall f "SBCL_HOME") (sb-ext:posix-getenv "SBCL_HOME"))))) +(unless (probe-file "alien-128.so") + (sb-ext:run-program "/bin/sh" + '("run-compiler.sh" "-sbcl-pic" "-sbcl-shared" + "-o" "alien-128.so" "alien-128.c"))) + +(with-test (:name :alien-128bit-value-passing + :skipped-on (not :x86-64)) + ;; Verify that both halves of a 128-bit alien value survive the FFI call. + ;; This guards against using a 32-bit mask instead of 64-bit when splitting + ;; the value into two 64-bit halves. + (load-shared-object (truename "alien-128.so")) + (let ((val (+ (ash #xDEADBEEFCAFEBABE 64) #x0123456789ABCDEF))) + (assert (= (alien-funcall + (extern-alien "echo_low_64" + (function (unsigned 64) (unsigned 128))) + val) + #x0123456789ABCDEF)) + (assert (= (alien-funcall + (extern-alien "echo_high_64" + (function (unsigned 64) (unsigned 128))) + val) + #xDEADBEEFCAFEBABE)))) + (cl:in-package "SB-KERNEL") (test-util:with-test (:name :hash-consing) (assert (eq (parse-alien-type '(integer 9) nil) -- 2.43.0