static void _memory_tracker_shutdown( void ) { if( _memory_table ) hashtable_deallocate( _memory_table ); if( _memory_tags ) { bool got_leaks = false; log_debug( "Checking for memory leaks" ); for( unsigned int it = 0; it < MAX_CONCURRENT_ALLOCATIONS; ++it ) { memory_tag_t* tag = _memory_tags + it; if( tag->address ) { char* trace = stacktrace_resolve( tag->trace, 14, 0 ); log_warnf( WARNING_MEMORY, "Memory leak: %d bytes @ " STRING_FORMAT_POINTER " : tag %d\n%s", (unsigned int)tag->size, tag->address, it, trace ); string_deallocate( trace ); got_leaks = true; } } memory_deallocate( _memory_tags ); if( !got_leaks ) log_debug( "No memory leaks detected" ); } }
DECLARE_TEST(stacktrace, resolve) { #define TEST_DEPTH 64 void* trace[TEST_DEPTH]; size_t num_frames; char* buffer; string_t resolved; if (system_platform() == PLATFORM_PNACL) return 0; num_frames = stacktrace_capture(trace, TEST_DEPTH, 0); EXPECT_GT(num_frames, 3); buffer = memory_allocate(0, 1024, 0, MEMORY_TEMPORARY); resolved = stacktrace_resolve(buffer, 1024, trace, num_frames, 0); EXPECT_NE(resolved.str, 0); EXPECT_NE(resolved.length, 0); //log_infof(HASH_TEST, STRING_CONST("Resolved stack trace:\n%.*s"), (int)resolved.length, // resolved.str); #if !FOUNDATION_PLATFORM_ANDROID && !(FOUNDATION_PLATFORM_WINDOWS && (FOUNDATION_COMPILER_GCC || FOUNDATION_COMPILER_CLANG)) EXPECT_NE(string_find_string(resolved.str, resolved.length, STRING_CONST("stacktraceresolve_fn"), 0), STRING_NPOS); EXPECT_NE(string_find_string(resolved.str, resolved.length, STRING_CONST("main"), 0), STRING_NPOS); #endif memory_deallocate(buffer); return 0; }
int assert_report(hash_t context, const char* condition, size_t cond_length, const char* file, size_t file_length, unsigned int line, const char* msg, size_t msg_length) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %.*s\nFile/line: %.*s : %d\n%.*s%.*s\n%.*s\n"; #if BUILD_ENABLE_ASSERT string_t tracestr = { _assert_stacktrace_buffer, sizeof(_assert_stacktrace_buffer) }; string_t contextstr = { _assert_context_buffer, sizeof(_assert_context_buffer) }; string_t messagestr = { _assert_message_buffer, sizeof(_assert_message_buffer) }; #endif if (!condition || !cond_length) { condition = nocondition; cond_length = sizeof(nocondition); } if (!file || !file_length) { file = nofile; file_length = sizeof(nofile); } if (!msg || !msg_length) { msg = nomsg; msg_length = sizeof(nomsg); } if (_assert_handler && (_assert_handler != assert_report)) return (*_assert_handler)(context, condition, cond_length, file, file_length, line, msg, msg_length); #if BUILD_ENABLE_ASSERT contextstr = error_context_buffer(STRING_ARGS(contextstr)); if (foundation_is_initialized()) { size_t num_frames = stacktrace_capture(_assert_stacktrace, ASSERT_STACKTRACE_MAX_DEPTH, ASSERT_STACKTRACE_SKIP_FRAMES); if (num_frames) tracestr = stacktrace_resolve(STRING_ARGS(tracestr), _assert_stacktrace, num_frames, 0U); else tracestr = string_copy(STRING_ARGS(tracestr), STRING_CONST("<no stacktrace>")); } else { tracestr = string_copy(STRING_ARGS(tracestr), STRING_CONST("<no stacktrace - not initialized>")); } messagestr = string_format(STRING_ARGS(messagestr), assert_format, sizeof(assert_format) - 1, (int)cond_length, condition, (int)file_length, file, line, STRING_FORMAT(contextstr), (int)msg_length, msg, STRING_FORMAT(tracestr)); log_errorf(context, ERROR_ASSERT, STRING_CONST("%.*s"), STRING_FORMAT(messagestr)); system_message_box(STRING_CONST("Assert Failure"), STRING_ARGS(messagestr), false); #else log_errorf(context, ERROR_ASSERT, assert_format, sizeof(assert_format) - 1, (int)cond_length, condition, (int)file_length, file, line, 0, "", (int)msg_length, msg, 0, ""); #endif return 1; }
int assert_report( uint64_t context, const char* condition, const char* file, int line, const char* msg ) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %s\nFile/line: %s : %d\n%s%s\n%s\n"; if( !condition ) condition = nocondition; if( !file ) file = nofile; if( !msg ) msg = nomsg; if( _assert_handler && ( _assert_handler != assert_report ) ) return (*_assert_handler)( context, condition, file, line, msg ); #if BUILD_ENABLE_ASSERT _assert_context_buffer[0] = 0; error_context_buffer( _assert_context_buffer, ASSERT_BUFFER_SIZE ); _assert_stacktrace_buffer[0] = 0; if( foundation_is_initialized() ) { unsigned int num_frames = stacktrace_capture( _assert_stacktrace, ASSERT_STACKTRACE_MAX_DEPTH, ASSERT_STACKTRACE_SKIP_FRAMES ); if( num_frames ) { //TODO: Resolve directly into buffer to avoid memory allocations in assert handler char* trace = stacktrace_resolve( _assert_stacktrace, num_frames, 0U ); string_copy( _assert_stacktrace_buffer, trace, ASSERT_BUFFER_SIZE ); string_deallocate( trace ); } } else { string_copy( _assert_stacktrace_buffer, "<no stacktrace - not initialized>", ASSERT_BUFFER_SIZE ); } snprintf( _assert_box_buffer, (size_t)ASSERT_BUFFER_SIZE, assert_format, condition, file, line, _assert_context_buffer, msg, _assert_stacktrace_buffer ); log_errorf( context, ERROR_ASSERT, "%s", _assert_box_buffer ); system_message_box( "Assert Failure", _assert_box_buffer, false ); #else log_errorf( context, ERROR_ASSERT, assert_format, condition, file, line, "", msg, "" ); #endif return 1; }
int assert_report( const char* condition, const char* file, int line, const char* msg ) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %s\nFile/line: %s : %d\n%s%s\n%s\n"; int ret; if( !condition ) condition = nocondition; if( !file ) file = nofile; if( !msg ) msg = nomsg; if( _assert_handler && ( _assert_handler != assert_report ) ) return (*_assert_handler)( condition, file, line, msg ); _assert_context_buffer[0] = 0; error_context_buffer( _assert_context_buffer, ASSERT_BUFFER_SIZE ); _assert_stacktrace_buffer[0] = 0; if( foundation_is_initialized() ) { if( stacktrace_capture( _assert_stacktrace, 128, 1 ) > 0 ) { //TODO: Resolve directly into buffer to avoid memory allocations in assert handler char* trace = stacktrace_resolve( _assert_stacktrace, 128, 0 ); string_copy( _assert_stacktrace_buffer, trace, ASSERT_BUFFER_SIZE ); string_deallocate( trace ); } } else { string_copy( _assert_stacktrace_buffer, "<no stacktrace - not initialized>", ASSERT_BUFFER_SIZE ); } ret = snprintf( _assert_box_buffer, (size_t)ASSERT_BUFFER_SIZE, assert_format, condition, file, line, _assert_context_buffer, msg, _assert_stacktrace_buffer ); if( ( ret < 0 ) || ( ret >= ASSERT_BUFFER_SIZE ) ) _assert_box_buffer[ASSERT_BUFFER_SIZE-1] = 0; log_errorf( 0, ERROR_ASSERT, "%s", _assert_box_buffer ); system_message_box( "Assert Failure", _assert_box_buffer, false ); return 1; }
DECLARE_TEST( stacktrace, resolve ) { #define TEST_DEPTH 64 void* trace[TEST_DEPTH]; unsigned int num_frames = 0; char* resolved = 0; num_frames = stacktrace_capture( trace, TEST_DEPTH, 0 ); EXPECT_GT( num_frames, 3 ); resolved = stacktrace_resolve( trace, num_frames, 0 ); EXPECT_NE( resolved, 0 ); log_infof( HASH_TEST, "Resolved stack trace:\n%s", resolved ); EXPECT_NE( string_find_string( resolved, "stacktraceresolve_fn", 0 ), STRING_NPOS ); EXPECT_NE( string_find_string( resolved, "test_run", 0 ), STRING_NPOS ); //EXPECT_NE( string_find_string( resolved, "main_run", 0 ), STRING_NPOS ); memory_deallocate( resolved ); return 0; }