comparison dep/animone/src/win/x11.cc @ 336:d260549151d6

dep/animone: fix undefined behavior, get correct length value
author Paper <paper@paper.us.eu.org>
date Wed, 19 Jun 2024 06:32:25 -0400
parents a4257370de16
children a7d4e5107531
comparison
equal deleted inserted replaced
335:5098387a3a46 336:d260549151d6
13 #include <xcb/xcb.h> 13 #include <xcb/xcb.h>
14 14
15 #include <climits> 15 #include <climits>
16 #include <cstdint> 16 #include <cstdint>
17 #include <cstring> 17 #include <cstring>
18 #include <cstdlib>
18 #include <set> 19 #include <set>
19 #include <string> 20 #include <string>
20 #include <memory> 21 #include <memory>
21 22
22 #include <chrono> 23 #include <chrono>
30 return i; 31 return i;
31 } 32 }
32 33
33 namespace animone::internal::x11 { 34 namespace animone::internal::x11 {
34 35
36 template<typename T>
37 struct XcbDestructor {
38 using pointer = T*;
39 void operator()(pointer t) const { std::free(t); };
40 };
41
42 template<typename T>
43 using XcbPtr = std::unique_ptr<T, XcbDestructor<T>>;
44
35 static bool GetAllTopLevelWindowsEWMH(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots, 45 static bool GetAllTopLevelWindowsEWMH(xcb_connection_t* connection, const std::vector<xcb_window_t>& roots,
36 std::set<xcb_window_t>& result) { 46 std::set<xcb_window_t>& result) {
37 const xcb_atom_t Atom__NET_CLIENT_LIST = [connection] { 47 const xcb_atom_t Atom__NET_CLIENT_LIST = [connection] {
38 static constexpr std::string_view name = "_NET_CLIENT_LIST"; 48 static constexpr std::string_view name = "_NET_CLIENT_LIST";
39 xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data()); 49 xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
40 std::unique_ptr<xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(connection, cookie, NULL)); 50 XcbPtr<xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(connection, cookie, NULL));
41 51
42 xcb_atom_t atom = reply->atom; 52 xcb_atom_t atom = reply->atom;
43 53
44 return atom; 54 return atom;
45 }(); 55 }();
53 63
54 for (const auto& root : roots) 64 for (const auto& root : roots)
55 cookies.push_back(::xcb_get_property(connection, 0, root, Atom__NET_CLIENT_LIST, XCB_ATOM_ANY, 0L, UINT_MAX)); 65 cookies.push_back(::xcb_get_property(connection, 0, root, Atom__NET_CLIENT_LIST, XCB_ATOM_ANY, 0L, UINT_MAX));
56 66
57 for (const auto& cookie : cookies) { 67 for (const auto& cookie : cookies) {
58 std::unique_ptr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, cookie, NULL)); 68 XcbPtr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, cookie, NULL));
59 69
60 if (reply) { 70 if (reply) {
61 xcb_window_t* value = reinterpret_cast<xcb_window_t*>(::xcb_get_property_value(reply.get())); 71 xcb_window_t* value = reinterpret_cast<xcb_window_t*>(::xcb_get_property_value(reply.get()));
62 int len = ::xcb_get_property_value_length(reply.get()); 72 int len = ::xcb_get_property_value_length(reply.get()) / sizeof(xcb_window_t);
63 73
64 for (size_t i = 0; i < len; i++) 74 for (size_t i = 0; i < len; i++)
65 result.insert(value[i]); 75 result.insert(value[i]);
66 76
67 success |= true; 77 success |= true;
88 98
89 for (int i = 0; i < windows_len; i++) 99 for (int i = 0; i < windows_len; i++)
90 cookies.push_back(::xcb_query_tree(connection, windows[i])); 100 cookies.push_back(::xcb_query_tree(connection, windows[i]));
91 101
92 for (const auto& cookie : cookies) { 102 for (const auto& cookie : cookies) {
93 std::unique_ptr<xcb_query_tree_reply_t> query_tree_reply(::xcb_query_tree_reply(connection, cookie, NULL)); 103 XcbPtr<xcb_query_tree_reply_t> query_tree_reply(::xcb_query_tree_reply(connection, cookie, NULL));
94 104
95 xcb_window_t* tree_children = ::xcb_query_tree_children(query_tree_reply.get()); 105 xcb_window_t* tree_children = ::xcb_query_tree_children(query_tree_reply.get());
96 int tree_children_len = ::xcb_query_tree_children_length(query_tree_reply.get()); 106 int tree_children_len = ::xcb_query_tree_children_length(query_tree_reply.get());
97 107
98 std::vector<xcb_get_property_cookie_t> state_property_cookies; 108 std::vector<xcb_get_property_cookie_t> state_property_cookies;
101 for (int i = 0; i < tree_children_len; i++) 111 for (int i = 0; i < tree_children_len; i++)
102 state_property_cookies.push_back( 112 state_property_cookies.push_back(
103 ::xcb_get_property(connection, 0, tree_children[i], Atom_WM_STATE, Atom_WM_STATE, 0, 0)); 113 ::xcb_get_property(connection, 0, tree_children[i], Atom_WM_STATE, Atom_WM_STATE, 0, 0));
104 114
105 for (int i = 0; i < tree_children_len; i++) { 115 for (int i = 0; i < tree_children_len; i++) {
106 std::unique_ptr<xcb_get_property_reply_t> get_property_reply( 116 XcbPtr<xcb_get_property_reply_t> get_property_reply(::xcb_get_property_reply(connection, state_property_cookies[i], NULL));
107 ::xcb_get_property_reply(connection, state_property_cookies[i], NULL));
108 117
109 /* X11 is unfriendly here. what this means is "did the property exist?" */ 118 /* X11 is unfriendly here. what this means is "did the property exist?" */
110 if (get_property_reply->format || get_property_reply->type || get_property_reply->length) { 119 if (get_property_reply->format || get_property_reply->type || get_property_reply->length) {
111 result.insert(tree_children[i]); 120 result.insert(tree_children[i]);
112 if (depth >= CUTOFF) 121 if (depth >= CUTOFF)
133 bool success = false; 142 bool success = false;
134 143
135 xcb_atom_t Atom_WM_STATE = [connection] { 144 xcb_atom_t Atom_WM_STATE = [connection] {
136 static constexpr std::string_view name = "WM_STATE"; 145 static constexpr std::string_view name = "WM_STATE";
137 xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data()); 146 xcb_intern_atom_cookie_t cookie = ::xcb_intern_atom(connection, true, name.size(), name.data());
138 xcb_intern_atom_reply_t* reply = ::xcb_intern_atom_reply(connection, cookie, NULL); 147 XcbPtr<xcb_intern_atom_reply_t> reply(::xcb_intern_atom_reply(connection, cookie, NULL));
139 148
140 xcb_atom_t atom = reply->atom; 149 xcb_atom_t atom = reply->atom;
141 free(reply); 150
142 return atom; 151 return atom;
143 }(); 152 }();
144 if (Atom_WM_STATE == XCB_ATOM_NONE) 153 if (Atom_WM_STATE == XCB_ATOM_NONE)
145 return success; 154 return success;
146 155
201 for (const auto& window_cookie : window_cookies) { 210 for (const auto& window_cookie : window_cookies) {
202 Window win = {0}; 211 Window win = {0};
203 win.id = window_cookie.window; 212 win.id = window_cookie.window;
204 { 213 {
205 /* Class name */ 214 /* Class name */
206 std::unique_ptr<xcb_get_property_reply_t> reply( 215 XcbPtr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, window_cookie.class_property_cookie, NULL));
207 ::xcb_get_property_reply(connection, window_cookie.class_property_cookie, NULL));
208 216
209 if (reply && reply->format == 8) { 217 if (reply && reply->format == 8) {
210 const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get())); 218 const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
211 const int data_len = ::xcb_get_property_value_length(reply.get()); 219 const int data_len = ::xcb_get_property_value_length(reply.get());
212 220
216 win.class_name = std::string(class_name, str_nlen(class_name, data_len - (instance_len + 1))); 224 win.class_name = std::string(class_name, str_nlen(class_name, data_len - (instance_len + 1)));
217 } 225 }
218 } 226 }
219 { 227 {
220 /* Title text */ 228 /* Title text */
221 std::unique_ptr<xcb_get_property_reply_t> reply( 229 XcbPtr<xcb_get_property_reply_t> reply(::xcb_get_property_reply(connection, window_cookie.name_property_cookie, NULL));
222 ::xcb_get_property_reply(connection, window_cookie.name_property_cookie, NULL));
223 230
224 if (reply) { 231 if (reply) {
225 const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get())); 232 const char* data = reinterpret_cast<const char*>(::xcb_get_property_value(reply.get()));
226 int len = ::xcb_get_property_value_length(reply.get()); 233 int len = ::xcb_get_property_value_length(reply.get());
227 234
229 } 236 }
230 } 237 }
231 Process proc = {0}; 238 Process proc = {0};
232 { 239 {
233 /* PID */ 240 /* PID */
234 std::unique_ptr<xcb_res_query_client_ids_reply_t> reply( 241 XcbPtr<xcb_res_query_client_ids_reply_t> reply(::xcb_res_query_client_ids_reply(connection, window_cookie.pid_property_cookie, NULL));
235 ::xcb_res_query_client_ids_reply(connection, window_cookie.pid_property_cookie, NULL));
236 242
237 if (reply) { 243 if (reply) {
238 xcb_res_client_id_value_iterator_t it = ::xcb_res_query_client_ids_ids_iterator(reply.get()); 244 xcb_res_client_id_value_iterator_t it = ::xcb_res_query_client_ids_ids_iterator(reply.get());
239 for (; it.rem; ::xcb_res_client_id_value_next(&it)) { 245 for (; it.rem; ::xcb_res_client_id_value_next(&it)) {
240 if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) { 246 if (it.data->spec.mask & XCB_RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID) {