mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-30 10:15:38 +00:00
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.
This commit is contained in:
parent
ff90c9ce4f
commit
a0cfcc50a2
3 changed files with 21 additions and 18 deletions
|
@ -176,26 +176,28 @@ namespace MWGui
|
|||
{
|
||||
if (it->begin()!=it->end())
|
||||
{
|
||||
const ESM::SavedGame& signature = it->getSignature();
|
||||
|
||||
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).
|
||||
// Fall back to name stored in savegame header in that case.
|
||||
std::string_view className;
|
||||
if (it->getSignature().mPlayerClassId.empty())
|
||||
className = it->getSignature().mPlayerClassName;
|
||||
if (signature.mPlayerClassId.empty())
|
||||
className = signature.mPlayerClassName;
|
||||
else
|
||||
{
|
||||
// Find the localised name for this class from the store
|
||||
const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>().search(
|
||||
it->getSignature().mPlayerClassId);
|
||||
const ESM::Class* class_ = MWBase::Environment::get().getWorld()->getStore().get<ESM::Class>()
|
||||
.search(signature.mPlayerClassId);
|
||||
if (class_)
|
||||
className = class_->mName;
|
||||
else
|
||||
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()));
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <filesystem>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
|
||||
#include <components/esm/defs.hpp>
|
||||
#include <components/esm3/esmreader.hpp>
|
||||
|
@ -172,23 +174,22 @@ MWState::Character::SlotIterator MWState::Character::end() const
|
|||
return mSlots.rend();
|
||||
}
|
||||
|
||||
ESM::SavedGame MWState::Character::getSignature() const
|
||||
const ESM::SavedGame& MWState::Character::getSignature() const
|
||||
{
|
||||
if (mSlots.empty())
|
||||
throw std::logic_error ("character signature not available");
|
||||
|
||||
std::vector<Slot>::const_iterator iter (mSlots.begin());
|
||||
const auto tiePlayerLevelAndTimeStamp = [] (const Slot& v)
|
||||
{
|
||||
return std::tie(v.mProfile.mPlayerLevel, v.mTimeStamp);
|
||||
};
|
||||
|
||||
Slot slot = *iter;
|
||||
const auto lessByPlayerLevelAndTimeStamp = [&] (const Slot& l, const Slot& r)
|
||||
{
|
||||
return tiePlayerLevelAndTimeStamp(l) < tiePlayerLevelAndTimeStamp(r);
|
||||
};
|
||||
|
||||
for (++iter; iter!=mSlots.end(); ++iter)
|
||||
if (iter->mProfile.mPlayerLevel>slot.mProfile.mPlayerLevel)
|
||||
slot = *iter;
|
||||
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
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace MWState
|
|||
|
||||
const std::filesystem::path& getPath() const;
|
||||
|
||||
ESM::SavedGame getSignature() const;
|
||||
const ESM::SavedGame& getSignature() const;
|
||||
///< Return signature information for this character.
|
||||
///
|
||||
/// \attention This function must not be called if there are no slots.
|
||||
|
|
Loading…
Reference in a new issue