I found this structure definition used to handle detection of process changes in Linux:
struct __attribute__((aligned(NLMSG_ALIGNTO))) event_message {
nlmsghdr f_nl_hdr;
struct __attribute__((__packed__)) {
cn_msg f_cn_msg;
proc_event f_proc_ev;
} f_nl_msg;
};
That worked great.
Now that I'm moving forward to newer versions of the C++ compiler (g++12.2.0 as found in Ubuntu 23.04), I get an error saying that the flexible array member __u8 data[], found in cn_msg, is not the last member as it ought to be:
/usr/include/linux/connector.h: In member function ‘void ed::process_changed::listen_for_events()’: /usr/include/linux/connector.h:78:14: error: flexible array member ‘cn_msg::data’ not at end of ‘struct ed::process_changed::listen_for_events()::multicast_message’ 78 | __u8 data[]; | ^~~~
At the moment, I can't think of anything other than the following which adds a malloc():
Computing the total size:
constexpr std::size_t size(sizeof(nlmsghdr) + sizeof(cn_msg) + sizeof(proc_event));Creating a simple buffer of
uint8_t:std::vector<std::uint8_t> buffer(std::vector<std::uint8_t>(size));And finally casting each location to the corresponding structure:
nlmsghdr * header = reinterpret_cast<nlmsghr *>(buffer.data()); cn_msg * msg = reinterpret_cast<cn_msg *>(header + 1); proc_event * event = reinterpret_cast<proc_event(msg + 1);Note: reading the
reinterpret_cast<T>()documentation, I do not think that these are UB because they match (currently) case 5 which says it is exactly equivalent tostatic_cast<cv T2*>(static_cast<cv void*>(expression))and that is 100% safe as long asT1*(type of expression) has the same alignment requirements asT2*(and of course the bytes at locationT2*represent a structure of typeT2).
But that looks rather ugly and prone to many mistakes.
What other solution would there be to handle this situation?
Also correct me if I'm wrong, it does not look like this is a warning (I do use -Werror because so many warnings are errors, but could use a #pragma to cancel this one if it were a warning).
Note 1: I will not consider redefining the structures. Using the files found in /usr/include is important to make sure the current version of the system is used.
Note 2: The library is very specific to Linux and the code is not expected to run on other systems than Ubuntu compiling with g++. So portability is not an issue outside of that.