在将一个大型C++代码库移植到Apple Silicon时,我观察到信号处理在本机构建上的行为不同。具体来说,我正在写入一个mmaped内存地址,并期望出现BUS_ADRERR总线错误。这是Windows,Linux以及运行x86代码的Apple Silicon Mac的情况,下面的代码使用Rosetta仿真。
然而,在本机构建中,BUS_ADRALN是我观察到的错误代码。这似乎完全出乎意料,因为地址是对齐的。下面我粘贴了一个min repro,用于这个问题和我在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;
}
字符串
1条答案
按热度按时间093gszye1#
XNU似乎无条件地在x86上使用
BUS_ADRERR
,在ARM上使用BUS_ADRALN
。参见
bsd/dev/i386/unix_signal.c
:字符串
和
bsd/dev/arm/unix_signal.c
型
Rosetta几乎可以肯定只是镜像了x86_64内核的功能,如果它没有完全包含相同的代码的话。
但由于这些都是硬编码的,我认为忽略它们是安全的。