2007-08-20 06:58:56 +02:00
|
|
|
/*
|
|
|
|
|
2014-02-23 20:12:25 +01:00
|
|
|
Copyright (c) 2007-2014, Arvid Norberg
|
2007-08-20 06:58:56 +02:00
|
|
|
All rights reserved.
|
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
|
|
|
|
* Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in
|
|
|
|
the documentation and/or other materials provided with the distribution.
|
|
|
|
* Neither the name of the author nor the names of its
|
|
|
|
contributors may be used to endorse or promote products derived
|
|
|
|
from this software without specific prior written permission.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2011-08-15 01:55:41 +02:00
|
|
|
#include "libtorrent/config.hpp"
|
2015-04-18 04:33:39 +02:00
|
|
|
#include "libtorrent/assert.hpp"
|
2011-08-15 01:55:41 +02:00
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-08-01 09:32:54 +02:00
|
|
|
#include <boost/atomic.hpp>
|
2013-03-28 00:41:04 +01:00
|
|
|
#endif
|
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
#if (defined TORRENT_DEBUG && TORRENT_USE_ASSERTS) \
|
2014-11-30 11:07:19 +01:00
|
|
|
|| defined TORRENT_ASIO_DEBUGGING \
|
|
|
|
|| defined TORRENT_PROFILE_CALLS \
|
2015-04-19 15:18:54 +02:00
|
|
|
|| defined TORRENT_RELEASE_ASSERTS \
|
2014-11-30 11:07:19 +01:00
|
|
|
|| defined TORRENT_DEBUG_BUFFERS
|
2012-02-16 19:24:53 +01:00
|
|
|
|
2008-12-19 10:17:55 +01:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <AvailabilityMacros.h>
|
|
|
|
#endif
|
|
|
|
|
2007-12-27 07:15:52 +01:00
|
|
|
#include <string>
|
2008-04-29 23:46:32 +02:00
|
|
|
#include <cstring>
|
2007-12-27 07:15:52 +01:00
|
|
|
#include <stdlib.h>
|
2014-07-06 21:18:00 +02:00
|
|
|
#include <stdarg.h>
|
2007-12-27 07:15:52 +01:00
|
|
|
|
2009-10-20 18:44:11 +02:00
|
|
|
// uClibc++ doesn't have cxxabi.h
|
2009-11-28 23:41:21 +01:00
|
|
|
#if defined __GNUC__ && __GNUC__ >= 3 \
|
|
|
|
&& !defined __UCLIBCXX_MAJOR__
|
2009-10-20 18:44:11 +02:00
|
|
|
|
|
|
|
#include <cxxabi.h>
|
|
|
|
|
2007-12-27 07:15:52 +01:00
|
|
|
std::string demangle(char const* name)
|
|
|
|
{
|
|
|
|
// in case this string comes
|
2008-12-19 07:12:55 +01:00
|
|
|
// this is needed on linux
|
2007-12-27 07:15:52 +01:00
|
|
|
char const* start = strchr(name, '(');
|
2008-12-19 07:12:55 +01:00
|
|
|
if (start != 0)
|
|
|
|
{
|
|
|
|
++start;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// this is needed on macos x
|
|
|
|
start = strstr(name, "0x");
|
|
|
|
if (start != 0)
|
|
|
|
{
|
|
|
|
start = strchr(start, ' ');
|
|
|
|
if (start != 0) ++start;
|
|
|
|
else start = name;
|
|
|
|
}
|
|
|
|
else start = name;
|
|
|
|
}
|
|
|
|
|
2007-12-27 07:15:52 +01:00
|
|
|
char const* end = strchr(start, '+');
|
2008-12-19 07:12:55 +01:00
|
|
|
if (end) while (*(end-1) == ' ') --end;
|
2007-12-27 07:15:52 +01:00
|
|
|
|
|
|
|
std::string in;
|
|
|
|
if (end == 0) in.assign(start);
|
|
|
|
else in.assign(start, end);
|
|
|
|
|
|
|
|
size_t len;
|
|
|
|
int status;
|
|
|
|
char* unmangled = ::abi::__cxa_demangle(in.c_str(), 0, &len, &status);
|
|
|
|
if (unmangled == 0) return in;
|
|
|
|
std::string ret(unmangled);
|
|
|
|
free(unmangled);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-01-26 11:33:39 +01:00
|
|
|
#elif defined WIN32
|
|
|
|
|
|
|
|
#undef _WIN32_WINNT
|
|
|
|
#define _WIN32_WINNT 0x0501 // XP
|
|
|
|
|
|
|
|
#include "windows.h"
|
|
|
|
#include "dbghelp.h"
|
|
|
|
|
|
|
|
std::string demangle(char const* name)
|
|
|
|
{
|
|
|
|
char demangled_name[256];
|
|
|
|
if (UnDecorateSymbolName(name, demangled_name, sizeof(demangled_name), UNDNAME_NO_THROW_SIGNATURES) == 0)
|
|
|
|
demangled_name[0] = 0;
|
|
|
|
return demangled_name;
|
|
|
|
}
|
2007-12-27 07:15:52 +01:00
|
|
|
|
2009-10-20 18:44:11 +02:00
|
|
|
#else
|
|
|
|
std::string demangle(char const* name) { return name; }
|
2007-12-27 07:15:52 +01:00
|
|
|
#endif
|
|
|
|
|
2007-09-01 06:08:39 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
2007-09-17 04:32:51 +02:00
|
|
|
#include <signal.h>
|
2009-01-14 09:41:14 +01:00
|
|
|
#include "libtorrent/version.hpp"
|
2008-12-19 07:12:55 +01:00
|
|
|
|
2013-05-26 23:36:20 +02:00
|
|
|
#if TORRENT_USE_EXECINFO
|
2007-08-20 06:58:56 +02:00
|
|
|
#include <execinfo.h>
|
2008-12-19 07:12:55 +01:00
|
|
|
|
2012-04-28 23:10:15 +02:00
|
|
|
TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth)
|
2008-12-19 07:12:55 +01:00
|
|
|
{
|
|
|
|
void* stack[50];
|
|
|
|
int size = backtrace(stack, 50);
|
|
|
|
char** symbols = backtrace_symbols(stack, size);
|
|
|
|
|
2011-04-15 10:37:27 +02:00
|
|
|
for (int i = 1; i < size && len > 0; ++i)
|
2008-12-19 07:12:55 +01:00
|
|
|
{
|
2011-04-15 10:37:27 +02:00
|
|
|
int ret = snprintf(out, len, "%d: %s\n", i, demangle(symbols[i]).c_str());
|
|
|
|
out += ret;
|
|
|
|
len -= ret;
|
2012-04-01 02:42:31 +02:00
|
|
|
if (i - 1 == max_depth && max_depth > 0) break;
|
2008-12-19 07:12:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
free(symbols);
|
|
|
|
}
|
2012-01-26 11:33:39 +01:00
|
|
|
|
2012-06-14 17:08:21 +02:00
|
|
|
// visual studio 9 and up appears to support this
|
|
|
|
#elif defined WIN32 && _MSC_VER >= 1500
|
2012-01-26 11:33:39 +01:00
|
|
|
|
|
|
|
#undef _WIN32_WINNT
|
|
|
|
#define _WIN32_WINNT 0x0501 // XP
|
|
|
|
|
|
|
|
#include "windows.h"
|
|
|
|
#include "libtorrent/utf8.hpp"
|
|
|
|
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "dbghelp.h"
|
|
|
|
|
2012-04-28 23:10:15 +02:00
|
|
|
TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth)
|
2012-01-26 11:33:39 +01:00
|
|
|
{
|
2012-11-23 16:34:44 +01:00
|
|
|
typedef USHORT (WINAPI *RtlCaptureStackBackTrace_t)(
|
2012-01-26 11:33:39 +01:00
|
|
|
__in ULONG FramesToSkip,
|
|
|
|
__in ULONG FramesToCapture,
|
|
|
|
__out PVOID *BackTrace,
|
|
|
|
__out_opt PULONG BackTraceHash);
|
|
|
|
|
|
|
|
static RtlCaptureStackBackTrace_t RtlCaptureStackBackTrace = 0;
|
|
|
|
|
|
|
|
if (RtlCaptureStackBackTrace == 0)
|
|
|
|
{
|
|
|
|
// we don't actually have to free this library, everyone has it loaded
|
|
|
|
HMODULE lib = LoadLibrary(TEXT("kernel32.dll"));
|
|
|
|
RtlCaptureStackBackTrace = (RtlCaptureStackBackTrace_t)GetProcAddress(lib, "RtlCaptureStackBackTrace");
|
|
|
|
if (RtlCaptureStackBackTrace == 0)
|
|
|
|
{
|
|
|
|
out[0] = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int i;
|
|
|
|
void* stack[50];
|
|
|
|
int size = CaptureStackBackTrace(0, 50, stack, 0);
|
|
|
|
|
|
|
|
SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR), 1);
|
|
|
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
|
|
|
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
|
|
|
|
|
|
|
HANDLE p = GetCurrentProcess();
|
|
|
|
static bool sym_initialized = false;
|
|
|
|
if (!sym_initialized)
|
|
|
|
{
|
|
|
|
sym_initialized = true;
|
|
|
|
SymInitialize(p, NULL, true);
|
|
|
|
}
|
|
|
|
for (i = 0; i < size && len > 0; ++i)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
if (SymFromAddr(p, uintptr_t(stack[i]), 0, symbol))
|
|
|
|
ret = snprintf(out, len, "%d: %s\n", i, symbol->Name);
|
|
|
|
else
|
|
|
|
ret = snprintf(out, len, "%d: <unknown>\n", i);
|
|
|
|
|
|
|
|
out += ret;
|
|
|
|
len -= ret;
|
2012-04-01 02:42:31 +02:00
|
|
|
if (i == max_depth && max_depth > 0) break;
|
2012-01-26 11:33:39 +01:00
|
|
|
}
|
|
|
|
free(symbol);
|
|
|
|
}
|
|
|
|
|
2008-12-19 07:12:55 +01:00
|
|
|
#else
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_EXPORT void print_backtrace(char* out, int len, int max_depth)
|
|
|
|
{ out[0] = 0; }
|
2008-12-19 07:12:55 +01:00
|
|
|
|
2007-09-17 04:32:51 +02:00
|
|
|
#endif
|
2007-08-20 06:58:56 +02:00
|
|
|
|
2014-01-08 06:45:13 +01:00
|
|
|
#endif
|
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS || defined TORRENT_ASIO_DEBUGGING
|
2014-01-08 06:45:13 +01:00
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2010-05-16 07:26:43 +02:00
|
|
|
char const* libtorrent_assert_log = "asserts.log";
|
2013-03-28 00:41:04 +01:00
|
|
|
// the number of asserts we've printed to the log
|
2014-08-01 09:32:54 +02:00
|
|
|
boost::atomic<int> assert_counter(0);
|
2010-05-16 07:26:43 +02:00
|
|
|
#endif
|
|
|
|
|
2015-05-10 07:11:51 +02:00
|
|
|
TORRENT_FORMAT(1,2)
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_EXPORT void assert_print(char const* fmt, ...)
|
2007-08-20 06:58:56 +02:00
|
|
|
{
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
if (assert_counter > 500) return;
|
2013-03-28 00:41:04 +01:00
|
|
|
|
2010-05-16 07:26:43 +02:00
|
|
|
FILE* out = fopen(libtorrent_assert_log, "a+");
|
2010-05-06 04:18:08 +02:00
|
|
|
if (out == 0) out = stderr;
|
|
|
|
#else
|
|
|
|
FILE* out = stderr;
|
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
va_list va;
|
|
|
|
va_start(va, fmt);
|
|
|
|
vfprintf(out, fmt, va);
|
|
|
|
va_end(va);
|
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
if (out != stderr) fclose(out);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-04-18 04:33:39 +02:00
|
|
|
TORRENT_NO_RETURN TORRENT_EXPORT void assert_fail(char const* expr, int line
|
|
|
|
, char const* file, char const* function, char const* value, int kind)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
// no need to flood the assert log with infinite number of asserts
|
2014-08-01 09:32:54 +02:00
|
|
|
if (assert_counter.fetch_add(1) + 1 > 500) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2010-05-06 04:18:08 +02:00
|
|
|
|
2011-04-15 10:37:27 +02:00
|
|
|
char stack[8192];
|
2013-09-04 07:50:40 +02:00
|
|
|
stack[0] = '\0';
|
2012-04-01 02:42:31 +02:00
|
|
|
print_backtrace(stack, sizeof(stack), 0);
|
2011-04-15 10:37:27 +02:00
|
|
|
|
2014-03-23 08:40:43 +01:00
|
|
|
char const* message = "assertion failed. Please file a bugreport at "
|
2013-03-02 22:48:20 +01:00
|
|
|
"http://code.google.com/p/libtorrent/issues\n"
|
2007-08-20 06:58:56 +02:00
|
|
|
"Please include the following information:\n\n"
|
2009-01-14 09:41:14 +01:00
|
|
|
"version: " LIBTORRENT_VERSION "\n"
|
2014-03-23 08:40:43 +01:00
|
|
|
LIBTORRENT_REVISION "\n";
|
|
|
|
|
|
|
|
switch (kind)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
message = "A precondition of a libtorrent function has been violated.\n"
|
|
|
|
"This indicates a bug in the client application using libtorrent\n";
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
assert_print("%s\n"
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
"#: %d\n"
|
|
|
|
#endif
|
2007-08-20 06:58:56 +02:00
|
|
|
"file: '%s'\n"
|
|
|
|
"line: %d\n"
|
2007-09-01 06:08:39 +02:00
|
|
|
"function: %s\n"
|
2010-09-25 19:46:13 +02:00
|
|
|
"expression: %s\n"
|
2011-04-15 10:37:27 +02:00
|
|
|
"%s%s\n"
|
|
|
|
"stack:\n"
|
|
|
|
"%s\n"
|
2014-07-06 21:18:00 +02:00
|
|
|
, message
|
2015-04-18 04:33:39 +02:00
|
|
|
#ifdef TORRENT_PRODUCTION_ASSERTS
|
2014-08-01 09:32:54 +02:00
|
|
|
, assert_counter.load()
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
, file, line, function, expr
|
2011-04-15 10:37:27 +02:00
|
|
|
, value ? value : "", value ? "\n" : ""
|
|
|
|
, stack);
|
2007-08-20 06:58:56 +02:00
|
|
|
|
2010-05-06 04:18:08 +02:00
|
|
|
// if production asserts are defined, don't abort, just print the error
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_PRODUCTION_ASSERTS
|
2007-09-17 04:32:51 +02:00
|
|
|
// send SIGINT to the current process
|
|
|
|
// to break into the debugger
|
|
|
|
raise(SIGINT);
|
|
|
|
abort();
|
2010-05-06 04:18:08 +02:00
|
|
|
#endif
|
2007-08-20 06:58:56 +02:00
|
|
|
}
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
#else
|
|
|
|
|
2015-05-10 07:11:51 +02:00
|
|
|
TORRENT_FORMAT(1,2)
|
2015-04-19 15:18:54 +02:00
|
|
|
TORRENT_EXPORT void assert_print(char const*, ...) {}
|
2015-04-22 02:59:35 +02:00
|
|
|
TORRENT_EXPORT void assert_fail(char const*, int, char const*
|
2015-04-19 15:18:54 +02:00
|
|
|
, char const*, char const*, int) {}
|
2007-10-05 02:30:00 +02:00
|
|
|
|
2007-08-20 06:58:56 +02:00
|
|
|
#endif
|
|
|
|
|