You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It took me a while to boil down a much larger code to the point where I'm becoming confident there's no Undefined Behavior here:
#include <fenv.h>
#include <iostream>
template <typename T, typename D>
struct DualNumber
{
DualNumber () : val(0), deriv(0) {}
template <typename T2, typename D2>
DualNumber (DualNumber<T2,D2>& a) :
val(a.val), deriv(a.deriv) {}
T val;
D deriv;
};
template <std::size_t N, typename T>
struct NumberArray
{
NumberArray (T a)
{ for (std::size_t i=0; i != N; ++i) _data[i] = a; }
// Access a[i] via a._data[i] and no more SIGFPE!
template <typename T2>
NumberArray (NumberArray<N,T2>& a)
{ for (std::size_t i=0; i != N; ++i) _data[i] = a[i]; }
T& operator[](std::size_t i)
{
// Remove this assert, even just std::endl, and no more SIGFPE!
if (!(i < N)) { std::cerr << "Assert failed." << std::endl; }
return _data[i]; }
NumberArray<N,T>& operator/= (const T& a)
{ for (std::size_t i=0; i != N; ++i) _data[i] /= a; return *this; }
T _data[N];
};
static const unsigned int N = 9; // 9 or 10 SIGFPEs
// static const unsigned int N = 8; // 8 or fewer doesn't SIGFPE
int main(int, char *[])
{
feenableexcept(FE_INVALID);
typedef float Scalar; // double doesn't SIGFPE!
DualNumber<Scalar, NumberArray<N, Scalar>> dn;
// No copy made, no SIGFPE!
DualNumber<Scalar, NumberArray<N, Scalar>> dncopy{dn};
// Changing only one member doesn't SIGFPE!
// 2 (or 2.0) in both denominators doesn't SIGFPE!
// Modifying dn *or* dncopy gives a SIGFPE!
dncopy.val /= 3.0;
dncopy.deriv /= 3.0;
DualNumber<double, NumberArray<N, double>> broken_conversion{dn};
return 0;
}
Trying out all the clang++ versions I have handy on Ubuntu 23.10:
clang++ 16.0.6 or 15.0.7 -O2 give a SIGFPE when running this
clang++ -O1, -O0, or -O3 give no SIGFPE
clang++ 14.0.6 or 13.0.1 give no SIGFPE clang++ -fsanitize=undefined,address -O2 gives no warnings ... and no SIGFPE!
I'm noticing that a lot of slightly-similar issues are getting marked as duplicates of #6422 or #8472, but nothing here is touching the rounding mode and nothing here should be triggering a FP exception, so this may be an independent bug. I do need that endl-emitting assertion in the code path, or the bug doesn't trigger, which confuses me further. I'm not sure what FP shenanigans iostream (from libstdc++, not libc++, in my Ubuntu clang packages) might be pulling ... or that might be an obvious red herring, since that assertion never fails in this code, and so iostream functions should never be getting called.
The text was updated successfully, but these errors were encountered:
There is UB here, at the line feenableexcept(FE_INVALID). Whether your source code contains operations that produce a division by zero is irrelevant, as they may be legally introduced by the compiler.
It took me a while to boil down a much larger code to the point where I'm becoming confident there's no Undefined Behavior here:
Trying out all the clang++ versions I have handy on Ubuntu 23.10:
clang++ 16.0.6 or 15.0.7 -O2 give a SIGFPE when running this
clang++ -O1, -O0, or -O3 give no SIGFPE
clang++ 14.0.6 or 13.0.1 give no SIGFPE
clang++ -fsanitize=undefined,address -O2
gives no warnings ... and no SIGFPE!I'm noticing that a lot of slightly-similar issues are getting marked as duplicates of #6422 or #8472, but nothing here is touching the rounding mode and nothing here should be triggering a FP exception, so this may be an independent bug. I do need that
endl
-emitting assertion in the code path, or the bug doesn't trigger, which confuses me further. I'm not sure what FP shenanigans iostream (from libstdc++, not libc++, in my Ubuntu clang packages) might be pulling ... or that might be an obvious red herring, since that assertion never fails in this code, and so iostream functions should never be getting called.The text was updated successfully, but these errors were encountered: