Fix dangling pointer access on clicking save in the main menu

getSignature() returns an object which means expression like:
className = it->getSignature().mPlayerClassName;
assigns a temporary object to className that does not outlive the statement.
Having className a string view such code leads to a dangling pointer.

Return a reference from getSignature to save on redundant copying.

Change getSignature implementation to make it visible that it finds a maximum
element.

Do not call getSignature multiple times when possible to avoid seaching for the
same max element multiple times.
make_linux_ci_do_zoomies
elsid 2 years ago
parent ff90c9ce4f
commit a0cfcc50a2
No known key found for this signature in database
GPG Key ID: 4DE04C198CBA7625

@ -176,26 +176,28 @@ namespace MWGui
{ {
if (it->begin()!=it->end()) if (it->begin()!=it->end())
{ {
const ESM::SavedGame& signature = it->getSignature();
std::stringstream title; std::stringstream title;
title << it->getSignature().mPlayerName; title << signature.mPlayerName;
// For a custom class, we will not find it in the store (unless we loaded the savegame first). // For a custom class, we will not find it in the store (unless we loaded the savegame first).
// Fall back to name stored in savegame header in that case. // Fall back to name stored in savegame header in that case.
std::string_view className; std::string_view className;
if (it->getSignature().mPlayerClassId.empty()) if (signature.mPlayerClassId.empty())
className = it->getSignature().mPlayerClassName; className = signature.mPlayerClassName;
else else
{ {
// Find the localised name for this class from the store // Find the localised name for this class from the store
const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().search( const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>()
it->getSignature().mPlayerClassId); .search(signature.mPlayerClassId);
if (class_) if (class_)
className = class_->mName; className = class_->mName;
else else
className = "?"; // From an older savegame format that did not support custom classes properly. className = "?"; // From an older savegame format that did not support custom classes properly.
} }
title << " (#{sLevel} " << it->getSignature().mPlayerLevel << " " << MyGUI::TextIterator::toTagsString(toUString(className)) << ")"; title << " (#{sLevel} " << signature.mPlayerLevel << " " << MyGUI::TextIterator::toTagsString(toUString(className)) << ")";
mCharacterSelection->addItem (MyGUI::LanguageManager::getInstance().replaceTags(title.str())); mCharacterSelection->addItem (MyGUI::LanguageManager::getInstance().replaceTags(title.str()));

@ -4,6 +4,8 @@
#include <filesystem> #include <filesystem>
#include <sstream> #include <sstream>
#include <utility> #include <utility>
#include <algorithm>
#include <tuple>
#include <components/esm/defs.hpp> #include <components/esm/defs.hpp>
#include <components/esm3/esmreader.hpp> #include <components/esm3/esmreader.hpp>
@ -172,23 +174,22 @@ MWState::Character::SlotIterator MWState::Character::end() const
return mSlots.rend(); return mSlots.rend();
} }
ESM::SavedGame MWState::Character::getSignature() const const ESM::SavedGame& MWState::Character::getSignature() const
{ {
if (mSlots.empty()) if (mSlots.empty())
throw std::logic_error ("character signature not available"); throw std::logic_error ("character signature not available");
std::vector<Slot>::const_iterator iter (mSlots.begin()); const auto tiePlayerLevelAndTimeStamp = [] (const Slot& v)
{
Slot slot = *iter; return std::tie(v.mProfile.mPlayerLevel, v.mTimeStamp);
};
for (++iter; iter!=mSlots.end(); ++iter) const auto lessByPlayerLevelAndTimeStamp = [&] (const Slot& l, const Slot& r)
if (iter->mProfile.mPlayerLevel>slot.mProfile.mPlayerLevel) {
slot = *iter; return tiePlayerLevelAndTimeStamp(l) < tiePlayerLevelAndTimeStamp(r);
else if (iter->mProfile.mPlayerLevel==slot.mProfile.mPlayerLevel && };
iter->mTimeStamp>slot.mTimeStamp)
slot = *iter;
return slot.mProfile; return std::max_element(mSlots.begin(), mSlots.end(), lessByPlayerLevelAndTimeStamp)->mProfile;
} }
const std::filesystem::path& MWState::Character::getPath() const const std::filesystem::path& MWState::Character::getPath() const

@ -62,7 +62,7 @@ namespace MWState
const std::filesystem::path& getPath() const; const std::filesystem::path& getPath() const;
ESM::SavedGame getSignature() const; const ESM::SavedGame& getSignature() const;
///< Return signature information for this character. ///< Return signature information for this character.
/// ///
/// \attention This function must not be called if there are no slots. /// \attention This function must not be called if there are no slots.

Loading…
Cancel
Save