You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Apple Silicon原生编译下BUS_ADRALN替代BUS_ADRERR问题问询

Apple Silicon原生编译下mmap未分配文件区域写入的SIGBUS错误码差异问题

问题现象

将大型C++代码库迁移至Apple Silicon(arm64 macOS)平台时,发现原生编译版本的信号处理行为存在差异:向mmap映射但未实际分配物理空间的文件地址写入数据时,预期会触发BUS_ADRERR总线错误(表示物理地址不存在或无效),该行为在Windows、Linux及通过Rosetta模拟运行x86代码的Apple Silicon Mac上均符合预期。但在Apple Silicon原生编译环境下,实际触发的却是BUS_ADRALN错误码,而该内存地址已通过代码确认是严格对齐的。

复现代码与运行输出

最小复现代码

/*
M1 Pro设备上的复现环境:
Clang版本:
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.1.0

M1 Mac上的运行输出:
clang++ repro.cpp && ./a.out
Obtained mmapped address: 0x102590000
Bus error (SIGBUS) occurred. Signal: 10
Siginfo code BUS_ADRALN -> Invalid address alignment
---------------------------------------------------------
对比Amazon Linux x86_64环境:
编译器版本:
clang version 11.1.0 (Amazon Linux 2 11.1.0-1.amzn2.0.2)
Target: x86_64-unknown-linux-gnu

运行输出:
Obtained mmapped address: 0x7facdaddf000
Bus error (SIGBUS) occurred. Signal: 7
Siginfo code BUS_ADRERR -> Non-existent physical address or invalid address
*/

#include <cassert>
#include <csignal>
#include <fcntl.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

using namespace std;

void sigbusHandler(int sig, siginfo_t* info, void*) {
   cerr << "Bus error (SIGBUS) occurred. Signal: " << sig << endl;
   switch (info->si_code) {
      case BUS_ADRALN:
         cerr << "Siginfo code BUS_ADRALN -> Invalid address alignment" << endl;
         break;
      case BUS_ADRERR:
         cerr << "Siginfo code BUS_ADRERR -> Non-existent physical address or invalid address" << endl;
         break;
      default:
         cerr << "Unknown bus error code: " << info->si_code << endl;
         break;
   }
   exit(sig);
}

int main() {
   // 注册SIGBUS信号处理器
   struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_sigaction = sigbusHandler;
   sa.sa_flags = SA_SIGINFO;
   sigfillset(&sa.sa_mask);
   if (sigaction(SIGBUS, &sa, nullptr) == -1) {
      perror("sigaction");
      return EXIT_FAILURE;
   }  

   // 创建并mmap文件
   int fd;
   off_t filesize = sizeof(int);
   void *mapped;
   fd = open("example_file.txt", O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0660);
   if (fd == -1) {
      perror("open");
      return EXIT_FAILURE;
   }
   mapped = mmap(NULL, filesize, PROT_WRITE, MAP_PRIVATE, fd, 0);
   if (mapped == MAP_FAILED) {
      perror("mmap");
      close(fd);
      return EXIT_FAILURE;
   }


   // 向mmap内存写入数据(会触发BUS_ADRALN,尽管地址已对齐)
   int value = 42;
   // 确保地址对齐符合int类型要求
   assert((reinterpret_cast<uintptr_t>(mapped) & (alignment_of<decltype(value)>::value - 1)) == 0);
   cerr << "Obtained mmapped address: " << mapped << endl;
   memcpy(mapped, &value, sizeof(int));
   cerr << "Did not trigger an error, repro didn't work" << endl;

   // 解除映射
   if (munmap(mapped, filesize) == -1) {
      perror("munmap");
      close(fd);
      return EXIT_FAILURE;
   }

   // 关闭文件描述符
   close(fd);

   return EXIT_SUCCESS;
}

原因分析

这是Apple Silicon(arm64)macOS内核特有的行为差异:当尝试写入mmap映射但未预先分配空间的文件区域时,内核返回的错误码被标记为BUS_ADRALN,但实际原因并非地址对齐问题,而是物理地址未分配(和其他平台的BUS_ADRERR场景本质一致)。这种错误码的映射差异是平台实现层面的区别,并非代码的对齐逻辑错误。

兼容处理方案

针对该平台差异,可通过以下方式处理:

  • 统一错误处理逻辑:在信号处理器中,将BUS_ADRALN和BUS_ADRERR视为同一类错误(无法写入目标内存区域)处理,不要依赖特定错误码区分场景。
  • 预先分配文件空间:在mmap之前,使用ftruncate(fd, filesize)扩展文件大小,确保映射区域已分配物理空间,从根源避免触发这类SIGBUS错误。
  • 平台特定分支处理:如果必须区分错误场景,可通过预编译宏(如__arm64__或__APPLE__)针对macOS arm64平台单独处理BUS_ADRALN错误码。

内容的提问来源于stack exchange,提问作者Diego H.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 01:10:26