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 
44 inline void _Abort(const char* prefix, const char* message)
45 {
46 #ifndef __WINDOWS__
47  const size_t prefix_len = strlen(prefix);
48  const size_t message_len = strlen(message);
49 
50  // Write the failure message in an async-signal safe manner,
51  // assuming strlen is async-signal safe or optimized out.
52  // In fact, it is highly unlikely that strlen would be
53  // implemented in an unsafe manner:
54  // http://austingroupbugs.net/view.php?id=692
55  // NOTE: we can't use `signal_safe::write`, because it's defined in the header
56  // which can't be included due to circular dependency of headers.
57  while (::write(STDERR_FILENO, prefix, prefix_len) == -1 &&
58  errno == EINTR);
59  while (message != nullptr &&
60  ::write(STDERR_FILENO, message, message_len) == -1 &&
61  errno == EINTR);
62 
63  // NOTE: Since `1` can be interpreted as either an `unsigned int` or a
64  // `size_t`, removing the `static_cast` here makes this call ambiguous
65  // between the `write` in windows.hpp and the (deprecated) `write` in the
66  // Windows CRT headers.
67  while (::write(STDERR_FILENO, "\n", static_cast<size_t>(1)) == -1 &&
68  errno == EINTR);
69 #else
70  // NOTE: On Windows, `WriteFile` takes an `DWORD`, not `size_t`. We
71  // perform an explicit type conversion here to silence the warning.
72  // `strlen` always returns a positive result, which means it is safe
73  // to cast it to an unsigned value.
74  const DWORD prefix_len = static_cast<DWORD>(strlen(prefix));
75  const DWORD message_len = static_cast<DWORD>(strlen(message));
76 
77  const HANDLE fd = ::GetStdHandle(STD_ERROR_HANDLE);
78 
79  // NOTE: There is really nothing to do if these fail during an
80  // abort, so we don't check for errors, or care about `bytes`.
81  DWORD bytes;
82  ::WriteFile(fd, prefix, prefix_len, &bytes, nullptr);
83  ::WriteFile(fd, message, message_len, &bytes, nullptr);
84  ::WriteFile(fd, "\n", 1, &bytes, nullptr);
85 #endif // __WINDOWS__
86 
87  abort();
88 }
89 
90 
92 inline void _Abort(const char* prefix, const std::string& message)
93 {
94  _Abort(prefix, message.c_str());
95 }
96 
97 
98 #endif // __STOUT_ABORT_HPP__
constexpr const char * prefix
Definition: os.hpp:96
#define STDERR_FILENO
Definition: windows.hpp:155
#define STOUT_NORETURN
Definition: attributes.hpp:31
constexpr Handle HANDLE
Definition: ingress.hpp:37
Protocol< WriteRequest, WriteResponse > write
STOUT_NORETURN void _Abort(const char *prefix, const char *message)
Definition: abort.hpp:44