Apache Mesos
abort.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_ABORT_HPP__
14 #define __STOUT_ABORT_HPP__
15 
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #ifdef __WINDOWS__
22 #include <stout/windows.hpp> // For `windows.h`.
23 #else
24 #include <unistd.h>
25 #endif // __WINDOWS__
26 
27 #include <string>
28 
29 #include <stout/attributes.hpp>
30 
31 // NOTE: These macros are already defined in Visual Studio (Windows) headers.
32 #ifndef __WINDOWS__
33 #define __STRINGIZE(x) #x
34 #define _STRINGIZE(x) __STRINGIZE(x)
35 #endif // __WINDOWS__
36 
37 // Signal safe abort which prints a message.
38 #define _ABORT_PREFIX "ABORT: (" __FILE__ ":" _STRINGIZE(__LINE__) "): "
39 
40 #define ABORT(...) _Abort(_ABORT_PREFIX, __VA_ARGS__)
41 
42 
43 inline NORETURN void _Abort(const char* prefix, const char* message)
44 {
45 #ifndef __WINDOWS__
46  const size_t prefix_len = strlen(prefix);
47  const size_t message_len = strlen(message);
48 
49  // Write the failure message in an async-signal safe manner,
50  // assuming strlen is async-signal safe or optimized out.
51  // In fact, it is highly unlikely that strlen would be
52  // implemented in an unsafe manner:
53  // http://austingroupbugs.net/view.php?id=692
54  // NOTE: we can't use `signal_safe::write`, because it's defined in the header
55  // which can't be included due to circular dependency of headers.
56  while (::write(STDERR_FILENO, prefix, prefix_len) == -1 &&
57  errno == EINTR);
58  while (message != nullptr &&
59  ::write(STDERR_FILENO, message, message_len) == -1 &&
60  errno == EINTR);
61 
62  // NOTE: Since `1` can be interpreted as either an `unsigned int` or a
63  // `size_t`, removing the `static_cast` here makes this call ambiguous
64  // between the `write` in windows.hpp and the (deprecated) `write` in the
65  // Windows CRT headers.
66  while (::write(STDERR_FILENO, "\n", static_cast<size_t>(1)) == -1 &&
67  errno == EINTR);
68 #else
69  // NOTE: On Windows, `WriteFile` takes an `DWORD`, not `size_t`. We
70  // perform an explicit type conversion here to silence the warning.
71  // `strlen` always returns a positive result, which means it is safe
72  // to cast it to an unsigned value.
73  const DWORD prefix_len = static_cast<DWORD>(strlen(prefix));
74  const DWORD message_len = static_cast<DWORD>(strlen(message));
75 
76  const HANDLE fd = ::GetStdHandle(STD_ERROR_HANDLE);
77 
78  // NOTE: There is really nothing to do if these fail during an
79  // abort, so we don't check for errors, or care about `bytes`.
80  DWORD bytes;
81  ::WriteFile(fd, prefix, prefix_len, &bytes, nullptr);
82  ::WriteFile(fd, message, message_len, &bytes, nullptr);
83  ::WriteFile(fd, "\n", 1, &bytes, nullptr);
84 #endif // __WINDOWS__
85 
86  abort();
87 }
88 
89 
90 inline NORETURN void _Abort(const char* prefix, const std::string& message)
91 {
92  _Abort(prefix, message.c_str());
93 }
94 
95 
96 #endif // __STOUT_ABORT_HPP__
constexpr const char * prefix
Definition: os.hpp:94
#define STDERR_FILENO
Definition: windows.hpp:155
constexpr Handle HANDLE
Definition: ingress.hpp:37
Protocol< WriteRequest, WriteResponse > write
NORETURN void _Abort(const char *prefix, const char *message)
Definition: abort.hpp:43
#define NORETURN
Definition: attributes.hpp:20