Skip to content
Merged
Show file tree
Hide file tree
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
63 changes: 42 additions & 21 deletions cxplat/cxplat_test/cxplat_size_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,52 @@
#else
#include <catch2/catch.hpp>
#endif
#include <limits>
#include "cxplat.h"

TEST_CASE("cxplat_safe_size_t_multiply", "[size]")
template <typename T>
constexpr T
cxplat_safe_integer_min_for_subtract_failure()
{
size_t result;
REQUIRE(cxplat_safe_size_t_multiply(3, 5, &result) == CXPLAT_STATUS_SUCCESS);
REQUIRE(result == 15);

REQUIRE(cxplat_safe_size_t_multiply(SIZE_MAX, 2, &result) == CXPLAT_STATUS_ARITHMETIC_OVERFLOW);
return std::numeric_limits<T>::is_signed ? std::numeric_limits<T>::lowest() : static_cast<T>(0);
}

TEST_CASE("cxplat_safe_size_t_add", "[size]")
{
size_t result;
REQUIRE(cxplat_safe_size_t_add(3, 5, &result) == CXPLAT_STATUS_SUCCESS);
REQUIRE(result == 8);
#define CXPLAT_DEFINE_SAFE_INTEGER_TESTS(type, name, intsafe_name) \
TEST_CASE("cxplat_safe_" #name "_multiply", "[size]") \
{ \
type result; \
REQUIRE(cxplat_safe_##name##_multiply(static_cast<type>(3), static_cast<type>(5), &result) == \
CXPLAT_STATUS_SUCCESS); \
REQUIRE(result == static_cast<type>(15)); \
\
REQUIRE( \
cxplat_safe_##name##_multiply(std::numeric_limits<type>::max(), static_cast<type>(2), &result) == \
CXPLAT_STATUS_ARITHMETIC_OVERFLOW); \
} \
\
TEST_CASE("cxplat_safe_" #name "_add", "[size]") \
{ \
type result; \
REQUIRE(cxplat_safe_##name##_add(static_cast<type>(3), static_cast<type>(5), &result) == \
CXPLAT_STATUS_SUCCESS); \
REQUIRE(result == static_cast<type>(8)); \
\
REQUIRE(cxplat_safe_##name##_add(std::numeric_limits<type>::max(), static_cast<type>(1), &result) == \
CXPLAT_STATUS_ARITHMETIC_OVERFLOW); \
} \
\
TEST_CASE("cxplat_safe_" #name "_subtract", "[size]") \
{ \
type result; \
REQUIRE(cxplat_safe_##name##_subtract(static_cast<type>(5), static_cast<type>(3), &result) == \
CXPLAT_STATUS_SUCCESS); \
REQUIRE(result == static_cast<type>(2)); \
\
REQUIRE(cxplat_safe_##name##_subtract( \
cxplat_safe_integer_min_for_subtract_failure<type>(), static_cast<type>(1), &result) == \
CXPLAT_STATUS_ARITHMETIC_OVERFLOW); \
}

REQUIRE(cxplat_safe_size_t_add(SIZE_MAX, 2, &result) == CXPLAT_STATUS_ARITHMETIC_OVERFLOW);
}

TEST_CASE("cxplat_safe_size_t_subtract", "[size]")
{
size_t result;
REQUIRE(cxplat_safe_size_t_subtract(5, 3, &result) == CXPLAT_STATUS_SUCCESS);
REQUIRE(result == 2);
CXPLAT_SAFE_INTEGER_TYPE_LIST(CXPLAT_DEFINE_SAFE_INTEGER_TESTS)

REQUIRE(cxplat_safe_size_t_subtract(3, 5, &result) == CXPLAT_STATUS_ARITHMETIC_OVERFLOW);
}
#undef CXPLAT_DEFINE_SAFE_INTEGER_TESTS
67 changes: 36 additions & 31 deletions cxplat/inc/cxplat_size.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,46 +2,51 @@
// SPDX-License-Identifier: MIT
#pragma once

#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>

CXPLAT_EXTERN_C_BEGIN

/**
* @brief Multiplies one value of type size_t by another and check for
* overflow.
* @param[in] multiplicand The value to be multiplied by multiplier.
* @param[in] multiplier The value by which to multiply multiplicand.
* @param[out] result A pointer to the result.
* @retval CXPLAT_STATUS_SUCCESS The operation was successful.
* @retval CXPLAT_STATUS_ARITHMETIC_OVERFLOW Multiplication overflowed.
* @brief Supported integer types for cxplat safe arithmetic helpers.
*
* The second parameter is the public function-name stem, and the third is the
* corresponding IntSafe/NtIntSafe primitive stem.
*/
_Must_inspect_result_ cxplat_status_t
cxplat_safe_size_t_multiply(
size_t multiplicand, size_t multiplier, _Out_ _Deref_out_range_(==, multiplicand* multiplier) size_t* result);
#define CXPLAT_SAFE_INTEGER_TYPE_LIST(X) \
X(size_t, size_t, SizeT) \
X(uint8_t, uint8_t, UInt8) \
X(int8_t, int8_t, Int8) \
X(uint16_t, uint16_t, UInt16) \
X(int16_t, int16_t, Int16) \
X(uint32_t, uint32_t, UInt32) \
X(int32_t, int32_t, Int32) \
X(uint64_t, uint64_t, UInt64) \
X(int64_t, int64_t, Int64)

/**
* @brief Add one value of type size_t by another and check for
* overflow.
* @param[in] augend The value to be added by addend.
* @param[in] addend The value add to augend.
* @param[out] result A pointer to the result.
* @retval CXPLAT_STATUS_SUCCESS The operation was successful.
* @retval CXPLAT_STATUS_ARITHMETIC_OVERFLOW Addition overflowed.
* @brief Safe checked arithmetic helpers for the supported integer types.
*
* Each listed type exposes:
* - cxplat_safe_<type>_multiply
* - cxplat_safe_<type>_add
* - cxplat_safe_<type>_subtract
*
* All helpers return CXPLAT_STATUS_SUCCESS on success and
* CXPLAT_STATUS_ARITHMETIC_OVERFLOW when the operation would overflow or
* underflow.
*/
_Must_inspect_result_ cxplat_status_t
cxplat_safe_size_t_add(size_t augend, size_t addend, _Out_ _Deref_out_range_(==, augend + addend) size_t* result);
#define CXPLAT_DECLARE_SAFE_INTEGER_OPERATIONS(type, name, intsafe_name) \
_Must_inspect_result_ cxplat_status_t cxplat_safe_##name##_multiply( \
type multiplicand, type multiplier, _Out_ _Deref_out_range_(==, multiplicand * multiplier) type * result); \
_Must_inspect_result_ cxplat_status_t \
cxplat_safe_##name##_add(type augend, type addend, _Out_ _Deref_out_range_(==, augend + addend) type * result); \
_Must_inspect_result_ cxplat_status_t cxplat_safe_##name##_subtract( \
type minuend, type subtrahend, _Out_ _Deref_out_range_(==, minuend - subtrahend) type * result);

/**
* @brief Subtract one value of type size_t from another and check for
* overflow or underflow.
* @param[in] minuend The value from which subtrahend is subtracted.
* @param[in] subtrahend The value subtract from minuend.
* @param[out] result A pointer to the result.
* @retval CXPLAT_STATUS_SUCCESS The operation was successful.
* @retval CXPLAT_STATUS_ARITHMETIC_OVERFLOW Addition overflowed or underflowed.
*/
_Must_inspect_result_ cxplat_status_t
cxplat_safe_size_t_subtract(
size_t minuend, size_t subtrahend, _Out_ _Deref_out_range_(==, minuend - subtrahend) size_t* result);
CXPLAT_SAFE_INTEGER_TYPE_LIST(CXPLAT_DECLARE_SAFE_INTEGER_OPERATIONS)

#undef CXPLAT_DECLARE_SAFE_INTEGER_OPERATIONS

CXPLAT_EXTERN_C_END
1 change: 1 addition & 0 deletions cxplat/src/cxplat_winkernel/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_library(cxplat_winkernel STATIC
module_winkernel.c
processor_winkernel.c
rundown_winkernel.c
size_winkernel.cpp
time_winkernel.c
workitem_winkernel.c
)
Expand Down
4 changes: 2 additions & 2 deletions cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<ClCompile Include="module_winkernel.c" />
<ClCompile Include="processor_winkernel.c" />
<ClCompile Include="rundown_winkernel.c" />
<ClCompile Include="size_winkernel.c" />
<ClCompile Include="size_winkernel.cpp" />
<ClCompile Include="time_winkernel.c" />
<ClCompile Include="workitem_winkernel.c" />
</ItemGroup>
Expand Down Expand Up @@ -117,4 +117,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<ClCompile Include="memory_winkernel.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="size_winkernel.c">
<ClCompile Include="size_winkernel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rundown_winkernel.c">
Expand Down Expand Up @@ -78,4 +78,4 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
</Project>
27 changes: 0 additions & 27 deletions cxplat/src/cxplat_winkernel/size_winkernel.c

This file was deleted.

40 changes: 40 additions & 0 deletions cxplat/src/cxplat_winkernel/size_winkernel.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) Microsoft Corporation
// SPDX-License-Identifier: MIT
#include "cxplat.h"

#define ENABLE_INTSAFE_SIGNED_FUNCTIONS
#include <ntintsafe.h>

#define CXPLAT_NTINTSAFE_OPERATION(stem, operation) CXPLAT_NTINTSAFE_OPERATION_(stem, operation)
#define CXPLAT_NTINTSAFE_OPERATION_(stem, operation) Rtl##stem##operation

#define CXPLAT_DEFINE_SAFE_INTEGER_OPERATIONS(type, name, intsafe_name) \
_Must_inspect_result_ cxplat_status_t cxplat_safe_##name##_multiply( \
type multiplicand, type multiplier, _Out_ _Deref_out_range_(==, multiplicand * multiplier) type * result) \
{ \
return CXPLAT_NTINTSAFE_OPERATION(intsafe_name, Mult)(multiplicand, multiplier, result) == STATUS_SUCCESS \
? CXPLAT_STATUS_SUCCESS \
: CXPLAT_STATUS_ARITHMETIC_OVERFLOW; \
} \
\
_Must_inspect_result_ cxplat_status_t \
cxplat_safe_##name##_add(type augend, type addend, _Out_ _Deref_out_range_(==, augend + addend) type * result) \
{ \
return CXPLAT_NTINTSAFE_OPERATION(intsafe_name, Add)(augend, addend, result) == STATUS_SUCCESS \
? CXPLAT_STATUS_SUCCESS \
: CXPLAT_STATUS_ARITHMETIC_OVERFLOW; \
} \
\
_Must_inspect_result_ cxplat_status_t cxplat_safe_##name##_subtract( \
type minuend, type subtrahend, _Out_ _Deref_out_range_(==, minuend - subtrahend) type * result) \
{ \
return CXPLAT_NTINTSAFE_OPERATION(intsafe_name, Sub)(minuend, subtrahend, result) == STATUS_SUCCESS \
? CXPLAT_STATUS_SUCCESS \
: CXPLAT_STATUS_ARITHMETIC_OVERFLOW; \
}

CXPLAT_SAFE_INTEGER_TYPE_LIST(CXPLAT_DEFINE_SAFE_INTEGER_OPERATIONS)

#undef CXPLAT_DEFINE_SAFE_INTEGER_OPERATIONS
#undef CXPLAT_NTINTSAFE_OPERATION_
#undef CXPLAT_NTINTSAFE_OPERATION
2 changes: 1 addition & 1 deletion cxplat/src/cxplat_winuser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ add_library(cxplat_winuser STATIC
module_winuser.cpp
processor_winuser.cpp
rundown_winuser.cpp
size_winuser.c
size_winuser.cpp
workitem_winuser.cpp
symbol_decoder.h
time_winuser.cpp
Expand Down
4 changes: 2 additions & 2 deletions cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,11 @@
<ClCompile Include="module_winuser.cpp" />
<ClCompile Include="processor_winuser.cpp" />
<ClCompile Include="rundown_winuser.cpp" />
<ClCompile Include="size_winuser.c" />
<ClCompile Include="size_winuser.cpp" />
<ClCompile Include="time_winuser.cpp" />
<ClCompile Include="workitem_winuser.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
4 changes: 2 additions & 2 deletions cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<ClCompile Include="..\memory.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="size_winuser.c">
<ClCompile Include="size_winuser.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="rundown_winuser.cpp">
Expand All @@ -99,4 +99,4 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>
</Project>
25 changes: 0 additions & 25 deletions cxplat/src/cxplat_winuser/size_winuser.c

This file was deleted.

Loading