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