diff --git a/intrinsiccv/include/utils.h b/intrinsiccv/include/utils.h index c50a0ced3961bf24c5d5ba519105f3a96380050a..7eb30840152b4eae876953cfb7a95d5e569cac1b 100644 --- a/intrinsiccv/include/utils.h +++ b/intrinsiccv/include/utils.h @@ -351,6 +351,17 @@ class LoopUnroll2 final { bool try_avoid_tail_loop_; }; // end of class LoopUnroll2 +// Check whether any of the arguments are null pointers. +template +bool any_null(Pointers... pointers) { + return (... || (pointers == nullptr)); +} + +#define CHECK_POINTERS(...) \ + if (any_null(__VA_ARGS__)) { \ + return INTRINSICCV_ERROR_NULL_POINTER; \ + } + } // namespace intrinsiccv #endif // INTRINSICCV_UTILS_H diff --git a/intrinsiccv/src/analysis/canny_neon.cpp b/intrinsiccv/src/analysis/canny_neon.cpp index 73aa15d0770067724bb4f9ef725083df0687061e..733e7e08c9df3aab506e299891f3ea360ab082be 100644 --- a/intrinsiccv/src/analysis/canny_neon.cpp +++ b/intrinsiccv/src/analysis/canny_neon.cpp @@ -468,6 +468,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); + Rectangle dst_rect{width, height}; // Allocate all temporary buffers in advance. diff --git a/intrinsiccv/src/analysis/count_nonzeros_neon.cpp b/intrinsiccv/src/analysis/count_nonzeros_neon.cpp index 86106a54541e24f60b9827eea915eafaf3af58a8..c453021b480302f92b33e924cdf5caa890d28d3d 100644 --- a/intrinsiccv/src/analysis/count_nonzeros_neon.cpp +++ b/intrinsiccv/src/analysis/count_nonzeros_neon.cpp @@ -67,9 +67,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) { - if (count == nullptr) { - return INTRINSICCV_ERROR_NULL_POINTER; - } + CHECK_POINTERS(src, count); *count = count_nonzeros(src, src_stride, width, height); return INTRINSICCV_OK; } diff --git a/intrinsiccv/src/analysis/min_max_loc_neon.cpp b/intrinsiccv/src/analysis/min_max_loc_neon.cpp index 338a58653383f480aeac65cd829612b9d83feb31..814cedecb8b8d38dc9ad1d0b5ba75fb770cf75df 100644 --- a/intrinsiccv/src/analysis/min_max_loc_neon.cpp +++ b/intrinsiccv/src/analysis/min_max_loc_neon.cpp @@ -310,6 +310,8 @@ 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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride}; MinMaxLoc operation; diff --git a/intrinsiccv/src/analysis/min_max_neon.cpp b/intrinsiccv/src/analysis/min_max_neon.cpp index cd13c4b93abc6c5c4d3e52bc1b2ba1c19c82df9f..76e8e9ef169d649aa5995ef71e9f54919865d633 100644 --- a/intrinsiccv/src/analysis/min_max_neon.cpp +++ b/intrinsiccv/src/analysis/min_max_neon.cpp @@ -48,6 +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); 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 7252fe77a90da2c3a1f3715c0e78c51dce12d62b..4d100c0f1d4e4a94903215bb6eab27969671f90d 100644 --- a/intrinsiccv/src/arithmetics/absdiff_neon.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_neon.cpp @@ -40,6 +40,8 @@ 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); + SaturatingAbsDiff operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/absdiff_sme2.cpp b/intrinsiccv/src/arithmetics/absdiff_sme2.cpp index e0007922517447984f47ebbfb93a9739cc77ccac..654286ea7f9f311a30e672baba4cef60448a1b09 100644 --- a/intrinsiccv/src/arithmetics/absdiff_sme2.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_sme2.cpp @@ -40,6 +40,8 @@ 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); + SaturatingAbsDiff operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/absdiff_sve2.cpp b/intrinsiccv/src/arithmetics/absdiff_sve2.cpp index 3d146d361c9304275edf5f2327c10054eaba73ac..56e5cddb6da921334f7bc0f8a0cb0eb686258962 100644 --- a/intrinsiccv/src/arithmetics/absdiff_sve2.cpp +++ b/intrinsiccv/src/arithmetics/absdiff_sve2.cpp @@ -38,6 +38,8 @@ 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); + SaturatingAbsDiff operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp b/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp index 89464ac6c6efd4a3da1417fa5bc4e415a9adc654..6effc7dff30d5c2e161127f76f609688b28ce23b 100644 --- a/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp +++ b/intrinsiccv/src/arithmetics/add_abs_with_threshold_neon.cpp @@ -39,6 +39,8 @@ 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); + AddAbsWithThreshold operation{threshold}; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h b/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h index 2faf46e3f6f72c8b368962c05d61e24f79d4c8c3..c2fa1643d623c5e23e86058d5ad43a753ad47284 100644 --- a/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h +++ b/intrinsiccv/src/arithmetics/add_abs_with_threshold_sc.h @@ -39,6 +39,8 @@ 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); + AddAbsWithThreshold operation{threshold}; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/add_neon.cpp b/intrinsiccv/src/arithmetics/add_neon.cpp index c78348702bfa73524bc8ba40e55c7e069704951f..c3f3ed5db64051c7e182d8f11c4069c791e49497 100644 --- a/intrinsiccv/src/arithmetics/add_neon.cpp +++ b/intrinsiccv/src/arithmetics/add_neon.cpp @@ -39,6 +39,8 @@ 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); + SaturatingAdd operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/add_sme2.cpp b/intrinsiccv/src/arithmetics/add_sme2.cpp index 3fb6486f2defe9950b95009813fe30dd4ebc3682..cd4dd5482b90f202395f03281d944d45c4da0ef5 100644 --- a/intrinsiccv/src/arithmetics/add_sme2.cpp +++ b/intrinsiccv/src/arithmetics/add_sme2.cpp @@ -26,6 +26,8 @@ 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); + SaturatingAdd operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/add_sve2.cpp b/intrinsiccv/src/arithmetics/add_sve2.cpp index 140dac6d4d677a20078f7c874d46ed273f2f8a43..8d44f99ee0552b0775d159e2f878c5cd51718f92 100644 --- a/intrinsiccv/src/arithmetics/add_sve2.cpp +++ b/intrinsiccv/src/arithmetics/add_sve2.cpp @@ -26,6 +26,8 @@ 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); + SaturatingAdd operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/multiply_neon.cpp b/intrinsiccv/src/arithmetics/multiply_neon.cpp index 12e94ed7ba14192da88898204df62246c124df9a..20563c78781dc3d6ba6b6f26896e1ec1a921325d 100644 --- a/intrinsiccv/src/arithmetics/multiply_neon.cpp +++ b/intrinsiccv/src/arithmetics/multiply_neon.cpp @@ -67,6 +67,8 @@ 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); + (void)scale; // TODO: figure out the way to process the scale. SaturatingMultiply operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/multiply_sve2.cpp b/intrinsiccv/src/arithmetics/multiply_sve2.cpp index 59b54391cf3d9a3f774ab9aa7c9f28c1c8cf7f24..7efca6a8fcb7573fa493aa141166074f451a4c7f 100644 --- a/intrinsiccv/src/arithmetics/multiply_sve2.cpp +++ b/intrinsiccv/src/arithmetics/multiply_sve2.cpp @@ -45,6 +45,8 @@ 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); + (void)scale; // TODO: figure out the way to process the scale. SaturatingMultiply operation; Rectangle rect{width, height}; diff --git a/intrinsiccv/src/arithmetics/scale_neon.cpp b/intrinsiccv/src/arithmetics/scale_neon.cpp index 52c5be3fe2662ac69ec74e6f4bf0077c2dea46a6..4d81862c988d88f47cd9ce7b172b4bad5d24b15a 100644 --- a/intrinsiccv/src/arithmetics/scale_neon.cpp +++ b/intrinsiccv/src/arithmetics/scale_neon.cpp @@ -172,6 +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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride}; diff --git a/intrinsiccv/src/arithmetics/sub_neon.cpp b/intrinsiccv/src/arithmetics/sub_neon.cpp index a015998669405a3420e58dd3a52f61d022e21cf8..318cd206af062855f86e5c20cd5018734b673306 100644 --- a/intrinsiccv/src/arithmetics/sub_neon.cpp +++ b/intrinsiccv/src/arithmetics/sub_neon.cpp @@ -39,6 +39,8 @@ 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); + SaturatingSub operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/sub_sme2.cpp b/intrinsiccv/src/arithmetics/sub_sme2.cpp index 07ac367e863a3c3da88af40cdec64c2c228c342d..b8d7b3926f909877f40e7ea71ab2b988415e5ccb 100644 --- a/intrinsiccv/src/arithmetics/sub_sme2.cpp +++ b/intrinsiccv/src/arithmetics/sub_sme2.cpp @@ -26,6 +26,8 @@ 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); + SaturatingSub operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/sub_sve2.cpp b/intrinsiccv/src/arithmetics/sub_sve2.cpp index 376180384c315a1fa21b55700da60dc44f683a6e..0ab4901e998b1ae220d166f1f3dbf17b58d39108 100644 --- a/intrinsiccv/src/arithmetics/sub_sve2.cpp +++ b/intrinsiccv/src/arithmetics/sub_sve2.cpp @@ -26,6 +26,8 @@ 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); + SaturatingSub operation; Rectangle rect{width, height}; Rows src_a_rows{src_a, src_a_stride}; diff --git a/intrinsiccv/src/arithmetics/threshold_neon.cpp b/intrinsiccv/src/arithmetics/threshold_neon.cpp index 94ae83eb2c6fa10460eeb1f495c6fdfcbdeb0008..979114fd62db4f3efddb702beb5d1e6ec2b098b9 100644 --- a/intrinsiccv/src/arithmetics/threshold_neon.cpp +++ b/intrinsiccv/src/arithmetics/threshold_neon.cpp @@ -41,6 +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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride}; diff --git a/intrinsiccv/src/arithmetics/threshold_sc.h b/intrinsiccv/src/arithmetics/threshold_sc.h index 5922a17778c807b6d2e0c52059db3f32ceb94dd6..78493799388464f3e785d89599e33207d3a3241c 100644 --- a/intrinsiccv/src/arithmetics/threshold_sc.h +++ b/intrinsiccv/src/arithmetics/threshold_sc.h @@ -37,6 +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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride}; diff --git a/intrinsiccv/src/arithmetics/transpose_neon.cpp b/intrinsiccv/src/arithmetics/transpose_neon.cpp index 55394649f0afec8d1022448252df4283b3249536..af7899db9051da2386212ee197fb7e680bba37b7 100644 --- a/intrinsiccv/src/arithmetics/transpose_neon.cpp +++ b/intrinsiccv/src/arithmetics/transpose_neon.cpp @@ -215,6 +215,8 @@ 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) { diff --git a/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp b/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp index 741e81e99cbdf216acfc607689de08b4eb515b3d..b0e01ea0446a17330aba324756c81a251f5810cb 100644 --- a/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/gray_to_rgb_neon.cpp @@ -108,6 +108,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; @@ -120,6 +121,7 @@ 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); 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 b68619bf92de62049dec8ab608a98fa4ffe7752a..69efea54752ba64efefe26208c4316c47074ac74 100644 --- a/intrinsiccv/src/conversions/gray_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/gray_to_rgb_sc.h @@ -199,6 +199,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride}; Rows dst_rows{dst, dst_stride, 3 /* RGB */}; @@ -215,6 +216,7 @@ 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); 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 83bdaeffc7f8d1f17deff02901c8d08d2942c4ec..9017e3d15404a723d0d61a10474c0169533a27f4 100644 --- a/intrinsiccv/src/conversions/merge_neon.cpp +++ b/intrinsiccv/src/conversions/merge_neon.cpp @@ -371,6 +371,12 @@ template intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, void *dst, 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]); + Rectangle rect{width, height}; Rows src_a_rows{srcs[0], src_strides[0]}; Rows src_b_rows{srcs[1], src_strides[1]}; @@ -384,6 +390,7 @@ intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, } break; case 3: { + CHECK_POINTERS(srcs[2]); Merge3 operation; Rows src_c_rows{srcs[2], src_strides[2]}; apply_operation_by_rows(operation, rect, src_a_rows, src_b_rows, @@ -391,6 +398,7 @@ intrinsiccv_error_t merge(const void **srcs, const size_t *src_strides, } break; case 4: { + CHECK_POINTERS(srcs[2], srcs[3]); Merge4 operation; Rows src_c_rows{srcs[2], src_strides[2]}; Rows src_d_rows{srcs[3], src_strides[3]}; diff --git a/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp b/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp index a16fae24d090537382d47baf1a714d35c78a9183..009424d3fe68e2904fbb75e9c0aeec85095d685c 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp +++ b/intrinsiccv/src/conversions/rgb_to_rgb_api.cpp @@ -29,6 +29,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -40,6 +41,7 @@ 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); 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 34357d34a0a3437360cbb94ac1ec3673067d4fa9..d2f56d54276876e41531375f3c6a59de3189d258 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/rgb_to_rgb_neon.cpp @@ -191,6 +191,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -203,6 +204,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -214,6 +216,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -225,6 +228,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; @@ -237,6 +241,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -249,6 +254,7 @@ 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); 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 2477d284653d1bc5a64f981f5bf327d02f526353..df0c3817aa7c5fff19f66d3dd8531f11284c5bcc 100644 --- a/intrinsiccv/src/conversions/rgb_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/rgb_to_rgb_sc.h @@ -184,6 +184,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -201,6 +202,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -213,6 +215,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* BGRA */}; @@ -225,6 +228,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 3 /* RGB */}; Rows dst_rows{dst, dst_stride, 4 /* RGBA */}; @@ -237,6 +241,7 @@ 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); Rectangle rect{width, height}; Rows src_rows{src, src_stride, 4 /* RGBA */}; Rows dst_rows{dst, dst_stride, 3 /* BGR */}; @@ -249,6 +254,7 @@ 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); 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 b1ff1b827e97f36ed9bb835d3d4eac89edb12fe4..4d6d5376c61d3677163bb58ce864e92972a1ee8e 100644 --- a/intrinsiccv/src/conversions/split_neon.cpp +++ b/intrinsiccv/src/conversions/split_neon.cpp @@ -256,6 +256,12 @@ template intrinsiccv_error_t split(const void *src_data, 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]); + Rectangle rect{width, height}; ScalarType *dst0 = reinterpret_cast(dst_data[0]), *dst1 = reinterpret_cast(dst_data[1]); @@ -270,6 +276,7 @@ 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]); Rows dst_rows2{dst2, dst_strides[2]}; Split3 operation; @@ -277,6 +284,7 @@ intrinsiccv_error_t split(const void *src_data, const size_t src_stride, 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]); Rows dst_rows2{dst2, dst_strides[2]}; diff --git a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp index 7ad86c3a2e808275674e9d966c520a8db3cdf2e0..3a7f9fa1457d4f75b9cdd60ef665e3193befc890 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp +++ b/intrinsiccv/src/conversions/yuv_to_rgb_neon.cpp @@ -292,6 +292,7 @@ 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); 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 e0580b6ba0bffe26b2cb8baf8ca456a2c42a307b..335fb03a8bd48f60b5e2e0b933ce3f3f6eea5e79 100644 --- a/intrinsiccv/src/conversions/yuv_to_rgb_sc.h +++ b/intrinsiccv/src/conversions/yuv_to_rgb_sc.h @@ -193,6 +193,7 @@ 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); 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_api.cpp b/intrinsiccv/src/filters/gaussian_blur_api.cpp index c76796c70326deaeddf34f095ac8fa5b67581c2f..ee9f96eba64a61064b0cb6c48285a4bbb54f74b4 100644 --- a/intrinsiccv/src/filters/gaussian_blur_api.cpp +++ b/intrinsiccv/src/filters/gaussian_blur_api.cpp @@ -13,6 +13,7 @@ extern "C" { intrinsiccv_error_t intrinsiccv_filter_create( intrinsiccv_filter_params_t *params, intrinsiccv_rectangle_t image) { + CHECK_POINTERS(params); auto workspace = SeparableFilterWorkspace::create( Rectangle{image}, params->channels, params->type_size); if (!workspace) { @@ -25,9 +26,8 @@ intrinsiccv_error_t intrinsiccv_filter_create( intrinsiccv_error_t intrinsiccv_filter_release( intrinsiccv_filter_params_t *params) { - if (!params->workspace) { - return INTRINSICCV_ERROR_NULL_POINTER; - } + CHECK_POINTERS(params); + CHECK_POINTERS(params->workspace); // Deliberately create and immediately destroy a unique_ptr to delete the // workspace. diff --git a/intrinsiccv/src/filters/gaussian_blur_neon.cpp b/intrinsiccv/src/filters/gaussian_blur_neon.cpp index 62038e762eabf861df6b79be62de43ab5c337f62..59f947eaed90d89302143e47cb1121a12e3ecad1 100644 --- a/intrinsiccv/src/filters/gaussian_blur_neon.cpp +++ b/intrinsiccv/src/filters/gaussian_blur_neon.cpp @@ -150,6 +150,9 @@ intrinsiccv_error_t discrete_gaussian_blur( const intrinsiccv_filter_params_t *params) { using GaussianBlurFilterType = DiscreteGaussianBlur; + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->workspace); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; diff --git a/intrinsiccv/src/filters/gaussian_blur_sc.h b/intrinsiccv/src/filters/gaussian_blur_sc.h index 738ab70c27cbd63ad5494ed3281b632bf5318e74..7ef65334e6102505ed6069c49ba2011d7958ca51 100644 --- a/intrinsiccv/src/filters/gaussian_blur_sc.h +++ b/intrinsiccv/src/filters/gaussian_blur_sc.h @@ -91,6 +91,9 @@ intrinsiccv_error_t discrete_gaussian_blur( INTRINSICCV_STREAMING_COMPATIBLE { using GaussianBlurFilterType = DiscreteGaussianBlur; + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->workspace); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; diff --git a/intrinsiccv/src/filters/sobel_neon.cpp b/intrinsiccv/src/filters/sobel_neon.cpp index 0dd403f4b03ac35e3bbaa3df96c81bd92fcb4592..6bb047ff2cdda48333f3b6124f68c25e7143b57f 100644 --- a/intrinsiccv/src/filters/sobel_neon.cpp +++ b/intrinsiccv/src/filters/sobel_neon.cpp @@ -132,6 +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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; @@ -154,6 +156,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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; diff --git a/intrinsiccv/src/filters/sobel_sc.h b/intrinsiccv/src/filters/sobel_sc.h index 47258922ddbd1e4069c414d9fcb09ee8f2240071..38e250fcb3e3982370a149acec5bb363988a9bfa 100644 --- a/intrinsiccv/src/filters/sobel_sc.h +++ b/intrinsiccv/src/filters/sobel_sc.h @@ -122,6 +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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; @@ -145,6 +147,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); + Rectangle rect{width, height}; Rows src_rows{src, src_stride, channels}; Rows dst_rows{dst, dst_stride, channels}; diff --git a/intrinsiccv/src/morphology/morphology_api.cpp b/intrinsiccv/src/morphology/morphology_api.cpp index d59f3ebfe3ae66db44c93f98d25e6da9cbafc08b..f715bb70257132b69c7537c5acff60f35d01270f 100644 --- a/intrinsiccv/src/morphology/morphology_api.cpp +++ b/intrinsiccv/src/morphology/morphology_api.cpp @@ -54,6 +54,8 @@ extern "C" { intrinsiccv_error_t intrinsiccv_morphology_create( intrinsiccv_morphology_params_t *params, intrinsiccv_rectangle_t image) { + CHECK_POINTERS(params); + auto workspace = MorphologyWorkspace::create(Rectangle{image}, Rectangle{params->kernel}, Margin{params->kernel, params->anchor}, @@ -68,9 +70,8 @@ intrinsiccv_error_t intrinsiccv_morphology_create( intrinsiccv_error_t intrinsiccv_morphology_release( intrinsiccv_morphology_params_t *params) { - if (!params->data) { - return INTRINSICCV_ERROR_NULL_POINTER; - } + CHECK_POINTERS(params); + CHECK_POINTERS(params->data); // Deliberately create and immediately destroy a unique_ptr to delete the // workspace. diff --git a/intrinsiccv/src/morphology/morphology_neon.cpp b/intrinsiccv/src/morphology/morphology_neon.cpp index a358c0ffce5014db8521cc1b20284c5925411302..d7886c2c9cfc6427ed476e9f48a492ac3c2a5d72 100644 --- a/intrinsiccv/src/morphology/morphology_neon.cpp +++ b/intrinsiccv/src/morphology/morphology_neon.cpp @@ -490,6 +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, const intrinsiccv_morphology_params_t *params) { + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->impl, params->data); + Rectangle rect{width, height}; Rectangle kernel{params->kernel}; Rows src_rows{src, src_stride, params->channels}; @@ -541,6 +544,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, const intrinsiccv_morphology_params_t *params) { + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->impl, params->data); + Rectangle rect{width, height}; Rectangle kernel{params->kernel}; Rows src_rows{src, src_stride, params->channels}; diff --git a/intrinsiccv/src/morphology/morphology_sc.h b/intrinsiccv/src/morphology/morphology_sc.h index a6ed84a9ff91683cc48563e48bd04feb4ea32c9a..fdcadbfd94690134271a8d4ad4be0ecce068279b 100644 --- a/intrinsiccv/src/morphology/morphology_sc.h +++ b/intrinsiccv/src/morphology/morphology_sc.h @@ -448,10 +448,13 @@ class DilateOperation final { }; // end of class DilateOperation template -static inline intrinsiccv_error_t dilate_sc( +static intrinsiccv_error_t dilate_sc( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, const intrinsiccv_morphology_params_t *params) INTRINSICCV_STREAMING_COMPATIBLE { + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->impl, params->data); + Rectangle rect{width, height}; Rectangle kernel{params->kernel}; Rows src_rows{src, src_stride, params->channels}; @@ -503,10 +506,13 @@ class ErodeOperation final { }; // end of class ErodeOperation template -static inline intrinsiccv_error_t erode_sc( +static intrinsiccv_error_t erode_sc( const T *src, size_t src_stride, T *dst, size_t dst_stride, size_t width, size_t height, const intrinsiccv_morphology_params_t *params) INTRINSICCV_STREAMING_COMPATIBLE { + CHECK_POINTERS(src, dst, params); + CHECK_POINTERS(params->impl, params->data); + Rectangle rect{width, height}; Rectangle kernel{params->kernel}; Rows src_rows{src, src_stride, params->channels}; diff --git a/intrinsiccv/src/resize/resize_neon.cpp b/intrinsiccv/src/resize/resize_neon.cpp index 58988f620ed7fa957056034f4362cf04c8d86340..777211d94b6fab7cd41c393a70f0c42aad3796e2 100644 --- a/intrinsiccv/src/resize/resize_neon.cpp +++ b/intrinsiccv/src/resize/resize_neon.cpp @@ -13,6 +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); + for (; src_height >= 2; src_height -= 2, src += (src_stride * 2), --dst_height, dst += dst_stride) { const uint8_t *src_l = src; diff --git a/intrinsiccv/src/resize/resize_sc.h b/intrinsiccv/src/resize/resize_sc.h index 42c9ed2fc77cff845f8ddfaa24aa60f0205b5440..0a77b5ef00388b4d11945c027e5038c697e34f09 100644 --- a/intrinsiccv/src/resize/resize_sc.h +++ b/intrinsiccv/src/resize/resize_sc.h @@ -143,6 +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); + Rows src_rows{src, src_stride, /* channels*/ 1}; Rows dst_rows{dst, dst_stride, /* channels*/ 1}; LoopUnroll2 loop{src_height, /* Process two rows */ 2}; diff --git a/test/api/test_canny.cpp b/test/api/test_canny.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9acc82b06646f91b294cc32467bdaba538b7b1c9 --- /dev/null +++ b/test/api/test_canny.cpp @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "framework/utils.h" + +#define INTRINSICCV_CANNY(type, suffix) \ + INTRINSICCV_API(canny, intrinsiccv_canny_##suffix, type) + +INTRINSICCV_CANNY(uint8_t, u8); + +using ElementTypes = ::testing::Types; + +template +class CannyTest : public testing::Test {}; + +TYPED_TEST_SUITE(CannyTest, ElementTypes); + +TYPED_TEST(CannyTest, NullPointer) { + TypeParam src[1], dst[1]; + test::test_null_args(canny(), src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, 0.0, 1.0); +} diff --git a/test/api/test_count_nonzeros.cpp b/test/api/test_count_nonzeros.cpp index 79c82ee499ffbe5532772310fb73333650e133b7..3b3368c02d7a83b08d85667124a31398a2fa4b09 100644 --- a/test/api/test_count_nonzeros.cpp +++ b/test/api/test_count_nonzeros.cpp @@ -110,3 +110,10 @@ TYPED_TEST(CountNonZeros, AllNonZerosPadded) { CountNonZerosTest{}.test( test::Options::vector_length()); } + +TYPED_TEST(CountNonZeros, NullPointer) { + TypeParam src[1]; + size_t count = 0; + test::test_null_args(count_nonzeros(), src, sizeof(TypeParam), 1, + 1, &count); +} diff --git a/test/api/test_gaussian_blur.cpp b/test/api/test_gaussian_blur.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b880a112e544674343f02f727cfa4eec73b60600 --- /dev/null +++ b/test/api/test_gaussian_blur.cpp @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "framework/utils.h" + +#define INTRINSICCV_GAUSSIAN_BLUR(type, kernel_suffix, type_suffix) \ + INTRINSICCV_API(gaussian_blur_##kernel_suffix, \ + intrinsiccv_gaussian_blur_##kernel_suffix##_##type_suffix, \ + type) + +INTRINSICCV_GAUSSIAN_BLUR(uint8_t, 3x3, u8); +INTRINSICCV_GAUSSIAN_BLUR(uint8_t, 5x5, u8); + +using ElementTypes = ::testing::Types; + +template +class GaussianBlurTest : public testing::Test {}; + +TYPED_TEST_SUITE(GaussianBlurTest, ElementTypes); + +TYPED_TEST(GaussianBlurTest, NullPointer) { + intrinsiccv_filter_params_t params = { + .channels = 1, + .type_size = sizeof(TypeParam), + .workspace = nullptr, + }; + ASSERT_EQ(INTRINSICCV_OK, + intrinsiccv_filter_create(¶ms, intrinsiccv_rectangle_t{1, 1})); + TypeParam src[1] = {}, dst[1]; + test::test_null_args(gaussian_blur_3x3(), src, sizeof(TypeParam), + dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, ¶ms); + test::test_null_args(gaussian_blur_5x5(), src, sizeof(TypeParam), + dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, ¶ms); + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_filter_release(¶ms)); + EXPECT_EQ(nullptr, params.workspace); + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + gaussian_blur_3x3()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, ¶ms)); + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + gaussian_blur_5x5()( + src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1, + INTRINSICCV_BORDER_TYPE_REFLECT, ¶ms)); +} diff --git a/test/api/test_merge.cpp b/test/api/test_merge.cpp index 4e2dd1e3cd34d8ba1cd1eaec77bdba325935e282..a71cfa6f675662a3919505b009f8f1a0c3ac0f6a 100644 --- a/test/api/test_merge.cpp +++ b/test/api/test_merge.cpp @@ -134,8 +134,8 @@ TYPED_TEST(Merge, FourChannels) { MergeTest().with_padding(test::Options::vector_length()).test(); } -TYPED_TEST(Merge, OneChannelNotImplemented) { - test_not_implemented(); +TYPED_TEST(Merge, OneChannelOutOfRange) { + test_not_implemented(INTRINSICCV_ERROR_RANGE); } TYPED_TEST(Merge, FiveChannelsNotImplemented) { @@ -143,3 +143,27 @@ TYPED_TEST(Merge, FiveChannelsNotImplemented) { } TEST(Merge128, NotImplemented) { test_not_implemented<__uint128_t, 2>(); } + +TYPED_TEST(Merge, NullPointer) { + const size_t kChannels = 4; + TypeParam src_arrays[kChannels]; + TypeParam dst[kChannels]; + size_t src_strides[kChannels] = {sizeof(TypeParam), sizeof(TypeParam), + sizeof(TypeParam), sizeof(TypeParam)}; + const void* srcs[kChannels] = {src_arrays, src_arrays + 1, src_arrays + 2, + src_arrays + 3}; + size_t dst_stride = kChannels * sizeof(TypeParam); + test::test_null_args(intrinsiccv_merge, srcs, src_strides, dst, dst_stride, 1, + 1, kChannels, sizeof(TypeParam)); + + for (int channels = 2; channels <= 4; ++channels) { + for (int null_src = 0; null_src < channels; ++null_src) { + for (int i = 0; i < channels; ++i) { + srcs[i] = (i == null_src) ? nullptr : src_arrays + i; + } + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + intrinsiccv_merge(srcs, src_strides, dst, dst_stride, 1, 1, + channels, sizeof(TypeParam))); + } + } +} diff --git a/test/api/test_min_max.cpp b/test/api/test_min_max.cpp index 71942bfb6c37b108be78e57631ac0d38ef283d50..44cc54177ca33f62348a5a7147bd074855dff1bb 100644 --- a/test/api/test_min_max.cpp +++ b/test/api/test_min_max.cpp @@ -197,8 +197,9 @@ class MinMaxTest { if (p_max) { *p_max = std::numeric_limits::min(); } - min_max()(source.data(), source.stride(), width(), height(), - p_min, p_max); + EXPECT_EQ(INTRINSICCV_OK, + min_max()(source.data(), source.stride(), width(), + height(), p_min, p_max)); if (p_min) { EXPECT_EQ(*p_min, expected_min); } @@ -215,7 +216,13 @@ class MinMaxTest { setup(source, testData); - ElementType actual_min, actual_max; + ElementType actual_min = 2, actual_max = 1; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + min_max()(nullptr, source.stride(), width(), + height(), &actual_min, &actual_max)); + EXPECT_EQ(2, actual_min); + EXPECT_EQ(1, actual_max); + one_test_call(source, nullptr, nullptr, 0, 0); one_test_call(source, &actual_min, nullptr, testData.expected_min, 0); one_test_call(source, nullptr, &actual_max, 0, testData.expected_max); @@ -261,7 +268,14 @@ class MinMaxLocTest : public MinMaxTest { setup(source, testData); - size_t min_offset = 0, max_offset = 0; + size_t min_offset = 2, max_offset = 1; + + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + min_max_loc()(nullptr, source.stride(), width(), + height(), &min_offset, &max_offset)); + EXPECT_EQ(2, min_offset); + EXPECT_EQ(1, max_offset); + one_test_call(source, nullptr, nullptr, 0, 0); one_test_call(source, &min_offset, nullptr, testData.expected_min_offset, 0); diff --git a/test/api/test_morphology.cpp b/test/api/test_morphology.cpp new file mode 100644 index 0000000000000000000000000000000000000000..957df297b3393d1ede1b4774e7846711356ce575 --- /dev/null +++ b/test/api/test_morphology.cpp @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include "framework/operation.h" + +#define INTRINSICCV_DILATE(type, suffix) \ + INTRINSICCV_API(dilate, intrinsiccv_dilate_##suffix, type) + +#define INTRINSICCV_ERODE(type, suffix) \ + INTRINSICCV_API(erode, intrinsiccv_erode_##suffix, type) + +INTRINSICCV_DILATE(uint8_t, u8); +INTRINSICCV_ERODE(uint8_t, u8); + +template +class DilateTest : public testing::Test {}; + +template +class ErodeTest : public testing::Test {}; + +using ElementTypes = ::testing::Types; +TYPED_TEST_SUITE(DilateTest, ElementTypes); +TYPED_TEST_SUITE(ErodeTest, ElementTypes); + +static intrinsiccv_morphology_params_t make_minimal_params(size_t type_size) { + intrinsiccv_morphology_params_t params = { + .kernel = {1, 1}, + .anchor = {0, 0}, + .border_type = INTRINSICCV_BORDER_TYPE_REPLICATE, + .border_values = {0, 0, 1, 1}, + .channels = 1, + .iterations = 1, + .type_size = type_size, + .impl = nullptr, + .data = nullptr, + }; + return params; +} + +TYPED_TEST(DilateTest, NullPointer) { + intrinsiccv_morphology_params_t params = + make_minimal_params(sizeof(TypeParam)); + ASSERT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_create( + ¶ms, intrinsiccv_rectangle_t{1, 1})); + TypeParam src[1] = {}, dst[1]; + test::test_null_args(dilate(), src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, ¶ms); + + { + intrinsiccv_morphology_params_t invalid_params = params; + invalid_params.impl = nullptr; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + dilate()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, &invalid_params)); + } + + { + intrinsiccv_morphology_params_t invalid_params = params; + invalid_params.data = nullptr; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + dilate()(src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, &invalid_params)); + } + + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(¶ms)); +} + +TYPED_TEST(ErodeTest, NullPointer) { + intrinsiccv_morphology_params_t params = + make_minimal_params(sizeof(TypeParam)); + ASSERT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_create( + ¶ms, intrinsiccv_rectangle_t{1, 1})); + + TypeParam src[1] = {}, dst[1]; + test::test_null_args(erode(), src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, ¶ms); + + { + intrinsiccv_morphology_params_t invalid_params = params; + invalid_params.impl = nullptr; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), + 1, 1, &invalid_params)); + } + + { + intrinsiccv_morphology_params_t invalid_params = params; + invalid_params.data = nullptr; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + erode()(src, sizeof(TypeParam), dst, sizeof(TypeParam), + 1, 1, &invalid_params)); + } + + EXPECT_EQ(INTRINSICCV_OK, intrinsiccv_morphology_release(¶ms)); +} diff --git a/test/api/test_resize_to_quarter.cpp b/test/api/test_resize_to_quarter.cpp index b4cf33f538f209112deef46e1d254e6c0927e4cb..128bf8d3454f8971d6d944dfaa061d1e3c3eff3a 100644 --- a/test/api/test_resize_to_quarter.cpp +++ b/test/api/test_resize_to_quarter.cpp @@ -211,3 +211,10 @@ TEST(ResizeToQuarter, OddDimsTruncated) { size_t dst_height = src_height / 2; resize_test.execute_test(src_width, src_height, dst_width, dst_height); } + +TEST(ResizeToQuarter, NullPointer) { + const uint8_t src[4] = {}; + uint8_t dst[1]; + test::test_null_args(intrinsiccv_resize_to_quarter_u8, src, 2, 2, 2, dst, 1, + 1, 1); +} diff --git a/test/api/test_rgb_and_gray.cpp b/test/api/test_rgb_and_gray.cpp index b0fff439f2072b59330cec0271ab810527959b90..38426a2ef4ba6c902fbb7953580281692fd4faac 100644 --- a/test/api/test_rgb_and_gray.cpp +++ b/test/api/test_rgb_and_gray.cpp @@ -33,6 +33,9 @@ class GrayTest final { ASSERT_EQ(INTRINSICCV_OK, err); EXPECT_EQ_ARRAY2D(actual, expected); + + test::test_null_args(impl, source.data(), source.stride(), actual.data(), + actual.stride(), logical_width, actual.height()); } private: @@ -85,6 +88,9 @@ class ColourTest final { ASSERT_EQ(INTRINSICCV_OK, err); EXPECT_EQ_ARRAY2D(actual, expected); + + test::test_null_args(impl, source.data(), source.stride(), actual.data(), + actual.stride(), logical_width, actual.height()); } private: diff --git a/test/api/test_saturating_absdiff.cpp b/test/api/test_saturating_absdiff.cpp index 0280de1c37abb09bbc6db92fd992436ef2ea9539..873c820d30f4a1b8c2d49f7a75595c833edb1f0a 100644 --- a/test/api/test_saturating_absdiff.cpp +++ b/test/api/test_saturating_absdiff.cpp @@ -97,4 +97,8 @@ TYPED_TEST(SaturatingAbsDiff, API) { SaturatingAbsDiffTest{} .with_padding(test::Options::vector_length()) .test(); + + TypeParam src[1], dst[1]; + test::test_null_args(saturating_absdiff(), src, sizeof(TypeParam), + src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } diff --git a/test/api/test_saturating_add.cpp b/test/api/test_saturating_add.cpp index d202abcec5f8a2c716b1e78cc024c73d27418fb5..030b44056098b8b1ffd6c26033058b97639e8f8b 100644 --- a/test/api/test_saturating_add.cpp +++ b/test/api/test_saturating_add.cpp @@ -89,4 +89,8 @@ TYPED_TEST(SaturatingAdd, API) { SaturatingAddTest{} .with_padding(test::Options::vector_length()) .test(); + + TypeParam src[1], dst[1]; + test::test_null_args(saturating_add(), src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } diff --git a/test/api/test_saturating_multiply.cpp b/test/api/test_saturating_multiply.cpp index 3ab8964788a8cd5aab24f5f7dd444f4ead0a592b..610128f73d3529f830de2d7b502cac6b4690050f 100644 --- a/test/api/test_saturating_multiply.cpp +++ b/test/api/test_saturating_multiply.cpp @@ -97,4 +97,8 @@ TYPED_TEST(SaturatingMultiply, API) { SaturatingMultiplyTest{} .with_padding(test::Options::vector_length()) .test(); + + TypeParam src[1], dst[1]; + test::test_null_args(saturating_multiply(), src, sizeof(TypeParam), + src, sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1, 1); } diff --git a/test/api/test_saturating_sub.cpp b/test/api/test_saturating_sub.cpp index 4ab3c7bb128e34d22072a315cd19fffe016137b7..1c78f4da7f7a02d0a9e83a0616e0234381514ca6 100644 --- a/test/api/test_saturating_sub.cpp +++ b/test/api/test_saturating_sub.cpp @@ -91,4 +91,8 @@ TYPED_TEST(SaturatingSub, API) { SaturatingSubTest{} .with_padding(test::Options::vector_length()) .test(); + + TypeParam src[1], dst[1]; + test::test_null_args(saturating_sub(), src, sizeof(TypeParam), src, + sizeof(TypeParam), dst, sizeof(TypeParam), 1, 1); } diff --git a/test/api/test_scale.cpp b/test/api/test_scale.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1caaf9b604a13f07212d0e81fd61485bcd7fc49 --- /dev/null +++ b/test/api/test_scale.cpp @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2024 Arm Limited and/or its affiliates +// +// SPDX-License-Identifier: Apache-2.0 + +#include +#include + +#include + +#include "framework/operation.h" + +#define INTRINSICCV_SCALE(type, suffix) \ + INTRINSICCV_API(scale, intrinsiccv_scale_##suffix, type) + +INTRINSICCV_SCALE(uint8_t, u8); + +template +class ScaleTest : public testing::Test {}; + +using ElementTypes = ::testing::Types; +TYPED_TEST_SUITE(ScaleTest, ElementTypes); + +TYPED_TEST(ScaleTest, NullPointer) { + TypeParam src[1] = {}, dst[1]; + test::test_null_args(scale(), src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, 2, 0); +} diff --git a/test/api/test_sobel.cpp b/test/api/test_sobel.cpp index b0370b26a48a7c2f8947758a0d531ef0f1bc295c..fdb8fa6d9be20e10a1e8da32976e74b3321be9ff 100644 --- a/test/api/test_sobel.cpp +++ b/test/api/test_sobel.cpp @@ -88,6 +88,11 @@ TYPED_TEST(Sobel, Horizontal3x3) { mask.set(1, 0, {-2, 0, 2}); mask.set(2, 0, {-1, 0, 1}); Sobel3x3Test{}.test(mask); + + typename KernelTestParams::InputType src[1] = {}; + typename KernelTestParams::OutputType dst[1]; + test::test_null_args(sobel_3x3_horizontal(), src, sizeof(src), dst, + sizeof(dst), 1, 1, 1); } // Tests sobel_3x3_vertical__ API. @@ -101,4 +106,9 @@ TYPED_TEST(Sobel, Vertical3x3) { mask.set(2, 0, { 1, 2, 1}); // clang-format on Sobel3x3Test{}.test(mask); + + typename KernelTestParams::InputType src[1] = {}; + typename KernelTestParams::OutputType dst[1]; + test::test_null_args(sobel_3x3_vertical(), src, sizeof(src), dst, + sizeof(dst), 1, 1, 1); } diff --git a/test/api/test_split.cpp b/test/api/test_split.cpp index 652bb3d6538996529bf7666b8ca5bbb671c23c29..91f36334b33cbc1bbc308aa5a4e90e30a3758069 100644 --- a/test/api/test_split.cpp +++ b/test/api/test_split.cpp @@ -133,8 +133,8 @@ TYPED_TEST(Split, FourChannels) { SplitTest().with_padding(test::Options::vector_length()).test(); } -TYPED_TEST(Split, OneChannelNotImplemented) { - test_not_implemented(); +TYPED_TEST(Split, OneChannelOutOfRange) { + test_not_implemented(INTRINSICCV_ERROR_RANGE); } TYPED_TEST(Split, FiveChannelsNotImplemented) { @@ -142,3 +142,29 @@ TYPED_TEST(Split, FiveChannelsNotImplemented) { } TEST(Split128, NotImplemented) { test_not_implemented<__uint128_t, 2>(); } + +TYPED_TEST(Split, NullPointer) { + const size_t kChannels = 4; + + TypeParam src_data[kChannels]; + size_t src_stride = kChannels * sizeof(TypeParam); + TypeParam dst_arrays[kChannels]; + void* dst_data[kChannels] = {dst_arrays, dst_arrays + 1, dst_arrays + 2, + dst_arrays + 3}; + size_t dst_strides[kChannels] = {sizeof(TypeParam), sizeof(TypeParam), + sizeof(TypeParam), sizeof(TypeParam)}; + + test::test_null_args(intrinsiccv_split, src_data, src_stride, dst_data, + dst_strides, 1, 1, kChannels, sizeof(TypeParam)); + + for (int channels = 2; channels <= 4; ++channels) { + for (int null_src = 0; null_src < channels; ++null_src) { + for (int i = 0; i < channels; ++i) { + dst_data[i] = (i == null_src) ? nullptr : dst_arrays + i; + } + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, + intrinsiccv_split(src_data, src_stride, dst_data, dst_strides, + 1, 1, channels, sizeof(TypeParam))); + } + } +} diff --git a/test/api/test_threshold_binary.cpp b/test/api/test_threshold_binary.cpp index 5ca3651d26e03b715729d7657d5ebf186454d06e..89c7366e6ecba9ead12bc69f12f8a204ac0bd5a0 100644 --- a/test/api/test_threshold_binary.cpp +++ b/test/api/test_threshold_binary.cpp @@ -119,3 +119,10 @@ TYPED_TEST(ThresholdBinary, TestZero) { TYPED_TEST(ThresholdBinary, TestMax) { ThresholdBinaryTestMax{}.test(); } + +TYPED_TEST(ThresholdBinary, NullPointer) { + const TypeParam src[1] = {}; + TypeParam dst[1]; + test::test_null_args(intrinsiccv_threshold_binary_u8, src, sizeof(TypeParam), + dst, sizeof(TypeParam), 1, 1, 1, 1); +} diff --git a/test/api/test_transpose.cpp b/test/api/test_transpose.cpp index bea30d121c53a4ceb6806fb63dc7c409c1e091ba..94ec882eef48211ecc02ff480b0c3892f9e270bc 100644 --- a/test/api/test_transpose.cpp +++ b/test/api/test_transpose.cpp @@ -122,3 +122,9 @@ TYPED_TEST(Transpose, VectorInplaceWithPadding) { TestTranspose test(1); test.vector_test(); } + +TYPED_TEST(Transpose, NullPointer) { + TypeParam src[1] = {}, dst[1]; + test::test_null_args(intrinsiccv_transpose, src, sizeof(TypeParam), dst, + sizeof(TypeParam), 1, 1, sizeof(TypeParam)); +} diff --git a/test/api/test_yuv_to_rgb.cpp b/test/api/test_yuv_to_rgb.cpp index ac0c31f539a92d0e2fc6d2359d46f8b2f61e1166..7f4dc641c3ba47dcf7723fcb2892d37bba0191cc 100644 --- a/test/api/test_yuv_to_rgb.cpp +++ b/test/api/test_yuv_to_rgb.cpp @@ -62,6 +62,11 @@ class YuvTest final { ASSERT_EQ(INTRINSICCV_OK, err); EXPECT_EQ_ARRAY2D(expected, actual); + + test::test_null_args(impl, input_y.data(), input_y.stride(), + input_uv.data(), input_uv.stride(), actual.data(), + actual.stride(), expected.width() / channel_number_, + expected.height(), is_nv21); } void calculate_expected(test::Array2D &y_arr, diff --git a/test/framework/utils.h b/test/framework/utils.h index a9ed38cb08379ffddbe52b349752f50dd2ba1873..e266a3a8fb30e86fe5f02596bdf5df9049110ef2 100644 --- a/test/framework/utils.h +++ b/test/framework/utils.h @@ -10,8 +10,10 @@ #include #include #include +#include #include +#include "ctypes.h" #include "framework/abstract.h" #include "framework/types.h" @@ -84,6 +86,58 @@ void dump(const TwoDimensional *elements); std::array default_array_layouts(size_t min_width, size_t min_height); +namespace internal { +template +class NullPointerTester { + // Set the given argument to null and test that the function diagnoses the + // error correctly. + template + static typename std::enable_if>::type + test_with_null_arg(Function f, Tuple t) { + std::get(t) = nullptr; + EXPECT_EQ(INTRINSICCV_ERROR_NULL_POINTER, std::apply(f, t)); + } + + // Skip arguments that aren't pointers. + template + static typename std::enable_if>::type + test_with_null_arg(Function, const Tuple &) {} + + public: + template + static void test(Function f, const Tuple &t) { + // Recurse to test earlier arguments first + test(f, t); + using ArgType = typename std::tuple_element_t; + test_with_null_arg(f, t); + } + + // Terminate recursion + template <> + static void test<-1>(Function, const Tuple &) {} +}; + +template +class ParamsExtractor; +template +class ParamsExtractor { + public: + using Tuple = std::tuple; +}; +} // namespace internal + +// Tests that the function returns INTRINSICCV_ERROR_NULL_POINTER if any of its +// pointer arguments are null. +template +void test_null_args(Function f, Args... args) { + // Ensure that the function parameter types are used otherwise arguments may + // not be recognised as pointers. + using Tuple = typename internal::ParamsExtractor::Tuple; + constexpr int LastArgIndex = std::tuple_size_v - 1; + using Tester = internal::NullPointerTester; + Tester::template test(f, Tuple(args...)); +} + } // namespace test #endif // INTRINSICCV_TEST_FRAMEWORK_UTILS_H_