Skip to content

Conversation

@DefaultRyan
Copy link
Member

A code analysis warning recently fired for a customer on detach_abi(com_array). This function returns a std::pair<uint32_t, some_pointer_type>, which will have, on 64-bit builds, 4 bytes of padding between the uint32 size and the pointer members. Currently, that padding is uninitialized.

The idea behind the code analysis warning is that information may be leaked via those unitialized bytes.

In practice, that's almost never going to be an issue for this function, because the std::pair is not an interesting object to pass around, and only exists as a convenience to return both the size and buffer of the com_array at the same time.

However, the fix removes a pain point for a customer, is simple, risk-free, and actually gets optimized away in the 99% use case (return value stored in a local variable, access only the first/second members, not the padding bytes). Demo showing optimization: https://godbolt.org/z/T4vPhMKxn

A code analysis warning recently fired for a customer on detach_abi(com_array<T>). This function returns a std::pair<uint32_t, some_pointer_type>, which will have, on 64-bit builds, 4 bytes of padding between the uint32 size and the pointer members. Currently, that padding is uninitialized.

The idea behind the code analysis warning is that information may be leaked via those unitialized bytes.

In practice, that's almost never going to be an issue for this function, because the std::pair is not an interesting object to pass around, and only exists as a convenience to return both the size and buffer of the com_array at the same time.

However, the fix removes a pain point for a customer, is simple, risk-free, and actually gets optimized away in the 99% use case (return value stored in a local variable, access only the first/second members, not the padding bytes).  Demo showing optimization: https://godbolt.org/z/T4vPhMKxn
@DefaultRyan DefaultRyan requested a review from kennykerr July 6, 2022 18:56
@DefaultRyan
Copy link
Member Author

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@DefaultRyan DefaultRyan merged commit f65801e into master Jul 6, 2022
@DefaultRyan DefaultRyan deleted the user/defaultryan/com_array_abi_padding branch July 6, 2022 21:05
alvinhochun added a commit to alvinhochun/cppwinrt that referenced this pull request Dec 29, 2022
`detach_abi(com_array<T>&)` uses two `memset` calls to zero two objects,
one is an `std::pair` (from [microsoft#1165]), the other is a `winrt::com_array`
(to clear its data pointer to prevent its destructor from freeing the
array). GCC rightfully warns about this because these types are not
trivially copyable, so calling memset on it is UB.

This change fixes the UB and the GCC warning by reverting the first
`memset` back to using the `std::pair` constructor as before [microsoft#1165],
and changing the second `memset` to setting the member fields directly.
Since this requires access to protected members, the function body is
moved into a private member function, then the `winrt::detach_abi` free
function is made `friend` of `com_array` to allow it to call the member
function.

This fix is not applied when `_MSC_VER` is defined in order to preserve
the current behaviour on MSVC, in case [microsoft#1165] is still relevant.

[microsoft#1165]: microsoft#1165
alvinhochun added a commit to alvinhochun/cppwinrt that referenced this pull request Dec 29, 2022
`detach_abi(com_array<T>&)` uses two `memset` calls to zero two objects,
one is an `std::pair` (from [microsoft#1165]), the other is a `winrt::com_array`
(to clear its data pointer to prevent its destructor from freeing the
array). GCC rightfully warns about this because these types are not
trivially copyable, so calling memset on it is UB.

This change fixes the UB and the GCC warning by reverting the first
`memset` back to using the `std::pair` constructor as before [microsoft#1165],
and changing the second `memset` to setting the member fields directly.
Since this requires access to protected members, the function body is
moved into a private member function, then the `winrt::detach_abi` free
function is made `friend` of `com_array` to allow it to call the member
function.

This fix is not applied when `_MSC_VER` is defined in order to preserve
the current behaviour on MSVC, in case [microsoft#1165] is still relevant.

[microsoft#1165]: microsoft#1165
alvinhochun added a commit to alvinhochun/cppwinrt that referenced this pull request Dec 29, 2022
`detach_abi(com_array<T>&)` uses two `memset` calls to zero two objects,
one is an `std::pair` (from [microsoft#1165]), the other is a `winrt::com_array`
(to clear its data pointer to prevent its destructor from freeing the
array). GCC rightfully warns about this because these types are not
trivially copyable, so calling memset on it is UB.

This change fixes the UB and the GCC warning by reverting the first
`memset` back to using the `std::pair` constructor as before [microsoft#1165],
and changing the second `memset` to setting the member fields directly.
Since this requires access to protected members, the function body is
moved into a private member function, then the `winrt::detach_abi` free
function is made `friend` of `com_array` to allow it to call the member
function.

This fix is not applied when `_MSC_VER` is defined in order to preserve
the current behaviour on MSVC, in case [microsoft#1165] is still relevant.

[microsoft#1165]: microsoft#1165
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants