Skip to content

Commit a3054bb

Browse files
committed
Avoid stack overflow in SubscriptionFlowTree.findMatching
1 parent ed684c0 commit a3054bb

File tree

8 files changed

+126
-71
lines changed

8 files changed

+126
-71
lines changed

src/main/java/com/hivemq/client/internal/mqtt/datatypes/MqttTopicLevel.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,12 @@ public class MqttTopicLevel extends ByteArray.Range {
3535
new ByteArray(new byte[]{MqttTopicFilter.SINGLE_LEVEL_WILDCARD});
3636

3737
public static @NotNull MqttTopicLevel root(final @NotNull MqttTopicImpl topic) {
38-
final byte[] binary = topic.toBinary();
39-
final int end = nextEnd(binary, 0);
40-
return new MqttTopicLevel(binary, 0, end);
38+
return new MqttTopicLevel(topic.toBinary(), -1, -1);
4139
}
4240

4341
public static @NotNull MqttTopicLevel root(final @NotNull MqttTopicFilterImpl topicFilter) {
44-
final byte[] binary = topicFilter.toBinary();
4542
final int start = topicFilter.getFilterByteStart() - 1;
46-
return new MqttTopicLevel(binary, start, start);
43+
return new MqttTopicLevel(topicFilter.toBinary(), start, start);
4744
}
4845

4946
private static int nextEnd(final @NotNull byte[] array, final int start) {

src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttIncomingPublishFlows.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,17 +106,17 @@ void cancel(final @NotNull MqttSubscribedPublishFlow flow) {
106106
}
107107

108108
@NotNull HandleList<MqttIncomingPublishFlow> findMatching(final @NotNull MqttStatefulPublish publish) {
109-
final HandleList<MqttIncomingPublishFlow> matchingFlows = new HandleList<>();
109+
final MqttMatchingPublishFlows matchingFlows = new MqttMatchingPublishFlows();
110110
findMatching(publish, matchingFlows);
111111
return matchingFlows;
112112
}
113113

114114
void findMatching(
115-
final @NotNull MqttStatefulPublish publish,
116-
final @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows) {
115+
final @NotNull MqttStatefulPublish publish, final @NotNull MqttMatchingPublishFlows matchingFlows) {
117116

118117
final MqttTopicImpl topic = publish.stateless().getTopic();
119-
if (subscriptionFlows.findMatching(topic, matchingFlows) || !matchingFlows.isEmpty()) {
118+
subscriptionFlows.findMatching(topic, matchingFlows);
119+
if (matchingFlows.subscriptionFound) {
120120
add(matchingFlows, globalFlows[MqttGlobalPublishFilter.SUBSCRIBED.ordinal()]);
121121
} else {
122122
add(matchingFlows, globalFlows[MqttGlobalPublishFilter.UNSOLICITED.ordinal()]);

src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttIncomingPublishFlowsWithId.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import com.hivemq.client.internal.mqtt.message.publish.MqttStatefulPublish;
2424
import com.hivemq.client.internal.mqtt.message.subscribe.MqttStatefulSubscribe;
2525
import com.hivemq.client.internal.mqtt.message.subscribe.suback.MqttSubAck;
26-
import com.hivemq.client.internal.util.collections.HandleList;
2726
import com.hivemq.client.internal.util.collections.ImmutableIntList;
2827
import org.jetbrains.annotations.NotNull;
2928
import org.jetbrains.annotations.Nullable;
@@ -127,8 +126,7 @@ void cancel(final @NotNull MqttSubscribedPublishFlow flow) {
127126

128127
@Override
129128
void findMatching(
130-
final @NotNull MqttStatefulPublish publish,
131-
final @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows) {
129+
final @NotNull MqttStatefulPublish publish, final @NotNull MqttMatchingPublishFlows matchingFlows) {
132130

133131
final ImmutableIntList subscriptionIdentifiers = publish.getSubscriptionIdentifiers();
134132
if (!subscriptionIdentifiers.isEmpty()) {
@@ -139,6 +137,9 @@ void findMatching(
139137
matchingFlows.add(flow);
140138
}
141139
}
140+
if (!matchingFlows.isEmpty()) {
141+
matchingFlows.subscriptionFound = true;
142+
}
142143
}
143144
super.findMatching(publish, matchingFlows);
144145
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2018 dc-square and the HiveMQ MQTT Client Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
package com.hivemq.client.internal.mqtt.handler.publish.incoming;
19+
20+
import com.hivemq.client.internal.util.collections.HandleList;
21+
22+
/**
23+
* @author Silvio Giebl
24+
*/
25+
class MqttMatchingPublishFlows extends HandleList<MqttIncomingPublishFlow> {
26+
27+
boolean subscriptionFound;
28+
}

src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttSubscriptionFlowList.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ public void cancel(final @NotNull MqttSubscribedPublishFlow flow) {
121121
}
122122

123123
@Override
124-
public boolean findMatching(
125-
final @NotNull MqttTopicImpl topic, final @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows) {
124+
public void findMatching(
125+
final @NotNull MqttTopicImpl topic, final @NotNull MqttMatchingPublishFlows matchingFlows) {
126126

127127
for (final MqttSubscribedPublishFlow flow : flows) {
128128
for (final MqttTopicFilterImpl topicFilter : flow.getTopicFilters()) {
@@ -133,14 +133,15 @@ public boolean findMatching(
133133
}
134134
}
135135
if (!matchingFlows.isEmpty()) {
136-
return true;
136+
matchingFlows.subscriptionFound = true;
137+
return;
137138
}
138139
for (final MqttTopicFilterImpl subscribedTopicFilter : subscribedTopicFilters.keySet()) {
139140
if (subscribedTopicFilter.matches(topic)) {
140-
return true;
141+
matchingFlows.subscriptionFound = true;
142+
return;
141143
}
142144
}
143-
return false;
144145
}
145146

146147
@Override

src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttSubscriptionFlowTree.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,14 @@ public void cancel(final @NotNull MqttSubscribedPublishFlow flow) {
108108
}
109109

110110
@Override
111-
public boolean findMatching(
112-
final @NotNull MqttTopicImpl topic, final @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows) {
111+
public void findMatching(
112+
final @NotNull MqttTopicImpl topic, final @NotNull MqttMatchingPublishFlows matchingFlows) {
113113

114-
return (rootNode != null) && rootNode.findMatching(MqttTopicLevel.root(topic), matchingFlows);
114+
final MqttTopicLevel level = MqttTopicLevel.root(topic);
115+
TopicTreeNode node = rootNode;
116+
while (node != null) {
117+
node = node.findMatching(level.next(), matchingFlows);
118+
}
115119
}
116120

117121
@Override
@@ -300,27 +304,35 @@ private static boolean cancel(
300304
return false;
301305
}
302306

303-
boolean findMatching(
304-
final @Nullable MqttTopicLevel level,
305-
final @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows) {
307+
@Nullable TopicTreeNode findMatching(
308+
final @Nullable MqttTopicLevel level, final @NotNull MqttMatchingPublishFlows matchingFlows) {
306309

307310
if (level == null) {
308311
add(matchingFlows, entries);
309312
add(matchingFlows, multiLevelEntries);
310-
return (subscriptions != 0) || (multiLevelSubscriptions != 0);
313+
if ((subscriptions != 0) || (multiLevelSubscriptions != 0)) {
314+
matchingFlows.subscriptionFound = true;
315+
}
316+
return null;
311317
}
312318
add(matchingFlows, multiLevelEntries);
313-
boolean subscriptionFound = (multiLevelSubscriptions != 0);
319+
if (multiLevelSubscriptions != 0) {
320+
matchingFlows.subscriptionFound = true;
321+
}
314322
if (next != null) {
315-
if (singleLevel != null) {
316-
subscriptionFound |= singleLevel.findMatching(level.fork().next(), matchingFlows);
317-
}
318-
final TopicTreeNode node = next.get(level);
319-
if (node != null) {
320-
subscriptionFound |= node.findMatching(level.next(), matchingFlows);
323+
final TopicTreeNode nextNode = next.get(level);
324+
if (nextNode != null) {
325+
if (singleLevel != null) {
326+
TopicTreeNode node = singleLevel;
327+
final MqttTopicLevel levelFork = level.fork();
328+
while (node != null) {
329+
node = node.findMatching(levelFork.next(), matchingFlows);
330+
}
331+
}
332+
return nextNode;
321333
}
322334
}
323-
return subscriptionFound;
335+
return singleLevel;
324336
}
325337

326338
private static void add(
@@ -369,12 +381,12 @@ private static void add(
369381
return null;
370382
}
371383

372-
private void removeNext(final @NotNull TopicTreeNode node) {
373-
assert next != null;
384+
void removeNext(final @NotNull TopicTreeNode node) {
374385
assert node.parentLevel != null;
375386
if (node.parentLevel == MqttTopicLevel.SINGLE_LEVEL_WILDCARD) {
376387
singleLevel = null;
377388
} else {
389+
assert next != null;
378390
next.remove(node.parentLevel);
379391
if (next.isEmpty()) {
380392
next = null;

src/main/java/com/hivemq/client/internal/mqtt/handler/publish/incoming/MqttSubscriptionFlows.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.hivemq.client.internal.annotations.NotThreadSafe;
2121
import com.hivemq.client.internal.mqtt.datatypes.MqttTopicFilterImpl;
2222
import com.hivemq.client.internal.mqtt.datatypes.MqttTopicImpl;
23-
import com.hivemq.client.internal.util.collections.HandleList;
2423
import org.jetbrains.annotations.NotNull;
2524
import org.jetbrains.annotations.Nullable;
2625

@@ -42,7 +41,7 @@ void unsubscribe(
4241

4342
void cancel(@NotNull MqttSubscribedPublishFlow flow);
4443

45-
boolean findMatching(@NotNull MqttTopicImpl topic, @NotNull HandleList<MqttIncomingPublishFlow> matchingFlows);
44+
void findMatching(@NotNull MqttTopicImpl topic, @NotNull MqttMatchingPublishFlows matchingFlows);
4645

4746
void clear(@NotNull Throwable cause);
4847
}

0 commit comments

Comments
 (0)