Răsfoiți Sursa

Fix Coverity warnings. (#1359)

Specify required output size in the Doxygen documentation for some functions.
Switch from using memcpy() to arm_memcpy_17().
Add NULL check for context buffer.
Add fixes for division by zero.
Added missing parameter in if-statement in dw_conv wrapper function.
Removed unneccessary testcase.

Change-Id: I9a8d67c4ba7087ede6c0070f39d481f0cce09d2d
Jens Elofsson 4 ani în urmă
părinte
comite
0748c8db60

+ 18 - 9
Include/arm_nnfunctions.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -1884,7 +1884,8 @@ int32_t arm_avgpool_s8_get_buffer_size(const int dim_dst_width, const int ch_src
  * @param[in]      pool_params    Pooling parameters
  * @param[in]      input_dims     Input (activation) tensor dimensions. Format: [H, W, C_IN]
  *                                Argument 'N' is not used.
- * @param[in]      input_data     Input (activation) data pointer. Data type: int8
+ * @param[in]      input_data     Input (activation) data pointer. The input tensor must not
+ *                                overlap with the output tensor. Data type: int8
  * @param[in]      filter_dims    Filter tensor dimensions. Format: [H, W]
  *                                Argument N and C are not used.
  * @param[in]      output_dims    Output tensor dimensions. Format: [H, W, C_OUT]
@@ -2102,12 +2103,14 @@ void arm_reshape_s8(const int8_t *input, int8_t *output, const uint32_t total_si
  * @note This function, data layout independent, can be used to concatenate either int8 or uint8 tensors because it
  *      does not involve any arithmetic operation
  *
- * @param[in]  input    Pointer to input tensor
+ * @param[in]  input    Pointer to input tensor. Input tensor must not overlap with the output tensor.
  * @param[in]  input_x  Width of input tensor
  * @param[in]  input_y  Height of input tensor
  * @param[in]  input_z  Channels in input tensor
  * @param[in]  input_w  Batch size in input tensor
- * @param[out] output   Pointer to output tensor
+ * @param[out] output   Pointer to output tensor. Expected to be at least
+ *                          (input_x * input_y * input_z * input_w) + offset_x
+ *                      bytes.
  * @param[in]  output_x Width of output tensor
  * @param[in]  offset_x The offset (in number of elements) on the X axis to start concatenating the input tensor
  *                      It is user responsibility to provide the correct value
@@ -2147,12 +2150,14 @@ void arm_concatenation_s8_x(const int8_t *input,
  * @note This function, data layout independent, can be used to concatenate either int8 or uint8 tensors because it
  *       does not involve any arithmetic operation
  *
- * @param[in]  input    Pointer to input tensor
+ * @param[in]  input    Pointer to input tensor. Input tensor must not overlap with the output tensor.
  * @param[in]  input_x  Width of input tensor
  * @param[in]  input_y  Height of input tensor
  * @param[in]  input_z  Channels in input tensor
  * @param[in]  input_w  Batch size in input tensor
- * @param[out] output   Pointer to output tensor
+ * @param[out] output   Pointer to output tensor. Expected to be at least
+ *                          (input_z * input_w * input_x * input_y) + offset_y
+ *                      bytes.
  * @param[in]  output_y Height of output tensor
  * @param[in]  offset_y The offset on the Y axis to start concatenating the input tensor
  *                      It is user responsibility to provide the correct value
@@ -2192,12 +2197,14 @@ void arm_concatenation_s8_y(const int8_t *input,
  * @note This function, data layout independent, can be used to concatenate either int8 or uint8 tensors because it
  *       does not involve any arithmetic operation
  *
- * @param[in]  input    Pointer to input tensor
+ * @param[in]  input    Pointer to input tensor. Input tensor must not overlap with output tensor.
  * @param[in]  input_x  Width of input tensor
  * @param[in]  input_y  Height of input tensor
  * @param[in]  input_z  Channels in input tensor
  * @param[in]  input_w  Batch size in input tensor
- * @param[out] output   Pointer to output tensor
+ * @param[out] output   Pointer to output tensor. Expected to be at least
+ *                          (input_x * input_y * input_z * input_w) + offset_z
+ *                      bytes.
  * @param[in]  output_z Channels in output tensor
  * @param[in]  offset_z The offset on the Z axis to start concatenating the input tensor
  *                      It is user responsibility to provide the correct value
@@ -2242,7 +2249,9 @@ void arm_concatenation_s8_z(const int8_t *input,
  * @param[in]  input_y  Height of input tensor
  * @param[in]  input_z  Channels in input tensor
  * @param[in]  input_w  Batch size in input tensor
- * @param[out] output   Pointer to output tensor
+ * @param[out] output   Pointer to output tensor. Expected to be at least
+ *                          input_x * input_y * input_z * input_w
+ *                      bytes.
  * @param[in]  offset_w The offset on the W axis to start concatenating the input tensor
  *                      It is user responsibility to provide the correct value
  *

+ 3 - 2
Source/ConcatenationFunctions/arm_concatenation_s8_w.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -29,6 +29,7 @@
  * -------------------------------------------------------------------- */
 
 #include "arm_nnfunctions.h"
+#include "arm_nnsupportfunctions.h"
 
 /**
  *  @ingroup groupNN
@@ -57,7 +58,7 @@ void arm_concatenation_s8_w(const int8_t *input,
 
     output += offset_w * (input_x * input_y * input_z);
 
-    memcpy(output, input, input_copy_size);
+    arm_memcpy_q7(output, input, input_copy_size);
 }
 
 /**

+ 3 - 2
Source/ConcatenationFunctions/arm_concatenation_s8_x.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -29,6 +29,7 @@
  * -------------------------------------------------------------------- */
 
 #include "arm_nnfunctions.h"
+#include "arm_nnsupportfunctions.h"
 
 /**
  *  @ingroup groupNN
@@ -63,7 +64,7 @@ void arm_concatenation_s8_x(const int8_t *input,
     // Copy per row
     for (i = 0; i < num_iterations; ++i)
     {
-        memcpy(output, input, input_x);
+        arm_memcpy_q7(output, input, input_x);
         input += input_x;
         output += output_x;
     }

+ 3 - 2
Source/ConcatenationFunctions/arm_concatenation_s8_y.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -29,6 +29,7 @@
  * -------------------------------------------------------------------- */
 
 #include "arm_nnfunctions.h"
+#include "arm_nnsupportfunctions.h"
 
 /**
  *  @ingroup groupNN
@@ -64,7 +65,7 @@ void arm_concatenation_s8_y(const int8_t *input,
     // Copy per tile
     for (i = 0; i < num_iterations; ++i)
     {
-        memcpy(output, input, input_copy_size);
+        arm_memcpy_q7(output, input, input_copy_size);
         input += input_copy_size;
         output += output_stride;
     }

+ 3 - 2
Source/ConcatenationFunctions/arm_concatenation_s8_z.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -29,6 +29,7 @@
  * -------------------------------------------------------------------- */
 
 #include "arm_nnfunctions.h"
+#include "arm_nnsupportfunctions.h"
 
 /**
  *  @ingroup groupNN
@@ -63,7 +64,7 @@ void arm_concatenation_s8_z(const int8_t *input,
 
     for (i = 0; i < input_w; ++i)
     {
-        memcpy(output, input, input_copy_size);
+        arm_memcpy_q7(output, input, input_copy_size);
         input += input_copy_size;
         output += output_stride;
     }

+ 6 - 1
Source/ConvolutionFunctions/arm_convolve_fast_s16.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -65,6 +65,11 @@ arm_status arm_convolve_fast_s16(const cmsis_nn_context *ctx,
     {
         return ARM_MATH_SIZE_MISMATCH;
     }
+
+    if (ctx->buf == NULL && arm_convolve_s8_get_buffer_size(input_dims, filter_dims) > 0)
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
     q15_t *buffer_a = (q15_t *)ctx->buf;
 
     const int32_t input_batches = input_dims->n;

+ 2 - 4
Source/ConvolutionFunctions/arm_convolve_s16.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -61,7 +61,7 @@ arm_status arm_convolve_s16(const cmsis_nn_context *ctx,
                             q15_t *output_data)
 {
     (void)bias_dims;
-    q15_t *buffer_a = (q15_t *)ctx->buf;
+    (void)ctx;
 
     const int32_t input_batches = input_dims->n;
     const int32_t input_x = input_dims->w;
@@ -86,8 +86,6 @@ arm_status arm_convolve_s16(const cmsis_nn_context *ctx,
     for (int i_batch = 0; i_batch < input_batches; i_batch++)
     {
         /* Run the following code as reference implementation for Cortex-M0 and Cortex-M3 */
-        (void)buffer_a;
-
         for (int32_t i_out_ch = 0; i_out_ch < output_ch; i_out_ch++)
         {
             const q31_t reduced_multiplier = REDUCE_MULTIPLIER(output_mult[i_out_ch]);

+ 5 - 0
Source/ConvolutionFunctions/arm_convolve_s8.c

@@ -61,6 +61,11 @@ arm_status arm_convolve_s8(const cmsis_nn_context *ctx,
                            q7_t *output_data)
 {
     (void)bias_dims;
+
+    if (ctx->buf == NULL && arm_convolve_s8_get_buffer_size(input_dims, filter_dims) > 0)
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
     q15_t *buffer_a = (q15_t *)ctx->buf;
 
     const int32_t input_batches = input_dims->n;

+ 6 - 1
Source/ConvolutionFunctions/arm_depthwise_conv_s8_opt.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -69,6 +69,11 @@ arm_status arm_depthwise_conv_s8_opt(const cmsis_nn_context *ctx,
     {
         return ARM_MATH_SIZE_MISMATCH;
     }
+
+    if (ctx->buf == NULL && arm_depthwise_conv_s8_opt_get_buffer_size(input_dims, filter_dims) > 0)
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
 #ifdef ARM_MATH_DSP
     const int32_t input_x = input_dims->w;
     const int32_t input_y = input_dims->h;

+ 3 - 2
Source/ConvolutionFunctions/arm_depthwise_conv_wrapper_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -62,7 +62,8 @@ arm_status arm_depthwise_conv_wrapper_s8(const cmsis_nn_context *ctx,
     if (1 == dw_conv_params->ch_mult && input_dims->n == 1)
     {
 #if !defined(ARM_MATH_MVEI)
-        if ((filter_dims->w == 3) && (filter_dims->h == 3) && (dw_conv_params->padding.h <= 1))
+        if ((filter_dims->w == 3) && (filter_dims->h == 3) && (dw_conv_params->padding.h <= 1) &&
+            (dw_conv_params->padding.w <= 1))
         {
             status = arm_depthwise_conv_3x3_s8(ctx,
                                                dw_conv_params,

+ 20 - 1
Source/PoolingFunctions/arm_avgpool_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2020 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -41,6 +41,13 @@ static void scale_q31_to_q7_and_clamp(const q31_t *buffer,
                                       const int act_max)
 {
     const int half_count = count / 2;
+
+    // Prevent static code issue DIVIDE_BY_ZERO.
+    if (count == 0)
+    {
+        return;
+    }
+
     for (int i = 0; i < length; i++)
     {
         int32_t sum = buffer[i] > 0 ? (buffer[i] + half_count) : (buffer[i] - half_count);
@@ -225,6 +232,13 @@ arm_status arm_avgpool_s8(const cmsis_nn_context *ctx,
                         count++;
                     }
                 }
+
+                // Prevent static code issue DIVIDE_BY_ZERO.
+                if (count == 0)
+                {
+                    return ARM_MATH_ARGUMENT_ERROR;
+                }
+
                 sum = sum > 0 ? (sum + count / 2) / count : (sum - count / 2) / count;
                 sum = MAX(sum, act_min);
                 sum = MIN(sum, act_max);
@@ -261,6 +275,11 @@ arm_status arm_avgpool_s8(const cmsis_nn_context *ctx,
     const int32_t act_min = pool_params->activation.min;
     const int32_t act_max = pool_params->activation.max;
     const int32_t ch_src = input_dims->c;
+
+    if (ctx->buf == NULL && arm_avgpool_s8_get_buffer_size(output_dims->w, input_dims->c))
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
     q31_t *buffer = (q31_t *)ctx->buf;
 
 #if defined(ARM_MATH_DSP)

+ 2 - 2
Source/PoolingFunctions/arm_max_pool_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -205,7 +205,7 @@ arm_status arm_max_pool_s8(const cmsis_nn_context *ctx,
 
                     if (count == 0)
                     {
-                        memcpy(dst, start, channel_in);
+                        arm_memcpy_q7(dst, start, channel_in);
                         count++;
                     }
                     else

+ 4 - 3
Source/ReshapeFunctions/arm_reshape_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2019 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -29,6 +29,7 @@
  * -------------------------------------------------------------------- */
 
 #include "arm_nnfunctions.h"
+#include "arm_nnsupportfunctions.h"
 
 /**
  *  @ingroup groupNN
@@ -48,9 +49,9 @@
 
 void arm_reshape_s8(const int8_t *input, int8_t *output, const uint32_t total_size)
 {
-    memcpy(output, input, total_size);
+    arm_memcpy_q7(output, input, total_size);
 }
 
 /**
  * @} end of Reshape group
- */
+ */

+ 10 - 1
Source/SVDFunctions/arm_svdf_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -87,7 +87,16 @@ arm_status arm_svdf_s8(const cmsis_nn_context *input_ctx,
     const int32_t time_batches = weights_time_dims->h;
     const int32_t unit_count = feature_batches / rank;
 
+    if (input_ctx->buf == NULL)
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
     q31_t *buffer_a = (q31_t *)input_ctx->buf;
+
+    if (output_ctx->buf == NULL)
+    {
+        return ARM_MATH_ARGUMENT_ERROR;
+    }
     q31_t *buffer_b = (q31_t *)output_ctx->buf;
 
     memmove((q15_t *)state_data,

+ 7 - 34
Tests/UnitTest/TestCases/test_arm_depthwise_conv_3x3_s8/test_arm_depthwise_conv_3x3_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -84,9 +84,10 @@ void depthwise_kernel_3x3_arm_depthwise_conv_3x3_s8(void)
     TEST_ASSERT_EQUAL(expected, result);
     TEST_ASSERT_TRUE(validate(output, depthwise_kernel_3x3_output_ref, DEPTHWISE_KERNEL_3X3_DST_SIZE));
 
-    ctx.buf = NULL;
+    const int32_t buf_size =
+        arm_depthwise_conv_wrapper_s8_get_buffer_size(&dw_conv_params, &input_dims, &filter_dims, &output_dims);
+    ctx.buf = malloc(buf_size);
     ctx.size = 0;
-
     result = arm_depthwise_conv_wrapper_s8(&ctx,
                                            &dw_conv_params,
                                            &quant_params,
@@ -162,15 +163,10 @@ void depthwise_kernel_3x3_arm_depthwise_conv_3x3_1_s8(void)
     free(ctx.buf);
     TEST_ASSERT_EQUAL(expected, result);
 
-    // The wrapper calls different functions for Cortex-M55 and Cortex-M7. Hence
-    // the different expected status.
-#if defined(ARM_MATH_MVEI)
     const arm_status expected_wrapper = ARM_MATH_SUCCESS;
-#else
-    const arm_status expected_wrapper = ARM_MATH_ARGUMENT_ERROR;
-#endif
-
-    ctx.buf = NULL;
+    const int32_t buf_size =
+        arm_depthwise_conv_wrapper_s8_get_buffer_size(&dw_conv_params, &input_dims, &filter_dims, &output_dims);
+    ctx.buf = malloc(buf_size);
     ctx.size = 0;
 
     result = arm_depthwise_conv_wrapper_s8(&ctx,
@@ -246,27 +242,4 @@ void depthwise_kernel_3x3_arm_depthwise_conv_3x3_2_s8(void)
 
     free(ctx.buf);
     TEST_ASSERT_EQUAL(expected, result);
-
-    ctx.buf = NULL;
-    ctx.size = 0;
-
-    // When calling the wrapper the arm_depthwise_conv_3x3_s8 will
-    // not be called. arm_depthwise_conv_s8_opt will be called and
-    // exit with success.
-    const arm_status expected_wrapper = ARM_MATH_SUCCESS;
-
-    result = arm_depthwise_conv_wrapper_s8(&ctx,
-                                           &dw_conv_params,
-                                           &quant_params,
-                                           &input_dims,
-                                           input_data,
-                                           &filter_dims,
-                                           kernel_data,
-                                           &bias_dims,
-                                           bias_data,
-                                           &output_dims,
-                                           output);
-
-    free(ctx.buf);
-    TEST_ASSERT_EQUAL(expected_wrapper, result);
 }

+ 7 - 5
Tests/UnitTest/TestCases/test_arm_depthwise_conv_s8/test_arm_depthwise_conv_s8.c

@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010-2021 Arm Limited or its affiliates. All rights reserved.
+ * Copyright (C) 2010-2021 Arm Limited or its affiliates.
  *
  * SPDX-License-Identifier: Apache-2.0
  *
@@ -84,8 +84,9 @@ void basic_arm_depthwise_conv_s8(void)
     TEST_ASSERT_EQUAL(expected, result);
     TEST_ASSERT_TRUE(validate(output, basic_output_ref, BASIC_DST_SIZE));
 
-    ctx.buf = NULL;
-    ctx.size = 0;
+    const int32_t buf_size =
+        arm_depthwise_conv_wrapper_s8_get_buffer_size(&dw_conv_params, &input_dims, &filter_dims, &output_dims);
+    ctx.buf = malloc(buf_size);
 
     result = arm_depthwise_conv_wrapper_s8(&ctx,
                                            &dw_conv_params,
@@ -163,9 +164,10 @@ void stride2pad1_arm_depthwise_conv_s8(void)
     TEST_ASSERT_EQUAL(expected, result);
     TEST_ASSERT_TRUE(validate(output, stride2pad1_output_ref, STRIDE2PAD1_DST_SIZE));
 
-    ctx.buf = NULL;
+    const int32_t buf_size =
+        arm_depthwise_conv_wrapper_s8_get_buffer_size(&dw_conv_params, &input_dims, &filter_dims, &output_dims);
+    ctx.buf = malloc(buf_size);
     ctx.size = 0;
-
     result = arm_depthwise_conv_wrapper_s8(&ctx,
                                            &dw_conv_params,
                                            &quant_params,