aom: dr_prediction_test.cc: Catch over-reads in zN predictors

From bad168356961c7afb87c35b7689296fe36ae168c Mon Sep 17 00:00:00 2001
From: George Steed <[EMAIL REDACTED]>
Date: Thu, 9 May 2024 14:52:43 +0000
Subject: [PATCH] dr_prediction_test.cc: Catch over-reads in zN predictors

The existing test setup does not allow us to catch code reading outside
the bounds of the input left/above arrays since the inputs are
statically allocated as part of a larger object.

To get around this, switch to creating a fresh vector of the correct
size as part of the test itself, mirroring the same approach previously
taken for the destination array.

Bug: aomedia:3571
Change-Id: If375c1d00e10ae910c878e70e801b6a49b4f329e
---
 test/dr_prediction_test.cc | 58 ++++++++++++++++++++------------------
 1 file changed, 31 insertions(+), 27 deletions(-)

diff --git a/test/dr_prediction_test.cc b/test/dr_prediction_test.cc
index c23b08e481..50d5320e8a 100644
--- a/test/dr_prediction_test.cc
+++ b/test/dr_prediction_test.cc
@@ -29,6 +29,9 @@
 
 namespace {
 
+const int kNumIntraNeighbourPixels = MAX_TX_SIZE * 2 + 32;
+const int kIntraPredInputPadding = 16;
+
 const int kZ1Start = 0;
 const int kZ2Start = 90;
 const int kZ3Start = 180;
@@ -151,8 +154,6 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
  protected:
   static const int kMaxNumTests = 10000;
   static const int kIterations = 10;
-  static const int kOffset = 16;
-  static const int kBufSize = ((2 * MAX_TX_SIZE) << 1) + 16;
 
   DrPredTest()
       : enable_upsample_(0), upsample_above_(0), upsample_left_(0), bw_(0),
@@ -160,20 +161,12 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
     params_ = this->GetParam();
     start_angle_ = params_.start_angle;
     stop_angle_ = start_angle_ + 90;
-
-    above_ = &above_data_[kOffset];
-    left_ = &left_data_[kOffset];
-
-    for (int i = 0; i < kBufSize; ++i) {
-      above_data_[i] = rng_.Rand8();
-      left_data_[i] = rng_.Rand8();
-    }
   }
 
   ~DrPredTest() override = default;
 
-  void Predict(bool speedtest, int tx, Pixel *dst_ref, Pixel *dst_tst,
-               int dst_stride) {
+  void Predict(bool speedtest, int tx, const Pixel *above, const Pixel *left,
+               Pixel *dst_ref, Pixel *dst_tst, int dst_stride) {
     const int kNumTests = speedtest ? kMaxNumTests : 1;
     aom_usec_timer timer;
     int tst_time = 0;
@@ -182,7 +175,7 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
 
     aom_usec_timer_start(&timer);
     for (int k = 0; k < kNumTests; ++k) {
-      params_.ref_fn(dst_ref, dst_stride, bw_, bh_, above_, left_,
+      params_.ref_fn(dst_ref, dst_stride, bw_, bh_, above, left,
                      upsample_above_, upsample_left_, dx_, dy_, bd_);
     }
     aom_usec_timer_mark(&timer);
@@ -192,7 +185,7 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
       aom_usec_timer_start(&timer);
       for (int k = 0; k < kNumTests; ++k) {
         API_REGISTER_STATE_CHECK(params_.tst_fn(dst_tst, dst_stride, bw_, bh_,
-                                                above_, left_, upsample_above_,
+                                                above, left, upsample_above_,
                                                 upsample_left_, dx_, dy_, bd_));
       }
       aom_usec_timer_mark(&timer);
@@ -211,11 +204,6 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
   void RunTest(bool speedtest, bool needsaturation, int p_angle) {
     bd_ = params_.bit_depth;
 
-    if (needsaturation) {
-      for (int i = 0; i < kBufSize; ++i) {
-        above_data_[i] = left_data_[i] = (1 << bd_) - 1;
-      }
-    }
     for (int tx = 0; tx < TX_SIZES_ALL; ++tx) {
       bw_ = tx_size_wide[kTxSize[tx]];
       bh_ = tx_size_high[kTxSize[tx]];
@@ -229,6 +217,28 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
         upsample_above_ = upsample_left_ = 0;
       }
 
+      // Declare input buffers as local arrays to allow checking for
+      // over-reads.
+      DECLARE_ALIGNED(16, Pixel, left_data[kNumIntraNeighbourPixels]);
+      DECLARE_ALIGNED(16, Pixel, above_data[kNumIntraNeighbourPixels]);
+
+      // We need to allow reading some previous bytes from the input pointers.
+      const Pixel *above = &above_data[kIntraPredInputPadding];
+      const Pixel *left = &left_data[kIntraPredInputPadding];
+
+      if (needsaturation) {
+        const Pixel sat = (1 << bd_) - 1;
+        for (int i = 0; i < kNumIntraNeighbourPixels; ++i) {
+          left_data[i] = sat;
+          above_data[i] = sat;
+        }
+      } else {
+        for (int i = 0; i < kNumIntraNeighbourPixels; ++i) {
+          left_data[i] = rng_.Rand8();
+          above_data[i] = rng_.Rand8();
+        }
+      }
+
       // Add additional padding to allow detection of over reads/writes when
       // the transform width is equal to MAX_TX_SIZE.
       const int dst_stride = MAX_TX_SIZE + 16;
@@ -242,7 +252,8 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
                                   (dst_stride - bw_) * sizeof(Pixel));
       }
 
-      Predict(speedtest, tx, dst_ref.data(), dst_tst.data(), dst_stride);
+      Predict(speedtest, tx, above, left, dst_ref.data(), dst_tst.data(),
+              dst_stride);
 
       for (int r = 0; r < bh_; ++r) {
         ASAN_UNPOISON_MEMORY_REGION(&dst_ref[r * dst_stride + bw_],
@@ -294,13 +305,6 @@ class DrPredTest : public ::testing::TestWithParam<DrPredFunc<FuncType> > {
     }
   }
 
-  Pixel left_data_[kBufSize];
-  Pixel dummy_data_[kBufSize];
-  Pixel above_data_[kBufSize];
-
-  Pixel *above_;
-  Pixel *left_;
-
   int enable_upsample_;
   int upsample_above_;
   int upsample_left_;