1+ #include < iostream>
2+ #include < memory>
3+ #include < thread>
4+ #include < chrono>
5+ #include < mutex>
6+ #include < unordered_map>
7+ #include < unordered_set>
8+
9+ // Простая диагностика утечек для shared_ptr
10+ class LeakDetector {
11+ public:
12+ static LeakDetector& instance () {
13+ static LeakDetector detector;
14+ return detector;
15+ }
16+
17+ void registerPointer (void * ptr, const char * type) {
18+ std::lock_guard<std::mutex> lock (mutex_);
19+ active_pointers_[ptr] = type;
20+ std::cout << " [LEAK_DEBUG] Created " << type << " at " << ptr << std::endl;
21+ }
22+
23+ void unregisterPointer (void * ptr) {
24+ std::lock_guard<std::mutex> lock (mutex_);
25+ auto it = active_pointers_.find (ptr);
26+ if (it != active_pointers_.end ()) {
27+ std::cout << " [LEAK_DEBUG] Destroyed " << it->second << " at " << ptr << std::endl;
28+ active_pointers_.erase (it);
29+ }
30+ }
31+
32+ void printActivePointers () {
33+ std::lock_guard<std::mutex> lock (mutex_);
34+ if (active_pointers_.empty ()) {
35+ std::cout << " [LEAK_DEBUG] No active pointers detected!" << std::endl;
36+ } else {
37+ std::cout << " [LEAK_DEBUG] Active pointers (" << active_pointers_.size () << " ):" << std::endl;
38+ for (const auto & [ptr, type] : active_pointers_) {
39+ std::cout << " " << type << " at " << ptr << std::endl;
40+ }
41+ }
42+ }
43+
44+ private:
45+ std::mutex mutex_;
46+ std::unordered_map<void *, std::string> active_pointers_;
47+ };
48+
49+ // Макросы для отладки утечек
50+ #define REGISTER_LEAK_DEBUG (ptr, type ) LeakDetector::instance().registerPointer(ptr, type)
51+ #define UNREGISTER_LEAK_DEBUG (ptr ) LeakDetector::instance().unregisterPointer(ptr)
52+ #define PRINT_ACTIVE_LEAKS () LeakDetector::instance().printActivePointers()
53+
54+ // Пример использования для диагностики YamuxedConnection
55+ class YamuxedConnectionDebug : public std ::enable_shared_from_this<YamuxedConnectionDebug> {
56+ public:
57+ YamuxedConnectionDebug () {
58+ REGISTER_LEAK_DEBUG (this , " YamuxedConnection" );
59+ }
60+
61+ ~YamuxedConnectionDebug () {
62+ UNREGISTER_LEAK_DEBUG (this );
63+ }
64+
65+ void debugSharedPtrReferences () {
66+ auto self = shared_from_this ();
67+ std::cout << " [DEBUG] shared_ptr use_count: " << self.use_count () << std::endl;
68+
69+ // Симулируем различные места, где могут держаться ссылки:
70+
71+ // 1. В streams_ (как было ранее)
72+ streams_[" test" ] = std::make_shared<int >(42 );
73+ std::cout << " [DEBUG] After adding to streams_, use_count: " << self.use_count () << std::endl;
74+
75+ // 2. В callback'ах
76+ auto callback = [self](){ /* do something */ };
77+ std::cout << " [DEBUG] After capturing in callback, use_count: " << self.use_count () << std::endl;
78+
79+ // 3. В timer'ах
80+ auto timer_callback = [weak_self = std::weak_ptr<YamuxedConnectionDebug>(self)](){
81+ if (auto strong = weak_self.lock ()) {
82+ /* do something */
83+ }
84+ };
85+ std::cout << " [DEBUG] After weak capture in timer, use_count: " << self.use_count () << std::endl;
86+
87+ // Очистка
88+ streams_.clear ();
89+ std::cout << " [DEBUG] After clearing streams_, use_count: " << self.use_count () << std::endl;
90+ }
91+
92+ private:
93+ std::unordered_map<std::string, std::shared_ptr<int >> streams_;
94+ };
95+
96+ // Mock classes for simple testing
97+ namespace libp2p {
98+ namespace peer {
99+ struct PeerId {
100+ std::string id;
101+ std::string toBase58 () const { return id; }
102+ };
103+ }
104+
105+ namespace connection {
106+ struct CapableConnection {
107+ virtual ~CapableConnection () = default ;
108+ virtual bool isClosed () const = 0;
109+ };
110+ }
111+
112+ namespace muxer ::yamux {
113+ // Simple test for shared_ptr behavior in unordered_set
114+ class YamuxedConnection {
115+ public:
116+ void debugPrintMemoryLeakSources () {
117+ std::cout << " === MEMORY LEAK DEBUG INFO ===" << std::endl;
118+ std::cout << " This is a test method" << std::endl;
119+ }
120+ };
121+ }
122+ }
123+
124+ // Test shared_ptr behavior in unordered_set
125+ void testSharedPtrInSet () {
126+ std::cout << " \n === Testing shared_ptr behavior in unordered_set ===" << std::endl;
127+
128+ auto obj = std::make_shared<int >(42 );
129+ auto obj2 = obj; // same object, different shared_ptr instance
130+
131+ std::unordered_set<std::shared_ptr<int >> set;
132+
133+ // Add first shared_ptr
134+ set.insert (obj);
135+ std::cout << " Added obj to set, size: " << set.size () << std::endl;
136+
137+ // Try to find with different shared_ptr to same object
138+ auto found = set.find (obj2);
139+ if (found != set.end ()) {
140+ std::cout << " SUCCESS: obj2 found in set (pointing to same object)" << std::endl;
141+ } else {
142+ std::cout << " FAIL: obj2 NOT found in set" << std::endl;
143+ }
144+
145+ // Try to erase with different shared_ptr to same object
146+ auto erased = set.erase (obj2);
147+ std::cout << " Erased count using obj2: " << erased << std::endl;
148+ std::cout << " Set size after erase: " << set.size () << std::endl;
149+
150+ // Test with shared_from_this equivalent
151+ struct TestClass : std::enable_shared_from_this<TestClass> {
152+ int value = 123 ;
153+ };
154+
155+ auto test_obj = std::make_shared<TestClass>();
156+ auto self_ptr = test_obj->shared_from_this ();
157+
158+ std::unordered_set<std::shared_ptr<TestClass>> test_set;
159+ test_set.insert (test_obj);
160+
161+ auto found2 = test_set.find (self_ptr);
162+ if (found2 != test_set.end ()) {
163+ std::cout << " SUCCESS: shared_from_this() found in set" << std::endl;
164+ } else {
165+ std::cout << " FAIL: shared_from_this() NOT found in set" << std::endl;
166+ }
167+
168+ auto erased2 = test_set.erase (self_ptr);
169+ std::cout << " Erased count using shared_from_this(): " << erased2 << std::endl;
170+ std::cout << " Test set size after erase: " << test_set.size () << std::endl;
171+ }
172+
173+ int main () {
174+ std::cout << " === Yamux Memory Leak Debug Tool ===" << std::endl;
175+
176+ // Test shared_ptr behavior
177+ testSharedPtrInSet ();
178+
179+ // Test our debug method
180+ auto yamux_conn = std::make_shared<libp2p::muxer::yamux::YamuxedConnection>();
181+ yamux_conn->debugPrintMemoryLeakSources ();
182+
183+ std::cout << " \n === Debug tool completed ===" << std::endl;
184+ return 0 ;
185+ }
0 commit comments