Commit 421a666b63fe88dca89e62d81c646b352943eab2
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.
Showing
2 changed files
with
28 additions
and
9 deletions
subscriptionstore.cpp
| @@ -61,6 +61,20 @@ void SubscriptionNode::removeSubscriber(const std::shared_ptr<Session> &subscrib | @@ -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 | SubscriptionStore::SubscriptionStore() : | 79 | SubscriptionStore::SubscriptionStore() : |
| 66 | root("root"), | 80 | root("root"), |
| @@ -122,26 +136,25 @@ void SubscriptionStore::removeSubscription(std::shared_ptr<Client> &client, cons | @@ -122,26 +136,25 @@ void SubscriptionStore::removeSubscription(std::shared_ptr<Client> &client, cons | ||
| 122 | RWLockGuard lock_guard(&subscriptionsRwlock); | 136 | RWLockGuard lock_guard(&subscriptionsRwlock); |
| 123 | lock_guard.wrlock(); | 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 | SubscriptionNode *deepestNode = &root; | 141 | SubscriptionNode *deepestNode = &root; |
| 127 | for(const std::string &subtopic : subtopics) | 142 | for(const std::string &subtopic : subtopics) |
| 128 | { | 143 | { |
| 129 | - std::unique_ptr<SubscriptionNode> *selectedChildren = nullptr; | 144 | + SubscriptionNode *selectedChildren = nullptr; |
| 130 | 145 | ||
| 131 | if (subtopic == "#") | 146 | if (subtopic == "#") |
| 132 | - selectedChildren = &deepestNode->childrenPound; | 147 | + selectedChildren = deepestNode->childrenPound.get(); |
| 133 | else if (subtopic == "+") | 148 | else if (subtopic == "+") |
| 134 | - selectedChildren = &deepestNode->childrenPlus; | 149 | + selectedChildren = deepestNode->childrenPlus.get(); |
| 135 | else | 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 | return; | 155 | return; |
| 143 | } | 156 | } |
| 144 | - deepestNode = node.get(); | 157 | + deepestNode = selectedChildren; |
| 145 | } | 158 | } |
| 146 | 159 | ||
| 147 | assert(deepestNode); | 160 | assert(deepestNode); |
| @@ -237,6 +250,10 @@ void SubscriptionStore::publishRecursively(std::vector<std::string>::const_itera | @@ -237,6 +250,10 @@ void SubscriptionStore::publishRecursively(std::vector<std::string>::const_itera | ||
| 237 | return; | 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 | if (this_node->children.empty() && !this_node->childrenPlus && !this_node->childrenPound) | 257 | if (this_node->children.empty() && !this_node->childrenPlus && !this_node->childrenPound) |
| 241 | return; | 258 | return; |
| 242 | 259 |
subscriptionstore.h
| @@ -64,6 +64,8 @@ public: | @@ -64,6 +64,8 @@ public: | ||
| 64 | std::unique_ptr<SubscriptionNode> childrenPlus; | 64 | std::unique_ptr<SubscriptionNode> childrenPlus; |
| 65 | std::unique_ptr<SubscriptionNode> childrenPound; | 65 | std::unique_ptr<SubscriptionNode> childrenPound; |
| 66 | 66 | ||
| 67 | + SubscriptionNode *getChildren(const std::string &subtopic) const; | ||
| 68 | + | ||
| 67 | int cleanSubscriptions(); | 69 | int cleanSubscriptions(); |
| 68 | }; | 70 | }; |
| 69 | 71 |