Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make compared have a copy of the inventory_entry rather than a pointer to fix segfault when using multiple filters. #36139

Closed
wants to merge 4 commits into from

Conversation

ishtatann
Copy link
Contributor

@ishtatann ishtatann commented Dec 15, 2019

SUMMARY: Bugfixes "Make compared have a copy of the inventory_entry rather than a pointer to fix segfault when using multiple filters"

Purpose of change

Fixes #34046

Describe the solution

Converted the compared vector to be a copy of the inventory_entry instead of a pointer.

Describe alternatives you've considered

I considered turning compared into an item* but that turned into something very invasive.

Testing

Verified that comparison works with and without filters after the change.

@KorGgenT KorGgenT added <Bugfix> This is a fix for a bug (or closes open issue) [C++] Changes (can be) made in C++. Previously named `Code` labels Dec 15, 2019
@AMurkin
Copy link
Contributor

AMurkin commented Dec 17, 2019

I'm getting a segfault.
Stack trace: https://gist.github.com/AMurkin/157efbdc9cb8656f3fac650f31119d7b
It's on Linux Tiles.

Steps:

  • with several items in inventory press
  • I<arrow right>/<some filtering text>Enter<choose any item>

Cannot reproduce on Windows with MS VS.

@ishtatann
Copy link
Contributor Author

I haven't been able to replicate this problem on MS VS19.

The stack trace points to the item disappearing on linux for some reason.
But my read through inventory_entry down to the item says that shouldn't be happening.

I did try a completely different approach of making the entries_unfiltered the master list and entries pointers to the inventory_entry's in that list. Ended up changing a ton of things and completely broke inventory as well as compare.

I know KorGgenT is doing heavy work in this area at the moment so am going to pause doing any more work on this PR to see how those changes shake out.

@KorGgenT
Copy link
Member

@ishtatann you got it backwards, the stuff i'm working on is low priority compared to this being a release blocker.

@ishtatann
Copy link
Contributor Author

Save a copy of the first selection before set_filter is called. Restore the first selection after set_filter finishes.

I'm hoping this will fix the crash people were seeing on the linux side.
Works fine in my testing of x64 Windows VS19.

@ishtatann ishtatann reopened this Dec 24, 2019
…r to fix segfault when using multiple filters.
Restore the selection after set_filter has changed all the entries.
@ymber
Copy link
Member

ymber commented Dec 24, 2019

I can still reproduce the crash with these changes.

The program has crashed.
See the log file for a stack trace.
CRASH LOG FILE: ./config/crash.log
VERSION: 0.D-10657-g710bf90bcb
TYPE: Signal
MESSAGE: SIGSEGV: Segmentation faultError creating SDL message box: No message system available

STACK TRACE:

    ./cataclysm-tiles(_Z21debug_write_backtraceRSo+0x39) [0x557711f7a7d9]
    ./cataclysm-tiles(+0x180df6a) [0x557711f58f6a]
    ./cataclysm-tiles(+0x180dd08) [0x557711f58d08]
    /usr/lib/libc.so.6(+0x3bfb0) [0x7f21ef906fb0]
    ./cataclysm-tiles(_ZNKSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE16_M_get_use_countEv+0) [0x557711c3d740]
    ./cataclysm-tiles(_ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE23_M_add_ref_lock_nothrowEv+0x9) [0x557711c3d719]
    ./cataclysm-tiles(_ZNSt14__shared_countILN9__gnu_cxx12_Lock_policyE2EEC2ERKSt12__weak_countILS1_2EESt9nothrow_t+0x14) [0x557711c3d6e4]
    ./cataclysm-tiles(_ZNSt12__shared_ptrI4itemLN9__gnu_cxx12_Lock_policyE2EEC2ERKSt10__weak_ptrIS0_LS2_2EESt9nothrow_t+0x1b) [0x557711c3d6ab]
    ./cataclysm-tiles(_ZNKSt8weak_ptrI4itemE4lockEv+0x9) [0x557711c3d649]
    ./cataclysm-tiles(_ZNK14safe_referenceI4itemE3getEv+0x23) [0x557711c3d603]
    ./cataclysm-tiles(_ZNK13item_locationeqERKS_+0x27) [0x5577122e3c77]
    ./cataclysm-tiles(_ZNSt7__equalILb0EE5equalIPK13item_locationS4_EEbT_S5_T0_+0x2b) [0x5577122077cb]
    ./cataclysm-tiles(_ZN9__gnu_cxx5__ops16_Iter_equals_valIK15inventory_entryEclINS_17__normal_iteratorIPS2_St6vectorIS2_SaIS2_EEEEEEbT_+0x2d) [0x55771220a3dd]
    ./cataclysm-tiles(_ZSt9__find_ifIN9__gnu_cxx17__normal_iteratorIP15inventory_entrySt6vectorIS2_SaIS2_EEEENS0_5__ops16_Iter_equals_valIKS2_EEET_SC_SC_T0_St26random_access_iterator_tag+0x145) [0x55771220a325]
    ./cataclysm-tiles(_ZSt9__find_ifIN9__gnu_cxx17__normal_iteratorIP15inventory_entrySt6vectorIS2_SaIS2_EEEENS0_5__ops16_Iter_equals_valIKS2_EEET_SC_SC_T0_+0x3a) [0x55771220a1ba]
    ./cataclysm-tiles(_ZN16selection_column9on_changeERK15inventory_entry+0x63) [0x5577121f5a93]
    ./cataclysm-tiles(_ZN18inventory_selector9on_changeERK15inventory_entry+0x74) [0x5577121faa94]
    ./cataclysm-tiles(_ZN26inventory_compare_selector12toggle_entryEP15inventory_entry+0xa7) [0x5577121fb8c7]
    ./cataclysm-tiles(_ZN26inventory_compare_selector7executeEv+0x2d1) [0x5577121fb731]
    ./cataclysm-tiles(_ZN10game_menus3inv7compareER6playerRKN4cata8optionalI8tripointEE+0x46d) [0x55771213ef2d]

    Attempting to repeat stack trace using debug symbols…
    debug_write_backtrace(std::ostream&)
    …/src/debug.cpp:620
    log_crash(char const*, char const*)
    crash.cpp:?
    signal_handler(int)
    …/src/crash.cpp:284
    ??
    ??:0
    std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_get_use_count() const
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/shared_ptr_base.h:203
    std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_add_ref_lock_nothrow()
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/shared_ptr_base.h:287
    __shared_count
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/shared_ptr_base.h:911
    __shared_ptr
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/shared_ptr_base.h:1357
    std::weak_ptr<item>::lock() const
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/shared_ptr.h:595
    safe_reference<item>::get() const
    …/src/safe_reference.h:30
    item_location::operator==(item_location const&) const
    …/src/item_location.cpp:497
    bool std::__equal<false>::equal<item_location const*, item_location const*>(item_location const*, item_location const*, item_location const*)
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/stl_algobase.h:820
    bool __gnu_cxx::__ops::_Iter_equals_val<inventory_entry const>::operator()<__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > > >(__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >)
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/predefined_ops.h:241
    __gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > > std::__find_if<__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__ops::_Iter_equals_val<inventory_entry const> >(__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__ops::_Iter_equals_val<inventory_entry const>, std::random_access_iterator_tag)
    /usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/9.2.0/../../../../include/c++/9.2.0/bits/stl_algo.h:148
    __gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > > std::__find_if<__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__ops::_Iter_equals_val<inventory_entry const> >(__gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__normal_iterator<inventory_entry*, std::vector<inventory_entry, std::allocator<inventory_entry> > >, __gnu_cxx::__ops::_Iter_equals_val<inventory_entry const>)
    ??:?
    selection_column::on_change(inventory_entry const&)
    …/src/inventory_ui.cpp:994
    inventory_selector::on_change(inventory_entry const&)
    …/src/inventory_ui.cpp:1692
    inventory_compare_selector::toggle_entry(inventory_entry*)
    …/src/inventory_ui.cpp:1928
    inventory_compare_selector::execute()
    ??:?
    game_menus::inv::compare(player&, cata::optional<tripoint> const&)
    …/src/game_inventory.cpp:1383

Built with make -j6 CLANG=1 CCACHE=1 RUNTESTS=0 TILES=1 SOUND=0 LOCALIZE=0. I'm on Arch Linux.

jbytheway added a commit to jbytheway/Cataclysm-DDA that referenced this pull request Jan 1, 2020
Fixes CleverRaven#34046.

Using the search filter causes all the inventory_entry objects to be
recreated, so it's not safe to store a pointer to them.

A previous attempt to solve this (CleverRaven#36139) stored copies of the
inventory_entry objects, but that was also unsafe.

This attempt instead stores just pointers to the underlying items.  This
seems to prevent the crashes.

The behaviour of the window is still not always exactly correct, because
using the filter will violate the invariant that the items in the
compared vector correspond to the selected entries.  I don't see a way
to fix that in general -- sometimes the compared item is filtered out,
and thus you can't possibly select the entry (because it doesn't exist).
We might want to add something that does its best to select the right
entries when the filter changes, but this is a sufficiently niche use
case that I'm not sure it's worth the complexity.  I've settled for just
fixing the crash for now.
@jbytheway
Copy link
Contributor

I've posted an alternate attempted fix at #36606. Testing by others welcome.

jbytheway added a commit to jbytheway/Cataclysm-DDA that referenced this pull request Jan 1, 2020
Fixes CleverRaven#34046.

Using the search filter causes all the inventory_entry objects to be
recreated, so it's not safe to store a pointer to them.

A previous attempt to solve this (CleverRaven#36139) stored copies of the
inventory_entry objects, but that was also unsafe.

This attempt instead stores just pointers to the underlying items.  This
seems to prevent the crashes.

The behaviour of the window is still not always exactly correct, because
using the filter will violate the invariant that the items in the
compared vector correspond to the selected entries.  I don't see a way
to fix that in general -- sometimes the compared item is filtered out,
and thus you can't possibly select the entry (because it doesn't exist).
We might want to add something that does its best to select the right
entries when the filter changes, but this is a sufficiently niche use
case that I'm not sure it's worth the complexity.  I've settled for just
fixing the crash for now.
kevingranade pushed a commit that referenced this pull request Jan 2, 2020
Fixes #34046.

Using the search filter causes all the inventory_entry objects to be
recreated, so it's not safe to store a pointer to them.

A previous attempt to solve this (#36139) stored copies of the
inventory_entry objects, but that was also unsafe.

This attempt instead stores just pointers to the underlying items.  This
seems to prevent the crashes.

The behaviour of the window is still not always exactly correct, because
using the filter will violate the invariant that the items in the
compared vector correspond to the selected entries.  I don't see a way
to fix that in general -- sometimes the compared item is filtered out,
and thus you can't possibly select the entry (because it doesn't exist).
We might want to add something that does its best to select the right
entries when the filter changes, but this is a sufficiently niche use
case that I'm not sure it's worth the complexity.  I've settled for just
fixing the crash for now.
@ZhilkinSerg
Copy link
Contributor

Obsoleted by #36606

@ZhilkinSerg ZhilkinSerg closed this Jan 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
<Bugfix> This is a fix for a bug (or closes open issue) [C++] Changes (can be) made in C++. Previously named `Code`
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash when comparing daypack and military rucksack
6 participants