1
OXCE Bugs FIXED / [FIXED] Crash in OpenXcom::SavedGame::selectGetOneFree()
« on: April 18, 2022, 06:00:41 pm »
Debian GNU/Linux 11 (bullseye)
OXCE 7.5.13 (140cb067)
XPiratez M5.2.1
Crash when finishing research on Humanist Activist, see attached savegame.
Debugging attempt below, using gdb on debug build:
Checking the stack
Through a bit of sleuthing I figure out the problem is in GeoscapeState::time1Day()
Some relevant variables:
Looks corrupted.
Somehow project is NULL. Let's inspect how finished is constructed, starting with base->getResearch()
It is of size three.
No NULL here.
Aha! An extra project seems to have been added somehow. Let's look closer.
Here I manage to hang gdb by attempting to print finished._M_impl._M_start[0]._project._name.
Let's start over and just print finished._M_impl._M_start[0]._project instead. I also added some debug prints.
Still crashes in OpenXcom::GeoscapeState::time1Day.
It seems four projects were added to finished after all. And yet base._research.size() == 3.
The last three are fprintf(stderr, "processing %p %p\n", project, research);
In calling OpenXcom::SavedGame::selectGetOneFree() project (but not research) gets set to NULL:
Through a process of elimination I've figured out this is "Humanist Activist" (STR_NAZI_KKK). What I don't understand is how that broken pointer gets in there.
For fun I try commenting out the call to getAvailableResearchProjects(), but that didn't help. I also confirmed finished[2] is intact and only the copy of it in project is borked.
OXCE 7.5.13 (140cb067)
XPiratez M5.2.1
Crash when finishing research on Humanist Activist, see attached savegame.
Debugging attempt below, using gdb on debug build:
Quote
Program received signal SIGSEGV, Segmentation fault.
0x0000555556094258 in __gnu_cxx::__normal_iterator<OpenXcom::RuleResearch const* const*, std::vector<OpenXcom::RuleResearch const*, std::allocator<OpenXcom::RuleResearch const*> > >::__normal_iterator (this=0x7fffffffcd08, __i=@0x5555000002d0: <error reading variable>)
at /usr/include/c++/10/bits/stl_iterator.h:979
979 : _M_current(__i) { }
Checking the stack
Quote
(gdb) bt
#0 0x0000555556094258 in __gnu_cxx::__normal_iterator<OpenXcom::RuleResearch const* const*, std::vector<OpenXcom::RuleResearch const*, std::allocator<OpenXcom::RuleResearch const*> > >::__normal_iterator (this=0x7fffffffcd08, __i=@0x5555000002d0: <error reading variable>)
at /usr/include/c++/10/bits/stl_iterator.h:979
#1 0x0000555556094169 in std::vector<OpenXcom::RuleResearch const*, std::allocator<OpenXcom::RuleResearch const*> >::end (this=0x5555000002c8) at /usr/include/c++/10/bits/stl_vector.h:839
#2 0x0000555556093f7a in std::vector<OpenXcom::RuleResearch const*, std::allocator<OpenXcom::RuleResearch const*> >::empty (this=0x5555000002c8) at /usr/include/c++/10/bits/stl_vector.h:1008
#3 0x00005555569dfe5f in OpenXcom::SavedGame::selectGetOneFree (this=0x55555ba856d0, research=0x555500000100) at ../src/Savegame/SavedGame.cpp:1525
#4 0x000055555643e8c6 in OpenXcom::GeoscapeState::time1Day (this=0x55555d22a8d0) at ../src/Geoscape/GeoscapeState.cpp:2383
#5 0x0000555556434cce in OpenXcom::GeoscapeState::timeAdvance (this=0x55555d22a8d0) at ../src/Geoscape/GeoscapeState.cpp:876
#6 0x00005555563e1fc2 in OpenXcom::Timer::think (this=0x7fffc6057dc0, state=0x55555d22a8d0, surface=0x0) at ../src/Engine/Timer.cpp:123
#7 0x000055555643430b in OpenXcom::GeoscapeState::think (this=0x55555d22a8d0) at ../src/Geoscape/GeoscapeState.cpp:753
#8 0x00005555562d33a9 in OpenXcom::Game::run (this=0x55555af41b30) at ../src/Engine/Game.cpp:334
#9 0x0000555556019f6b in main (argc=1, argv=0x7fffffffda98) at ../src/main.cpp:125
Through a bit of sleuthing I figure out the problem is in GeoscapeState::time1Day()
Quote
#4 0x000055555643e8c6 in OpenXcom::GeoscapeState::time1Day (this=0x55555d22a8d0) at ../src/Geoscape/GeoscapeState.cpp:2383
2383 if ((bonus = saveGame->selectGetOneFree(research)))
(gdb) list
2378 base->getStorageItems()->addItem(ruleCorpse->getType());
2379 }
2380 }
2381 }
2382 // 3c. handle getonefrees (topic+lookup)
2383 if ((bonus = saveGame->selectGetOneFree(research)))
2384 {
2385 saveGame->addFinishedResearch(bonus, mod, base);
2386 if (!bonus->getLookup().empty())
2387 {
Some relevant variables:
Quote
(gdb) print research
$1 = (const OpenXcom::RuleResearch *) 0x555500000100
Looks corrupted.
Quote
(gdb) print base
$2 = (OpenXcom::Base *) 0x55555ba4e5b0
(gdb) print project
$3 = (OpenXcom::ResearchProject *) 0x0
Somehow project is NULL. Let's inspect how finished is constructed, starting with base->getResearch()
Quote
(gdb) print base._research._M_impl._M_start
$6 = (std::_Vector_base<OpenXcom::ResearchProject*, std::allocator<OpenXcom::ResearchProject*> >::pointer) 0x55555bb25470
(gdb) print base._research.size()
$7 = 3
It is of size three.
Quote
(gdb) print base._research._M_impl._M_start[0]
$8 = (OpenXcom::ResearchProject *) 0x55555bbae600
(gdb) print base._research._M_impl._M_start[1]
$9 = (OpenXcom::ResearchProject *) 0x55555bbae410
(gdb) print base._research._M_impl._M_start[2]
$10 = (OpenXcom::ResearchProject *) 0x55555bbaea00
No NULL here.
Quote
(gdb) print finished
$11 = {<std::_Vector_base<OpenXcom::ResearchProject*, std::allocator<OpenXcom::ResearchProject*> >> = {
_M_impl = {<std::allocator<OpenXcom::ResearchProject*>> = {<__gnu_cxx::new_allocator<OpenXcom::ResearchProject*>> = {<No data fields>}, <No data fields>}, <std::_Vector_base<OpenXcom::ResearchProject*, std::allocator<OpenXcom::ResearchProject*> >::_Vector_impl_data> = {
_M_start = 0x7fffb951cdf0, _M_finish = 0x7fffb951ce10, _M_end_of_storage = 0x7fffb951ce10}, <No data fields>}}, <No data fields>}
(gdb) print finished.size()
$12 = 4
Aha! An extra project seems to have been added somehow. Let's look closer.
Quote
(gdb) print finished._M_impl._M_start
$13 = (std::_Vector_base<OpenXcom::ResearchProject*, std::allocator<OpenXcom::ResearchProject*> >::pointer) 0x7fffb951cdf0
(gdb) print finished._M_impl._M_start[0]
$14 = (OpenXcom::ResearchProject *) 0x55555bbaf3e0
(gdb) print finished._M_impl._M_start[1]
$15 = (OpenXcom::ResearchProject *) 0x55555bbae000
(gdb) print finished._M_impl._M_start[2]
$16 = (OpenXcom::ResearchProject *) 0x55555bbaedc0
(gdb) print finished._M_impl._M_start[3]
$17 = (OpenXcom::ResearchProject *) 0x55555bbaea00
Here I manage to hang gdb by attempting to print finished._M_impl._M_start[0]._project._name.
Let's start over and just print finished._M_impl._M_start[0]._project instead. I also added some debug prints.
Still crashes in OpenXcom::GeoscapeState::time1Day.
Quote
added 0x55555bb39440
added 0x55555bb380b0
added 0x55555bb38a40
added 0x55555bb38850
saveGame->getAvailableResearchProjects
processing 0x55555bb39440 0x7fffb34e2640
processing 0x55555bb380b0 0x7fffb346ce90
processing 0x55555bb38a40 0x555500000100
*crash*
It seems four projects were added to finished after all. And yet base._research.size() == 3.
The last three are fprintf(stderr, "processing %p %p\n", project, research);
In calling OpenXcom::SavedGame::selectGetOneFree() project (but not research) gets set to NULL:
Quote
(gdb) print project
$1 = (OpenXcom::ResearchProject *) 0x0
(gdb) print research
$2 = (const OpenXcom::RuleResearch *) 0x555500000100
Through a process of elimination I've figured out this is "Humanist Activist" (STR_NAZI_KKK). What I don't understand is how that broken pointer gets in there.
For fun I try commenting out the call to getAvailableResearchProjects(), but that didn't help. I also confirmed finished[2] is intact and only the copy of it in project is borked.