From 0838b7ab753b64b0bd773ed601a20b81c9c8c385 Mon Sep 17 00:00:00 2001 From: Michael Platings Date: Thu, 8 Feb 2024 17:01:00 +0000 Subject: [PATCH] Add checks for misaligned pointers & strides Update the documentation with alignment requirements. See SEI CERT EXP36-C [1] To reduce the chance of code being written that creates such undefined behaviour in future, add a check to the CI script to run tests with sanitizers enabled. To increase the chance that any alignment problems will become evident during testing, deliberately weaken the alignment of the storage created by the Array2D test class. [1] https://wiki.sei.cmu.edu/confluence/display/c/EXP36-C.+Do+not+cast+pointers+into+more+strictly+aligned+pointer+types --- adapters/opencv/intrinsiccv_hal.cpp | 4 ++ intrinsiccv/include/ctypes.h | 2 + intrinsiccv/include/intrinsiccv.h | 53 +++++++++++++---- intrinsiccv/include/types.h | 20 ------- intrinsiccv/include/utils.h | 58 +++++++++++++++++-- intrinsiccv/src/analysis/canny_neon.cpp | 8 ++- .../src/analysis/count_nonzeros_neon.cpp | 16 ++--- intrinsiccv/src/analysis/min_max_loc_neon.cpp | 2 +- intrinsiccv/src/analysis/min_max_neon.cpp | 2 +- intrinsiccv/src/arithmetics/absdiff_neon.cpp | 4 +- intrinsiccv/src/arithmetics/absdiff_sme2.cpp | 4 +- intrinsiccv/src/arithmetics/absdiff_sve2.cpp | 4 +- .../add_abs_with_threshold_neon.cpp | 4 +- .../arithmetics/add_abs_with_threshold_sc.h | 4 +- intrinsiccv/src/arithmetics/add_neon.cpp | 4 +- intrinsiccv/src/arithmetics/add_sme2.cpp | 4 +- intrinsiccv/src/arithmetics/add_sve2.cpp | 4 +- intrinsiccv/src/arithmetics/multiply_neon.cpp | 4 +- intrinsiccv/src/arithmetics/multiply_sve2.cpp | 4 +- intrinsiccv/src/arithmetics/scale_neon.cpp | 3 +- intrinsiccv/src/arithmetics/sub_neon.cpp | 4 +- intrinsiccv/src/arithmetics/sub_sme2.cpp | 4 +- intrinsiccv/src/arithmetics/sub_sve2.cpp | 4 +- .../src/arithmetics/threshold_neon.cpp | 3 +- intrinsiccv/src/arithmetics/threshold_sc.h | 3 +- .../src/arithmetics/transpose_neon.cpp | 38 ++++++------ .../src/conversions/gray_to_rgb_neon.cpp | 6 +- intrinsiccv/src/conversions/gray_to_rgb_sc.h | 6 +- intrinsiccv/src/conversions/merge_neon.cpp | 32 ++++++---- .../src/conversions/rgb_to_rgb_api.cpp | 6 +- .../src/conversions/rgb_to_rgb_neon.cpp | 18 ++++-- intrinsiccv/src/conversions/rgb_to_rgb_sc.h | 18 ++++-- intrinsiccv/src/conversions/split_neon.cpp | 33 ++++++----- .../src/conversions/yuv_to_rgb_neon.cpp | 4 +- intrinsiccv/src/conversions/yuv_to_rgb_sc.h | 4 +- .../src/filters/gaussian_blur_neon.cpp | 4 +- intrinsiccv/src/filters/gaussian_blur_sc.h | 4 +- intrinsiccv/src/filters/sobel_neon.cpp | 6 +- intrinsiccv/src/filters/sobel_sc.h | 6 +- .../src/morphology/morphology_neon.cpp | 8 ++- intrinsiccv/src/morphology/morphology_sc.h | 8 ++- intrinsiccv/src/resize/resize_neon.cpp | 3 +- intrinsiccv/src/resize/resize_sc.h | 3 +- scripts/ci.sh | 7 +++ test/api/test_canny.cpp | 14 +++++ test/api/test_count_nonzeros.cpp | 12 ++++ test/api/test_gaussian_blur.cpp | 29 ++++++++++ test/api/test_merge.cpp | 56 ++++++++++++++++++ test/api/test_min_max.cpp | 11 ++++ test/api/test_morphology.cpp | 34 +++++++++++ test/api/test_saturating_absdiff.cpp | 20 +++++++ test/api/test_saturating_add.cpp | 20 +++++++ test/api/test_saturating_multiply.cpp | 20 +++++++ test/api/test_saturating_sub.cpp | 20 +++++++ test/api/test_scale.cpp | 14 +++++ test/api/test_sobel.cpp | 32 ++++++++++ test/api/test_split.cpp | 56 ++++++++++++++++++ test/api/test_threshold_binary.cpp | 21 ++++++- test/api/test_transpose.cpp | 24 ++++++++ test/framework/array.h | 37 +++++++----- test/framework/test_array2d.cpp | 9 ++- 61 files changed, 713 insertions(+), 156 deletions(-) diff --git a/adapters/opencv/intrinsiccv_hal.cpp b/adapters/opencv/intrinsiccv_hal.cpp index df01e32ce..cb75119b1 100644 --- a/adapters/opencv/intrinsiccv_hal.cpp +++ b/adapters/opencv/intrinsiccv_hal.cpp @@ -32,6 +32,10 @@ static int convert_error(intrinsiccv_error_t e) { return CV_HAL_ERROR_OK; case INTRINSICCV_ERROR_NOT_IMPLEMENTED: return CV_HAL_ERROR_NOT_IMPLEMENTED; + // Even if IntrinsicCV returns this error it's possible that another + // implementation could handle the misalignment. + case INTRINSICCV_ERROR_ALIGNMENT: + return CV_HAL_ERROR_NOT_IMPLEMENTED; default: return CV_HAL_ERROR_UNKNOWN; } diff --git a/intrinsiccv/include/ctypes.h b/intrinsiccv/include/ctypes.h index 41494c38f..32ed71329 100644 --- a/intrinsiccv/include/ctypes.h +++ b/intrinsiccv/include/ctypes.h @@ -31,6 +31,8 @@ typedef enum INTRINSICCV_NODISCARD { INTRINSICCV_ERROR_RANGE, /// Could not allocate memory. INTRINSICCV_ERROR_ALLOCATION, + /// A value did not meet alignment requirements. + INTRINSICCV_ERROR_ALIGNMENT, } intrinsiccv_error_t; typedef struct { diff --git a/intrinsiccv/include/intrinsiccv.h b/intrinsiccv/include/intrinsiccv.h index 91471de6d..a2804f1b6 100644 --- a/intrinsiccv/include/intrinsiccv.h +++ b/intrinsiccv/include/intrinsiccv.h @@ -47,13 +47,16 @@ extern "C" { /// @param src_b Pointer to the second source data. Must be non-null. /// @param src_a_stride Distance in bytes from the start of one row to the /// start of the next row for the first source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param src_b_stride Distance in bytes from the start of one row to the /// start of the next row for the second source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. @@ -86,13 +89,16 @@ INTRINSICCV_BINARY_OP(intrinsiccv_saturating_add_u64, uint64_t); /// @param src_b Pointer to the second source data. Must be non-null. /// @param src_a_stride Distance in bytes from the start of one row to the /// start of the next row for the first source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param src_b_stride Distance in bytes from the start of one row to the /// start of the next row for the second source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. @@ -125,13 +131,16 @@ INTRINSICCV_BINARY_OP(intrinsiccv_saturating_sub_u64, uint64_t); /// @param src_b Pointer to the second source data. Must be non-null. /// @param src_a_stride Distance in bytes from the start of one row to the /// start of the next row for the first source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param src_b_stride Distance in bytes from the start of one row to the /// start of the next row for the second source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. @@ -158,13 +167,16 @@ INTRINSICCV_BINARY_OP(intrinsiccv_saturating_absdiff_s32, int32_t); /// @param src_b Pointer to the second source data. Must be non-null. /// @param src_a_stride Distance in bytes from the start of one row to the /// start of the next row for the first source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param src_b_stride Distance in bytes from the start of one row to the /// start of the next row for the second source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. @@ -555,10 +567,12 @@ intrinsiccv_error_t intrinsiccv_yuv_sp_to_bgra_u8( /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row for the source data. Must /// not be less than width * sizeof(type). +/// Must be a multiple of sizeof(type). /// @param dst Pointer to the first destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. Must /// not be less than width * sizeof(type). +/// Must be a multiple of sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. /// @param threshold The value that the elements of the source data are @@ -591,6 +605,7 @@ intrinsiccv_error_t intrinsiccv_erode_u8( /// @param src Pointer to the source data. Must be non-null. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row for the source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. @@ -625,12 +640,14 @@ intrinsiccv_error_t intrinsiccv_count_nonzeros_u8(const uint8_t *src, /// @param src Pointer to the source data. Must be non-null. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row for the source data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param src_width Number of elements in the source row. /// @param src_height Number of rows in the source data. /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of sizeof(type). /// Must not be less than width * sizeof(type). /// @param dst_width Number of elements in the destination row. /// Should be src_width / 2 for even src_width. @@ -661,11 +678,13 @@ intrinsiccv_error_t intrinsiccv_resize_to_quarter_u8( /// @param src Pointer to the source data. Must be non-null. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row in the source data. Must not be -/// less than width * sizeof(type) * channels. +/// less than width * sizeof(src type) * channels. +/// Must be a multiple of sizeof(src type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row in the destination data. Must not -/// be less than width * sizeof(type) * channels. +/// be less than width * sizeof(dst type) * channels. +/// Must be a multiple of sizeof(dst type). /// @param width Number of pixels in the data. (One pixel consists of /// 'channels' number of elements.) /// @param height Number of rows in the data. @@ -691,11 +710,13 @@ intrinsiccv_error_t intrinsiccv_sobel_3x3_vertical_s16_u8( /// @param src Pointer to the source data. Must be non-null. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row in the source data. Must not be -/// less than width * sizeof(type) * channels. +/// less than width * sizeof(src type) * channels. +/// Must be a multiple of sizeof(src type). /// @param dst Pointer to the destination data. Must be non-null. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row in the destination data. Must not -/// be less than width * sizeof(type) * channels. +/// be less than width * sizeof(dst type) * channels. +/// Must be a multiple of sizeof(dst type). /// @param width Number of pixels in the data. (One pixel consists of /// 'channels' number of elements.) /// @param height Number of rows in the data. @@ -733,19 +754,22 @@ intrinsiccv_error_t intrinsiccv_gaussian_blur_5x5_u8( /// Splits a multi channel source stream into separate 1-channel streams. /// /// @param src_data Pointer to the source data. Must be non-null. +/// Must be aligned to element_size. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row in the source data. Must not be -/// less than width * sizeof(type) * channels. +/// less than width * element_size * channels. +/// Must be a multiple of element_size. /// @param dst_data A C style array of pointers to the destination data. /// Number of pointers in the array must be the same as the /// channel number. All pointers must be non-null. +/// All pointers must be aligned to element_size. /// @param dst_strides A C style array of stride values for the destination /// streams. A stride value represents the distance in /// bytes from the start of one row to the start of the /// next row in the given destination stream. Number of /// stride values in the array must be the same as the -/// channel number. All stride values must not be less than -/// width * sizeof(type). +/// channel number. All stride values must be a multiple of +/// element_size and not be less than width * element_size. /// @param width Number of pixels in one row of the source data. (One /// pixel consists of 'channels' number of elements.) /// @param height Number of rows in the source data. @@ -771,13 +795,17 @@ intrinsiccv_error_t intrinsiccv_split(const void *src_data, size_t src_stride, /// ``` /// /// @param src Pointer to the source data. Must be non-null. +/// Must be aligned to element_size. /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row for the source data. +/// Must be a multiple of element_size. /// Must not be less than width * element_size. /// @param dst Pointer to the destination data. Must be non-null. /// Can be the same as source data for inplace operation. +/// Must be aligned to element_size. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row for the destination data. +/// Must be a multiple of element_size. /// Must not be less than height * element_size. /// @param src_width Number of elements in a row. /// @param src_height Number of rows in the data. @@ -793,17 +821,20 @@ intrinsiccv_error_t intrinsiccv_transpose(const void *src, size_t src_stride, /// @param srcs A C style array of pointers to the source data. /// Number of pointers in the array must be the same as the /// channel number. All pointers must be non-null. +/// All pointers must be aligned to element_size. /// @param src_strides A C style array of stride values for the source /// streams. A stride value represents the distance in /// bytes from the start of one row to the start of the /// next row in the given source stream. Number of /// stride values in the array must be the same as the -/// channel number. All stride values must not be less than -/// width * sizeof(type). +/// channel number. All stride values must be a multiple of +/// element_size and not be less than width * element_size. /// @param dst Pointer to the destination data. Must be non-null. +/// Must be aligned to element_size. /// @param dst_stride Distance in bytes from the start of one row to the /// start of the next row in the destination data. Must not -/// be less than width * sizeof(type) * channels. +/// be less than width * element_size * channels. +/// Must be a multiple of element_size. /// @param width Number of elements in a row. /// @param height Number of rows in the data. /// @param channels Number of channels in the destination data. @@ -821,6 +852,7 @@ intrinsiccv_error_t intrinsiccv_merge(const void **srcs, /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row in the source data. Must not be /// less than width * sizeof(type). +/// Must be a multiple of sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. /// @param min_value Pointer to save result minimum value to, or nullptr if @@ -861,6 +893,7 @@ intrinsiccv_error_t intrinsiccv_min_max_s32(const int32_t *src, /// @param src_stride Distance in bytes from the start of one row to the /// start of the next row in the source data. Must not be /// less than width * sizeof(type). +/// Must be a multiple of sizeof(type). /// @param width Number of elements in a row. /// @param height Number of rows in the data. /// @param min_offset Pointer to save result offset of minimum value to, or diff --git a/intrinsiccv/include/types.h b/intrinsiccv/include/types.h index 03b12d62e..f3da18420 100644 --- a/intrinsiccv/include/types.h +++ b/intrinsiccv/include/types.h @@ -308,26 +308,6 @@ class Rows final : public RowBase { explicit Rows(T *ptr) INTRINSICCV_STREAMING_COMPATIBLE : Rows(ptr, 0, 0) {} - explicit Rows(void *ptr, size_t stride, - size_t channels) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), stride, channels) {} - - explicit Rows(const void *ptr, size_t stride, - size_t channels) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), stride, channels) {} - - explicit Rows(void *ptr, size_t stride) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), stride, 1) {} - - explicit Rows(const void *ptr, size_t stride) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), stride, 1) {} - - explicit Rows(void *ptr) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), 0, 0) {} - - explicit Rows(const void *ptr) INTRINSICCV_STREAMING_COMPATIBLE - : Rows(reinterpret_cast(ptr), 0, 0) {} - // Subscript operator to return an arbitrary position within the current row. // To account for stride and channel count use at() method. T &operator[](ptrdiff_t index) INTRINSICCV_STREAMING_COMPATIBLE { diff --git a/intrinsiccv/include/utils.h b/intrinsiccv/include/utils.h index 7eb308401..cf39b1581 100644 --- a/intrinsiccv/include/utils.h +++ b/intrinsiccv/include/utils.h @@ -11,6 +11,7 @@ #include #include "config.h" +#include "ctypes.h" namespace intrinsiccv { @@ -353,14 +354,63 @@ class LoopUnroll2 final { // Check whether any of the arguments are null pointers. template -bool any_null(Pointers... pointers) { +bool any_null(Pointers... pointers) INTRINSICCV_STREAMING_COMPATIBLE { return (... || (pointers == nullptr)); } -#define CHECK_POINTERS(...) \ - if (any_null(__VA_ARGS__)) { \ - return INTRINSICCV_ERROR_NULL_POINTER; \ +#define CHECK_POINTERS(...) \ + do { \ + if (any_null(__VA_ARGS__)) { \ + return INTRINSICCV_ERROR_NULL_POINTER; \ + } \ + } while (false) + +template +bool is_misaligned(Value v) INTRINSICCV_STREAMING_COMPATIBLE { + constexpr size_t kMask = alignof(AlignType) - 1; + static_assert(kMask == 0b0001 || kMask == 0b0011 || kMask == 0b0111 || + kMask == 0b1111); + return (v & kMask) != 0; +} + +// Specialisation for when stride misalignment is possible. +template +std::enable_if_t check_pointer_and_stride( + T *pointer, size_t stride) INTRINSICCV_STREAMING_COMPATIBLE { + if (pointer == nullptr) { + return INTRINSICCV_ERROR_NULL_POINTER; + } + if (is_misaligned(stride)) { + return INTRINSICCV_ERROR_ALIGNMENT; + } + return INTRINSICCV_OK; +} + +// Specialisation for when stride misalignment is impossible. +template +std::enable_if_t check_pointer_and_stride( + T *pointer, size_t /*stride*/) INTRINSICCV_STREAMING_COMPATIBLE { + if (pointer == nullptr) { + return INTRINSICCV_ERROR_NULL_POINTER; } + return INTRINSICCV_OK; +} + +#define CHECK_POINTER_AND_STRIDE(pointer, stride) \ + do { \ + if (intrinsiccv_error_t ptr_stride_err = \ + check_pointer_and_stride(pointer, stride)) { \ + return ptr_stride_err; \ + } \ + } while (false) + +#define MAKE_POINTER_CHECK_ALIGNMENT(ElementType, name, from) \ + if constexpr (alignof(ElementType) > 1) { \ + if (is_misaligned(reinterpret_cast(from))) { \ + return INTRINSICCV_ERROR_ALIGNMENT; \ + } \ + } \ + ElementType *name = reinterpret_cast(from) } // namespace intrinsiccv diff --git a/intrinsiccv/src/analysis/canny_neon.cpp b/intrinsiccv/src/analysis/canny_neon.cpp index ec06a51a4..c6a57bc64 100644 --- a/intrinsiccv/src/analysis/canny_neon.cpp +++ b/intrinsiccv/src/analysis/canny_neon.cpp @@ -361,8 +361,9 @@ static void directional_masking(const int16_t *prev_rows, } static bool is_vect_len_memory_null(const int16_t *data) { - const auto *s64_data = reinterpret_cast(data); - return ((s64_data[0] | s64_data[1]) == 0); + int64_t data64[2]; + memcpy(data64, data, sizeof(data64)); + return data64[0] == 0 && data64[1] == 0; } static void non_maxima_suppression_and_high_thresholding( @@ -468,7 +469,8 @@ static void perform_hysteresis(StrongEdgeStack &strong_edge_pixels, extern "C" INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t intrinsiccv_canny_u8( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height, double low_threshold, double high_threshold) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle dst_rect{width, height}; diff --git a/intrinsiccv/src/analysis/count_nonzeros_neon.cpp b/intrinsiccv/src/analysis/count_nonzeros_neon.cpp index c453021b4..66272e7dc 100644 --- a/intrinsiccv/src/analysis/count_nonzeros_neon.cpp +++ b/intrinsiccv/src/analysis/count_nonzeros_neon.cpp @@ -51,13 +51,15 @@ static size_t count_nonzeros_impl(Rows src, Rectangle rect) { } // namespace neon template -INTRINSICCV_TARGET_FN_ATTRS static size_t count_nonzeros(const T *src, - size_t src_stride, - size_t width, - size_t height) { +INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t count_nonzeros( + const T *src, size_t src_stride, size_t width, size_t height, + size_t *count) { + CHECK_POINTERS(count); + CHECK_POINTER_AND_STRIDE(src, src_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; - return neon::count_nonzeros_impl(src_rows, rect); + *count = neon::count_nonzeros_impl(src_rows, rect); + return INTRINSICCV_OK; } extern "C" { @@ -67,9 +69,7 @@ intrinsiccv_error_t intrinsiccv_count_nonzeros_u8(const uint8_t *src, size_t src_stride, size_t width, size_t height, size_t *count) { - CHECK_POINTERS(src, count); - *count = count_nonzeros(src, src_stride, width, height); - return INTRINSICCV_OK; + return count_nonzeros(src, src_stride, width, height, count); } } // extern "C" diff --git a/intrinsiccv/src/analysis/min_max_loc_neon.cpp b/intrinsiccv/src/analysis/min_max_loc_neon.cpp index 814cedecb..4dac4d23c 100644 --- a/intrinsiccv/src/analysis/min_max_loc_neon.cpp +++ b/intrinsiccv/src/analysis/min_max_loc_neon.cpp @@ -310,7 +310,7 @@ template intrinsiccv_error_t min_max_loc(const ScalarType *src, size_t src_stride, size_t width, size_t height, size_t *min_offset, size_t *max_offset) { - CHECK_POINTERS(src); + CHECK_POINTER_AND_STRIDE(src, src_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; diff --git a/intrinsiccv/src/analysis/min_max_neon.cpp b/intrinsiccv/src/analysis/min_max_neon.cpp index 76e8e9ef1..6291bab4b 100644 --- a/intrinsiccv/src/analysis/min_max_neon.cpp +++ b/intrinsiccv/src/analysis/min_max_neon.cpp @@ -48,7 +48,7 @@ template intrinsiccv_error_t min_max(const ScalarType *src, size_t src_stride, size_t width, size_t height, ScalarType *min_value, ScalarType *max_value) { - CHECK_POINTERS(src); + CHECK_POINTER_AND_STRIDE(src, src_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; MinMax operation; diff --git a/intrinsiccv/src/arithmetics/absdiff_neon.cpp b/intrinsiccv/src/arithmetics/absdiff_neon.cpp index 4d100c0f1..43dc44b7f 100644 --- a/intrinsiccv/src/arithmetics/absdiff_neon.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_neon.cpp @@ -40,7 +40,9 @@ intrinsiccv_error_t saturating_absdiff(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAbsDiff operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/absdiff_sme2.cpp b/intrinsiccv/src/arithmetics/absdiff_sme2.cpp index 654286ea7..3002d7dc8 100644 --- a/intrinsiccv/src/arithmetics/absdiff_sme2.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_sme2.cpp @@ -40,7 +40,9 @@ template INTRINSICCV_LOCALLY_STREAMING intrinsiccv_error_t saturating_absdiff( const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAbsDiff operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/absdiff_sve2.cpp b/intrinsiccv/src/arithmetics/absdiff_sve2.cpp index 56e5cddb6..1b04676c3 100644 --- a/intrinsiccv/src/arithmetics/absdiff_sve2.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_sve2.cpp @@ -38,7 +38,9 @@ intrinsiccv_error_t saturating_absdiff(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAbsDiff operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp b/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp index 6effc7dff..eb337442f 100644 --- a/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp +++ b/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp @@ -39,7 +39,9 @@ intrinsiccv_error_t add_abs_with_threshold(const T *src_a, size_t src_a_stride, T *dst, size_t dst_stride, size_t width, size_t height, T threshold) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); AddAbsWithThreshold operation{threshold}; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h b/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h index c2fa1643d..cc03e0365 100644 --- a/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h +++ b/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h @@ -39,7 +39,9 @@ intrinsiccv_error_t add_abs_with_threshold_sc( const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height, T threshold) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); AddAbsWithThreshold operation{threshold}; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/add_neon.cpp b/intrinsiccv/src/arithmetics/add_neon.cpp index c3f3ed5db..0b63b527d 100644 --- a/intrinsiccv/src/arithmetics/add_neon.cpp +++ b/intrinsiccv/src/arithmetics/add_neon.cpp @@ -39,7 +39,9 @@ intrinsiccv_error_t saturating_add(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAdd operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/add_sme2.cpp b/intrinsiccv/src/arithmetics/add_sme2.cpp index cd4dd5482..aea4ae725 100644 --- a/intrinsiccv/src/arithmetics/add_sme2.cpp +++ b/intrinsiccv/src/arithmetics/add_sme2.cpp @@ -26,7 +26,9 @@ template INTRINSICCV_LOCALLY_STREAMING intrinsiccv_error_t saturating_add( const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAdd operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/add_sve2.cpp b/intrinsiccv/src/arithmetics/add_sve2.cpp index 8d44f99ee..12743b6b1 100644 --- a/intrinsiccv/src/arithmetics/add_sve2.cpp +++ b/intrinsiccv/src/arithmetics/add_sve2.cpp @@ -26,7 +26,9 @@ intrinsiccv_error_t saturating_add(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingAdd operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/multiply_neon.cpp b/intrinsiccv/src/arithmetics/multiply_neon.cpp index 20563c787..ea3a0a202 100644 --- a/intrinsiccv/src/arithmetics/multiply_neon.cpp +++ b/intrinsiccv/src/arithmetics/multiply_neon.cpp @@ -67,7 +67,9 @@ intrinsiccv_error_t saturating_multiply(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height, double scale) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); (void)scale; // TODO: figure out the way to process the scale. SaturatingMultiply operation; diff --git a/intrinsiccv/src/arithmetics/multiply_sve2.cpp b/intrinsiccv/src/arithmetics/multiply_sve2.cpp index 7efca6a8f..e2c9093e8 100644 --- a/intrinsiccv/src/arithmetics/multiply_sve2.cpp +++ b/intrinsiccv/src/arithmetics/multiply_sve2.cpp @@ -45,7 +45,9 @@ intrinsiccv_error_t saturating_multiply(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height, double scale) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); (void)scale; // TODO: figure out the way to process the scale. SaturatingMultiply operation; diff --git a/intrinsiccv/src/arithmetics/scale_neon.cpp b/intrinsiccv/src/arithmetics/scale_neon.cpp index 4d81862c9..7193aa32c 100644 --- a/intrinsiccv/src/arithmetics/scale_neon.cpp +++ b/intrinsiccv/src/arithmetics/scale_neon.cpp @@ -172,7 +172,8 @@ template intrinsiccv_error_t scale(const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, float scale, float shift) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; diff --git a/intrinsiccv/src/arithmetics/sub_neon.cpp b/intrinsiccv/src/arithmetics/sub_neon.cpp index 318cd206a..12bb85855 100644 --- a/intrinsiccv/src/arithmetics/sub_neon.cpp +++ b/intrinsiccv/src/arithmetics/sub_neon.cpp @@ -39,7 +39,9 @@ intrinsiccv_error_t saturating_sub(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingSub operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/sub_sme2.cpp b/intrinsiccv/src/arithmetics/sub_sme2.cpp index b8d7b3926..fa1348d38 100644 --- a/intrinsiccv/src/arithmetics/sub_sme2.cpp +++ b/intrinsiccv/src/arithmetics/sub_sme2.cpp @@ -26,7 +26,9 @@ template INTRINSICCV_LOCALLY_STREAMING intrinsiccv_error_t saturating_sub( const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingSub operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/sub_sve2.cpp b/intrinsiccv/src/arithmetics/sub_sve2.cpp index 0ab4901e9..94a1ff889 100644 --- a/intrinsiccv/src/arithmetics/sub_sve2.cpp +++ b/intrinsiccv/src/arithmetics/sub_sve2.cpp @@ -26,7 +26,9 @@ intrinsiccv_error_t saturating_sub(const T *src_a, size_t src_a_stride, const T *src_b, size_t src_b_stride, T *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_a, src_b, dst); + CHECK_POINTER_AND_STRIDE(src_a, src_a_stride); + CHECK_POINTER_AND_STRIDE(src_b, src_b_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); SaturatingSub operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/threshold_neon.cpp b/intrinsiccv/src/arithmetics/threshold_neon.cpp index 979114fd6..c6bd35a13 100644 --- a/intrinsiccv/src/arithmetics/threshold_neon.cpp +++ b/intrinsiccv/src/arithmetics/threshold_neon.cpp @@ -41,7 +41,8 @@ template intrinsiccv_error_t threshold_binary(const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, T threshold, T value) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; diff --git a/intrinsiccv/src/arithmetics/threshold_sc.h b/intrinsiccv/src/arithmetics/threshold_sc.h index 784937993..93c38d29f 100644 --- a/intrinsiccv/src/arithmetics/threshold_sc.h +++ b/intrinsiccv/src/arithmetics/threshold_sc.h @@ -37,7 +37,8 @@ template intrinsiccv_error_t threshold_binary_sc( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, T threshold, T value) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; diff --git a/intrinsiccv/src/arithmetics/transpose_neon.cpp b/intrinsiccv/src/arithmetics/transpose_neon.cpp index af7899db9..642fa95ce 100644 --- a/intrinsiccv/src/arithmetics/transpose_neon.cpp +++ b/intrinsiccv/src/arithmetics/transpose_neon.cpp @@ -197,14 +197,22 @@ static intrinsiccv_error_t transpose(Rectangle rect, } template -static intrinsiccv_error_t transpose(const void *src, size_t src_stride, - void *dst, size_t dst_stride, - size_t src_width, size_t src_height, - bool inplace) { +static intrinsiccv_error_t transpose(const void *src_void, size_t src_stride, + void *dst_void, size_t dst_stride, + size_t src_width, size_t src_height) { + MAKE_POINTER_CHECK_ALIGNMENT(const T, src, src_void); + MAKE_POINTER_CHECK_ALIGNMENT(T, dst, dst_void); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); + Rectangle rect{src_width, src_height}; Rows dst_rows{dst, dst_stride}; - if (inplace) { + if (src == dst) { + if (src_width != src_height) { + // Inplace transpose only implemented if width and height are the same + return INTRINSICCV_ERROR_NOT_IMPLEMENTED; + } return transpose(rect, dst_rows); } Rows src_rows{src, src_stride}; @@ -215,31 +223,19 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t transpose(const void *src, size_t src_stride, void *dst, size_t dst_stride, size_t src_width, size_t src_height, size_t element_size) { - CHECK_POINTERS(src, dst); - - bool inplace = false; - - if (src == dst) { - if (src_width != src_height) { - // Inplace transpose only implemented if width and height are the same - return INTRINSICCV_ERROR_NOT_IMPLEMENTED; - } - inplace = true; - } - switch (element_size) { case sizeof(uint8_t): return transpose(src, src_stride, dst, dst_stride, src_width, - src_height, inplace); + src_height); case sizeof(uint16_t): return transpose(src, src_stride, dst, dst_stride, src_width, - src_height, inplace); + src_height); case sizeof(uint32_t): return transpose(src, src_stride, dst, dst_stride, src_width, - src_height, inplace); + src_height); case sizeof(uint64_t): return transpose(src, src_stride, dst, dst_stride, src_width, - src_height, inplace); + src_height); default: return INTRINSICCV_ERROR_NOT_IMPLEMENTED; } diff --git a/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp b/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp index b0e01ea04..477b7c265 100644 --- a/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp @@ -108,7 +108,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t gray_to_rgb_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; @@ -121,7 +122,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t gray_to_rgba_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; diff --git a/intrinsiccv/src/conversions/gray_to_rgb_sc.h b/intrinsiccv/src/conversions/gray_to_rgb_sc.h index 69efea547..1f309fa60 100644 --- a/intrinsiccv/src/conversions/gray_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/gray_to_rgb_sc.h @@ -199,7 +199,8 @@ class GrayToRGBA final : INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t gray_to_rgb_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; @@ -216,7 +217,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t gray_to_rgb_u8_sc( INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t gray_to_rgba_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; diff --git a/intrinsiccv/src/conversions/merge_neon.cpp b/intrinsiccv/src/conversions/merge_neon.cpp index 9017e3d15..15018866f 100644 --- a/intrinsiccv/src/conversions/merge_neon.cpp +++ b/intrinsiccv/src/conversions/merge_neon.cpp @@ -367,19 +367,26 @@ class Merge4 final : public UnrollTwice { #endif // !INTRINSICCV_PREFER_INTERLEAVING_LOAD_STORE +// Most of the complexity comes from parameter checking. +// NOLINTBEGIN(readability-function-cognitive-complexity) template intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, - void *dst, size_t dst_stride, size_t width, + void *dst_void, size_t dst_stride, size_t width, size_t height, size_t channels) { if (channels < 2) { return INTRINSICCV_ERROR_RANGE; } - CHECK_POINTERS(srcs, src_strides, dst); - CHECK_POINTERS(srcs[0], srcs[1]); + CHECK_POINTERS(srcs, src_strides); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src0, srcs[0]); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src1, srcs[1]); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst, dst_void); + CHECK_POINTER_AND_STRIDE(src0, src_strides[0]); + CHECK_POINTER_AND_STRIDE(src1, src_strides[1]); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; - Rows src_a_rows{srcs[0], src_strides[0]}; - Rows src_b_rows{srcs[1], src_strides[1]}; + Rows src_a_rows{src0, src_strides[0]}; + Rows src_b_rows{src1, src_strides[1]}; Rows dst_rows{dst, dst_stride, channels}; switch (channels) { @@ -390,18 +397,22 @@ intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, } break; case 3: { - CHECK_POINTERS(srcs[2]); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src2, srcs[2]); + CHECK_POINTER_AND_STRIDE(src2, src_strides[2]); Merge3 operation; - Rows src_c_rows{srcs[2], src_strides[2]}; + Rows src_c_rows{src2, src_strides[2]}; apply_operation_by_rows(operation, rect, src_a_rows, src_b_rows, src_c_rows, dst_rows); } break; case 4: { - CHECK_POINTERS(srcs[2], srcs[3]); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src2, srcs[2]); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src3, srcs[3]); + CHECK_POINTER_AND_STRIDE(src2, src_strides[2]); + CHECK_POINTER_AND_STRIDE(src3, src_strides[3]); Merge4 operation; - Rows src_c_rows{srcs[2], src_strides[2]}; - Rows src_d_rows{srcs[3], src_strides[3]}; + Rows src_c_rows{src2, src_strides[2]}; + Rows src_d_rows{src3, src_strides[3]}; apply_operation_by_rows(operation, rect, src_a_rows, src_b_rows, src_c_rows, src_d_rows, dst_rows); } break; @@ -411,6 +422,7 @@ intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, } return INTRINSICCV_OK; } +// NOLINTEND(readability-function-cognitive-complexity) INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, diff --git a/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp b/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp index 009424d3f..fe0c8a3b2 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp +++ b/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp @@ -29,7 +29,8 @@ intrinsiccv_error_t intrinsiccv_rgb_to_rgb_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -41,7 +42,8 @@ intrinsiccv_error_t intrinsiccv_rgba_to_rgba_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; diff --git a/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp b/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp index d2f56d542..bb9e54de4 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp @@ -191,7 +191,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgb_to_bgr_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -204,7 +205,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgba_to_bgra_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -216,7 +218,8 @@ intrinsiccv_error_t rgba_to_bgra_u8(const uint8_t *src, size_t src_stride, INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgb_to_bgra_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -228,7 +231,8 @@ rgb_to_bgra_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgb_to_rgba_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; @@ -241,7 +245,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgba_to_bgr_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -254,7 +259,8 @@ INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t rgba_to_rgb_u8(const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; diff --git a/intrinsiccv/src/conversions/rgb_to_rgb_sc.h b/intrinsiccv/src/conversions/rgb_to_rgb_sc.h index df0c3817a..d2b1ea030 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/rgb_to_rgb_sc.h @@ -184,7 +184,8 @@ class RGBAToRGB final : public UnrollTwice { INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgb_to_bgr_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -202,7 +203,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgba_to_bgra_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -215,7 +217,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgb_to_bgra_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -228,7 +231,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgb_to_rgba_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; @@ -241,7 +245,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgba_to_bgr_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -254,7 +259,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t rgba_to_rgb_u8_sc( const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; diff --git a/intrinsiccv/src/conversions/split_neon.cpp b/intrinsiccv/src/conversions/split_neon.cpp index 4d6d5376c..6f86f7c85 100644 --- a/intrinsiccv/src/conversions/split_neon.cpp +++ b/intrinsiccv/src/conversions/split_neon.cpp @@ -252,22 +252,27 @@ class Split4 final : public UnrollTwice { }; #endif +// Most of the complexity comes from parameter checking. +// NOLINTBEGIN(readability-function-cognitive-complexity) template -intrinsiccv_error_t split(const void *src_data, const size_t src_stride, +intrinsiccv_error_t split(const void *src_void, const size_t src_stride, void **dst_data, const size_t *dst_strides, size_t width, size_t height, size_t channels) { if (channels < 2) { return INTRINSICCV_ERROR_RANGE; } - CHECK_POINTERS(src_data, dst_data, dst_strides); - CHECK_POINTERS(dst_data[0], dst_data[1]); + + CHECK_POINTERS(dst_data, dst_strides); + MAKE_POINTER_CHECK_ALIGNMENT(const ScalarType, src_data, src_void); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst0, dst_data[0]); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst1, dst_data[1]); + CHECK_POINTER_AND_STRIDE(src_data, src_stride); + CHECK_POINTER_AND_STRIDE(dst0, dst_strides[0]); + CHECK_POINTER_AND_STRIDE(dst1, dst_strides[1]); Rectangle rect{width, height}; - ScalarType *dst0 = reinterpret_cast(dst_data[0]), - *dst1 = reinterpret_cast(dst_data[1]); - Rows src_rows{ - const_cast(reinterpret_cast(src_data)), - src_stride, channels}; + Rows src_rows{const_cast(src_data), src_stride, + channels}; Rows dst_rows0{dst0, dst_strides[0]}; Rows dst_rows1{dst1, dst_strides[1]}; switch (channels) { @@ -276,17 +281,18 @@ intrinsiccv_error_t split(const void *src_data, const size_t src_stride, apply_operation_by_rows(operation, rect, src_rows, dst_rows0, dst_rows1); } break; case 3: { - CHECK_POINTERS(dst_data[2]); - ScalarType *dst2 = reinterpret_cast(dst_data[2]); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst2, dst_data[2]); + CHECK_POINTER_AND_STRIDE(dst2, dst_strides[2]); Rows dst_rows2{dst2, dst_strides[2]}; Split3 operation; apply_operation_by_rows(operation, rect, src_rows, dst_rows0, dst_rows1, dst_rows2); } break; case 4: { - CHECK_POINTERS(dst_data[2], dst_data[3]); - ScalarType *dst2 = reinterpret_cast(dst_data[2]), - *dst3 = reinterpret_cast(dst_data[3]); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst2, dst_data[2]); + MAKE_POINTER_CHECK_ALIGNMENT(ScalarType, dst3, dst_data[3]); + CHECK_POINTER_AND_STRIDE(dst2, dst_strides[2]); + CHECK_POINTER_AND_STRIDE(dst3, dst_strides[3]); Rows dst_rows2{dst2, dst_strides[2]}; Rows dst_rows3{dst3, dst_strides[3]}; Split4 operation; @@ -298,6 +304,7 @@ intrinsiccv_error_t split(const void *src_data, const size_t src_stride, } return INTRINSICCV_OK; } +// NOLINTEND(readability-function-cognitive-complexity) INTRINSICCV_TARGET_FN_ATTRS intrinsiccv_error_t split(const void *src_data, size_t src_stride, diff --git a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp index 3a7f9fa14..0c44da628 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp @@ -292,7 +292,9 @@ intrinsiccv_error_t yuv2rgbx_operation( OperationType &operation, const ScalarType *src_y, size_t src_y_stride, const ScalarType *src_uv, size_t src_uv_stride, ScalarType *dst, size_t dst_stride, size_t width, size_t height) { - CHECK_POINTERS(src_y, src_uv, dst); + CHECK_POINTER_AND_STRIDE(src_y, src_y_stride); + CHECK_POINTER_AND_STRIDE(src_uv, src_uv_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; ParallelRows y_rows{src_y, src_y_stride}; Rows uv_rows{src_uv, src_uv_stride}; diff --git a/intrinsiccv/src/conversions/yuv_to_rgb_sc.h b/intrinsiccv/src/conversions/yuv_to_rgb_sc.h index 335fb03a8..e6f789ce5 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/yuv_to_rgb_sc.h @@ -193,7 +193,9 @@ intrinsiccv_error_t yuv2rgbx_operation( const ScalarType *src_uv, size_t src_uv_stride, ScalarType *dst, size_t dst_stride, size_t width, size_t height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src_y, src_uv, dst); + CHECK_POINTER_AND_STRIDE(src_y, src_y_stride); + CHECK_POINTER_AND_STRIDE(src_uv, src_uv_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; ParallelRows y_rows{src_y, src_y_stride}; Rows uv_rows{src_uv, src_uv_stride}; diff --git a/intrinsiccv/src/filters/gaussian_blur_neon.cpp b/intrinsiccv/src/filters/gaussian_blur_neon.cpp index d858478da..8cd1833cf 100644 --- a/intrinsiccv/src/filters/gaussian_blur_neon.cpp +++ b/intrinsiccv/src/filters/gaussian_blur_neon.cpp @@ -150,7 +150,9 @@ intrinsiccv_error_t discrete_gaussian_blur( intrinsiccv_filter_context_t *context) { using GaussianBlurFilterType = DiscreteGaussianBlur; - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; diff --git a/intrinsiccv/src/filters/gaussian_blur_sc.h b/intrinsiccv/src/filters/gaussian_blur_sc.h index 4adb4677d..51ef9b141 100644 --- a/intrinsiccv/src/filters/gaussian_blur_sc.h +++ b/intrinsiccv/src/filters/gaussian_blur_sc.h @@ -90,7 +90,9 @@ intrinsiccv_error_t discrete_gaussian_blur( intrinsiccv_filter_context_t *context) INTRINSICCV_STREAMING_COMPATIBLE { using GaussianBlurFilterType = DiscreteGaussianBlur; - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; diff --git a/intrinsiccv/src/filters/sobel_neon.cpp b/intrinsiccv/src/filters/sobel_neon.cpp index 6bb047ff2..9cf62eea8 100644 --- a/intrinsiccv/src/filters/sobel_neon.cpp +++ b/intrinsiccv/src/filters/sobel_neon.cpp @@ -132,7 +132,8 @@ intrinsiccv_error_t sobel_3x3_horizontal_s16_u8(const uint8_t *src, size_t dst_stride, size_t width, size_t height, size_t channels) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; @@ -156,7 +157,8 @@ intrinsiccv_error_t sobel_3x3_vertical_s16_u8(const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; diff --git a/intrinsiccv/src/filters/sobel_sc.h b/intrinsiccv/src/filters/sobel_sc.h index 38e250fcb..47a90aed2 100644 --- a/intrinsiccv/src/filters/sobel_sc.h +++ b/intrinsiccv/src/filters/sobel_sc.h @@ -122,7 +122,8 @@ static intrinsiccv_error_t sobel_3x3_horizontal_s16_u8_sc( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; @@ -147,7 +148,8 @@ static intrinsiccv_error_t sobel_3x3_vertical_s16_u8_sc( const uint8_t *src, size_t src_stride, int16_t *dst, size_t dst_stride, size_t width, size_t height, size_t channels) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; diff --git a/intrinsiccv/src/morphology/morphology_neon.cpp b/intrinsiccv/src/morphology/morphology_neon.cpp index f88eb791a..3f5b55769 100644 --- a/intrinsiccv/src/morphology/morphology_neon.cpp +++ b/intrinsiccv/src/morphology/morphology_neon.cpp @@ -490,7 +490,9 @@ template intrinsiccv_error_t dilate(const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, intrinsiccv_morphology_context_t *context) { - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); auto *workspace = reinterpret_cast(context); @@ -543,7 +545,9 @@ template intrinsiccv_error_t erode(const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, intrinsiccv_morphology_context_t *context) { - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); auto *workspace = reinterpret_cast(context); diff --git a/intrinsiccv/src/morphology/morphology_sc.h b/intrinsiccv/src/morphology/morphology_sc.h index bdbc6154a..7271504fd 100644 --- a/intrinsiccv/src/morphology/morphology_sc.h +++ b/intrinsiccv/src/morphology/morphology_sc.h @@ -453,7 +453,9 @@ static intrinsiccv_error_t dilate_sc(const T *src, size_t src_stride, T *dst, size_t height, intrinsiccv_morphology_context_t *context) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); auto *workspace = reinterpret_cast(context); @@ -511,7 +513,9 @@ static intrinsiccv_error_t erode_sc(const T *src, size_t src_stride, T *dst, size_t height, intrinsiccv_morphology_context_t *context) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst, context); + CHECK_POINTERS(context); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); auto *workspace = reinterpret_cast(context); diff --git a/intrinsiccv/src/resize/resize_neon.cpp b/intrinsiccv/src/resize/resize_neon.cpp index 777211d94..38f54c260 100644 --- a/intrinsiccv/src/resize/resize_neon.cpp +++ b/intrinsiccv/src/resize/resize_neon.cpp @@ -13,7 +13,8 @@ intrinsiccv_error_t resize_to_quarter_u8(const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height) { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); for (; src_height >= 2; src_height -= 2, src += (src_stride * 2), --dst_height, dst += dst_stride) { diff --git a/intrinsiccv/src/resize/resize_sc.h b/intrinsiccv/src/resize/resize_sc.h index 0a77b5ef0..78ca4529a 100644 --- a/intrinsiccv/src/resize/resize_sc.h +++ b/intrinsiccv/src/resize/resize_sc.h @@ -143,7 +143,8 @@ INTRINSICCV_TARGET_FN_ATTRS static intrinsiccv_error_t resize_to_quarter_u8_sc( const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height) INTRINSICCV_STREAMING_COMPATIBLE { - CHECK_POINTERS(src, dst); + CHECK_POINTER_AND_STRIDE(src, src_stride); + CHECK_POINTER_AND_STRIDE(dst, dst_stride); Rows src_rows{src, src_stride, /* channels*/ 1}; Rows dst_rows{dst, dst_stride, /* channels*/ 1}; diff --git a/scripts/ci.sh b/scripts/ci.sh index 037b265c6..f6592562f 100755 --- a/scripts/ci.sh +++ b/scripts/ci.sh @@ -56,6 +56,13 @@ scripts/prefix_testsuite_names.py build/test-results/sme/intrinsiccv-api-test.xm # Generate test coverage report LLVM_COV=llvm-cov scripts/generate_coverage_report.py +# Clang address & undefined behaviour sanitizers +cmake -S . -B build/sanitize -G Ninja \ + -DINTRINSICCV_ENABLE_SME2=OFF \ + -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -Wno-pass-failed" +ninja -C build/sanitize intrinsiccv-api-test +build/sanitize/test/api/intrinsiccv-api-test + # Check OpenCV-IntrinsicCV integration scripts/ci-opencv.sh diff --git a/test/api/test_canny.cpp b/test/api/test_canny.cpp index 9acc82b06..4415bea41 100644 --- a/test/api/test_canny.cpp +++ b/test/api/test_canny.cpp @@ -24,3 +24,17 @@ TYPED_TEST(CannyTest, NullPointer) { test::test_null_args(canny(), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 0.0, 1.0); } + +TYPED_TEST(CannyTest, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1], dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + canny()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, 0.0, 1.0)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + canny()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, 0.0, 1.0)); +} diff --git a/test/api/test_count_nonzeros.cpp b/test/api/test_count_nonzeros.cpp index 3b3368c02..6365d79d3 100644 --- a/test/api/test_count_nonzeros.cpp +++ b/test/api/test_count_nonzeros.cpp @@ -117,3 +117,15 @@ TYPED_TEST(CountNonZeros, NullPointer) { test::test_null_args(count_nonzeros(), src, sizeof(TypeParam), 1, 1, &count); } + +TYPED_TEST(CountNonZeros, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1]; + size_t count = 0; + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + count_nonzeros()(src, sizeof(TypeParam) + 1, 1, 1, &count)); +} diff --git a/test/api/test_gaussian_blur.cpp b/test/api/test_gaussian_blur.cpp index e0c5f3f61..581980d66 100644 --- a/test/api/test_gaussian_blur.cpp +++ b/test/api/test_gaussian_blur.cpp @@ -36,3 +36,32 @@ TYPED_TEST(GaussianBlurTest, NullPointer) { INTRINSICCV_BORDER_TYPE_REFLECT, context); EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_filter_release(context)); } + +TYPED_TEST(GaussianBlurTest, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + intrinsiccv_filter_context_t *context = nullptr; + ASSERT_EQ(INTRINSICCV_OK, + intrinsiccv_filter_create(&context, 1, sizeof(TypeParam), + intrinsiccv_rectangle_t{1, 1})); + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + gaussian_blur_3x3()( + src, sizeof(TypeParam) + 1, dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, context)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + gaussian_blur_3x3()( + src, sizeof(TypeParam), dst, sizeof(TypeParam) + 1, 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, context)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + gaussian_blur_5x5()( + src, sizeof(TypeParam) + 1, dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, context)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + gaussian_blur_5x5()( + src, sizeof(TypeParam), dst, sizeof(TypeParam) + 1, 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, context)); + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_filter_release(context)); +} diff --git a/test/api/test_merge.cpp b/test/api/test_merge.cpp index a71cfa6f6..b263f15a7 100644 --- a/test/api/test_merge.cpp +++ b/test/api/test_merge.cpp @@ -167,3 +167,59 @@ TYPED_TEST(Merge, NullPointer) { } } } + +TYPED_TEST(Merge, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + + const size_t kChannels = 4; + // A size comfortably large enough to hold the data, taking into account the + // various offsets that this test will make. + const size_t kBufSize = kChannels * sizeof(TypeParam) * 2; + alignas(TypeParam) char src_arrays[kBufSize] = {}; + alignas(TypeParam) char dst[kBufSize] = {}; + size_t src_strides[kChannels] = {}; + const char* srcs[kChannels] = {}; + const size_t dst_stride = kChannels * sizeof(TypeParam); + + auto init = [&]() { + for (size_t i = 0; i < kChannels; ++i) { + srcs[i] = src_arrays + sizeof(TypeParam) * i; + src_strides[i] = sizeof(TypeParam); + } + }; + + auto check_merge = [&](int channels, void* dst_maybe_misaligned, + size_t dst_stride_maybe_misaligned) { + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_merge(reinterpret_cast(srcs), src_strides, + dst_maybe_misaligned, dst_stride_maybe_misaligned, 1, + 1, channels, sizeof(TypeParam))); + }; + + for (size_t channels = 2; channels <= kChannels; ++channels) { + init(); + + // Misaligned destination pointer + check_merge(channels, dst + 1, dst_stride); + + // Misaligned destination stride + check_merge(channels, dst, dst_stride + 1); + + for (size_t misaligned_channel = 0; misaligned_channel < channels; + ++misaligned_channel) { + // Misaligned source pointer + init(); + ++srcs[misaligned_channel]; + check_merge(channels, dst, dst_stride); + + // Misaligned source stride + init(); + ++src_strides[misaligned_channel]; + check_merge(channels, dst, dst_stride); + } + } +} diff --git a/test/api/test_min_max.cpp b/test/api/test_min_max.cpp index 44cc54177..420c5d89a 100644 --- a/test/api/test_min_max.cpp +++ b/test/api/test_min_max.cpp @@ -299,6 +299,17 @@ TYPED_TEST(MinMax, API) { MinMaxTest{}.test(); } +TYPED_TEST(MinMax, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1] = {}, min_value, max_value; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + min_max()(src, sizeof(TypeParam) + 1, 1, 1, &min_value, + &max_value)); +} + template class MinMaxLoc : public testing::Test {}; diff --git a/test/api/test_morphology.cpp b/test/api/test_morphology.cpp index 76826c745..239a7f559 100644 --- a/test/api/test_morphology.cpp +++ b/test/api/test_morphology.cpp @@ -54,3 +54,37 @@ TYPED_TEST(ErodeTest, NullPointer) { EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); } + +TYPED_TEST(DilateTest, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + intrinsiccv_morphology_context_t *context = nullptr; + ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + dilate()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, context)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + dilate()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, context)); + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); +} + +TYPED_TEST(ErodeTest, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + intrinsiccv_morphology_context_t *context = nullptr; + ASSERT_EQ(INTRINSICCV_OK, make_minimal_context(&context, sizeof(TypeParam))); + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + erode()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, context)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + erode()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, context)); + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(context)); +} diff --git a/test/api/test_saturating_absdiff.cpp b/test/api/test_saturating_absdiff.cpp index 873c820d3..ead2aed1b 100644 --- a/test/api/test_saturating_absdiff.cpp +++ b/test/api/test_saturating_absdiff.cpp @@ -102,3 +102,23 @@ TYPED_TEST(SaturatingAbsDiff, API) { test::test_null_args(saturating_absdiff(), src, sizeof(TypeParam), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } + +TYPED_TEST(SaturatingAbsDiff, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1], dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_absdiff()(src, sizeof(TypeParam) + 1, src, + sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_absdiff()(src, sizeof(TypeParam), src, + sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_absdiff()(src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1)); +} diff --git a/test/api/test_saturating_add.cpp b/test/api/test_saturating_add.cpp index 030b44056..e52ca4fbe 100644 --- a/test/api/test_saturating_add.cpp +++ b/test/api/test_saturating_add.cpp @@ -94,3 +94,23 @@ TYPED_TEST(SaturatingAdd, API) { test::test_null_args(saturating_add(), src, sizeof(TypeParam), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } + +TYPED_TEST(SaturatingAdd, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_add()(src, sizeof(TypeParam) + 1, src, + sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_add()(src, sizeof(TypeParam), src, + sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_add()(src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1)); +} diff --git a/test/api/test_saturating_multiply.cpp b/test/api/test_saturating_multiply.cpp index 610128f73..d17c6d06e 100644 --- a/test/api/test_saturating_multiply.cpp +++ b/test/api/test_saturating_multiply.cpp @@ -102,3 +102,23 @@ TYPED_TEST(SaturatingMultiply, API) { test::test_null_args(saturating_multiply(), src, sizeof(TypeParam), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1); } + +TYPED_TEST(SaturatingMultiply, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1], dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_multiply()(src, sizeof(TypeParam) + 1, src, + sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_multiply()(src, sizeof(TypeParam), src, + sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_multiply()(src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, 1)); +} diff --git a/test/api/test_saturating_sub.cpp b/test/api/test_saturating_sub.cpp index 1c78f4da7..f85a2f59b 100644 --- a/test/api/test_saturating_sub.cpp +++ b/test/api/test_saturating_sub.cpp @@ -96,3 +96,23 @@ TYPED_TEST(SaturatingSub, API) { test::test_null_args(saturating_sub(), src, sizeof(TypeParam), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } + +TYPED_TEST(SaturatingSub, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_sub()(src, sizeof(TypeParam) + 1, src, + sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_sub()(src, sizeof(TypeParam), src, + sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + saturating_sub()(src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1)); +} diff --git a/test/api/test_scale.cpp b/test/api/test_scale.cpp index f1caaf9b6..dda7d8436 100644 --- a/test/api/test_scale.cpp +++ b/test/api/test_scale.cpp @@ -25,3 +25,17 @@ TYPED_TEST(ScaleTest, NullPointer) { test::test_null_args(scale(), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 2, 0); } + +TYPED_TEST(ScaleTest, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + scale()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, 2, 0)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + scale()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, 2, 0)); +} diff --git a/test/api/test_sobel.cpp b/test/api/test_sobel.cpp index fdb8fa6d9..03ed3cdbc 100644 --- a/test/api/test_sobel.cpp +++ b/test/api/test_sobel.cpp @@ -112,3 +112,35 @@ TYPED_TEST(Sobel, Vertical3x3) { test::test_null_args(sobel_3x3_vertical(), src, sizeof(src), dst, sizeof(dst), 1, 1, 1); } + +TYPED_TEST(Sobel, MisalignmentHorizontal) { + using KernelTestParams = SobelKernelTestParams; + typename KernelTestParams::InputType src[1] = {}; + typename KernelTestParams::OutputType dst[1]; + if (sizeof(typename KernelTestParams::InputType) != 1) { + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + sobel_3x3_horizontal()(src, sizeof(src) + 1, dst, + sizeof(dst), 1, 1, 1)); + } + if (sizeof(typename KernelTestParams::OutputType) != 1) { + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + sobel_3x3_horizontal()(src, sizeof(src), dst, + sizeof(dst) + 1, 1, 1, 1)); + } +} + +TYPED_TEST(Sobel, MisalignmentVertical) { + using KernelTestParams = SobelKernelTestParams; + typename KernelTestParams::InputType src[1] = {}; + typename KernelTestParams::OutputType dst[1]; + if (sizeof(typename KernelTestParams::InputType) != 1) { + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + sobel_3x3_vertical()(src, sizeof(src) + 1, dst, + sizeof(dst), 1, 1, 1)); + } + if (sizeof(typename KernelTestParams::OutputType) != 1) { + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + sobel_3x3_vertical()(src, sizeof(src), dst, + sizeof(dst) + 1, 1, 1, 1)); + } +} diff --git a/test/api/test_split.cpp b/test/api/test_split.cpp index 91f36334b..42680237f 100644 --- a/test/api/test_split.cpp +++ b/test/api/test_split.cpp @@ -168,3 +168,59 @@ TYPED_TEST(Split, NullPointer) { } } } + +TYPED_TEST(Split, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + + const size_t kChannels = 4; + // A size comfortably large enough to hold the data, taking into account the + // various offsets that this test will make. + const size_t kBufSize = kChannels * sizeof(TypeParam) * 2; + alignas(TypeParam) char src_data[kBufSize]; + size_t src_stride = kChannels * sizeof(TypeParam); + alignas(TypeParam) char dst_arrays[kBufSize]; + char* dst_data[kChannels] = {}; + size_t dst_strides[kChannels] = {}; + + auto init = [&]() { + for (size_t i = 0; i < kChannels; ++i) { + dst_data[i] = dst_arrays + sizeof(TypeParam) * i; + dst_strides[i] = sizeof(TypeParam); + } + }; + + auto check_split = [&](int channels, void* src_maybe_misaligned, + size_t src_stride_maybe_misaligned) { + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_split(src_maybe_misaligned, src_stride_maybe_misaligned, + reinterpret_cast(dst_data), dst_strides, 1, 1, + channels, sizeof(TypeParam))); + }; + + for (size_t channels = 2; channels <= kChannels; ++channels) { + init(); + + // Misaligned source pointer + check_split(channels, src_data + 1, src_stride); + + // Misaligned source stride + check_split(channels, src_data, src_stride + 1); + + for (size_t misaligned_channel = 0; misaligned_channel < channels; + ++misaligned_channel) { + // Misaligned destination pointer + init(); + ++dst_data[misaligned_channel]; + check_split(channels, src_data, src_stride); + + // Misaligned destination stride + init(); + ++dst_strides[misaligned_channel]; + check_split(channels, src_data, src_stride); + } + } +} diff --git a/test/api/test_threshold_binary.cpp b/test/api/test_threshold_binary.cpp index 89c7366e6..996fb846f 100644 --- a/test/api/test_threshold_binary.cpp +++ b/test/api/test_threshold_binary.cpp @@ -7,6 +7,11 @@ #include "framework/operation.h" +#define INTRINSICCV_THRESHOLD_BINARY(type, suffix) \ + INTRINSICCV_API(threshold_binary, intrinsiccv_threshold_binary_##suffix, type) + +INTRINSICCV_THRESHOLD_BINARY(uint8_t, u8); + template class ThresholdBinaryTestBase : public UnaryOperationTest { // Needed to initialize value() @@ -123,6 +128,20 @@ TYPED_TEST(ThresholdBinary, TestMax) { TYPED_TEST(ThresholdBinary, NullPointer) { const TypeParam src[1] = {}; TypeParam dst[1]; - test::test_null_args(intrinsiccv_threshold_binary_u8, src, sizeof(TypeParam), + test::test_null_args(threshold_binary(), src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1, 1); } + +TYPED_TEST(ThresholdBinary, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + TypeParam src[1] = {}, dst[1]; + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + threshold_binary()(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, 1, 1)); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + threshold_binary()(src, sizeof(TypeParam), dst, + sizeof(TypeParam) + 1, 1, 1, 1, 1)); +} diff --git a/test/api/test_transpose.cpp b/test/api/test_transpose.cpp index 2e3868eb7..1da3d7155 100644 --- a/test/api/test_transpose.cpp +++ b/test/api/test_transpose.cpp @@ -163,3 +163,27 @@ TYPED_TEST(Transpose, NotImplementedDims) { TEST(Transpose, NotImplementedType) { TestNotImplemented::wrong_type<__uint128_t>(); } + +TYPED_TEST(Transpose, Misalignment) { + if (sizeof(TypeParam) == 1) { + // misalignment impossible + return; + } + + const size_t kBufSize = sizeof(TypeParam) * 10; + char src[kBufSize] = {}, dst[kBufSize] = {}; + + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_transpose(src + 1, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, sizeof(TypeParam))); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_transpose(src, sizeof(TypeParam) + 1, dst, + sizeof(TypeParam), 1, 1, sizeof(TypeParam))); + EXPECT_EQ(INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_transpose(src, sizeof(TypeParam), dst + 1, + sizeof(TypeParam), 1, 1, sizeof(TypeParam))); + EXPECT_EQ( + INTRINSICCV_ERROR_ALIGNMENT, + intrinsiccv_transpose(src, sizeof(TypeParam), dst, sizeof(TypeParam) + 1, + 1, 1, sizeof(TypeParam))); +} diff --git a/test/framework/array.h b/test/framework/array.h index 19bf2a03e..ba72b4a3a 100644 --- a/test/framework/array.h +++ b/test/framework/array.h @@ -41,7 +41,7 @@ class Array2D : public TwoDimensional { : width_{width}, height_{height}, channels_{channels}, - stride_{width * sizeof(ElementType) + padding} { + stride_{(width + padding) * sizeof(ElementType)} { try_allocate(); fill_padding(); } @@ -69,7 +69,7 @@ class Array2D : public TwoDimensional { EXPECT_TRUE(valid()); if (valid()) { - std::memcpy(data_.get(), other.data_.get(), height_ * stride_); + std::memcpy(data(), other.data(), height_ * stride_); } return *this; @@ -80,7 +80,8 @@ class Array2D : public TwoDimensional { if (this == &other) { return *this; } - data_ = std::move(other.data_); + buffer_ = std::move(other.buffer_); + data_ = other.data_; width_ = other.width_; height_ = other.height_; channels_ = other.channels_; @@ -178,12 +179,10 @@ class Array2D : public TwoDimensional { } // Returns a pointer to the first element. - ElementType *data() { return reinterpret_cast(data_.get()); } + ElementType *data() { return data_; } // Returns a const pointer to the first element. - const ElementType *data() const { - return reinterpret_cast(data_.get()); - } + const ElementType *data() const { return data_; } // Returns the width of this array. size_t width() const override { return width_; } @@ -237,7 +236,7 @@ class Array2D : public TwoDimensional { return; } - uint8_t *ptr = data_.get(); + uint8_t *ptr = reinterpret_cast(data()); for (size_t row = 0; row < height(); ++row) { for (size_t column = padding_offset(); column < stride(); ++column) { ptr[column] = kPaddingValue; @@ -253,7 +252,7 @@ class Array2D : public TwoDimensional { return; } - const uint8_t *ptr = data_.get(); + const uint8_t *ptr = reinterpret_cast(data()); for (size_t row = 0; row < height(); ++row) { for (size_t offset = padding_offset(); offset < stride(); ++offset) { if (ptr[offset] != kPaddingValue) { @@ -283,15 +282,24 @@ class Array2D : public TwoDimensional { // Resets the instance to the default instance. void reset() { width_ = height_ = channels_ = stride_ = 0; - data_.reset(); + data_ = nullptr; + buffer_.reset(); } // Tries to allocate backing memory. void try_allocate() { - size_t allocation_size = height_ * stride_; + size_t data_size = height_ * stride_; + // Allocate extra to allow weakening alignment. + size_t allocation_size = data_size + alignof(ElementType); try { - data_ = std::make_unique(allocation_size); + buffer_ = std::make_unique(allocation_size); + // Weaken alignment to flush out potential alignment issues. + // buffer_.get() will contain a pointer that is at least 16-byte aligned. + // By adding a small offset to that we get a pointer that is only aligned + // to alignof(ElementType). + data_ = + reinterpret_cast(buffer_.get() + alignof(ElementType)); } catch (...) { reset(); GTEST_FAIL() << "Failed to allocate memory of " << allocation_size @@ -303,7 +311,10 @@ class Array2D : public TwoDimensional { static constexpr uint8_t kPaddingValue = std::numeric_limits::max(); // Smart pointer to the managed memory. - std::unique_ptr data_; + std::unique_ptr buffer_; + // Pointer to the start of the data. This is offset from the start of buffer_ + // to flush out potential alignment issues. + ElementType *data_{nullptr}; // Width a row in the array. size_t width_{0}; // Number of rows in the array. diff --git a/test/framework/test_array2d.cpp b/test/framework/test_array2d.cpp index b52cfbd26..8c143ebc9 100644 --- a/test/framework/test_array2d.cpp +++ b/test/framework/test_array2d.cpp @@ -48,7 +48,7 @@ TEST(Array2D, ConstructFromArrayLayout) { EXPECT_EQ(array.width(), width); EXPECT_EQ(array.height(), height); EXPECT_EQ(array.channels(), channels); - EXPECT_EQ(array.stride(), width * sizeof(ElementType) + padding); + EXPECT_EQ(array.stride(), (width + padding) * sizeof(ElementType)); EXPECT_TRUE(array.valid()); } @@ -375,7 +375,7 @@ static void PaddingClobbered(size_t row, size_t offset) { using ElementType = uint32_t; size_t width = 5, height = 2, padding = 10; - size_t stride = width * sizeof(ElementType) + padding; + size_t stride = (width + padding) * sizeof(ElementType); test::Array2D array(width, height, padding); uint8_t* ptr = reinterpret_cast(array.data()); @@ -407,7 +407,10 @@ TEST(Array2D, PaddingClobbered_LastRow_LastByte) { } static void Array2DCoverageBadAlloc() { - test::Array2D array{std::numeric_limits::max(), 1}; + size_t big = std::numeric_limits::max() / sizeof(uint64_t); + // Allow a little extra room for Array2D internals, to avoid overflow. + big -= 0x1000; + test::Array2D array{big, 1}; EXPECT_FALSE(array.valid()); } -- GitLab