Open diablodale opened 1 year ago
This will likely best be addressed (for now) by doing function wide try/catch, until either the lib is C++ified or if more fine grained handling is added (though I assume most cases will be general issues, as libusb ret value handling is already fine grained)
Got it. I will look into this late this week or next.
I intend to mark functions noexcept
at the C/C++ boundaries. Also, use normal try/catch
where needed around large blocks of code.
I hesitate in using the function-level try/catch
as it is intended to be used on constructors since that's the only way to catch exceptions in their initializer lists. It is a rare language feature that dev's might overlook or not understand.
This is straightforward though needs supporting code. In XLink today, I saw how I need to handle libusb while managing exceptions. For example...
refLibusbDeviceByName()
libusb_get_device_list(context, &devs)
populates the device listgetLibusbDevicePath()
getLibusbDevicePath()
throws exceptionThe exception handling has to be in refLibusbDeviceByName()
because the handler needs to libusb_free_device_list(devs, 1)
Tracing all the code to find where to insert try/catch/freeResources is time consuming and error-prone. I recommend using a RAII wrapper; similar to a unique_ptr with custom deleter. I would prefer:
unique_any
needs to be cut/isolated from the files that contain Windows-only derived classesAt https://github.com/diablodale/XLink/commit/2cfde5b58ebce9cc5769dc84ce54f3eb632a901b is a wrapper class LibusbDeviceList
for libusb_get_device_list/free
. It is an STL container and can be used with language/library features. Changed XLink to use it and is good in casual testing.
libusb_open/close
, libusb_get_config_descriptor/free
, maybe libusb_claim_interface/release
.LibusbDeviceList::create(context)
.std::unique_ptr<LibusbDeviceList>
mvLog()
entry is made and an empty unique_ptr is returned to the Caller. Caller can then check for an empty unique_ptr with if (!myuniqueptr) { handle_error() }
. The libusb error code is not available to the Caller.LibusbDeviceList{context}
, std::make_unique<LibusbDeviceList>(context)
, etc.mvLog()
entry. Should that be in the wrapper? Or should the Caller do it withcatch() { mvLog("had an error: " + myexception.what()); }
https://github.com/diablodale/XLink/commit/461e30ad4fbb437e6ec9dfd7df1237b326a22ea3 adds the Constructor-approach. I think I like this Constructor-approach more. It feels more "STL" where containers are created with constructors (not factories).
However, I also updated the Factory-approach to be non-throwing. The Caller does not need try/catch and can always test the result with if (!myuniqueptr) { handle_error() }
Any feedback on which approach is preferred?
added PR to fix this issue. I need a few questions answered in the PR to move further. :-)
I've pushed the last commit to draft PR above. It includes markdown and mermaid documentation for usage and object model for the libusb wrapper. Its really quite simple. 🔢 This wrapper replaces much of the old Xlink C-style code for its usb transport and fixes this issue.
Moving forward, this issue's fixes and more will usually be in my fork at https://github.com/diablodale/XLink/ I'll leave this issue open as the Luxonis fork does not have any fixes for this issue's crashes.
Xlink can easily crash due to the newer C++ code within it yet having no exception handling.
For example, the file
usb_host.cpp
has a lot of C++ code in it and most of it can throw exceptions. However, there is no exception handling in functions, e.g.getUSBDevices()
, to prevent their doomed cascade upward into standard-C code...which causes an app crash/segfault. 💥Since exceptions can be throw by trivial uses like
std::string(...)
orcontainer::at()
, I recommend that the top-level functions in all cpp files be markednoexcept
. Then add try/catch to all needed places to catch any exceptions and return relevant error codes instead. All modern editors like vscode and analyzers provide clear feedback of functions marked noexcept yet calling things which can throw.Setup
Repro
usb_host.cpp
and insert as the first line of the functiongetUSBDevices()
the following:throw std::runtime_error("crash me");
tests/color_camera_node_test
Result
App immediately crashes.
Expected
App somehow gracefully fails, in this case it should report it could find no usb devices.