/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.24k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
13 | | /* Create topic tree */ |
14 | 2.95M | 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.95M | 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.95M | if (s->topics.size() == 0) { |
24 | 2.37k | return true; |
25 | 2.37k | } |
26 | | |
27 | | /* Success */ |
28 | 2.95M | return false; |
29 | 2.95M | }); |
30 | | |
31 | | /* Holder for all manually allocated subscribers */ |
32 | 3.24k | std::map<uint32_t, uWS::Subscriber *> subscribers; |
33 | | |
34 | | /* Iterate the padded fuzz as chunks */ |
35 | 4.28M | makeChunked(makePadded(data, size), size, [&topicTree, &subscribers](const uint8_t *data, size_t size) { |
36 | | /* We need at least 5 bytes */ |
37 | 4.28M | if (size > 4) { |
38 | | /* Last of all is a string */ |
39 | 3.75M | std::string_view lastString((char *) data + 5, size - 5); |
40 | | |
41 | | /* Why not */ |
42 | 3.75M | topicTree.lookupTopic(lastString); |
43 | | |
44 | | /* First 4 bytes is the subscriber id */ |
45 | 3.75M | uint32_t id; |
46 | 3.75M | memcpy(&id, data, 4); |
47 | | |
48 | | /* Then one byte action */ |
49 | 3.75M | if (data[4] == 'S') { |
50 | | |
51 | | /* Some ridiculously long topics has to be cut short (OOM) */ |
52 | 1.12M | if (lastString.length() > 512) { |
53 | 20 | lastString = "too long!"; |
54 | 20 | } |
55 | | |
56 | | /* Subscribe */ |
57 | 1.12M | if (subscribers.find(id) == subscribers.end()) { |
58 | | |
59 | | /* Limit number of subscribers to 100 (OOM) */ |
60 | 968k | if (subscribers.size() > 100) { |
61 | 659 | return; |
62 | 659 | } |
63 | | |
64 | 968k | uWS::Subscriber *subscriber = topicTree.createSubscriber(); |
65 | 968k | subscribers[id] = subscriber; |
66 | 968k | topicTree.subscribe(subscriber, lastString); |
67 | 968k | } else { |
68 | | /* Limit per subscriber subscriptions (OOM) */ |
69 | 155k | uWS::Subscriber *subscriber = subscribers[id]; |
70 | 155k | if (subscriber->topics.size() < 50) { |
71 | 153k | topicTree.subscribe(subscriber, lastString); |
72 | 153k | } |
73 | 155k | } |
74 | 2.62M | } else if (data[4] == 'U') { |
75 | | /* Unsubscribe */ |
76 | 20.5k | auto it = subscribers.find(id); |
77 | 20.5k | if (it != subscribers.end()) { |
78 | 17.5k | topicTree.unsubscribe(it->second, lastString); |
79 | 17.5k | } |
80 | 2.60M | } else if (data[4] == 'F') { |
81 | | /* Free subscriber */ |
82 | 1.01M | auto it = subscribers.find(id); |
83 | 1.01M | if (it != subscribers.end()) { |
84 | 946k | topicTree.freeSubscriber(it->second); |
85 | 946k | subscribers.erase(it); |
86 | 946k | } |
87 | 1.59M | } else if (data[4] == 'A') { |
88 | | /* Unsubscribe from all */ |
89 | 19.3k | auto it = subscribers.find(id); |
90 | 19.3k | if (it != subscribers.end()) { |
91 | 17.8k | std::vector<std::string> topics; |
92 | 58.4k | for (auto *topic : it->second->topics) { |
93 | 58.4k | topics.push_back(topic->name); |
94 | 58.4k | } |
95 | | |
96 | 58.4k | for (std::string &topic : topics) { |
97 | 58.4k | topicTree.unsubscribe(it->second, topic); |
98 | 58.4k | } |
99 | 17.8k | } |
100 | 1.57M | } else if (data[4] == 'O') { |
101 | | /* Drain one socket */ |
102 | 4.96k | auto it = subscribers.find(id); |
103 | 4.96k | if (it != subscribers.end()) { |
104 | 3.76k | topicTree.drain(it->second); |
105 | 3.76k | } |
106 | 1.57M | } else if (data[4] == 'P') { |
107 | | /* Publish only if we actually have data */ |
108 | 1.29M | if (lastString.length()) { |
109 | 14.3k | topicTree.publish(nullptr, lastString, std::string(lastString)); |
110 | 1.28M | } else { |
111 | | /* We could use having more strings */ |
112 | 1.28M | topicTree.publish(nullptr, "", "anything"); |
113 | 1.28M | } |
114 | 1.29M | } else { |
115 | | /* Drain for everything else (OOM) */ |
116 | 274k | topicTree.drain(); |
117 | 274k | } |
118 | 3.75M | } |
119 | 4.28M | }); |
120 | | |
121 | | /* Remove any subscriber from the tree */ |
122 | 21.8k | for (auto &p : subscribers) { |
123 | 21.8k | topicTree.freeSubscriber(p.second); |
124 | 21.8k | } |
125 | | |
126 | 3.24k | return 0; |
127 | 3.24k | } |
128 | | |