|
From: Carlo W. <li...@us...> - 2002-02-17 01:42:19
|
CVSROOT : /cvsroot/libcw
Module : src
Commit time: 2002-01-17 01:42:17 UTC
Modified files:
libcwd/NEWS libcwd/debug.cc libcwd/debugmalloc.cc libcwd/elf32.cc
libcwd/include/sys.ho.in libcwd/include/libcw/class_debug.h
libcwd/include/libcw/private_struct_TSD.h
libcwd/testsuite/libcwd.tst/sys.h
Log message:
Fixed two theoretically possible dead locks.
---------------------- diff included ----------------------
Index: src/libcwd/NEWS
diff -u src/libcwd/NEWS:1.70 src/libcwd/NEWS:1.71
--- src/libcwd/NEWS:1.70 Thu Feb 14 21:19:31 2002
+++ src/libcwd/NEWS Sat Feb 16 17:42:06 2002
@@ -17,6 +17,28 @@
that is defined under preferences -> appearance -> fonts.
This should be set to -adobe-helvetica-*-.
+ Fixed a dead lock in object_file_ct::find_nearest_line().
+ The dead lock occured when debug output written from
+ load_dwarf/load_stabs, which must be done with userspace
+ allocations, caused a recursive entry into this function.
+
+ Fixed a dead lock in std::__default_allocator<true, 0>, the
+ default userspace allocator of the STL. The problem here
+ is that this lock is set when it calls malloc() to increase
+ its internal memory pool, causing a dead lock when memory
+ needs to be allocated during the writing of debug output
+ to dc::malloc or dc::bfd (this happens *extremely* seldom,
+ I even knew about this when I released 0.99.16). The solution
+ is to queue messages instead of writing them to the final
+ ostream when we find that the std::__default_allocator<true, 0>
+ is set and we are printing debug output from within malloc()
+ et al (then we assume we took the lock). The queued messages
+ are flushed the first time this condition is not true. The
+ queue is debug object specific which means that if you use
+ two or more different debug objects that write to the same
+ ostream, the ordering of messages could become non chronologic,
+ but then again - we could also put a man on Pluto next year.
+
libcwd-0.99.16
* libcwd is now thread-safe *
Index: src/libcwd/debug.cc
diff -u src/libcwd/debug.cc:1.70 src/libcwd/debug.cc:1.71
--- src/libcwd/debug.cc:1.70 Thu Feb 14 21:36:09 2002
+++ src/libcwd/debug.cc Sat Feb 16 17:42:06 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/debug.cc,v 1.70 2002/02/15 05:36:09 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/debug.cc,v 1.71 2002/02/17 01:42:06 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -13,6 +13,14 @@
#include "sys.h"
#include <libcw/debug_config.h>
+
+#if (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97) && defined(LIBCWD_THREAD_SAFE) && defined(DEBUGMALLOC)
+// This has to be very early (must not have been included elsewhere already).
+#define private public // Ugly, I know.
+#include <bits/stl_alloc.h>
+#undef private
+#endif // (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97) && defined(LIBCWD_THREAD_SAFE) && defined(DEBUGMALLOC)
+
#include <errno.h>
#include <iostream>
#include <sys/time.h> // Needed for setrlimit()
@@ -59,8 +67,42 @@
namespace libcw {
namespace debug {
+namespace _private_ {
+
+#if (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97) && defined(LIBCWD_THREAD_SAFE) && defined(DEBUGMALLOC)
+// The following tries to take the "node allocator" lock -- the lock of the
+// default allocator for threaded applications. The parameter is the value to
+// return when no lock exist. This should probably be implemented as a macro
+// test instead.
+__inline__
+bool allocator_trylock(void)
+{
+ if (!(__NODE_ALLOCATOR_THREADS)) return true;
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+ if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
+ std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
+#endif
+ return (__gthread_mutex_trylock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock) == 0);
+}
+
+// The following unlocks the node allocator.
+__inline__
+void allocator_unlock(void)
+{
+ if (!(__NODE_ALLOCATOR_THREADS)) return;
+#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
+ if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
+ std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
+#endif
+ __gthread_mutex_unlock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock);
+}
+#endif // (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97) && defined(LIBCWD_THREAD_SAFE) && defined(DEBUGMALLOC)
+
+} // namespace _private_
+
using _private_::set_alloc_checking_on;
using _private_::set_alloc_checking_off;
+ using _private_::debug_message_st;
class buffer_ct : public _private_::internal_stringstream {
private:
@@ -71,24 +113,56 @@
#endif
public:
#ifdef LIBCWD_THREAD_SAFE
- void writeto(std::ostream* os, _private_::lock_interface_base_ct* mutex LIBCWD_COMMA_TSD_PARAM)
+ void writeto(std::ostream* os, _private_::lock_interface_base_ct* mutex LIBCWD_COMMA_TSD_PARAM, debug_ct&
+#ifdef DEBUGMALLOC
+ debug_object
+#endif
+ )
#else
- void writeto(std::ostream* os LIBCWD_COMMA_TSD_PARAM)
+ void writeto(std::ostream* os LIBCWD_COMMA_TSD_PARAM, debug_ct&
+#ifdef DEBUGMALLOC
+ debug_object
#endif
+ )
+#endif // LIBCWD_THREAD_SAFE
{
- char* buf;
- bool used_malloc = false;
- int curlen = rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out) - rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
- if (curlen > 512 || !(buf = (char*)__builtin_alloca(curlen)))
+#if defined(DEBUGMALLOC) && defined(LIBCWD_THREAD_SAFE)
+ typedef debug_message_st* msgbuf_t;
+ msgbuf_t msgbuf;
+ // Queue the message when the default (STL) allocator is locked and it could be that we
+ // did that (because we got here via malloc or free). At least as important: if
+ // this is the last thread, just prior to exiting the application, and we CAN
+ // get the lock - then DON'T queue the message (and thus flush all possibly queued
+ // messages); this garantees that there will never messages be left in the queue
+ // when the application exits.
+ bool const queue_msg = __libcwd_tsd.inside_malloc_or_free && !_private_::allocator_trylock();
+ if (__libcwd_tsd.inside_malloc_or_free && !queue_msg)
+ _private_::allocator_unlock(); // Always immedeately release the lock again.
+ int const extra_size = sizeof(debug_message_st) - sizeof(msgbuf->buf);
+#else
+ typedef char* msgbuf_t;
+ msgbuf_t msgbuf;
+ bool const queue_msg = false;
+ int const extra_size = 0;
+#endif
+ int curlen;
+ curlen = rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out) - rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
+ bool free_msgbuf = false;
+ if (queue_msg)
+ msgbuf = (msgbuf_t)malloc(curlen + extra_size);
+ else if (curlen > 512 || !(msgbuf = (msgbuf_t)__builtin_alloca(curlen + extra_size)))
{
- set_alloc_checking_off(LIBCWD_TSD);
- buf = (char*)malloc(curlen);
- set_alloc_checking_on(LIBCWD_TSD);
- used_malloc = true;
+ msgbuf = (msgbuf_t)malloc(curlen + extra_size);
+ free_msgbuf = true;
}
- rdbuf()->sgetn(buf, curlen);
+#if defined(DEBUGMALLOC) && defined(LIBCWD_THREAD_SAFE)
+ rdbuf()->sgetn(msgbuf->buf, curlen);
+#else
+ rdbuf()->sgetn(msgbuf, curlen);
+#endif
#ifdef DEBUGMALLOC
// Writing to the final std::ostream (ie std::cerr) must be non-internal!
+ // LIBCWD_DISABLE_CANCEL/LIBCWD_ENABLE_CANCEL must be done non-internal too.
int saved_internal = __libcwd_tsd.internal;
__libcwd_tsd.internal = 0;
++__libcwd_tsd.library_call;
@@ -97,40 +171,69 @@
#ifdef LIBCWD_THREAD_SAFE
LIBCWD_DISABLE_CANCEL // We don't want Dout() to be a cancellation point.
if (mutex)
- {
mutex->lock();
- os->write(buf, curlen);
- mutex->unlock();
- }
else if (_private_::WST_multi_threaded)
{
static bool WST_second_time = false; // Break infinite loop.
- if (WST_second_time)
- os->write(buf, curlen);
- else
+ if (!WST_second_time)
{
WST_second_time = true;
DoutFatal(dc::core, "When using multiple threads, you must provide a locking mechanism for the debug output stream. "
"You can pass a pointer to a mutex with `debug_ct::set_ostream' (see documentation/html/group__group__destination.html).");
}
}
+#endif // !LIBCWD_THREAD_SAFE
+#if defined(DEBUGMALLOC) && defined(LIBCWD_THREAD_SAFE)
+ if (queue_msg) // Inside a call to malloc and possibly owning lock of std::__default_alloc_template<true, 0>?
+ {
+ // We don't write debug output to the final ostream when inside malloc and std::__default_alloc_template<true, 0> is locked.
+ // It is namely possible that this will again try to acquire the lock in std::__default_alloc_template<true, 0>, resulting
+ // in a dead lock. Append it to the queue instead.
+ msgbuf->curlen = curlen;
+ msgbuf->prev = NULL;
+ msgbuf->next = debug_object.queue;
+ if (debug_object.queue)
+ debug_object.queue->prev = msgbuf;
+ else
+ debug_object.queue_top = msgbuf;
+ debug_object.queue = msgbuf;
+ }
else
- os->write(buf, curlen);
+ {
+ debug_message_st* message = debug_object.queue_top;
+ if (message)
+ {
+ // First empty the whole queue.
+ debug_message_st* next_message;
+ do
+ {
+ next_message = message->prev;
+ os->write(message->buf, message->curlen);
+ __libcwd_tsd.internal = 1;
+ free(message);
+ __libcwd_tsd.internal = 0;
+ }
+ while ((message = next_message));
+ debug_object.queue_top = debug_object.queue = NULL;
+ }
+ // Then write the new message.
+ os->write(msgbuf->buf, curlen);
+ }
+#else // !(defined(DEBUGMALLOC) && defined(LIBCWD_THREAD_SAFE))
+ os->write(msgbuf, curlen);
+#endif // !DEBUGMALLOC
+#ifdef LIBCWD_THREAD_SAFE
+ if (mutex)
+ mutex->unlock();
LIBCWD_ENABLE_CANCEL
-#else // !LIBCWD_THREAD_SAFE
- os->write(buf, curlen);
#endif // !LIBCWD_THREAD_SAFE
#ifdef DEBUGMALLOC
--LIBCWD_DO_TSD_MEMBER_OFF(libcw_do);
--__libcwd_tsd.library_call;
__libcwd_tsd.internal = saved_internal;
#endif
- if (used_malloc)
- {
- set_alloc_checking_off(LIBCWD_TSD);
- free(buf);
- set_alloc_checking_on(LIBCWD_TSD);
- }
+ if (free_msgbuf)
+ free(msgbuf);
}
void store_position(void) {
position = rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
@@ -735,7 +838,7 @@
current_oss->write("<unfinished>\n", 13); // Continued debug output should end on a space by itself,
// And write out what is in the buffer till now.
std::ostream* target_os = (channel_set.mask & cerr_cf) ? &std::cerr : debug_object.real_os;
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD, debug_object);
// Truncate the buffer to its prefix and append "<continued>" to it already.
static_cast<buffer_ct*>(current_oss)->restore_position();
current_oss->write("<continued> ", 12); // therefore we repeat the space here.
@@ -831,7 +934,7 @@
if ((current->mask & flush_cf))
{
// Write buffer to ostream.
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD, debug_object);
// Flush ostream. Note that in the case of nested debug output this `os' can be an stringstream,
// in that case, no actual flushing is done until the debug output to the real ostream has
// finished.
@@ -851,7 +954,7 @@
current_oss->put('\n');
// Write buffer to ostream.
- static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD);
+ static_cast<buffer_ct*>(current_oss)->writeto(target_os LIBCWD_COMMA_MUTEX LIBCWD_COMMA_TSD, debug_object);
// Handle control flags, if any:
if (current->mask != 0)
@@ -1066,44 +1169,14 @@
debug_tsd_st::~debug_tsd_st()
{
- if (!tsd_initialized) // Don't de-initialize when it wasn't initialized.
+ if (!tsd_initialized) // Skip when it wasn't initialized.
return;
// Sanity checks:
if (continued_stack.size())
DoutFatal( dc::core|cerr_cf, "Destructing debug_tsd_st with a non-empty continued_stack (missing dc::finish?)" );
if (laf_stack.size())
DoutFatal( dc::core|cerr_cf, "Destructing debug_tsd_st with a non-empty laf_stack" );
-
- LIBCWD_TSD_DECLARATION
- set_alloc_checking_off(LIBCWD_TSD);
- marker.ST_internal_deinit();
- margin.ST_internal_deinit();
- set_alloc_checking_on(LIBCWD_TSD);
- tsd_initialized = false;
- }
-
- /**
- * \brief Destructor
- */
- debug_ct::~debug_ct()
- {
- WNS_initialized = false;
-#ifdef DEBUGDEBUG
- init_magic = 0;
-#endif
- LIBCWD_TSD_DECLARATION
- LIBCWD_DEFER_CANCEL
- set_alloc_checking_off(LIBCWD_TSD);
- DEBUG_OBJECTS_ACQUIRE_WRITE_LOCK
- {
- _private_::debug_objects_ct::container_type& objects(_private_::debug_objects.write_locked());
- objects.erase(find(objects.begin(), objects.end(), this));
- if (objects.empty())
- _private_::debug_objects.ST_uninit();
- }
- DEBUG_OBJECTS_RELEASE_WRITE_LOCK
- set_alloc_checking_on(LIBCWD_TSD);
- LIBCWD_RESTORE_CANCEL
+ // Don't actually deinitialize anything.
}
/**
@@ -1450,7 +1523,7 @@
LIBCWD_TSD_DECLARATION
if (__libcwd_tsd.recursive_assert
#ifdef DEBUGDEBUGMALLOC
- || __libcwd_tsd.recursive
+ || __libcwd_tsd.inside_malloc_or_free
#endif
)
{
Index: src/libcwd/debugmalloc.cc
diff -u src/libcwd/debugmalloc.cc:1.82 src/libcwd/debugmalloc.cc:1.83
--- src/libcwd/debugmalloc.cc:1.82 Fri Feb 8 19:22:59 2002
+++ src/libcwd/debugmalloc.cc Sat Feb 16 17:42:06 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/debugmalloc.cc,v 1.82 2002/02/09 03:22:59 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/debugmalloc.cc,v 1.83 2002/02/17 01:42:06 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -122,12 +122,6 @@
#define DEBUGMALLOC_INTERNAL
#include "sys.h"
#include <libcw/debug_config.h>
-#if defined(LIBCWD_THREAD_SAFE) && (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97)
-// This has to be very early (must not have been included elsewhere already).
-#define private public // Ugly, I know.
-#include <bits/stl_alloc.h>
-#undef private
-#endif // __GNUC__ >= 3 && LIBCWD_THREAD_SAFE
#if defined(DEBUGMALLOC) || defined(LIBCW_DOXYGEN)
@@ -222,37 +216,6 @@
namespace _private_ {
-#if __GNUC__ >= 3 || __GNUC_MINOR__ >= 97
-#ifdef LIBCWD_THREAD_SAFE
-// The following tries to take the "node allocator" lock -- the lock of the
-// default allocator for threaded applications. The parameter is the value to
-// return when no lock exist. This should probably be implemented as a macro
-// test instead.
-bool allocator_trylock(bool when_no_threads)
-{
- if (!(__NODE_ALLOCATOR_THREADS)) return when_no_threads;
-
-#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
- if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
- std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
-#endif
- return (__gthread_mutex_trylock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock) == 0);
-}
-
-// The following unlocks the node allocator.
-void allocator_unlock(void)
-{
- if (!(__NODE_ALLOCATOR_THREADS)) return;
-
-#if !defined(__GTHREAD_MUTEX_INIT) && defined(__GTHREAD_MUTEX_INIT_FUNCTION)
- if (!std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_init_flag)
- std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_initialize();
-#endif
- __gthread_mutex_unlock(&std::__default_alloc_template<true, 0>::_S_node_allocator_lock._M_lock);
-}
-#endif // LIBCWD_THREAD_SAFE
-#endif // __GNUC__ >= 3
-
void no_alloc_print_int_to(std::ostream* os, unsigned long val, bool hexadecimal)
{
char buf[32]; // 32 > x where x is the number of digits of the largest unsigned long.
@@ -1297,12 +1260,11 @@
{
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#endif
#if defined(DEBUGDEBUGMALLOC) && defined(__GLIBCPP__) && !defined(DEBUGMALLOCEXTERNALCLINKAGE)
LIBCWD_ASSERT( _private_::WST_ios_base_initialized || __libcwd_tsd.internal );
@@ -1325,12 +1287,7 @@
#endif // DEBUGDEBUGMALLOC
#ifdef DEBUGMAGICMALLOC
if (!ptr)
- {
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
return;
- }
ptr = static_cast<size_t*>(ptr) - 2;
if (from == from_delete)
{
@@ -1357,22 +1314,18 @@
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_TWELVE(((size_t*)ptr)[1])))[-1] ^= (size_t)-1;
#endif // DEBUGMAGICMALLOC
__libc_free(ptr);
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
return;
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
if (!ptr)
{
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc, "Trying to free NULL - ignored [" << ++__libcwd_tsd.marker << "]." );
#else
DoutInternal( dc_malloc, "Trying to free NULL - ignored." );
#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return;
}
@@ -1502,9 +1455,7 @@
if (visible)
DoutInternal( dc::finish, "" );
}
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
}
void init_debugmalloc(void)
@@ -1527,16 +1478,13 @@
#endif // __GLIBCPP__
)
{
- WST_initialization_state = 1; // ST_initialize_globals() calls malloc again of course.
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive; // Allow that.
-#endif
+ WST_initialization_state = 1; // ST_initialize_globals() calls malloc again of course.
+ int recursive_store = __libcwd_tsd.inside_malloc_or_free;
+ __libcwd_tsd.inside_malloc_or_free = 0; // Allow that (this call to malloc will not have done from STL allocator).
libcw::debug::ST_initialize_globals(); // This doesn't belong in the malloc department at all, but malloc() happens
// to be a function that is called _very_ early - and hence this is a good moment
// to initialize ALL of libcwd.
-#ifdef DEBUGDEBUGMALLOC
- ++__libcwd_tsd.recursive;
-#endif
+ __libcwd_tsd.inside_malloc_or_free = recursive_store;
}
}
}
@@ -1645,7 +1593,7 @@
#ifdef DEBUGDEBUGMALLOC
{
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
}
#endif
@@ -1805,7 +1753,7 @@
{
#ifdef DEBUGDEBUGMALLOC
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
#endif
Dout( dc_malloc, "New libcw::debug::marker_ct at " << this );
bool error = false;
@@ -1837,7 +1785,7 @@
{
#ifdef DEBUGDEBUGMALLOC
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
#endif
LIBCWD_DEFER_CANCEL_NO_BRACE
@@ -1882,7 +1830,7 @@
{
#ifdef DEBUGDEBUGMALLOC
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
#endif
LIBCWD_DEFER_CANCEL_NO_BRACE
@@ -1980,7 +1928,7 @@
{
#ifdef DEBUGDEBUGMALLOC
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
#endif
alloc_ct const* res;
@@ -2096,10 +2044,9 @@
//
void register_external_allocation(void const* mptr, size_t size)
{
-#ifdef DEBUGDEBUGMALLOC
LIBCWD_TSD_DECLARATION
- LIBCWD_ASSERT( !__libcwd_tsd.recursive && !__libcwd_tsd.internal );
- ++__libcwd_tsd.recursive;
+#ifdef DEBUGDEBUGMALLOC
+ LIBCWD_ASSERT( !__libcwd_tsd.inside_malloc_or_free && !__libcwd_tsd.internal );
#endif
#if defined(DEBUGDEBUGMALLOC) && defined(__GLIBCPP__)
LIBCWD_ASSERT( _private_::WST_ios_base_initialized );
@@ -2108,7 +2055,7 @@
DoutFatalInternal( dc::core, "Calling register_external_allocation while `internal' is non-zero! "
"You can't use RegisterExternalAlloc() inside a Dout() et. al. "
"(or whenever alloc_checking is off)." );
-
+ ++__libcwd_tsd.inside_malloc_or_free;
DoutInternal( dc_malloc, "register_external_allocation(" << (void*)mptr << ", " << size << ')' );
if (WST_initialization_state == 0) // Only true once.
@@ -2150,10 +2097,7 @@
#ifdef DEBUGUSEBFD
memblk_info.get_alloc_node()->location_reference().move(loc);
#endif
-
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
}
#endif // !DEBUGMALLOCEXTERNALCLINKAGE
@@ -2190,21 +2134,14 @@
void* __libcwd_malloc(size_t size)
{
-#if (__GNUC__ >= 3 || __GNUC_MINOR__ >= 97) && defined(LIBCWD_THREAD_SAFE) && defined(DEBUGDEBUG)
- bool locked = false;
- if (_private_::WST_multi_threaded)
- locked = _private_::allocator_trylock(true); // Fake a std::string (etc) lock.
-#endif
-
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- FATALDEBUGDEBUG_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ FATALDEBUGDEBUG_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#ifdef DEBUGDEBUGOUTPUT
int saved_marker = ++__libcwd_tsd.marker;
#endif
@@ -2217,49 +2154,34 @@
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Entering `__libcwd_malloc(" << size << ")' [" << saved_marker << ']' );
#if !defined(DEBUGDEBUGMALLOC) && !defined(DEBUGMAGICMALLOC)
- UNLOCK
return __libc_malloc(size);
#else // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
#ifndef DEBUGMAGICMALLOC
void* ptr = __libc_malloc(size);
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_malloc': " << ptr << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
- UNLOCK
return ptr;
#else // DEBUGMAGICMALLOC
void* ptr = __libc_malloc(SIZE_PLUS_TWELVE(size));
if (!ptr)
- {
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
- UNLOCK
return NULL;
- }
((size_t*)ptr)[0] = INTERNAL_MAGIC_MALLOC_BEGIN;
((size_t*)ptr)[1] = size;
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_TWELVE(size)))[-1] = INTERNAL_MAGIC_MALLOC_END;
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_malloc': " << static_cast<size_t*>(ptr) + 2 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
- UNLOCK
return static_cast<size_t*>(ptr) + 2;
#endif // DEBUGMAGICMALLOC
#endif // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc|continued_cf, "malloc(" << size << ") = [" << saved_marker << ']' );
#else
DoutInternal( dc_malloc|continued_cf, "malloc(" << size << ") = " );
#endif
void* ptr = internal_malloc(size, memblk_type_malloc CALL_ADDRESS LIBCWD_COMMA_TSD SAVEDMARKER);
-
#ifdef DEBUGMAGICMALLOC
if (ptr)
{
@@ -2268,11 +2190,7 @@
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_FOUR(size)))[-1] = MAGIC_MALLOC_END;
}
#endif
-
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
- UNLOCK
+ --__libcwd_tsd.inside_malloc_or_free;
return ptr;
}
@@ -2281,12 +2199,11 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#ifdef DEBUGDEBUGOUTPUT
int saved_marker = ++__libcwd_tsd.marker;
#endif
@@ -2304,34 +2221,24 @@
#ifndef DEBUGMAGICMALLOC
void* ptr = __libc_calloc(nmemb, size);
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_calloc': " << ptr << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif
return ptr;
#else // DEBUGMAGICMALLOC
void* ptr = __libc_malloc(SIZE_PLUS_TWELVE(nmemb * size));
if (!ptr)
- {
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
return NULL;
- }
memset(static_cast<void*>(static_cast<size_t*>(ptr) + 2), 0, nmemb * size);
((size_t*)ptr)[0] = INTERNAL_MAGIC_MALLOC_BEGIN;
((size_t*)ptr)[1] = nmemb * size;
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_TWELVE(nmemb * size)))[-1] = INTERNAL_MAGIC_MALLOC_END;
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_calloc': " << static_cast<size_t*>(ptr) + 2 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return static_cast<size_t*>(ptr) + 2;
#endif // DEBUGMAGICMALLOC
#endif // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc|continued_cf, "calloc(" << nmemb << ", " << size << ") = [" << saved_marker << ']' );
#else
@@ -2341,7 +2248,6 @@
size *= nmemb;
if ((ptr = internal_malloc(size, memblk_type_malloc CALL_ADDRESS LIBCWD_COMMA_TSD SAVEDMARKER)))
memset(ptr, 0, size);
-
#ifdef DEBUGMAGICMALLOC
if (ptr)
{
@@ -2350,10 +2256,7 @@
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_FOUR(size)))[-1] = MAGIC_MALLOC_END;
}
#endif
-
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return ptr;
}
@@ -2369,12 +2272,11 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#ifdef DEBUGDEBUGOUTPUT
int saved_marker = ++__libcwd_tsd.marker;
#endif
@@ -2392,10 +2294,7 @@
#ifndef DEBUGMAGICMALLOC
void* ptr1 = __libc_realloc(ptr, size);
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_realloc': " << ptr1 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return ptr1;
#else // DEBUGMAGICMALLOC
void* ptr1;
@@ -2408,10 +2307,7 @@
if (size == 0)
{
__libc_free(ptr);
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_realloc': NULL [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return NULL;
}
ptr1 = __libc_realloc(ptr, SIZE_PLUS_TWELVE(size));
@@ -2421,16 +2317,14 @@
((size_t*)ptr1)[0] = INTERNAL_MAGIC_MALLOC_BEGIN;
((size_t*)ptr1)[1] = size;
((size_t*)(static_cast<char*>(ptr1) + SIZE_PLUS_TWELVE(size)))[-1] = INTERNAL_MAGIC_MALLOC_END;
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `__libcwd_realloc': " << static_cast<size_t*>(ptr1) + 2 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return static_cast<size_t*>(ptr1) + 2;
#endif // DEBUGMAGICMALLOC
#endif // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc|continued_cf, "realloc(" << ptr << ", " << size << ") = [" << saved_marker << ']' );
#else
@@ -2449,10 +2343,7 @@
((size_t*)(static_cast<char*>(mptr) + SIZE_PLUS_FOUR(size)))[-1] = MAGIC_MALLOC_END;
}
#endif
-
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return mptr;
}
@@ -2493,15 +2384,15 @@
// again set a lock and again try to find the ptr in the memblk_map.
// It might print "free" instead of "realloc", but the program is ill-formed
// anyway in this case.
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
internal_free(ptr, from_free LIBCWD_COMMA_TSD);
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc::finish, "NULL [" << saved_marker << ']' );
#else
DoutInternal( dc::finish, "NULL" );
#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return NULL;
}
@@ -2537,9 +2428,7 @@
DoutInternal( dc::finish, "NULL" );
#endif
DoutInternal( dc_malloc, "Out of memory! This is only a pre-detection!" );
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return NULL; // A fatal error should occur directly after this
}
#ifdef DEBUGMAGICMALLOC
@@ -2579,9 +2468,7 @@
#else
DoutInternal( dc::finish, (void*)(mptr) );
#endif
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return mptr;
}
@@ -2597,12 +2484,11 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#ifdef DEBUGDEBUGOUTPUT
int saved_marker = ++__libcwd_tsd.marker;
#endif
@@ -2619,10 +2505,7 @@
void* ptr = __libc_malloc(size);
if (!ptr)
DoutFatalInternal( dc::core, "Out of memory in `operator new'" );
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `operator new': " << ptr << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return ptr;
#else // DEBUGMAGICMALLOC
void* ptr = __libc_malloc(SIZE_PLUS_TWELVE(size));
@@ -2631,16 +2514,14 @@
((size_t*)ptr)[0] = INTERNAL_MAGIC_NEW_BEGIN;
((size_t*)ptr)[1] = size;
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_TWELVE(size)))[-1] = INTERNAL_MAGIC_NEW_END;
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `operator new': " << static_cast<size_t*>(ptr) + 2 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return static_cast<size_t*>(ptr) + 2;
#endif // DEBUGMAGICMALLOC
#endif // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc|continued_cf, "operator new (size = " << size << ") = [" << saved_marker << ']' );
#else
@@ -2657,9 +2538,7 @@
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_FOUR(size)))[-1] = MAGIC_NEW_END;
}
#endif
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return ptr;
}
@@ -2668,12 +2547,11 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#ifdef DEBUGDEBUGOUTPUT
int saved_marker = ++__libcwd_tsd.marker;
#endif
@@ -2690,10 +2568,7 @@
void* ptr = __libc_malloc(size);
if (!ptr)
DoutFatalInternal( dc::core, "Out of memory in `operator new[]'" );
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `operator new[]': " << ptr << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return ptr;
#else // DEBUGMAGICMALLOC
void* ptr = __libc_malloc(SIZE_PLUS_TWELVE(size));
@@ -2702,16 +2577,14 @@
((size_t*)ptr)[0] = INTERNAL_MAGIC_NEW_ARRAY_BEGIN;
((size_t*)ptr)[1] = size;
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_TWELVE(size)))[-1] = INTERNAL_MAGIC_NEW_ARRAY_END;
-#ifdef DEBUGDEBUGMALLOC
DEBUGDEBUGMALLOC_CERR( "DEBUGDEBUGMALLOC: Internal: Leaving `operator new[]': " << static_cast<size_t*>(ptr) + 2 << " [" << saved_marker << ']' );
- --__libcwd_tsd.recursive;
-#endif // DEBUGDEBUGMALLOC
return static_cast<size_t*>(ptr) + 2;
#endif // DEBUGMAGICMALLOC
#endif // defined(DEBUGDEBUGMALLOC) || defined(DEBUGMAGICMALLOC)
} // internal
+ ++__libcwd_tsd.inside_malloc_or_free;
#if defined(DEBUGDEBUGMALLOC) && defined(DEBUGDEBUGOUTPUT)
DoutInternal( dc_malloc|continued_cf, "operator new[] (size = " << size << ") = [" << saved_marker << ']' );
#else
@@ -2728,9 +2601,7 @@
((size_t*)(static_cast<char*>(ptr) + SIZE_PLUS_FOUR(size)))[-1] = MAGIC_NEW_ARRAY_END;
}
#endif
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
+ --__libcwd_tsd.inside_malloc_or_free;
return ptr;
}
@@ -2744,19 +2615,15 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#endif
#if defined(DEBUGDEBUGMALLOC) && defined(__GLIBCPP__) && !defined(DEBUGMALLOCEXTERNALCLINKAGE)
LIBCWD_ASSERT( _private_::WST_ios_base_initialized || __libcwd_tsd.internal );
#endif
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
internal_free(ptr, from_delete LIBCWD_COMMA_TSD);
}
@@ -2765,22 +2632,18 @@
LIBCWD_TSD_DECLARATION
#ifdef DEBUGDEBUGMALLOC
// We can't use `assert' here, because that can call malloc.
- if (__libcwd_tsd.recursive > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
+ if (__libcwd_tsd.inside_malloc_or_free > __libcwd_tsd.library_call && !__libcwd_tsd.internal)
{
- DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.recursive <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
+ DEBUGDEBUGMALLOC_CERR("DEBUGDEBUGMALLOC: debugmalloc.cc:" << __LINE__ - 2 << ": " << __PRETTY_FUNCTION__ << ": Assertion `__libcwd_tsd.inside_malloc_or_free <= __libcwd_tsd.library_call || __libcwd_tsd.internal' failed.");
core_dump();
}
- ++__libcwd_tsd.recursive;
#endif
#if defined(DEBUGDEBUGMALLOC) && defined(__GLIBCPP__) && !defined(DEBUGMALLOCEXTERNALCLINKAGE)
LIBCWD_ASSERT( _private_::WST_ios_base_initialized || __libcwd_tsd.internal );
#endif
-#ifdef DEBUGDEBUGMALLOC
- --__libcwd_tsd.recursive;
-#endif
internal_free(ptr, from_delete_array LIBCWD_COMMA_TSD); // Note that the standard demands that we call free(), and not delete().
- // This forces everyone to overload both, operator delete() and operator delete[]()
- // and not only operator delete().
+ // This forces everyone to overload both, operator delete() and operator
+ // delete[]() and not only operator delete().
}
#endif /* DEBUGMALLOC */
Index: src/libcwd/elf32.cc
diff -u src/libcwd/elf32.cc:1.36 src/libcwd/elf32.cc:1.37
--- src/libcwd/elf32.cc:1.36 Sat Feb 2 20:15:11 2002
+++ src/libcwd/elf32.cc Sat Feb 16 17:42:06 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/elf32.cc,v 1.36 2002/02/03 04:15:11 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/elf32.cc,v 1.37 2002/02/17 01:42:06 libcw Exp $
//
// Copyright (C) 2001, by
//
@@ -798,7 +798,11 @@
object_files_string_set_ct M_source_files;
object_files_range_location_map_ct M_ranges;
bool M_debug_info_loaded;
+#ifndef LIBCWD_THREAD_SAFE
bool M_inside_find_nearest_line;
+#else
+ static pthread_t S_thread_inside_find_nearest_line;
+#endif
Elf32_Word M_stabs_section_index;
Elf32_Word M_dwarf_debug_info_section_index;
Elf32_Word M_dwarf_debug_abbrev_section_index;
@@ -827,6 +831,10 @@
uint32_t elf_hash(unsigned char const* name, unsigned char delim) const;
};
+#ifdef LIBCWD_THREAD_SAFE
+pthread_t object_file_ct::S_thread_inside_find_nearest_line;
+#endif
+
//-------------------------------------------------------------------------------------------------------------------------------------------
void location_ct::M_store(void)
@@ -1868,13 +1876,11 @@
void object_file_ct::find_nearest_line(asymbol_st const* symbol, Elf32_Addr offset, char const** file, char const** func, unsigned int* line)
{
- if (!M_debug_info_loaded)
+ while (!M_debug_info_loaded) // So we can use 'break'.
{
-#ifdef LIBCWD_THREAD_SAFE
- // `object_files_string' and the STL containers using `_private_::object_files_allocator' in the
- // following functions need this lock.
- _private_::rwlock_tct<_private_::object_files_instance>::wrlock();
-#endif
+ // The call to load_dwarf()/load_stabs() below can call malloc, causing us to recursively enter this function
+ // for this object or another object_file_ct.
+#ifndef LIBCWD_THREAD_SAFE
if (M_inside_find_nearest_line) // Break loop caused by re-entry through a call to malloc.
{
*file = NULL;
@@ -1883,6 +1889,29 @@
return;
}
M_inside_find_nearest_line = true;
+#else
+ // `S_thread_inside_find_nearest_line' is only *changed* inside the critical area
+ // of `object_files_instance'. Therefore, when it is set to our thread id at
+ // this moment - then other threads can't change it.
+ if (pthread_equal(S_thread_inside_find_nearest_line, pthread_self()))
+ {
+ // This thread set the lock. Don't try to acquire it again...
+ *file = NULL;
+ *func = symbol->name;
+ *line = 0;
+ return;
+ }
+ // Ok, now we are sure that THIS thread doesn't hold the following lock, try to acquire it.
+ // `object_files_string' and the STL containers using `_private_::object_files_allocator' in the following functions need this lock.
+ _private_::rwlock_tct<_private_::object_files_instance>::wrlock();
+ // Now we acquired the lock, check again if another thread not already read the debug info.
+ if (M_debug_info_loaded)
+ {
+ _private_::rwlock_tct<_private_::object_files_instance>::wrunlock();
+ break;
+ }
+ S_thread_inside_find_nearest_line = pthread_self();
+#endif
#if DEBUGSTABS || DEBUGDWARF
libcw::debug::debug_ct::OnOffState state;
Debug( libcw_do.force_on(state) );
@@ -1897,11 +1926,14 @@
Debug( dc::bfd.restore(state2) );
Debug( libcw_do.restore(state) );
#endif
+#ifndef LIBCWD_THREAD_SAFE
M_inside_find_nearest_line = false;
-#ifdef LIBCWD_THREAD_SAFE
+#else
+ S_thread_inside_find_nearest_line = (pthread_t) 0;
_private_::rwlock_tct<_private_::object_files_instance>::wrunlock();
#endif
M_input_stream.close();
+ break;
}
range_st range;
range.start = offset;
@@ -1991,7 +2023,9 @@
if (DEBUGELF32)
Debug( libcw_do.inc_indent(4) );
M_debug_info_loaded = false;
+#ifndef LIBCWD_THREAD_SAFE
M_inside_find_nearest_line = false;
+#endif
M_stabs_section_index = 0;
M_dwarf_debug_line_section_index = 0;
for(int i = 0; i < M_header.e_shnum; ++i)
Index: src/libcwd/include/libcw/class_debug.h
diff -u src/libcwd/include/libcw/class_debug.h:1.11 src/libcwd/include/libcw/class_debug.h:1.12
--- src/libcwd/include/libcw/class_debug.h:1.11 Tue Feb 12 19:55:26 2002
+++ src/libcwd/include/libcw/class_debug.h Sat Feb 16 17:42:07 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.h,v 1.11 2002/02/13 03:55:26 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/class_debug.h,v 1.12 2002/02/17 01:42:07 libcw Exp $
//
// Copyright (C) 2000 - 2002, by
//
@@ -41,6 +41,19 @@
namespace libcw {
namespace debug {
+#ifdef DEBUGMALLOC
+namespace _private_ {
+
+struct debug_message_st {
+ struct debug_message_st* next;
+ struct debug_message_st* prev;
+ int curlen;
+ char buf[sizeof(int)];
+};
+
+}
+#endif
+
//===================================================================================================
// class debug_ct
//
@@ -110,6 +123,14 @@
bool interactive;
// Set true if the last or current debug output is to cerr
+#ifdef DEBUGMALLOC
+public:
+ _private_::debug_message_st* queue;
+ _private_::debug_message_st* queue_top;
+ // Queue of messages written inside malloc/realloc/calloc/free/new/delete.
+ // Locked by mutex provided through set_ostream.
+#endif
+
public:
/** \addtogroup group_formatting */
/** \{ */
@@ -189,7 +210,6 @@
//
debug_ct(void);
- ~debug_ct();
private:
void private_set_ostream(std::ostream* os);
Index: src/libcwd/include/libcw/private_struct_TSD.h
diff -u src/libcwd/include/libcw/private_struct_TSD.h:1.7 src/libcwd/include/libcw/private_struct_TSD.h:1.8
--- src/libcwd/include/libcw/private_struct_TSD.h:1.7 Sat Feb 9 21:41:58 2002
+++ src/libcwd/include/libcw/private_struct_TSD.h Sat Feb 16 17:42:07 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/private_struct_TSD.h,v 1.7 2002/02/10 05:41:58 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/libcw/private_struct_TSD.h,v 1.8 2002/02/17 01:42:07 libcw Exp $
//
// Copyright (C) 2001, by
//
@@ -136,9 +136,9 @@
#ifdef DEBUGMALLOC
int internal;
int library_call;
+ int inside_malloc_or_free; // Set when entering a (de)allocation routine non-internal.
#ifdef DEBUGDEBUGMALLOC
int marker;
- int recursive; // Used for sanity double checks in debugmalloc.cc.
#endif
#endif // DEBUGMALLOC
bool recursive_fatal; // Detect loop involving dc::fatal or dc::core.
Index: src/libcwd/include/sys.ho.in
diff -u src/libcwd/include/sys.ho.in:1.8 src/libcwd/include/sys.ho.in:1.9
--- src/libcwd/include/sys.ho.in:1.8 Thu Feb 14 21:19:32 2002
+++ src/libcwd/include/sys.ho.in Sat Feb 16 17:42:07 2002
@@ -1,5 +1,5 @@
// @configure_input@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/include/sys.ho.in,v 1.8 2002/02/15 05:19:32 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/include/sys.ho.in,v 1.9 2002/02/17 01:42:07 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -15,6 +15,7 @@
#ifndef SYS_H
#define SYS_H
+#undef _GNU_SOURCE // Could be defined by g++ itself and redefined in ../config.h
#include "../config.h"
//
Index: src/libcwd/testsuite/libcwd.tst/sys.h
diff -u src/libcwd/testsuite/libcwd.tst/sys.h:1.4 src/libcwd/testsuite/libcwd.tst/sys.h:1.5
--- src/libcwd/testsuite/libcwd.tst/sys.h:1.4 Thu Feb 7 20:03:47 2002
+++ src/libcwd/testsuite/libcwd.tst/sys.h Sat Feb 16 17:42:07 2002
@@ -1,4 +1,4 @@
-// $Header: /cvsroot/l/li/libcw/src/libcwd/testsuite/libcwd.tst/sys.h,v 1.4 2002/02/08 04:03:47 libcw Exp $
+// $Header: /cvsroot/l/li/libcw/src/libcwd/testsuite/libcwd.tst/sys.h,v 1.5 2002/02/17 01:42:07 libcw Exp $
//
// Copyright (C) 2000 - 2001, by
//
@@ -19,6 +19,7 @@
#endif
#include <libcw/sysd.h>
+#undef _GNU_SOURCE
#include "../../config.h"
#ifdef HAVE__G_CONFIG_H
#include <_G_config.h>
----------------------- End of diff -----------------------
|