OR-Tools  8.2
logging_utilities.cc
Go to the documentation of this file.
1// Copyright 2010-2018 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <signal.h>
17#include <stdio.h>
18#if !defined(_MSC_VER)
19#include <pwd.h>
20#include <syslog.h>
21#include <unistd.h> // For geteuid.
22#endif
23
24#if defined(_MSC_VER) // windows compatibility layer.
25#ifndef WIN32_LEAN_AND_MEAN
26#define WIN32_LEAN_AND_MEAN /* We always want minimal includes */
27#endif
28
29#include <direct.h> /* for _getcwd() */
30#include <io.h> /* because we so often use open/close/etc */
31#include <process.h> /* for _getpid() */
32#include <stdarg.h> /* template_dictionary.cc uses va_copy */
33#include <string.h> /* for _strnicmp(), strerror_s() */
34#include <time.h> /* for localtime_s() */
35#include <windows.h>
36#include <winsock.h> /* for gethostname */
37/* Note: the C++ #includes are all together at the bottom. This file is
38 * used by both C and C++ code, so we put all the C++ together.
39 */
40
41/* 4244: otherwise we get problems when subtracting two size_t's to an int
42 * 4251: it's complaining about a private struct I've chosen not to dllexport
43 * 4355: we use this in a constructor, but we do it safely
44 * 4715: for some reason VC++ stopped realizing you can't return after abort()
45 * 4800: we know we're casting ints/char*'s to bools, and we're ok with that
46 * 4996: Yes, we're ok using "unsafe" functions like fopen() and strerror()
47 * 4312: Converting uint32_t to a pointer when testing %p
48 * 4267: also subtracting two size_t to int
49 * 4722: Destructor never returns due to abort()
50 */
51#pragma warning(disable : 4244 4251 4355 4715 4800 4996 4267 4312 4722)
52
53/* file I/O */
54#define PATH_MAX 1024
55#define access _access
56#define getcwd _getcwd
57#define open _open
58#define read _read
59#define write _write
60#define lseek _lseek
61#define close _close
62#define popen _popen
63#define pclose _pclose
64#define R_OK 04 /* read-only (for access()) */
65#define S_ISDIR(m) (((m)&_S_IFMT) == _S_IFDIR)
66
67#define O_WRONLY _O_WRONLY
68#define O_CREAT _O_CREAT
69#define O_EXCL _O_EXCL
70
71#ifndef __MINGW32__
72enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
73#endif
74#define S_IRUSR S_IREAD
75#define S_IWUSR S_IWRITE
76
77/* Not quite as lightweight as a hard-link, but more than good enough for us. */
78#define link(oldpath, newpath) CopyFileA(oldpath, newpath, false)
79
80#define strcasecmp _stricmp
81#define strncasecmp _strnicmp
82
83/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
84/* VC11 provides std::hash */
85#if defined(_MSC_VER) && (_MSC_VER < 1700)
86#define hash hash_compare
87#endif
88
89/* We can't just use _vsnprintf and _snprintf as drop-in-replacements,
90 * because they don't always NUL-terminate. :-( We also can't use the
91 * name vsnprintf, since windows defines that (but not snprintf (!)).
92 */
93
94// These call the windows _vsnprintf, but always NUL-terminate.
95int safe_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
96 if (size == 0) // not even room for a \0?
97 return -1; // not what C99 says to do, but what windows does
98 str[size - 1] = '\0';
99 return _vsnprintf(str, size - 1, format, ap);
100}
101
102#define vsnprintf(str, size, format, ap) safe_vsnprintf(str, size, format, ap)
103#ifndef va_copy
104#define va_copy(dst, src) (dst) = (src)
105#endif
106
107/* Windows doesn't support specifying the number of buckets as a
108 * hash_map constructor arg, so we leave this blank.
109 */
110#define CTEMPLATE_SMALL_HASHTABLE
111#define DEFAULT_TEMPLATE_ROOTDIR ".."
112
113// ----------------------------------- SYSTEM/PROCESS
114typedef int pid_t;
115#define getpid _getpid
116
117// ----------------------------------- THREADS
118typedef DWORD pthread_t;
119#define pthread_self GetCurrentThreadId
120
121inline struct tm* localtime_r(const time_t* timep, struct tm* result) {
122 localtime_s(result, timep);
123 return result;
124}
125
126inline char* strerror_r(int errnum, char* buf, size_t buflen) {
127 strerror_s(buf, buflen, errnum);
128 return buf;
129}
130
131#endif // _MSC_VER
132
133namespace google {
134
135static const char* g_program_invocation_short_name = NULL;
136static pthread_t g_main_thread_id;
137
138} // namespace google
139
140// The following APIs are all internal.
141#include "absl/debugging/failure_signal_handler.h"
142#include "absl/debugging/stacktrace.h"
143#include "absl/debugging/symbolize.h"
144#include "absl/time/time.h"
146
147ABSL_FLAG(bool, symbolize_stacktrace, true,
148 "Symbolize the stack trace in the tombstone");
149
150namespace google {
151
152typedef void DebugWriter(const char*, void*);
153
154// The %p field width for printf() functions is two characters per byte.
155// For some environments, add two extra bytes for the leading "0x".
156static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
157
158static void DebugWriteToStderr(const char* data, void*) {
159 // This one is signal-safe.
160 if (write(STDERR_FILENO, data, strlen(data)) < 0) {
161 // Ignore errors.
162 }
163}
164
165static void DebugWriteToString(const char* data, void* arg) {
166 reinterpret_cast<std::string*>(arg)->append(data);
167}
168
169// Print a program counter and its symbol name.
170static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
171 const char* const prefix) {
172 char tmp[1024];
173 const char* symbol = "(unknown)";
174 // Symbolizes the previous address of pc because pc may be in the
175 // next function. The overrun happens when the function ends with
176 // a call to a function annotated noreturn (e.g. CHECK).
177 if (absl::Symbolize(reinterpret_cast<char*>(pc) - 1, tmp, sizeof(tmp))) {
178 symbol = tmp;
179 }
180 char buf[1024];
181 snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix, kPrintfPointerFieldWidth,
182 pc, symbol);
183 writerfn(buf, arg);
184}
185
186static void DumpPC(DebugWriter* writerfn, void* arg, void* pc,
187 const char* const prefix) {
188 char buf[100];
189 snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth, pc);
190 writerfn(buf, arg);
191}
192
193// Dump current stack trace as directed by writerfn
194static void DumpStackTrace(int skip_count, DebugWriter* writerfn, void* arg) {
195 // Print stack trace
196 void* stack[32];
197 int depth = absl::GetStackTrace(stack, ABSL_ARRAYSIZE(stack), skip_count + 1);
198 for (int i = 0; i < depth; i++) {
199 if (absl::GetFlag(FLAGS_symbolize_stacktrace)) {
200 DumpPCAndSymbol(writerfn, arg, stack[i], " ");
201 } else {
202 DumpPC(writerfn, arg, stack[i], " ");
203 }
204 }
205}
206
209 abort();
210}
211
212namespace logging_internal {
213
217 } else {
218 // TODO(user): Use /proc/self/cmdline and so?
219 return "UNKNOWN";
220 }
221}
222
224 return g_program_invocation_short_name != NULL;
225}
226
227unsigned int GetTID() {
228 return static_cast<unsigned int>(absl::base_internal::GetTID());
229}
230
231int64 CycleClock_Now() { return absl::ToUnixMicros(absl::Now()); }
232
233int64 UsecToCycles(int64 usec) { return usec; }
234
235static int32 g_main_thread_pid = getpid();
237
238const char* const_basename(const char* filepath) {
239 const char* base = strrchr(filepath, '/');
240#ifdef _MSC_VER // Look for either path separator in Windows
241 if (!base) base = strrchr(filepath, '\\');
242#endif
243 return base ? (base + 1) : filepath;
244}
245
246static std::string g_my_user_name; // NOLINT
247const std::string& MyUserName() { return g_my_user_name; }
249#if defined(_MSC_VER)
250 const char* user = getenv("USERNAME");
251#else
252 const char* user = getenv("USER");
253#endif
254 if (user != NULL) {
255 g_my_user_name = user;
256 } else {
257#if !defined(_MSC_VER) // Not windows.
258 struct passwd pwd;
259 struct passwd* result = NULL;
260 char buffer[1024] = {'\0'};
261 uid_t uid = geteuid();
262 int pwuid_res = getpwuid_r(uid, &pwd, buffer, sizeof(buffer), &result);
263 if (pwuid_res == 0) {
264 g_my_user_name = pwd.pw_name;
265 } else {
266 snprintf(buffer, sizeof(buffer), "uid%d", uid);
267 g_my_user_name = buffer;
268 }
269#endif // _defined(_MSC_VER)
270 if (g_my_user_name.empty()) {
271 g_my_user_name = "invalid-user";
272 }
273 }
274}
275
277 public:
278 typedef void (*void_function)(void);
279 GoogleInitializer(const char*, void_function f) { f(); }
280};
281
282#define REGISTER_MODULE_INITIALIZER(name, body) \
283 namespace { \
284 static void google_init_module_##name() { body; } \
285 GoogleInitializer google_initializer_module_##name( \
286 #name, google_init_module_##name); \
287 }
288
290
291void DumpStackTraceToString(std::string* stacktrace) {
292 DumpStackTrace(1, DebugWriteToString, stacktrace);
293}
294
295// We use an atomic operation to prevent problems with calling CrashReason
296// from inside the Mutex implementation (potentially through RAW_CHECK).
297static const CrashReason* g_reason = 0;
298
300 sync_val_compare_and_swap(&g_reason, reinterpret_cast<const CrashReason*>(0),
301 r);
302}
303
304void InitGoogleLoggingUtilities(const char* argv0) {
306 << "You called InitGoogleLogging() twice!";
307 const char* slash = strrchr(argv0, '/');
308#ifdef _MSC_VER
309 if (!slash) slash = strrchr(argv0, '\\');
310#endif
311 g_program_invocation_short_name = slash ? slash + 1 : argv0;
312 g_main_thread_id = pthread_self();
313
315}
316
319 << "You called ShutdownGoogleLogging() without calling "
320 "InitGoogleLogging() first!";
322#if !defined(_MSC_VER)
323 closelog();
324#endif // !defined(_MSC_VER)
325}
326
327} // namespace logging_internal
328
329} // namespace google
#define CHECK(condition)
Definition: base/logging.h:495
GoogleInitializer(const char *, void_function f)
int int32
int64_t int64
ABSL_FLAG(bool, symbolize_stacktrace, true, "Symbolize the stack trace in the tombstone")
void DumpStackTraceToString(std::string *stacktrace)
T sync_val_compare_and_swap(T *ptr, T oldval, T newval)
REGISTER_MODULE_INITIALIZER(logging_utilities, MyUserNameInitializer())
void InitGoogleLoggingUtilities(const char *argv0)
const char * ProgramInvocationShortName()
const std::string & MyUserName()
void SetCrashReason(const CrashReason *r)
static const CrashReason * g_reason
static std::string g_my_user_name
int64 UsecToCycles(int64 usec)
const char * const_basename(const char *filepath)
static pthread_t g_main_thread_id
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc, const char *const prefix)
static void DebugWriteToStderr(const char *data, void *)
void InstallFailureFunction(void(*fail_func)())
static void DumpStackTraceAndExit()
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc, const char *const prefix)
static const int kPrintfPointerFieldWidth
static const char * g_program_invocation_short_name
static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg)
void DebugWriter(const char *, void *)
static void DebugWriteToString(const char *data, void *arg)