Author Topic: [FIXED] Crash in OpenXcom::SavedGame::selectGetOneFree()  (Read 1229 times)

Offline ayylmao

  • Squaddie
  • *
  • Posts: 2
    • View Profile
[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:

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.
« Last Edit: February 02, 2023, 03:25:47 pm by Meridian »

Offline Meridian

  • Global Moderator
  • Commander
  • *****
  • Posts: 8597
    • View Profile
Re: [Bug] Crash in OpenXcom::SavedGame::selectGetOneFree()
« Reply #1 on: April 18, 2022, 08:09:17 pm »
Hi, thanks for the report.

Fixed: https://github.com/MeridianOXC/OpenXcom/commit/6c39933bff6e30abf7bfa1bf93842103b2ce9154

please pull, retest and confirm if it works

Offline ayylmao

  • Squaddie
  • *
  • Posts: 2
    • View Profile
Re: [Bug] Crash in OpenXcom::SavedGame::selectGetOneFree()
« Reply #2 on: April 18, 2022, 09:05:54 pm »
Yep, that fixed it. Thanks :)