Commit 421a666b63fe88dca89e62d81c646b352943eab2

Authored by Wiebe Cazemier
1 parent 9cbd0be5

Fix creating invalid subscription tree on unsubscribe

Unsubscribing paths that didn't exist caused creation of null nodes,
which subsequent use of the tree crashed on.
subscriptionstore.cpp
... ... @@ -61,6 +61,20 @@ void SubscriptionNode::removeSubscriber(const std::shared_ptr<Session> &subscrib
61 61 }
62 62 }
63 63  
  64 +/**
  65 + * @brief SubscriptionNode::getChildren gets children or null pointer. Const, so doesn't default-create node for
  66 + * non-existing children.
  67 + * @param subtopic
  68 + * @return
  69 + */
  70 +SubscriptionNode *SubscriptionNode::getChildren(const std::string &subtopic) const
  71 +{
  72 + auto it = children.find(subtopic);
  73 + if (it != children.end())
  74 + return it->second.get();
  75 + return nullptr;
  76 +}
  77 +
64 78  
65 79 SubscriptionStore::SubscriptionStore() :
66 80 root("root"),
... ... @@ -122,26 +136,25 @@ void SubscriptionStore::removeSubscription(std::shared_ptr<Client> &client, cons
122 136 RWLockGuard lock_guard(&subscriptionsRwlock);
123 137 lock_guard.wrlock();
124 138  
125   - // TODO: because it's so similar to adding a subscription, make a function to retrieve the deepest node?
  139 + // This code looks like that for addSubscription(), but it's specifically different in that we don't want to default-create non-existing
  140 + // nodes. We need to abort when that happens.
126 141 SubscriptionNode *deepestNode = &root;
127 142 for(const std::string &subtopic : subtopics)
128 143 {
129   - std::unique_ptr<SubscriptionNode> *selectedChildren = nullptr;
  144 + SubscriptionNode *selectedChildren = nullptr;
130 145  
131 146 if (subtopic == "#")
132   - selectedChildren = &deepestNode->childrenPound;
  147 + selectedChildren = deepestNode->childrenPound.get();
133 148 else if (subtopic == "+")
134   - selectedChildren = &deepestNode->childrenPlus;
  149 + selectedChildren = deepestNode->childrenPlus.get();
135 150 else
136   - selectedChildren = &deepestNode->children[subtopic];
137   -
138   - std::unique_ptr<SubscriptionNode> &node = *selectedChildren;
  151 + selectedChildren = deepestNode->getChildren(subtopic);
139 152  
140   - if (!node)
  153 + if (!selectedChildren)
141 154 {
142 155 return;
143 156 }
144   - deepestNode = node.get();
  157 + deepestNode = selectedChildren;
145 158 }
146 159  
147 160 assert(deepestNode);
... ... @@ -237,6 +250,10 @@ void SubscriptionStore::publishRecursively(std::vector&lt;std::string&gt;::const_itera
237 250 return;
238 251 }
239 252  
  253 + // Null nodes in the tree shouldn't happen at this point. It points to bugs elsewhere. However, I don't remember why I check the pointer
  254 + // inside the if-block above, instead of the start of the method.
  255 + assert(this_node != nullptr);
  256 +
240 257 if (this_node->children.empty() && !this_node->childrenPlus && !this_node->childrenPound)
241 258 return;
242 259  
... ...
subscriptionstore.h
... ... @@ -64,6 +64,8 @@ public:
64 64 std::unique_ptr<SubscriptionNode> childrenPlus;
65 65 std::unique_ptr<SubscriptionNode> childrenPound;
66 66  
  67 + SubscriptionNode *getChildren(const std::string &subtopic) const;
  68 +
67 69 int cleanSubscriptions();
68 70 };
69 71  
... ...