1 | // ================================================================= // |
---|
2 | // // |
---|
3 | // File : arb_mem.cxx // |
---|
4 | // Purpose : "Failsafe" memory handlers // |
---|
5 | // ("succeed or terminate"!) // |
---|
6 | // // |
---|
7 | // Coded by Elmar Pruesse and Ralf Westram // |
---|
8 | // http://www.arb-home.de/ // |
---|
9 | // // |
---|
10 | // ================================================================= // |
---|
11 | |
---|
12 | #include "arb_mem.h" |
---|
13 | #include "arb_msg.h" |
---|
14 | |
---|
15 | static char panicBuffer[500] = { 0 }; |
---|
16 | |
---|
17 | static __ATTR__NORETURN void alloc_failure_panic() { |
---|
18 | arb_assert(panicBuffer[0]); // sth should have been printed into buffer |
---|
19 | |
---|
20 | fputs("\n--------------------\n", stderr); |
---|
21 | fputs(panicBuffer, stderr); |
---|
22 | fputs("\n" |
---|
23 | "To avoid memory allocation problems\n" |
---|
24 | " - increase your swap space (see 'man 8 mkswap'),\n" |
---|
25 | " - reduce the amount of data (used for the failing operation)\n" |
---|
26 | " - or buy more memory.\n" |
---|
27 | "\n" |
---|
28 | "The program will terminate now!\n\n", |
---|
29 | stderr); |
---|
30 | |
---|
31 | GBK_terminate(panicBuffer); |
---|
32 | } |
---|
33 | |
---|
34 | void arb_mem::failed_to_allocate(const char *reason) { |
---|
35 | sprintf(panicBuffer, "Failed to allocate memory: %s", reason); |
---|
36 | alloc_failure_panic(); |
---|
37 | } |
---|
38 | void arb_mem::failed_to_allocate(size_t size) { |
---|
39 | sprintf(panicBuffer, "Failed to allocate memory (tried to get %zu bytes)", size); |
---|
40 | alloc_failure_panic(); |
---|
41 | } |
---|
42 | void arb_mem::failed_to_allocate(size_t nelem, size_t elsize) { |
---|
43 | if (nelem == 1) failed_to_allocate(elsize); |
---|
44 | if (elsize == 1) failed_to_allocate(nelem); |
---|
45 | sprintf(panicBuffer, "Failed to allocate memory (tried to get %zu*%zu bytes)", nelem, elsize); |
---|
46 | alloc_failure_panic(); |
---|
47 | } |
---|
48 | |
---|
49 | |
---|
50 | // -------------------------------------------------------------------------------- |
---|
51 | |
---|
52 | #ifdef UNIT_TESTS |
---|
53 | #ifndef TEST_UNIT_H |
---|
54 | #include <test_unit.h> |
---|
55 | #endif |
---|
56 | |
---|
57 | #if !defined(LEAKS_SANITIZED) && !defined(__clang__) && defined(ENABLE_CRASH_TESTS) |
---|
58 | // @@@ TEST_DISABLED_CLANG: clang version fails to segfault after allocation failure. needs fix. |
---|
59 | # define TEST_ALLOC_SEGFAULTS |
---|
60 | #endif |
---|
61 | |
---|
62 | #if defined(TEST_ALLOC_SEGFAULTS) |
---|
63 | static size_t TOO_MUCH = 1; // changed before use (to avoid "-Walloc-size-larger-than=" warning) |
---|
64 | |
---|
65 | static void alloc_too_much() { ARB_alloc<char>(TOO_MUCH); } |
---|
66 | static void calloc_too_much() { ARB_calloc<char>(TOO_MUCH); } |
---|
67 | static void realloc_too_much() { char *s = NULp; ARB_realloc(s, TOO_MUCH); } |
---|
68 | static void recalloc_too_much() { char *s = NULp; ARB_recalloc(s, 0, TOO_MUCH); } |
---|
69 | |
---|
70 | #endif |
---|
71 | |
---|
72 | static bool mem_is_cleared(const char *mem, size_t size) { |
---|
73 | for (size_t s = 0; s<size; ++s) { |
---|
74 | if (mem[s]) return false; |
---|
75 | } |
---|
76 | return true; |
---|
77 | } |
---|
78 | |
---|
79 | void TEST_allocators__crashtest() { |
---|
80 | const int SIZE = 100; |
---|
81 | const int SIZE2 = 200; |
---|
82 | char *s = NULp; TEST_EXPECT_NULL(s); |
---|
83 | |
---|
84 | s = ARB_alloc<char>(0); TEST_REJECT_NULL((void*)s); // allocating empty block works |
---|
85 | freeset(s, ARB_alloc<char>(SIZE)); TEST_REJECT_NULL((void*)s); |
---|
86 | |
---|
87 | freenull(s); TEST_EXPECT_NULL(s); |
---|
88 | |
---|
89 | ARB_realloc(s, 0); TEST_REJECT_NULL((void*)s); |
---|
90 | ARB_realloc(s, SIZE); TEST_REJECT_NULL((void*)s); |
---|
91 | // ARB_realloc(s, 0); TEST_REJECT_NULL(s); // fails |
---|
92 | |
---|
93 | freenull(s); TEST_EXPECT_NULL(s); |
---|
94 | |
---|
95 | s = ARB_calloc<char>(0); TEST_REJECT_NULL((void*)s); |
---|
96 | freeset(s, ARB_calloc<char>(SIZE)); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, SIZE)); |
---|
97 | |
---|
98 | freenull(s); TEST_EXPECT_NULL(s); |
---|
99 | |
---|
100 | ARB_recalloc(s, 0, 1); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, 1)); |
---|
101 | ARB_recalloc(s, 1, SIZE); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, SIZE)); |
---|
102 | ARB_recalloc(s, SIZE, SIZE2); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, SIZE2)); |
---|
103 | ARB_recalloc(s, SIZE2, SIZE); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, SIZE)); |
---|
104 | ARB_recalloc(s, SIZE, 1); TEST_REJECT_NULL((void*)s); TEST_EXPECT(mem_is_cleared(s, 1)); |
---|
105 | // ARB_recalloc(s, 1, 0); TEST_REJECT_NULL(s); // fails |
---|
106 | |
---|
107 | freenull(s); TEST_EXPECT_NULL(s); |
---|
108 | |
---|
109 | #if defined(TEST_ALLOC_SEGFAULTS) |
---|
110 | // test out-of-mem = > terminate |
---|
111 | |
---|
112 | TOO_MUCH = -1; |
---|
113 | |
---|
114 | TEST_EXPECT_SEGFAULT(alloc_too_much); |
---|
115 | TEST_EXPECT_SEGFAULT(calloc_too_much); |
---|
116 | TEST_EXPECT_SEGFAULT(realloc_too_much); |
---|
117 | TEST_EXPECT_SEGFAULT(recalloc_too_much); |
---|
118 | #endif |
---|
119 | } |
---|
120 | |
---|
121 | #endif // UNIT_TESTS |
---|
122 | |
---|
123 | // -------------------------------------------------------------------------------- |
---|
124 | |
---|