shithub: dav1d

Download patch

ref: 5c416dce1a1cdc7a4b9d7537fa47500bfeab07fa
parent: c38b3923bbb14fcdf00f6fa31104bf57d27150b3
author: Janne Grunau <janne-vlc@jannau.net>
date: Mon Oct 15 18:01:23 EDT 2018

intrabc: clip displacement vector to current tile

Reverts commit f17c5e084f9a983c00a48b25c4f6422b6c521435 "check IntraBC
displacement vector".
Fixes #63 and an overlapping memcpy in
clusterfuzz-testcase-minimized-dav1d_fuzzer-5675967192760320. Credits to
oss-fuzz and Tyson Smith.

--- a/src/decode.c
+++ b/src/decode.c
@@ -1189,12 +1189,66 @@
 
         const struct mv ref = b->mv[0];
         read_mv_residual(t, &b->mv[0], &ts->cdf.dmv, 0);
+
+        // clip intrabc motion vector to decoded parts of current tile
+        int border_left = ts->tiling.col_start * 4;
+        int border_top  = ts->tiling.row_start * 4;
+        if (has_chroma) {
+            if (bw4 < 2 &&  ss_hor)
+                border_left += 4;
+            if (bh4 < 2 &&  ss_ver)
+                border_top  += 4;
+        }
+        int src_left   = t->bx * 4 + (b->mv[0].x >> 3);
+        int src_top    = t->by * 4 + (b->mv[0].y >> 3);
+        int src_right  = src_left + bw4 * 4;
+        int src_bottom = src_top  + bh4 * 4;
+
+        // check against left or right tile boundary and adjust if necessary
+        if (src_left < border_left) {
+            src_right += border_left - src_left;
+            src_left  += border_left - src_left;
+        } else if (src_right > ts->tiling.col_end * 4) {
+            src_left  -= src_right - ts->tiling.col_end * 4;
+            src_right -= src_right - ts->tiling.col_end * 4;
+        }
+        // check against top tile boundary and adjust if necessary
+        if (src_top < border_top) {
+            src_bottom += border_top - src_top;
+            src_top    += border_top - src_top;
+        }
+
+        const int sbx = (t->bx >> (4 + f->seq_hdr.sb128)) << (6 + f->seq_hdr.sb128);
+        const int sby = (t->by >> (4 + f->seq_hdr.sb128)) << (6 + f->seq_hdr.sb128);
+        const int sb_size = 1 << (6 + f->seq_hdr.sb128);
+        // check for overlap with current superblock
+        if (src_bottom > sby && src_right > sbx) {
+            if (src_top - border_top >= src_bottom - sby) {
+                // if possible move src up into the previous suberblock row
+                src_top    -= src_bottom - sby;
+                src_bottom -= src_bottom - sby;
+            } else if (src_left - border_left >= src_right - sbx) {
+                // if possible move src left into the previous suberblock
+                src_left  -= src_right - sbx;
+                src_right -= src_right - sbx;
+            }
+        }
+        // move src up if it is below current superblock row
+        if (src_bottom > sby + sb_size) {
+            src_top    -= src_bottom - (sby + sb_size);
+            src_bottom -= src_bottom - (sby + sb_size);
+        }
+        // error out if mv still overlaps with the current superblock
+        if (src_bottom > sby && src_right > sbx)
+            return -1;
+
+        b->mv[0].x = (src_left - t->bx * 4) * 8;
+        b->mv[0].y = (src_top  - t->by * 4) * 8;
+
         if (DEBUG_BLOCK_INFO)
             printf("Post-dmv[%d/%d,ref=%d/%d|%d/%d]: r=%d\n",
                    b->mv[0].y, b->mv[0].x, ref.y, ref.x,
                    mvlist[0][0].y, mvlist[0][0].x, ts->msac.rng);
-        if (b->mv[0].x >= 0 && b->mv[0].y >= 0)
-            b->mv[0] = ref;
         read_vartx_tree(t, b, bs, bx4, by4);
 
         // reconstruction