Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions include/wil/safecast.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ namespace details

// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
_Out_range_(==, var) NewT safe_cast_failfast(const OldT var)
{
NewT newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
Expand All @@ -274,7 +274,7 @@ NewT safe_cast_failfast(const OldT var)

// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
_Out_range_(==, var) NewT safe_cast_failfast(const OldT var)
{
NewT newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
Expand All @@ -283,7 +283,7 @@ NewT safe_cast_failfast(const OldT var)

// Unsafe conversion where failure results in fail fast.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
_Out_range_(==, var) NewT safe_cast_failfast(const OldT var)
{
unsigned short newVar;
FAIL_FAST_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
Expand All @@ -292,15 +292,15 @@ NewT safe_cast_failfast(const OldT var)

// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_failfast(const OldT var)
_Out_range_(==, var) NewT safe_cast_failfast(const OldT var)
{
return static_cast<NewT>(var);
}

#ifdef WIL_ENABLE_EXCEPTIONS
// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
_Out_range_(==, var) NewT safe_cast(const OldT var)
{
NewT newVar;
THROW_IF_FAILED((details::intsafe_conversion<OldT, NewT>(var, &newVar)));
Expand All @@ -309,7 +309,7 @@ NewT safe_cast(const OldT var)

// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
_Out_range_(==, var) NewT safe_cast(const OldT var)
{
NewT newVar;
THROW_IF_FAILED((details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), &newVar)));
Expand All @@ -318,7 +318,7 @@ NewT safe_cast(const OldT var)

// Unsafe conversion where failure results in a thrown exception.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
_Out_range_(==, var) NewT safe_cast(const OldT var)
{
unsigned short newVar;
THROW_IF_FAILED((details::intsafe_conversion<OldT, unsigned short>(var, &newVar)));
Expand All @@ -327,43 +327,43 @@ NewT safe_cast(const OldT var)

// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast(const OldT var)
_Out_range_(==, var) NewT safe_cast(const OldT var)
{
return static_cast<NewT>(var);
}
#endif

// This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_nothrow(const OldT /*var*/)
_Out_range_(==, _Param_(1)) NewT safe_cast_nothrow(const OldT /*var*/)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, if this is absent, does the analyzer error still trigger? This is a static assert that should always fire (and if it doesn't, the function doesn't have a return statement and should warn). Just curious if the analyzer is smart enough to determine the correct overload.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This variant wasn't part of the false positive. I included the annotation for completeness. It probably isn't necessary but it also doesn't hurt to include.

{
static_assert(!wistd::is_same_v<NewT, NewT>, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead");
}

// This conversion is always safe, therefore a static_cast is fine.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
NewT safe_cast_nothrow(const OldT var)
_Out_range_(==, var) NewT safe_cast_nothrow(const OldT var)
{
return static_cast<NewT>(var);
}

// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_no_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
_At_(*newTResult, _Out_range_(==, var)) HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<OldT, NewT>(var, newTResult);
}

// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_from_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
_At_(*newTResult, _Out_range_(==, var)) HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<unsigned short, NewT>(static_cast<unsigned short>(var), newTResult);
}

// Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_unsafe_cast_to_wchar_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
_At_(*newTResult, _Out_range_(==, var)) HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
return details::intsafe_conversion<OldT, unsigned short>(var, reinterpret_cast<unsigned short*>(newTResult));
}
Expand All @@ -372,7 +372,7 @@ HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
// does not involve a variably sized type, then the compilation will fail and say the single parameter version
// of safe_cast_nothrow should be used instead.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_supported_safe_static_cast_v<NewT, OldT>, int> = 0>
HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
_At_(*newTResult, _Out_range_(==, var)) HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
{
static_assert(
details::is_potentially_variably_sized_cast_v<OldT, NewT>,
Expand All @@ -389,7 +389,7 @@ HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult)
// wil::safe_zero_extending_cast<ULONG_PTR>(-1)
// will return 0x00000000`FFFFFFFF on a 64-bit system.
template <typename NewT, typename OldT, wistd::enable_if_t<details::is_sign_extending_cast_v<NewT, OldT>, int> = 0>
NewT safe_zero_extending_cast(const OldT var)
_Out_range_(==, var) NewT safe_zero_extending_cast(const OldT var)
{
// The first cast is to an unsigned type of the same size as the original. The second cast is to the
// larger type. Being an unsigned cast, the upper bits are zeroed out.
Expand Down