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 | 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<std::string>::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