nana: undefined behaviour - many violations of strict aliasing

All of these reinterpret_casts are undefined behaviour:

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/source/gui/programming_interface.cpp#L297-L310

owner and parent arguments are of type window which is:

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/include/nana/gui/basis.hpp#L90-L93

which is:

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/include/nana/gui/basis.hpp#L25-L31

The other side of casts is basic_window which is

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/include/nana/gui/detail/basic_window.hpp#L83-L84

which is a separate class that does not share any ancestors in it’s inheritance tree with detail::window_handle_impl

Therefore, the dereference of pointers coming from casts between detail::window_handle_impl* and basic_window* is undefined behaviour.


This issue is probably related to #445 because:

  • the intialization path practically always goes through this code (in order to create a window)
  • the code does not crash without link-time optimization (used -flto -fno-fat-lto-objects) (this suggests that crucial violations are probably across source-file/function boundary)
  • some minimal examples do not crash when compiled with -fno-strict-aliasing

Other notes:

  • there are many more suspicious reinterpret_casts in the repository, all of them should be checked; total 684 casts in the project as reported by grep -r reinterpret_cast
  • compilers can not validate strict aliasing at compile time, in majority of non-trivial cases there are no warnings
  • GCC 8.3 with -Wstrict-aliasing=2 or -Wstict-aliasing=1 on this project catches only a small number of only possible strict aliasing violations
nana\source\system\dataexch.cpp:73:72: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
    if (::GetDIBits(hDC, (HBITMAP)g.pixmap(), 0, 1, NULL, (BITMAPINFO *)&bmi, DIB_RGB_COLORS) == 0) {
                                                                        ^~~~
nana\source\paint\graphics.cpp: In member function 'void nana::paint::graphics::make(const nana::size&)':
nana\source\paint\graphics.cpp:349:90: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
     HBITMAP bmp = ::CreateDIBSection(cdc, &bmi, DIB_RGB_COLORS, reinterpret_cast<void**>(&(dw->pixbuf_ptr)), 0, 0);
                                                                                          ^~~~~~~~~~~~~~~~~
nana\source\paint\graphics.cpp: In member function 'void nana::paint::graphics::save_as_file(const char*) const':
nana\source\paint\graphics.cpp:1079:98: warning: dereferencing type-punned pointer might break strict-aliasing rules [-Wstrict-aliasing]
     HBITMAP hBmp = ::CreateDIBSection(hdcMem, &bmpInfo, DIB_RGB_COLORS, reinterpret_cast<void**>(&pData), 0, 0);
                                                                                                  ^~~~~~

This is guuaranteed to crash given powerful enough optimizer (the last line violates both type aliasing rules and type alignment requirements):

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/source/paint/detail/image_bmp.hpp#L79-L85

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 1
  • Comments: 26 (13 by maintainers)

Commits related to this issue

Most upvoted comments

Can do some PRs. … Should not be hard to fix.

waiting…

Hi @Xeverous , still wating for your ideas about how to make the code better…

But detail::window_handle_impl is an incomplete type.

It is complete. These are not forward declarations:

https://github.com/cnjinhao/nana/blob/ffa170b5f560dbf899030bdeb0e539aa95b03649/include/nana/gui/basis.hpp#L25-L31

Note that the completeness has no meaning for strict aliasing.

alignof(basic_window*) <= alignof(window) is guaranteed

My typo in previous comment - alignment not of pointers but of pointed types should be compared. So alignof(basic_window) <= alignof(detail::native_window_impl)

window is a pointer of an incomplete type

It is not, even more - you can not query the alignment of an incomplete type.


Right now you are trying to defend the current implementation. Please stop it. There is no place for reinterpret_casts outside dealing with bit representation (ie when reading encoded file formats) or reading raw memory for debug purposes. Object-oriented code that relies on reinterpretation casts will be broken. It would be much better to think how to refactor and correctly hide the API using forward declarations or detail namespace. C++ type system exists for a reason, don’t try to defend code that breaks it.