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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions