microsoft / microsoft/cppwinrt

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

Open
#1,568 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
1.9k
Forks
281
PR merge metrics
No merged PRs in 30d

Description

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:

[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).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the provided CMakeLists.txt and test.cpp, building the reproducible x86 Release example with GCC 14.2. Inspect the reported strict-aliasing warnings in winrt/base.h and winrt/Windows.Foundation.h, including the _WIN64 branch for comparison. Done means the example builds without these warnings while preserving the existing behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
cmake, cpp
Domain
compilers, operating-systems
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.