1 #include <config.h>
2 
3 #include <cstdint>
4 #include <new>
5 #include <tuple>
6 #include <utility>
7 
8 #include <dune/common/debugalign.hh>
9 #include <dune/common/hybridutilities.hh>
10 #include <dune/common/parallel/mpihelper.hh>
11 #include <dune/common/test/arithmetictestsuite.hh>
12 #include <dune/common/test/testsuite.hh>
13 
14 class WithViolatedAlignmentHandler {
15   Dune::ViolatedAlignmentHandler oldhandler;
16 public:
17   template<class H>
WithViolatedAlignmentHandler(H && newhandler)18   WithViolatedAlignmentHandler(H &&newhandler) :
19     oldhandler(Dune::violatedAlignmentHandler())
20   {
21     Dune::violatedAlignmentHandler() = std::forward<H>(newhandler);
22   }
23 
24   WithViolatedAlignmentHandler(const WithViolatedAlignmentHandler &) = delete;
25   WithViolatedAlignmentHandler(WithViolatedAlignmentHandler &&) = delete;
26 
27   WithViolatedAlignmentHandler&
28   operator=(const WithViolatedAlignmentHandler &) = delete;
29   WithViolatedAlignmentHandler&
30   operator=(WithViolatedAlignmentHandler &&) = delete;
31 
~WithViolatedAlignmentHandler()32   ~WithViolatedAlignmentHandler()
33   {
34     Dune::violatedAlignmentHandler() = oldhandler;
35   }
36 };
37 
38 // intentionally violate alignment and check that that is detected
39 template<class T>
checkAlignmentViolation(Dune::TestSuite & test)40 void checkAlignmentViolation(Dune::TestSuite &test)
41 {
42   bool misalignmentDetected = false;
43   WithViolatedAlignmentHandler
44     guard([&](auto&&...){ misalignmentDetected = true; });
45 
46   char buffer[alignof(T)+sizeof(T)];
47 
48   void* misalignedAddr;
49   {
50     // a more portable way to ddo this would be to use std::align(), but that
51     // isn't supported by g++-4.9 yet
52     auto addr = std::uintptr_t( (void*)buffer );
53     addr += alignof(T) - 1;
54     addr &= -std::uintptr_t(alignof(T));
55     addr += 1;
56     misalignedAddr = (void*)addr;
57   }
58 
59   auto ptr = new(misalignedAddr) T;
60   test.check(misalignmentDetected, "default construct")
61     << "misalignment not detected for " << Dune::className<T>();
62 
63   misalignmentDetected = false;
64 
65   ptr->~T();
66   test.check(misalignmentDetected, "destruct")
67     << "misalignment not detected for " << Dune::className<T>();
68 
69   misalignmentDetected = false;
70 
71   ptr = new(misalignedAddr) T(T(0));
72   test.check(misalignmentDetected, "move construct")
73     << "misalignment not detected for " << Dune::className<T>();
74   ptr->~T(); // ignore any misalignment here
75 
76   misalignmentDetected = false;
77 
78   T t(0);
79   ptr = new(misalignedAddr) T(t);
80   test.check(misalignmentDetected, "copy construct")
81     << "misalignment not detected for " << Dune::className<T>();
82   ptr->~T(); // ignore any misalignment here
83 }
84 
main(int argc,char ** argv)85 int main(int argc, char **argv)
86 {
87   Dune::MPIHelper::instance(argc, argv);
88 
89   Dune::ArithmeticTestSuite test;
90 
91   using ArithmeticTypes = std::tuple<
92     bool,
93     char, signed char, unsigned char,
94     short, unsigned short,
95     int, unsigned,
96     long, long unsigned,
97     long long, long long unsigned,
98     wchar_t, char16_t, char32_t,
99     float, double, long double>;
100 
101   Dune::Hybrid::forEach(ArithmeticTypes(), [&](auto val) {
102       using T = decltype(val);
103       using Aligned = Dune::AlignedNumber<T>;
104       test.checkArithmetic<Aligned, T>();
105 
106       checkAlignmentViolation<Aligned>(test);
107     });
108 
109   return test.exit();
110 }
111