Skip to content

Bug: GCC warns about breaking strict-aliasing rules for 32-bit builds #1568

@danpla

Description

@danpla

Version

v2.0.250303.1

Summary

When I build my project for x86 (32-bit) with GCC 14.2.0 (MSYS2) in release mode, I get warnings dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing] for winrt/base.h:

[...]winrt/base.h: In member function 'void winrt::impl::factory_cach
e_entry_base::clear()':
[...]winrt/base.h:6357:86: warning: dereferencing type-punned pointer
 will break strict-aliasing rules [-Wstrict-aliasing]
 6357 |             int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_
t*)&current_value);
[...]winrt/base.h:6359:28: warning: dereferencing type-punned pointer
 will break strict-aliasing rules [-Wstrict-aliasing]
 6359 |             if (result == *(int64_t*)&current_value)
[...]winrt/Windows.Foundation.h:173:43: warning: dereferencing type-p
unned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  173 |             auto const _winrt_abi_type = *(abi_t<winrt::Windows::Foundation::IAsyncInfo>**)&
_winrt_casted_result;
[...]winrt/Windows.Foundation.h:2498:102: warning: dereferencing type
-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
 2498 |             (*this)(*reinterpret_cast<winrt::Windows::Foundation::IAsyncAction const*>(&asyn
cInfo), *reinterpret_cast<winrt::Windows::Foundation::AsyncStatus const*>(&asyncStatus));

The problematic code in base.h is:

#if defined _WIN64
#if defined(__GNUC__)
            bool exchanged = __sync_bool_compare_and_swap((__int128*)this, *(__int128*)&current_value, (__int128)0);
#else
            bool exchanged = 1 == _InterlockedCompareExchange128((int64_t*)this, 0, 0, (int64_t*)&current_value);
#endif
            if (exchanged)
            {
                pointer_value->Release();
            }
#else
            int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_t*)&current_value);

            if (result == *(int64_t*)&current_value)
            {
                pointer_value->Release();
            }
#endif

Unlike base.h, the problematic code from Windows.Foundation.h doesn't seem to be architecture-specific (no _WIN64 and other macros).

Reproducible example

Save the following CMakeLists.txt and test.cpp to the same directory and run:

cmake -DCMAKE_BUILD_TYPE=Release -DWINRT_INCLUDE_DIR=<your-path-here> -B build
cmake --build build

CMakeLists.txt:

cmake_minimum_required(VERSION 3.22)

project(test)

add_executable(test test.cpp)

set_target_properties(
    test PROPERTIES
    CXX_STANDARD 20
    CXX_STANDARD_REQUIRED YES
    CXX_EXTENSIONS NO)

if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
        OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    target_compile_options(test PRIVATE -Wall -Wextra -pedantic)
endif()

target_include_directories(test PRIVATE "${WINRT_INCLUDE_DIR}")

target_link_libraries(test PRIVATE windowsapp)

test.cpp

#include <winrt/base.h>
#include <winrt/Windows.ApplicationModel.h>
#include <winrt/Windows.Foundation.h>


using namespace winrt::Windows::ApplicationModel;


int main()
{
    auto startupTask = StartupTask::GetAsync(L"id").get();
}

The full output in my case is:

Details
[1/2] Building CXX object CMakeFiles/test.dir/test.cpp.obj
In file included from [...]/test/test.cpp:1:
[...]/include/winrt/base.h: In member function 'void winrt::impl::factory_cach
e_entry_base::clear()':
[...]/include/winrt/base.h:6357:86: warning: dereferencing type-punned pointer
 will break strict-aliasing rules [-Wstrict-aliasing]
 6357 |             int64_t const result = _InterlockedCompareExchange64((int64_t*)this, 0, *(int64_
t*)&current_value);
      |                                                                                      ^~~~~~~
~~~~~~~~~~~~~~~~~
[...]/include/winrt/base.h:6359:28: warning: dereferencing type-punned pointer
 will break strict-aliasing rules [-Wstrict-aliasing]
 6359 |             if (result == *(int64_t*)&current_value)
      |                            ^~~~~~~~~~~~~~~~~~~~~~~~
In file included from [...]/test/test.cpp:3:
[...]/include/winrt/Windows.Foundation.h: In instantiation of 'auto winrt::imp
l::consume_Windows_Foundation_IAsyncInfo<D>::Status() const [with D = winrt::Windows::Foundation::IA
syncAction]':
[...]/include/winrt/Windows.Foundation.h:5133:35:   required from 'auto winrt:
:impl::wait_get(const Async&) [with Async = winrt::Windows::Foundation::IAsyncAction]'
 5133 |         auto status = async.Status();
      |                       ~~~~~~~~~~~~^~
[...]/include/winrt/Windows.Foundation.h:5261:23:   required from here
 5261 |         impl::wait_get(static_cast<Windows::Foundation::IAsyncAction const&>(static_cast<D c
onst&>(*this)));
      |         ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~
[...]/include/winrt/Windows.Foundation.h:173:43: warning: dereferencing type-p
unned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  173 |             auto const _winrt_abi_type = *(abi_t<winrt::Windows::Foundation::IAsyncInfo>**)&
_winrt_casted_result;
      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~
[...]/include/winrt/Windows.Foundation.h: In instantiation of 'auto winrt::imp
l::consume_Windows_Foundation_IAsyncInfo<D>::Status() const [with D = winrt::Windows::Foundation::IA
syncOperation<winrt::Windows::ApplicationModel::StartupTask>]':
[...]/include/winrt/Windows.Foundation.h:5133:35:   required from 'auto winrt:
:impl::wait_get(const Async&) [with Async = winrt::Windows::Foundation::IAsyncOperation<winrt::Windo
ws::ApplicationModel::StartupTask>]'
 5133 |         auto status = async.Status();
      |                       ~~~~~~~~~~~~^~
[...]/include/winrt/Windows.Foundation.h:5272:30:   required from 'auto winrt:
:impl::consume_Windows_Foundation_IAsyncOperation<D, TResult>::get() const [with D = winrt::Windows:
:Foundation::IAsyncOperation<winrt::Windows::ApplicationModel::StartupTask>; TResult = winrt::Window
s::ApplicationModel::StartupTask]'
 5272 |         return impl::wait_get(static_cast<Windows::Foundation::IAsyncOperation<TResult> cons
t&>(static_cast<D const&>(*this)));
      |                ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...]/test/test.cpp:11:56:   required from here
   11 |     auto startupTask = StartupTask::GetAsync(L"id").get();
      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
[...]/include/winrt/Windows.Foundation.h:173:43: warning: dereferencing type-p
unned pointer will break strict-aliasing rules [-Wstrict-aliasing]
  173 |             auto const _winrt_abi_type = *(abi_t<winrt::Windows::Foundation::IAsyncInfo>**)&
_winrt_casted_result;
      |                                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~
[...]/include/winrt/Windows.Foundation.h: In instantiation of 'int32_t winrt::
impl::delegate<winrt::Windows::Foundation::AsyncOperationCompletedHandler<TResult>, H>::Invoke(void*
, int32_t) [with H = winrt::impl::wait_for_completed<winrt::Windows::Foundation::IAsyncOperation<win
rt::Windows::ApplicationModel::StartupTask> >(const winrt::Windows::Foundation::IAsyncOperation<winr
t::Windows::ApplicationModel::StartupTask>&, uint32_t)::shared_type; TResult = winrt::Windows::Appli
cationModel::StartupTask; int32_t = int]':
[...]/include/winrt/Windows.Foundation.h:2529:27:   required from here
 2529 |         int32_t __stdcall Invoke(void* asyncInfo, int32_t asyncStatus) noexcept final try
      |                           ^~~~~~
[...]/include/winrt/Windows.Foundation.h:2531:114: warning: dereferencing type
-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
 2531 |             (*this)(*reinterpret_cast<winrt::Windows::Foundation::IAsyncOperation<TResult> c
onst*>(&asyncInfo), *reinterpret_cast<winrt::Windows::Foundation::AsyncStatus const*>(&asyncStatus))
;
      |
                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[...]/include/winrt/Windows.Foundation.h: In instantiation of 'int32_t winrt::
impl::delegate<winrt::Windows::Foundation::AsyncActionCompletedHandler, H>::Invoke(void*, int32_t) [
with H = winrt::impl::wait_for_completed<winrt::Windows::Foundation::IAsyncAction>(const winrt::Wind
ows::Foundation::IAsyncAction&, uint32_t)::shared_type; int32_t = int]':
[...]/include/winrt/Windows.Foundation.h:2496:27:   required from here
 2496 |         int32_t __stdcall Invoke(void* asyncInfo, int32_t asyncStatus) noexcept final try
      |                           ^~~~~~
[...]/include/winrt/Windows.Foundation.h:2498:102: warning: dereferencing type
-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
 2498 |             (*this)(*reinterpret_cast<winrt::Windows::Foundation::IAsyncAction const*>(&asyn
cInfo), *reinterpret_cast<winrt::Windows::Foundation::AsyncStatus const*>(&asyncStatus));
      |
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[2/2] Linking CXX executable test.exe

Expected behavior

No response

Actual behavior

No response

Additional comments

I haven't tried compiling for 64 bit, but it's possible that similar warnings would appear in that case (in particular, the code in base.h intended for _WIN64 uses similar pointer dereferencing).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions