Browse Source

Wrapped IRC User object instances in shared_ptr to avoid iterator invalidation

release/1.0.1
Jessica James 4 years ago
parent
commit
15c69edc7c
  1. 64
      src/common/IRC_Client.cpp
  2. 19
      src/include/Jupiter/IRC_Client.h

64
src/common/IRC_Client.cpp

@ -353,11 +353,11 @@ size_t Jupiter::IRC::Client::getUserCount() const
return m_users.size(); return m_users.size();
} }
Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(const Jupiter::ReadableString &in_nickname) const std::shared_ptr<Jupiter::IRC::Client::User> Jupiter::IRC::Client::getUser(const Jupiter::ReadableString &in_nickname) const
{ {
auto user = m_users.find(in_nickname); auto user = m_users.find(in_nickname);
if (user != m_users.end()) { if (user != m_users.end()) {
return const_cast<User*>(&user->second); return user->second;
} }
return nullptr; return nullptr;
@ -913,7 +913,7 @@ int Jupiter::IRC::Client::process_line(const Jupiter::ReadableString &line)
{ {
m_nickname = newnick; m_nickname = newnick;
} }
Jupiter::IRC::Client::User *user = Client::findUser(nick); auto user = Client::findUser(nick);
if (user != nullptr) if (user != nullptr)
{ {
user->m_nickname = newnick; user->m_nickname = newnick;
@ -969,7 +969,7 @@ int Jupiter::IRC::Client::process_line(const Jupiter::ReadableString &line)
Channel *channel = getChannel(chan); Channel *channel = getChannel(chan);
if (channel != nullptr) if (channel != nullptr)
{ {
Jupiter::IRC::Client::User *user = getUser(nick); auto user = getUser(nick);
if (user != nullptr) if (user != nullptr)
{ {
channel->delUser(nick); channel->delUser(nick);
@ -1008,7 +1008,7 @@ int Jupiter::IRC::Client::process_line(const Jupiter::ReadableString &line)
Channel *channel = getChannel(chan); Channel *channel = getChannel(chan);
if (channel != nullptr) if (channel != nullptr)
{ {
Jupiter::IRC::Client::User *user = getUser(kicked); auto user = getUser(kicked);
if (user != nullptr) if (user != nullptr)
{ {
channel->delUser(kicked); channel->delUser(kicked);
@ -1042,7 +1042,7 @@ int Jupiter::IRC::Client::process_line(const Jupiter::ReadableString &line)
{ {
Jupiter::ReferenceString nick = getSender(line); Jupiter::ReferenceString nick = getSender(line);
Jupiter::ReferenceString message = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1); Jupiter::ReferenceString message = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1);
Jupiter::IRC::Client::User *user = getUser(nick); auto user = getUser(nick);
if (user != nullptr) if (user != nullptr)
{ {
for (auto& channel : m_channels) { for (auto& channel : m_channels) {
@ -1450,24 +1450,24 @@ void Jupiter::IRC::Client::delChannel(const Jupiter::ReadableString &in_channel)
m_channels.erase(in_channel); m_channels.erase(in_channel);
} }
Jupiter::IRC::Client::User *Jupiter::IRC::Client::findUser(const Jupiter::ReadableString &in_nickname) const std::shared_ptr<Jupiter::IRC::Client::User> Jupiter::IRC::Client::findUser(const Jupiter::ReadableString &in_nickname) const
{ {
return getUser(in_nickname); return getUser(in_nickname);
} }
Jupiter::IRC::Client::User *Jupiter::IRC::Client::findUserOrAdd(const Jupiter::ReadableString &name) std::shared_ptr<Jupiter::IRC::Client::User> Jupiter::IRC::Client::findUserOrAdd(const Jupiter::ReadableString &name)
{ {
Jupiter::ReferenceString nick = Jupiter::ReferenceString::getWord(name, 0, "!"); Jupiter::ReferenceString nick = Jupiter::ReferenceString::getWord(name, 0, "!");
Jupiter::IRC::Client::User *result = Jupiter::IRC::Client::findUser(nick); auto result = Jupiter::IRC::Client::findUser(nick);
if (result != nullptr) if (result != nullptr)
return result; return result;
User user; auto user = std::make_shared<User>();
user.m_nickname = nick; user->m_nickname = nick;
user.m_username = Jupiter::ReferenceString::getWord(name, 1, "!@"); user->m_username = Jupiter::ReferenceString::getWord(name, 1, "!@");
user.m_hostname = Jupiter::ReferenceString::getWord(name, 2, "!@"); user->m_hostname = Jupiter::ReferenceString::getWord(name, 2, "!@");
return &m_users.emplace(nick, user).first->second; return m_users.emplace(nick, user).first->second;
} }
void Jupiter::IRC::Client::addNamesToChannel(Channel &in_channel, Jupiter::ReadableString &in_names) void Jupiter::IRC::Client::addNamesToChannel(Channel &in_channel, Jupiter::ReadableString &in_names)
@ -1485,7 +1485,7 @@ void Jupiter::IRC::Client::addNamesToChannel(Channel &in_channel, Jupiter::Reada
offset = tmp.span(m_prefixes); offset = tmp.span(m_prefixes);
tmp.shiftRight(offset); tmp.shiftRight(offset);
Client::User *user = Client::findUserOrAdd(tmp); auto user = Client::findUserOrAdd(tmp);
tmp.shiftLeft(offset); tmp.shiftLeft(offset);
in_channel.addUser(user); in_channel.addUser(user);
@ -1594,27 +1594,27 @@ Jupiter::IRC::Client::Channel::Channel(const Jupiter::ReadableString &in_name, J
m_type = read_type(*m_parent->getPrimaryConfigSection(), m_type); m_type = read_type(*m_parent->getPrimaryConfigSection(), m_type);
} }
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User *user) std::shared_ptr<Jupiter::IRC::Client::Channel::User> Jupiter::IRC::Client::Channel::addUser(std::shared_ptr<Client::User> user)
{ {
Channel::User channel_user; auto channel_user = std::make_shared<Channel::User>();
channel_user.m_user = user; channel_user->m_user = user;
++user->m_channel_count; ++user->m_channel_count;
m_users[channel_user.getNickname()] = channel_user; m_users[channel_user->getNickname()] = channel_user;
return &m_users[channel_user.getNickname()]; return channel_user;
} }
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User *user, const char prefix) std::shared_ptr<Jupiter::IRC::Client::Channel::User> Jupiter::IRC::Client::Channel::addUser(std::shared_ptr<Client::User> user, const char prefix)
{ {
Channel::User channel_user; auto channel_user = std::make_shared<Channel::User>();
channel_user.m_user = user; channel_user->m_user = user;
channel_user.m_prefixes = prefix; channel_user->m_prefixes = prefix;
++user->m_channel_count; ++user->m_channel_count;
m_users[channel_user.getNickname()] = channel_user; m_users[channel_user->getNickname()] = channel_user;
return &m_users[channel_user.getNickname()]; return channel_user;
} }
void Jupiter::IRC::Client::Channel::delUser(const Jupiter::ReadableString &in_nickname) void Jupiter::IRC::Client::Channel::delUser(const Jupiter::ReadableString &in_nickname)
@ -1624,7 +1624,7 @@ void Jupiter::IRC::Client::Channel::delUser(const Jupiter::ReadableString &in_ni
void Jupiter::IRC::Client::Channel::addUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix) void Jupiter::IRC::Client::Channel::addUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix)
{ {
Channel::User *user = getUser(in_nickname); auto user = getUser(in_nickname);
if (user != nullptr && user->m_prefixes.contains(prefix) == false) if (user != nullptr && user->m_prefixes.contains(prefix) == false)
user->m_prefixes += prefix; user->m_prefixes += prefix;
@ -1632,7 +1632,7 @@ void Jupiter::IRC::Client::Channel::addUserPrefix(const Jupiter::ReadableString
void Jupiter::IRC::Client::Channel::delUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix) void Jupiter::IRC::Client::Channel::delUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix)
{ {
Channel::User *user = getUser(in_nickname); auto user = getUser(in_nickname);
if (user != nullptr) if (user != nullptr)
user->m_prefixes.remove(prefix); user->m_prefixes.remove(prefix);
@ -1643,11 +1643,11 @@ const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::getName() const
return m_name; return m_name;
} }
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(const Jupiter::ReadableString &in_nickname) const std::shared_ptr<Jupiter::IRC::Client::Channel::User> Jupiter::IRC::Client::Channel::getUser(const Jupiter::ReadableString &in_nickname) const
{ {
auto user = m_users.find(in_nickname); auto user = m_users.find(in_nickname);
if (user != m_users.end()) { if (user != m_users.end()) {
return const_cast<Channel::User*>(&user->second); return user->second;
} }
return nullptr; return nullptr;
@ -1666,7 +1666,7 @@ char Jupiter::IRC::Client::Channel::getUserPrefix(const Channel::User &in_user)
char Jupiter::IRC::Client::Channel::getUserPrefix(const Jupiter::ReadableString &in_nickname) const char Jupiter::IRC::Client::Channel::getUserPrefix(const Jupiter::ReadableString &in_nickname) const
{ {
Channel::User *user = getUser(in_nickname); auto user = getUser(in_nickname);
if (user != nullptr) if (user != nullptr)
return this->getUserPrefix(*user); return this->getUserPrefix(*user);
@ -1706,7 +1706,7 @@ Jupiter::IRC::Client::Channel::User::~User()
Jupiter::IRC::Client::User *Jupiter::IRC::Client::Channel::User::getUser() const Jupiter::IRC::Client::User *Jupiter::IRC::Client::Channel::User::getUser() const
{ {
return m_user; return m_user.get();
} }
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getPrefixes() const const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getPrefixes() const

19
src/include/Jupiter/IRC_Client.h

@ -26,6 +26,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>
#include <utility>
#include "Jupiter.h" #include "Jupiter.h"
#include "Thinker.h" #include "Thinker.h"
#include "IRC.h" #include "IRC.h"
@ -310,11 +311,11 @@ namespace Jupiter
/** Private members */ /** Private members */
private: private:
Jupiter::IRC::Client::User *m_user = nullptr; std::shared_ptr<Jupiter::IRC::Client::User> m_user;
Jupiter::StringS m_prefixes; Jupiter::StringS m_prefixes;
}; };
using UserTableType = std::unordered_map<Jupiter::StringS, Channel::User, default_hash_function>; using UserTableType = std::unordered_map<Jupiter::StringS, std::shared_ptr<Channel::User>, default_hash_function>;
/** /**
* @brief Returns the name of the channel. * @brief Returns the name of the channel.
@ -329,7 +330,7 @@ namespace Jupiter
* @param nickname String containing the nickname of the user to find. * @param nickname String containing the nickname of the user to find.
* @return A user if a match is found, nullptr otherwise. * @return A user if a match is found, nullptr otherwise.
*/ */
Jupiter::IRC::Client::Channel::User *getUser(const Jupiter::ReadableString &in_nickname) const; std::shared_ptr<Channel::User> getUser(const Jupiter::ReadableString &in_nickname) const;
/** /**
* @brief Adds a user to the channel * @brief Adds a user to the channel
@ -337,7 +338,7 @@ namespace Jupiter
* @param nickname Nickname of the user. * @param nickname Nickname of the user.
* @return Index of the new user. * @return Index of the new user.
*/ */
Channel::User *addUser(Jupiter::IRC::Client::User *in_user); std::shared_ptr<Channel::User> addUser(std::shared_ptr<Client::User> in_user);
/** /**
* @brief Adds a user to the channel * @brief Adds a user to the channel
@ -346,7 +347,7 @@ namespace Jupiter
* @param prefix The user's prefix. * @param prefix The user's prefix.
* @return Index of the new user. * @return Index of the new user.
*/ */
Channel::User *addUser(Jupiter::IRC::Client::User *in_user, const char in_prefix); std::shared_ptr<Channel::User> addUser(std::shared_ptr<Client::User> in_user, const char in_prefix);
/** /**
* @brief Removes a user from the channel. * @brief Removes a user from the channel.
@ -429,7 +430,7 @@ namespace Jupiter
}; // Jupiter::IRC::Client::Channel class }; // Jupiter::IRC::Client::Channel class
using ChannelTableType = std::unordered_map<Jupiter::StringS, Client::Channel, default_hash_function>; using ChannelTableType = std::unordered_map<Jupiter::StringS, Client::Channel, default_hash_function>;
using UserTableType = std::unordered_map<Jupiter::StringS, Client::User, default_hash_function>; using UserTableType = std::unordered_map<Jupiter::StringS, std::shared_ptr<Client::User>, default_hash_function>;
/** /**
* @brief Returns the name of the primary config section this client reads from. * @brief Returns the name of the primary config section this client reads from.
@ -597,7 +598,7 @@ namespace Jupiter
* @param nickname String containing the nickname of the user to fetch. * @param nickname String containing the nickname of the user to fetch.
* @return A User if a match is found, nullptr otherwise. * @return A User if a match is found, nullptr otherwise.
*/ */
Jupiter::IRC::Client::User *getUser(const Jupiter::ReadableString &in_nickname) const; std::shared_ptr<User> getUser(const Jupiter::ReadableString &in_nickname) const;
/** /**
* @brief Fetches the channel table * @brief Fetches the channel table
@ -876,8 +877,8 @@ namespace Jupiter
bool startCAP(); bool startCAP();
bool registerClient(); bool registerClient();
Jupiter::IRC::Client::User *findUser(const Jupiter::ReadableString &in_nickname) const; std::shared_ptr<User> findUser(const Jupiter::ReadableString &in_nickname) const;
Jupiter::IRC::Client::User *findUserOrAdd(const Jupiter::ReadableString &in_nickname); std::shared_ptr<User> findUserOrAdd(const Jupiter::ReadableString &in_nickname);
}; // Jupiter::IRC::Client class }; // Jupiter::IRC::Client class
} // Jupiter::IRC namespace } // Jupiter::IRC namespace

Loading…
Cancel
Save