提问人:user46317 提问时间:11/16/2023 最后编辑:Peter Cordesuser46317 更新时间:11/17/2023 访问量:65
在 Apple Silicon 上预期BUS_ADRERR时出现BUS_ADRALN错误
BUS_ADRALN error when BUS_ADRERR is expected on Apple Silicon
问:
在将大型 C++ 代码库移植到 Apple Silicon 时,我观察到信号处理在本机构建中的行为有所不同。具体来说,我正在写入 mmap 内存地址,并预计会出现BUS_ADRERR总线错误。Windows、Linux 和 Apple Silicon Mac 就是这种情况,这些 Mac 运行具有 Rosetta 仿真功能的 x86 代码,适用于以下代码。
但是,在本机构建中,BUS_ADRALN是我观察到的错误代码。这似乎完全出乎意料,因为地址是对齐的。下面我粘贴了我在 M1 Pro 机器上观察到的问题和输出的最小重现
/*
Reproducing the issue on M1 Pro laptop:
Clang version:
Apple clang version 15.0.0 (clang-1500.0.40.1)
Target: arm64-apple-darwin23.1.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
Observed output on M1 Mac:
clang++ repro.cpp && ./a.out
Obtained mmapped address: 0x102590000
Bus error (SIGBUS) occurred. Signal: 10
Siginfo code BUS_ADRALN -> Invalid address alignment
---------------------------------------------------------
On a Amazon Linux system on the other hand:
Compiler version:
clang version 11.1.0 (Amazon Linux 2 11.1.0-1.amzn2.0.2)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
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() {
// Install sighandler for 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;
}
// mmaped file
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;
}
// Write int to mmaped memory
// (triggers bus error with signal code BUS_ADRALN, even though address seems to be properly aligned)
int value = 42;
// Make sure alignment is fine to write 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;
// Unmap the file
if (munmap(mapped, filesize) == -1) {
perror("munmap");
close(fd);
return EXIT_FAILURE;
}
// Close the file descriptor
close(fd);
return EXIT_SUCCESS;
}
答:
3赞
Siguza
11/16/2023
#1
XNU 似乎无条件地在 x86 和 ARM 上使用。BUS_ADRERR
BUS_ADRALN
参见 bsd/dev/i386/unix_signal.c
:
case SIGBUS:
sinfo64.si_code = BUS_ADRERR;
sinfo64.si_addr = ua_cr2;
break;
case SIGBUS:
if (proc_is64bit_data(p)) {
#if defined(__arm64__)
sinfo.si_addr = user_frame.uf64.mctx.es.far;
#else
#error Unsupported architecture
#endif
} else {
sinfo.si_addr = user_frame.uf32.mctx.es.far;
}
sinfo.si_code = BUS_ADRALN;
break;
Rosetta 几乎可以肯定只是镜像了 x86_64 内核的功能,如果它没有完全包含相同的代码。
但是,由于这些无论如何都是硬编码的,因此我认为忽略它们是安全的。 是。SIGBUS
SIGBUS
评论
0赞
user46317
11/17/2023
谢谢你的回答!帮助我理解我在信号处理程序中观察到的内容
评论
cerr
exit()