/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  |  |  |