Call to std::remainder(double(411.0), int(365));
results in a crash due to a nan in libsystem_m.dylib
. MCVE program is provided + lldb backtrace and system report.
$ clang++ -g -arch arm64 -std=c++20 main.cpp -o test
$ ./test
ori_fpcr=0, new_fpcr=1792
std::fmod(simTimeInDays, numDays) = 46
Illegal instruction: 4
main.cpp
#include <cassert>
#include <cfenv>
#include <cmath>
#include <iostream>
#if !defined(__arm64__) || !defined(__APPLE__)
# error "Meant to be run on arm64 apple"
#endif
inline int feenableexcept(unsigned int excepts) {
static fenv_t fenv;
if (std::fegetenv(&fenv) != 0) {
return -1;
}
const unsigned long long old_fpcr = fenv.__fpcr;
const unsigned int old_excepts = (old_fpcr >> 8u) & unsigned(FE_ALL_EXCEPT);
// Check the bits passed are valid, and bit shift them
const unsigned int new_excepts = excepts & unsigned(FE_ALL_EXCEPT);
const unsigned long long new_fpcr = new_excepts << 8u;
// Set the new bits
fenv.__fpcr = fenv.__fpcr | new_fpcr;
return (std::fesetenv(&fenv) != 0) ? -1 : static_cast<int>(old_excepts);
}
int main([[maybe_unused]] int argc, [[maybe_unused]] const char** argv) {
constexpr unsigned int flags = FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW;
static_assert(flags == 7);
constexpr uint32_t fpcr_flags_shifted = flags << 8;
constexpr uint32_t fpcr_flags = (__fpcr_trap_divbyzero | __fpcr_trap_invalid | __fpcr_trap_overflow);
static_assert(fpcr_flags_shifted == fpcr_flags);
static_assert(fpcr_flags_shifted == 1792);
uint32_t ori_fpcr = __builtin_arm_rsr("fpcr");
feenableexcept(flags);
uint32_t new_fpcr = __builtin_arm_rsr("fpcr");
// std::cout << "(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) = " << flags << '\n';
// std::cout << "((FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW) << 8) = " << fpcr_flags_shifted << '\n';
// std::cout << "(__fpcr_trap_divbyzero | __fpcr_trap_invalid | __fpcr_trap_overflow) = " << fpcr_flags << '\n';
std::cout << "ori_fpcr=" << ori_fpcr << ", new_fpcr=" << new_fpcr << '\n';
const double simTimeInDays = 411.0;
const int numDays = 365;
// This is fine
std::cout << "std::fmod(simTimeInDays, numDays) = " << std::fmod(simTimeInDays, numDays) << '\n';
// This isn't
std::cout << "std::fmod(simTimeInDays, numDays) = " << std::remainder(simTimeInDays, numDays) << '\n';
return 0;
}
backtrace: see attachment
$ system_profiler SPSoftwareDataType SPHardwareDataType
Software:
System Software Overview:
System Version: macOS 13.2 (22D49)
Kernel Version: Darwin 22.3.0
Boot Volume: Macintosh HD
Boot Mode: Normal
Secure Virtual Memory: Enabled
System Integrity Protection: Enabled
Time since boot: 7 hours, 58 minutes
Hardware:
Hardware Overview:
Model Name: MacBook Pro
Model Identifier: MacBookPro18,2
Model Number: Z14V000NBFN/A
Chip: Apple M1 Max
Total Number of Cores: 10 (8 performance and 2 efficiency)
Memory: 64 GB
System Firmware Version: 8419.80.7
OS Loader Version: 8419.80.7
Activation Lock Status: Enabled
$ otool -L test
test:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1300.36.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0
$ clang++ --version
Apple clang version 14.0.0 (clang-1400.0.29.202)
Target: arm64-apple-darwin22.3.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin