Hallo,
nachdem ich nun schon mehrere Wochen am verzweifeln bin und nach etlichen Debugging Sessions mit einigen Entwicklern und eigenen Stunden über Stunden keine Lösung gefunden habe, wird es Zeit die Community mit ins Boot zu holen. Vielleicht weiß ja einer von euch mehr.
Die Grundproblematik:
In einem bestimmten Dungeon crasht die Core kurz nach dem Aufruf von "d.kill_all()". Ergo die Abfolge ist:
1) Monster spawnen durch d.regen_file()
2) Dungeonbedingung (Töte X Monster) erfüllt -> d.kill_all()
3) Man kann für einige Sekunden weiter machen, doch irgendwann danach (Nachdem man einen weiteren Monster killt) erhält man folgenden Sanitizer Output in der Konsole:
Sanitizer Output:
- #0 0xe584da in std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<CEntity*, int>, void*>*> std::__1::__hash_table<std::__1::__hash_value_type<CEntity*, int>, std::__1::__unord ered_map_hasher<CEntity*, std::__1::__hash_value_type<CEntity*, int>, std::__1::hash<CEntity*>, true>, std::__1::__unordered_map_equal<CEntity*, std::__1::__hash_value_type<CEntity*, int>, std::__1::equal _to<CEntity*>, true>, std::__1::allocator<std::__1::__hash_value_type<CEntity*, int> > >::find<CEntity*>(CEntity* const&) /usr/include/c++/v1/__hash_table:2466:31
- #1 0xe574be in std::__1::unordered_map<CEntity*, int, std::__1::hash<CEntity*>, std::__1::equal_to<CEntity*>, std::__1::allocator<std::__1::pair<CEntity* const, int> > >::find(CEntity* const&) /usr/in clude/c++/v1/unordered_map:1278:69
- #2 0xe54b57 in CEntity::ViewRemove(CEntity*, bool) /usr/home/src/Server/game/src/entity_view.cpp:71:39
- #3 0xe548ea in CEntity::ViewCleanup() /usr/home/src/Server/game/src/entity_view.cpp:17:11
- #4 0xe4ce1f in CEntity::Destroy() /usr/home/src/Server/game/src/entity.cpp:39:2
- #5 0xa80de9 in CHARACTER::Destroy() /usr/home/src/Server/game/src/char.cpp:737:11
- #6 0xa7f005 in CHARACTER::~CHARACTER() /usr/home/src/Server/game/src/char.cpp:250:2
- #7 0xa81096 in CHARACTER::~CHARACTER() /usr/home/src/Server/game/src/char.cpp:249:1
- #8 0xc34c6b in CHARACTER_MANAGER::DestroyCharacter(CHARACTER*) /usr/home/src/Server/game/src/char_manager.cpp:202:2
- #9 0xb778b3 in dead_event(boost::intrusive_ptr<event>, int) /usr/home/src/Server/game/src/char_battle.cpp:520:3
- #10 0xe5f397 in event_process(int) /usr/home/src/Server/game/src/event.cpp:143:15
- #11 0x152aa27 in heartbeat(heart*, int) /usr/home/src/Server/game/src/main.cpp:223:23
- #12 0x15300f3 in idle() /usr/home/src/Server/game/src/main.cpp:717:3
- #13 0x152d05e in main /usr/home/src/Server/game/src/main.cpp:416:9
- #14 0x9380ff in _start /usr/src/lib/csu/amd64/crt1.c:76:7
- 0x603000000003 is located 13 bytes to the left of 20-byte region [0x603000000010,0x603000000024)
- allocated by thread T0 here:
- #0 0x9905f2 in calloc /usr/ports/devel/llvm11/work/compiler-rt-11.0.0.src/lib/asan/asan_malloc_linux.cpp:154:3
- #1 0x801f3e323 (/lib/libthr.so.3+0x1b323)
- #2 0x801f3e1c6 in pthread_cond_broadcast (/lib/libthr.so.3+0x1b1c6)
- #3 0x801ed17cb in std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*)) (/usr/lib/libc++.so.1+0x9d7cb)
- #4 0x801eb7383 (/usr/lib/libc++.so.1+0x83383)
- #5 0x801ebd8da in std::__1::locale::__global() (/usr/lib/libc++.so.1+0x898da)
- #6 0x801ebd93d in std::__1::locale::locale() (/usr/lib/libc++.so.1+0x8993d)
- #7 0x801edc2ef in std::__1::basic_streambuf<char, std::__1::char_traits<char> >::basic_streambuf() (/usr/lib/libc++.so.1+0xa82ef)
- #8 0x801e92147 in std::__1::DoIOSInit::DoIOSInit() (/usr/lib/libc++.so.1+0x5e147)
- #9 0x801e9358b (/usr/lib/libc++.so.1+0x5f58b)
- #10 0x801a2b2fc (/libexec/ld-elf.so.1+0xd2fc)
- #11 0x801a2a03c (/libexec/ld-elf.so.1+0xc03c)
- #12 0x801a278c8 (/libexec/ld-elf.so.1+0x98c8)
- SUMMARY: AddressSanitizer: heap-buffer-overflow /usr/include/c++/v1/__hash_table:2466:31 in std::__1::__hash_iterator<std::__1::__hash_node<std::__1::__hash_value_type<CEntity*, int>, void*>*> std::__1::_ _hash_table<std::__1::__hash_value_type<CEntity*, int>, std::__1::__unordered_map_hasher<CEntity*, std::__1::__hash_value_type<CEntity*, int>, std::__1::hash<CEntity*>, true>, std::__1::__unordered_map_eq ual<CEntity*, std::__1::__hash_value_type<CEntity*, int>, std::__1::equal_to<CEntity*>, true>, std::__1::allocator<std::__1::__hash_value_type<CEntity*, int> > >::find<CEntity*>(CEntity* const&)
- Shadow bytes around the buggy address:
- 0x4c05ffffffb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 0x4c05ffffffc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 0x4c05ffffffd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 0x4c05ffffffe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- 0x4c05fffffff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- =>0x4c0600000000:[fa]fa 00 00 04 fa fa fa fd fd fd fa fa fa 00 00
- 0x4c0600000010: 00 fa fa fa 00 00 00 fa fa fa 00 00 00 00 fa fa
- 0x4c0600000020: 00 00 00 00 fa fa 00 00 00 00 fa fa fd fd fd fa
- 0x4c0600000030: fa fa fd fd fd fa fa fa 00 00 00 fa fa fa 00 00
- 0x4c0600000040: 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00 fa fa
- 0x4c0600000050: 00 00 00 00 fa fa 00 00 00 00 fa fa 00 00 00 00
- Shadow byte legend (one shadow byte represents 8 application bytes):
- Addressable: 00
- Partially addressable: 01 02 03 04 05 06 07
- Heap left redzone: fa
- Freed heap region: fd
- Stack left redzone: f1
- Stack mid redzone: f2
- Stack right redzone: f3
- Stack after return: f5
- Stack use after scope: f8
- Global redzone: f9
- Global init order: f6
- Poisoned by user: f7
- Container overflow: fc
- Array cookie: ac
- Intra object redzone: bb
- ASan internal: fe
- Left alloca redzone: ca
- Right alloca redzone: cb
- Shadow gap: cc
- ==16408==ABORTING
Reproduzierbar?
Ja.
Was wurde versucht?
1) Es wurden die Monster ausgetauscht, um die Fehlerquelle ausfindig zu machen. Kein Erfolg.
2) Es wurden insgesamt weniger Monster gespawned -> Bei extrem wenig Monstern (5-7 pro Ebene) crasht die Core nicht. Man darf nur kein /kill (Töte alle Monster) benutzen, sondern muss sie Per Linksklick und Schlagen töten.
3) Es wurde einiges technisches versucht, wie die entity_view.cpp zu refactoren und mehr Abfragen einzufügen auf Entity.
4) Einen Garbage Collector um Entity zu bauen und anhand der syserr Meldungen eine womöglich 'falsche doppelte Entität' ausfindig zu machen, die beim Entfernen aus der View Probleme macht.
5) Compilerwechsel (mit Verdacht auf Fehler durch Optimierung).
6) Die Ebenen des Dungeons wurden geswitched um eine bestimmte Ebene festzumachen -> Auch erfolglos.
7) Größere Entwickler gefragt (Namen lass ich mal raus, aufjedenfall alle mit +5 Jahren Metinerfahrung) und Ergebnis war nur: "d.kill_all() macht ab und zu Probleme, warum wieso weshalb weiß keiner".
8. d.purge() statt d.kill_all() verwendet, macht die selben Probleme. 7) scheint damit also unwahrscheinlicher.
Liebe Grüße
Louca