On 2026-05-18 21:50, Aurelien Jarno wrote:
> control: tag -1 + patch
> control: forwarded -1 https://github.com/microsoft/mimalloc/pull/1296
> 
> Hi:
> 
> On 2026-05-15 00:06, Aurelien Jarno wrote:
> > control: retitle -1 mimalloc: riscv64: build-time MMU detection causes 
> > crashes on SV48 systems
> > control: reassign -1 src:mimalloc
> > control: found -1 3.0.1+ds-1
> > 
> > Hi,
> > 
> > On 2026-05-14 22:09, Aurelien Jarno wrote:
> > > On 2026-05-14 13:02, Aurelien Jarno wrote:
> > > > Hi,
> > > > 
> > > > On 2026-05-14 01:02, Peter Green wrote:
> > > > > found 1136400 0.1.40-1
> > > > > thanks
> > > > > 
> > > > > I believe you've quoted the wrong part of the log,
> > > > > quoting output from a test that is already marked as "broken".
> > > > > 
> > > > > I belive the actual failure is.
> > > > > 
> > > > > 142s   process didn't exit successfully: `CARGO=/usr/bin/cargo 
> > > > > CARGO_MANIFEST_DIR=/usr/share/cargo/registry/libmimalloc-sys-0.1.40 
> > > > > CARGO_MANIFEST_PATH=/usr/share/cargo/registry/libmimalloc-sys-0.1.40/Cargo.toml
> > > > >  CARGO_PKG_AUTHORS='Octavian Oncescu <[email protected]>' 
> > > > > CARGO_PKG_DESCRIPTION='Sys crate wrapping the mimalloc allocator' 
> > > > > CARGO_PKG_HOMEPAGE='' CARGO_PKG_LICENSE=MIT CARGO_PKG_LICENSE_FILE='' 
> > > > > CARGO_PKG_NAME=libmimalloc-sys CARGO_PKG_README='' 
> > > > > CARGO_PKG_REPOSITORY='https://github.com/purpleprotocol/mimalloc_rust/tree/master/libmimalloc-sys'
> > > > >  CARGO_PKG_RUST_VERSION='' CARGO_PKG_VERSION=0.1.40 
> > > > > CARGO_PKG_VERSION_MAJOR=0 CARGO_PKG_VERSION_MINOR=1 
> > > > > CARGO_PKG_VERSION_PATCH=40 CARGO_PKG_VERSION_PRE='' 
> > > > > LD_LIBRARY_PATH='/tmp/tmp.YhgzhQ6wzU/target/riscv64gc-unknown-linux-gnu/debug:/tmp/tmp.YhgzhQ6wzU/target/riscv64gc-unknown-linux-gnu/debug/deps:/usr/lib/rustlib/riscv64gc-unknown-linux-gnu/lib'
> > > > >  
> > > > > OUT_DIR=/tmp/tmp.YhgzhQ6wzU/target/riscv64gc-unknown-linux-gnu/debug/build/libmimalloc-sys-4d9f02f6027bf000/out
> > > > >  
> > > > > /tmp/tmp.YhgzhQ6wzU/target/riscv64gc-unknown-linux-gnu/debug/deps/libmimalloc_sys-ceadfc72acec09f8`
> > > > >  (signal: 11, SIGSEGV: invalid memory reference)
> > > > > 142s autopkgtest [05:06:41]: test librust-libmimalloc-sys-dev:arena: 
> > > > > -----------------------]
> > > > 
> > > > I am personally unable to reproduce the issue on two different boards, 
> > > > using JH7110 and SpacemiT K1 CPU. That said after retrying the 
> > > > autopkgtest a few time on debci (it runs fast), I have noticed the 
> > > > following pattern:
> > > > - Tests pass on debci-10 running Linux 6.12.86+deb13-riscv64
> > > > - Tests fail on debci-31, debci-32 and debci-33 running Linux 
> > > > 6.6.88-win2030
> > > > 
> > > > Therefore I believe it could be a kernel or a hardware issue. I guess 
> > > > the boards running the 6.6.88-win2030 kernel are the P550 ones.
> > > 
> > > I am able to reproduce the issue on a P550 board, either running kernel 
> > > 6.6.77, 6.12.33 or 6.12.78. I am also able to reproduce it on the same 
> > > hardware in a VM running kernel 6.12.86+deb13-riscv64.
> > > 
> > > On the other hand I am unable to reproduce it on the riscv64 porterbox 
> > > (ricci.d.o).
> > > 
> > > I therefore believe there is something fishy with the hardware that 
> > > needs more investigation.
> > 
> > I finally found the issue. It is in mimalloc, which contains the 
> > following build time check:
> > 
> > | # Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits.
> > | # (this will skip the aligned hinting in that case. Issue #939, #949)
> > | if (EXISTS /proc/cpuinfo)
> > |   file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$")
> > |   if (mi_sv39_mmu)
> > |     MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" )
> > |     list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39)
> > |   endif()
> > | endif()
> > 
> > Our build daemons are using a sv39 nmu:
> > 
> > | aurel32@ricci:~$ grep ^mmu /proc/cpuinfo  | head -n1
> > | mmu             : sv39
> > 
> > While the P550 defaults to a sv48 nmu:
> > | aurel32@p550:~$ grep ^mmu /proc/cpuinfo  | head -n1
> > | mmu             : sv48
> > 
> > Therefore libmimalloc.so.3 is built with a 39-bit virtual address space
> > support. When the binary is run on a sv48 system, things explodes.  
> > Rebuilding libmimalloc.so.3 on the P550 enables sv48 support and things 
> > work again, even on a sv39 mmu.
> > 
> > It's not clear to me if there is a drawback to always enable sv48 
> > support, if yes I guess a runtime detection should be implemented. 
> > Anyway for now reassigning the bug to the correct package.
> 
> I have send a patch upstream:
> https://github.com/microsoft/mimalloc/pull/1296

The upstream patch got merged, but doesn't apply cleanly. Please find 
attached a patch to drop into debian/patches.

Regards
Aurelien

-- 
Aurelien Jarno                          GPG: 4096R/1DDD8C9B
[email protected]                     http://aurel32.net
commit 7abd6bfcf2c56a9729dc2204aba8e3e0369a5910
Author: Aurelien Jarno <[email protected]>
Date:   Mon May 25 11:41:28 2026 +0200

    RISC-V: detect virtual address space at runtime using hwprobe
    
    The virtual address space on RISC-V is currently detected at build time
    by parsing /proc/cpuinfo. This works when the binary runs on the same
    hardware it was built, however running such a binary on a system with a
    larger address space just causes a segmentation fault.
    
    Replace the build time check with a runtime detection using the hwprobe
    interface (available since Linux 6.11, commit c9b8cd139c1d "riscv:
    hwprobe export highest virtual userspace address"), with a fallback to
    parsing /proc/cpuinfo on older kernels.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c33c3046..a23169a5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -475,13 +475,14 @@ else()
   # list(APPEND mi_defines MI_WIN_INIT_USE_CRT_TLS=1)
 endif()

-# Check /proc/cpuinfo for an SV39 MMU and limit the virtual address bits.
-# (this will skip the aligned hinting in that case. Issue #939, #949)
-if (EXISTS /proc/cpuinfo)
-  file(STRINGS /proc/cpuinfo mi_sv39_mmu REGEX "^mmu[ \t]+:[ \t]+sv39$")
-  if (mi_sv39_mmu)
-    MESSAGE( STATUS "Set virtual address bits to 39 (SV39 MMU detected)" )
-    list(APPEND mi_defines MI_DEFAULT_VIRTUAL_ADDRESS_BITS=39)
+if(MI_ARCH MATCHES "riscv")
+  CHECK_INCLUDE_FILES("asm/hwprobe.h;" MI_HAS_ASM_HWPROBEH)
+  if (MI_HAS_ASM_HWPROBEH)
+    list(APPEND mi_defines MI_HAS_ASM_HWPROBEH=1)
+  endif()
+  CHECK_INCLUDE_FILES("sys/hwprobe.h;" MI_HAS_SYS_HWPROBEH)
+  if (MI_HAS_SYS_HWPROBEH)
+    list(APPEND mi_defines MI_HAS_SYS_HWPROBEH=1)
   endif()
 endif()
 
diff --git a/src/prim/unix/prim.c b/src/prim/unix/prim.c
index 7781a37a..fc08712d 100644
--- a/src/prim/unix/prim.c
+++ b/src/prim/unix/prim.c
@@ -41,6 +41,13 @@ terms of the MIT license. A copy of the license can be found in the file
   #else
   #include <sys/mman.h>
   #endif
+  #if defined(__riscv) || defined(_M_RISCV)
+    #if defined(MI_HAS_SYS_HWPROBEH)
+      #include <sys/hwprobe.h>
+    #elif defined(MI_HAS_ASM_HWPROBEH)
+      #include <asm/hwprobe.h>
+    #endif
+  #endif
 #elif defined(__APPLE__)
   #include <AvailabilityMacros.h>
   #include <TargetConditionals.h>
@@ -206,6 +213,52 @@ static void unix_detect_physical_memory( size_t page_size, size_t* physical_memo
   #endif
 }
 
+// Detect the virtual address bits (currently Linux/RISC-V only)
+static size_t unix_detect_virtual_address_bits(void)
+{
+  #if defined(__riscv) || defined(_M_RISCV)
+    #if defined(RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS)
+      struct riscv_hwprobe probe = {
+        .key = RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS,
+      };
+
+      // Prefer the GNU libc interface if available, as it can also use the VDSO
+      #if defined(MI_HAS_SYS_HWPROBEH)
+      if (__riscv_hwprobe(&probe, 1, 0, NULL, 0) == 0) {
+      #else
+      if (syscall(__NR_riscv_hwprobe, &probe, 1, 0, NULL, 0) == 0) {
+      #endif
+        // If a key is unknown to the kernel, its key field will be cleared to -1.
+        if (probe.key != -1) {
+          return MI_SIZE_BITS - mi_clz((uintptr_t)probe.value);
+        }
+      }
+    #endif
+
+    // Fallback to checking /proc/cpuinfo for older kernels
+    const int fd = mi_prim_open("/proc/cpuinfo", O_RDONLY);
+    if (fd >= 0) {
+      char buf[2048];
+      ssize_t nread = mi_prim_read(fd, &buf, sizeof(buf));
+      mi_prim_close(fd);
+      if ((nread >= 1) && (nread <= (ssize_t)sizeof(buf))) {
+        if (_mi_strnstr(buf, nread, "sv39")) {
+          return 39;
+        }
+        if (_mi_strnstr(buf, nread, "sv48")) {
+          return 48;
+        }
+        if (_mi_strnstr(buf, nread, "sv57")) {
+          return 57;
+        }
+      }
+    }
+  #endif
+
+  // default: MI_MAX_VABITS
+  return MI_MAX_VABITS;
+}
+
 void _mi_prim_mem_init( mi_os_mem_config_t* config )
 {
   long psize = sysconf(_SC_PAGESIZE);
@@ -219,6 +272,7 @@ void _mi_prim_mem_init( mi_os_mem_config_t* config )
   config->has_partial_free = true;    // mmap can free in parts
   config->has_virtual_reserve = true; // todo: check if this true for NetBSD?  (for anonymous mmap with PROT_NONE)
   config->has_transparent_huge_pages = unix_detect_thp();
+  config->virtual_address_bits = unix_detect_virtual_address_bits();
 
   // disable transparent huge pages for this process?
   #if (defined(__linux__) || defined(__ANDROID__)) && defined(PR_GET_THP_DISABLE)

Reply via email to