Mercurial > libanimone
comparison src/win/x11.cc @ 20:7174ff20498d
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 | 6596be6917a1 |
| children | 973734ebd2be |
comparison
equal
deleted
inserted
replaced
| 19:6596be6917a1 | 20:7174ff20498d |
|---|---|
| 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) { |
