/src/uWebSockets/fuzzing/TopicTree.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #define WIN32_EXPORT |
2 | | |
3 | | #include "helpers.h" |
4 | | |
5 | | /* Test for the topic tree */ |
6 | | #include "../src/TopicTree.h" |
7 | | |
8 | | #include <memory> |
9 | | |
10 | | // std::vector<std::string_view> topics = {"", "one", "two", "three"}; |
11 | | |
12 | 3.29k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
13 | | /* Create topic tree */ |
14 | 2.54M | uWS::TopicTree<std::string, std::string_view> topicTree([](uWS::Subscriber *s, std::string &message, auto flags) { |
15 | | |
16 | | /* Depending on what publishing we do below (with or without empty strings), |
17 | | * this assumption can hold true or not. For now it should hold true */ |
18 | 2.54M | if (!message.length()) { |
19 | 0 | free((void *) -1); |
20 | 0 | } |
21 | | |
22 | | /* Break if we have no subscriptions (not really an error, just to bring more randomness) */ |
23 | 2.54M | if (s->topics.size() == 0) { |
24 | 1.40k | return true; |
25 | 1.40k | } |
26 | | |
27 | | /* Success */ |
28 | 2.54M | return false; |
29 | 2.54M | }); |
30 | | |
31 | | /* Holder for all manually allocated subscribers */ |
32 | 3.29k | std::map<uint32_t, uWS::Subscriber *> subscribers; |
33 | | |
34 | | /* Iterate the padded fuzz as chunks */ |
35 | 3.88M | makeChunked(makePadded(data, size), size, [&topicTree, &subscribers](const uint8_t *data, size_t size) { |
36 | | /* We need at least 5 bytes */ |
37 | 3.88M | if (size > 4) { |
38 | | /* Last of all is a string */ |
39 | 3.34M | std::string_view lastString((char *) data + 5, size - 5); |
40 | | |
41 | | /* Why not */ |
42 | 3.34M | topicTree.lookupTopic(lastString); |
43 | | |
44 | | /* First 4 bytes is the subscriber id */ |
45 | 3.34M | uint32_t id; |
46 | 3.34M | memcpy(&id, data, 4); |
47 | | |
48 | | /* Then one byte action */ |
49 | 3.34M | if (data[4] == 'S') { |
50 | | |
51 | | /* Some ridiculously long topics has to be cut short (OOM) */ |
52 | 1.09M | if (lastString.length() > 512) { |
53 | 22 | lastString = "too long!"; |
54 | 22 | } |
55 | | |
56 | | /* Subscribe */ |
57 | 1.09M | if (subscribers.find(id) == subscribers.end()) { |
58 | | |
59 | | /* Limit number of subscribers to 100 (OOM) */ |
60 | 951k | if (subscribers.size() > 100) { |
61 | 4.78k | return; |
62 | 4.78k | } |
63 | | |
64 | 946k | uWS::Subscriber *subscriber = topicTree.createSubscriber(); |
65 | 946k | subscribers[id] = subscriber; |
66 | 946k | topicTree.subscribe(subscriber, lastString); |
67 | 946k | } else { |
68 | | /* Limit per subscriber subscriptions (OOM) */ |
69 | 147k | uWS::Subscriber *subscriber = subscribers[id]; |
70 | 147k | if (subscriber->topics.size() < 50) { |
71 | 146k | topicTree.subscribe(subscriber, lastString); |
72 | 146k | } |
73 | 147k | } |
74 | 2.24M | } else if (data[4] == 'U') { |
75 | | /* Unsubscribe */ |
76 | 18.6k | auto it = subscribers.find(id); |
77 | 18.6k | if (it != subscribers.end()) { |
78 | 16.1k | topicTree.unsubscribe(it->second, lastString); |
79 | 16.1k | } |
80 | 2.22M | } else if (data[4] == 'F') { |
81 | | /* Free subscriber */ |
82 | 986k | auto it = subscribers.find(id); |
83 | 986k | if (it != subscribers.end()) { |
84 | 923k | topicTree.freeSubscriber(it->second); |
85 | 923k | subscribers.erase(it); |
86 | 923k | } |
87 | 1.24M | } else if (data[4] == 'A') { |
88 | | /* Unsubscribe from all */ |
89 | 15.0k | auto it = subscribers.find(id); |
90 | 15.0k | if (it != subscribers.end()) { |
91 | 13.5k | std::vector<std::string> topics; |
92 | 47.5k | for (auto *topic : it->second->topics) { |
93 | 47.5k | topics.push_back(topic->name); |
94 | 47.5k | } |
95 | | |
96 | 47.5k | for (std::string &topic : topics) { |
97 | 47.5k | topicTree.unsubscribe(it->second, topic); |
98 | 47.5k | } |
99 | 13.5k | } |
100 | 1.22M | } else if (data[4] == 'O') { |
101 | | /* Drain one socket */ |
102 | 3.79k | auto it = subscribers.find(id); |
103 | 3.79k | if (it != subscribers.end()) { |
104 | 2.36k | topicTree.drain(it->second); |
105 | 2.36k | } |
106 | 1.22M | } else if (data[4] == 'P') { |
107 | | /* Publish only if we actually have data */ |
108 | 980k | if (lastString.length()) { |
109 | 20.3k | topicTree.publish(nullptr, lastString, std::string(lastString)); |
110 | 960k | } else { |
111 | | /* We could use having more strings */ |
112 | 960k | topicTree.publish(nullptr, "", "anything"); |
113 | 960k | } |
114 | 980k | } else { |
115 | | /* Drain for everything else (OOM) */ |
116 | 240k | topicTree.drain(); |
117 | 240k | } |
118 | 3.34M | } |
119 | 3.88M | }); |
120 | | |
121 | | /* Remove any subscriber from the tree */ |
122 | 22.7k | for (auto &p : subscribers) { |
123 | 22.7k | topicTree.freeSubscriber(p.second); |
124 | 22.7k | } |
125 | | |
126 | 3.29k | return 0; |
127 | 3.29k | } |
128 | | |