diff --git a/cxplat/cxplat_test/cxplat_size_test.cpp b/cxplat/cxplat_test/cxplat_size_test.cpp index a71b41d..4bcc069 100644 --- a/cxplat/cxplat_test/cxplat_size_test.cpp +++ b/cxplat/cxplat_test/cxplat_size_test.cpp @@ -6,31 +6,52 @@ #else #include #endif +#include #include "cxplat.h" -TEST_CASE("cxplat_safe_size_t_multiply", "[size]") +template +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::is_signed ? std::numeric_limits::lowest() : static_cast(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(3), static_cast(5), &result) == \ + CXPLAT_STATUS_SUCCESS); \ + REQUIRE(result == static_cast(15)); \ + \ + REQUIRE( \ + cxplat_safe_##name##_multiply(std::numeric_limits::max(), static_cast(2), &result) == \ + CXPLAT_STATUS_ARITHMETIC_OVERFLOW); \ + } \ + \ + TEST_CASE("cxplat_safe_" #name "_add", "[size]") \ + { \ + type result; \ + REQUIRE(cxplat_safe_##name##_add(static_cast(3), static_cast(5), &result) == \ + CXPLAT_STATUS_SUCCESS); \ + REQUIRE(result == static_cast(8)); \ + \ + REQUIRE(cxplat_safe_##name##_add(std::numeric_limits::max(), static_cast(1), &result) == \ + CXPLAT_STATUS_ARITHMETIC_OVERFLOW); \ + } \ + \ + TEST_CASE("cxplat_safe_" #name "_subtract", "[size]") \ + { \ + type result; \ + REQUIRE(cxplat_safe_##name##_subtract(static_cast(5), static_cast(3), &result) == \ + CXPLAT_STATUS_SUCCESS); \ + REQUIRE(result == static_cast(2)); \ + \ + REQUIRE(cxplat_safe_##name##_subtract( \ + cxplat_safe_integer_min_for_subtract_failure(), static_cast(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); -} \ No newline at end of file +#undef CXPLAT_DEFINE_SAFE_INTEGER_TESTS diff --git a/cxplat/inc/cxplat_size.h b/cxplat/inc/cxplat_size.h index d407426..35ac44c 100644 --- a/cxplat/inc/cxplat_size.h +++ b/cxplat/inc/cxplat_size.h @@ -2,46 +2,51 @@ // SPDX-License-Identifier: MIT #pragma once +#include +#include #include 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__multiply + * - cxplat_safe__add + * - cxplat_safe__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 diff --git a/cxplat/src/cxplat_winkernel/CMakeLists.txt b/cxplat/src/cxplat_winkernel/CMakeLists.txt index 38f019f..0fb2909 100644 --- a/cxplat/src/cxplat_winkernel/CMakeLists.txt +++ b/cxplat/src/cxplat_winkernel/CMakeLists.txt @@ -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 ) diff --git a/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj b/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj index f9f7558..e3436e6 100644 --- a/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj +++ b/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj @@ -12,7 +12,7 @@ - + @@ -117,4 +117,4 @@ - \ No newline at end of file + diff --git a/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj.filters b/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj.filters index d251f3c..4308da7 100644 --- a/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj.filters +++ b/cxplat/src/cxplat_winkernel/cxplat_winkernel.vcxproj.filters @@ -21,7 +21,7 @@ Source Files - + Source Files @@ -78,4 +78,4 @@ Header Files - \ No newline at end of file + diff --git a/cxplat/src/cxplat_winkernel/size_winkernel.c b/cxplat/src/cxplat_winkernel/size_winkernel.c deleted file mode 100644 index c0f67a8..0000000 --- a/cxplat/src/cxplat_winkernel/size_winkernel.c +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation -// SPDX-License-Identifier: MIT -#include "cxplat.h" -#include - -_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) -{ - return RtlSizeTMult(multiplicand, multiplier, result) == STATUS_SUCCESS ? CXPLAT_STATUS_SUCCESS - : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} - -_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) -{ - return RtlSizeTAdd(augend, addend, result) == STATUS_SUCCESS ? CXPLAT_STATUS_SUCCESS - : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} - -_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) -{ - return RtlSizeTSub(minuend, subtrahend, result) == STATUS_SUCCESS ? CXPLAT_STATUS_SUCCESS - : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} \ No newline at end of file diff --git a/cxplat/src/cxplat_winkernel/size_winkernel.cpp b/cxplat/src/cxplat_winkernel/size_winkernel.cpp new file mode 100644 index 0000000..f862999 --- /dev/null +++ b/cxplat/src/cxplat_winkernel/size_winkernel.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT +#include "cxplat.h" + +#define ENABLE_INTSAFE_SIGNED_FUNCTIONS +#include + +#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 diff --git a/cxplat/src/cxplat_winuser/CMakeLists.txt b/cxplat/src/cxplat_winuser/CMakeLists.txt index fc20ab5..749f2f7 100644 --- a/cxplat/src/cxplat_winuser/CMakeLists.txt +++ b/cxplat/src/cxplat_winuser/CMakeLists.txt @@ -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 diff --git a/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj b/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj index ae5f872..0bb61ba 100644 --- a/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj +++ b/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj @@ -120,11 +120,11 @@ - + - \ No newline at end of file + diff --git a/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj.filters b/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj.filters index 9854f89..ced706d 100644 --- a/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj.filters +++ b/cxplat/src/cxplat_winuser/cxplat_winuser.vcxproj.filters @@ -80,7 +80,7 @@ Source Files - + Source Files @@ -99,4 +99,4 @@ Source Files - \ No newline at end of file + diff --git a/cxplat/src/cxplat_winuser/size_winuser.c b/cxplat/src/cxplat_winuser/size_winuser.c deleted file mode 100644 index 7f17876..0000000 --- a/cxplat/src/cxplat_winuser/size_winuser.c +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Microsoft Corporation -// SPDX-License-Identifier: MIT -#include "cxplat.h" -#include - -_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) -{ - return SUCCEEDED(SizeTMult(multiplicand, multiplier, result)) ? CXPLAT_STATUS_SUCCESS - : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} - -_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) -{ - return SUCCEEDED(SizeTAdd(augend, addend, result)) ? CXPLAT_STATUS_SUCCESS : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} - -_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) -{ - return SUCCEEDED(SizeTSub(minuend, subtrahend, result)) ? CXPLAT_STATUS_SUCCESS : CXPLAT_STATUS_ARITHMETIC_OVERFLOW; -} \ No newline at end of file diff --git a/cxplat/src/cxplat_winuser/size_winuser.cpp b/cxplat/src/cxplat_winuser/size_winuser.cpp new file mode 100644 index 0000000..c0c23f2 --- /dev/null +++ b/cxplat/src/cxplat_winuser/size_winuser.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation +// SPDX-License-Identifier: MIT +#include "cxplat.h" + +#define ENABLE_INTSAFE_SIGNED_FUNCTIONS +#include + +#define CXPLAT_INTSAFE_OPERATION(stem, operation) CXPLAT_INTSAFE_OPERATION_(stem, operation) +#define CXPLAT_INTSAFE_OPERATION_(stem, operation) 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 SUCCEEDED(CXPLAT_INTSAFE_OPERATION(intsafe_name, Mult)(multiplicand, multiplier, result)) \ + ? 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 SUCCEEDED(CXPLAT_INTSAFE_OPERATION(intsafe_name, Add)(augend, addend, result)) \ + ? 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 SUCCEEDED(CXPLAT_INTSAFE_OPERATION(intsafe_name, Sub)(minuend, subtrahend, result)) \ + ? 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_INTSAFE_OPERATION_ +#undef CXPLAT_INTSAFE_OPERATION