Patch attached.

Main changes from v1 are switching to from int to size_t/ptrdiff_t
where relevant and removing av_image_fill_pointers_from_sizes()

Some things to note:
 - The av_image_fill_planes_sizes uses size_t/ptrdiff_t for buffer
sizes, but as mentioned during the v1 review, this leads to some
inconvenient conversions and range checks when using it with existing
functions. We could keep the return type as int to alleviate this, but
that seems like it would somewhat defeat the purpose of moving to
these types.
 - SIZE_MAX is used in several places in libavutil, so I used
PTRDIFF_MAX, but I could not see any mention of these being allowed.
From a47b3f3b5c2ed4a1caf9f0a3429dd425ce708bb1 Mon Sep 17 00:00:00 2001
From: Brian Kim <bk...@google.com>
Date: Tue, 7 Jul 2020 11:36:19 -0700
Subject: [PATCH 1/3] libavutil/imgutils: add utility to get plane sizes

This utility helps avoid undefined behavior when doing things like
checking how much memory we need to allocate for an image before we have
allocated a buffer.

Signed-off-by: Brian Kim <bk...@google.com>
---
 doc/APIchanges       |  3 ++
 libavutil/frame.c    | 15 ++++++---
 libavutil/imgutils.c | 74 ++++++++++++++++++++++++++++++++------------
 libavutil/imgutils.h | 12 +++++++
 libavutil/version.h  |  2 +-
 5 files changed, 82 insertions(+), 24 deletions(-)

diff --git a/doc/APIchanges b/doc/APIchanges
index 1d6cc36b8c..44defd9ca8 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -15,6 +15,9 @@ libavutil:     2017-10-21
 
 API changes, most recent first:
 
+2020-07-xx - xxxxxxxxxx - lavu 56.56.100 - imgutils.h
+  Add av_image_fill_plane_sizes().
+
 2020-06-12 - b09fb030c1 - lavu 56.55.100 - pixdesc.h
   Add AV_PIX_FMT_X2RGB10.
 
diff --git a/libavutil/frame.c b/libavutil/frame.c
index 9884eae054..b664dcfbe8 100644
--- a/libavutil/frame.c
+++ b/libavutil/frame.c
@@ -214,6 +214,8 @@ static int get_video_buffer(AVFrame *frame, int align)
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format);
     int ret, i, padded_height;
     int plane_padding = FFMAX(16 + 16/*STRIDE_ALIGN*/, align);
+    ptrdiff_t total_size, linesizes[4];
+    size_t size[4];
 
     if (!desc)
         return AVERROR(EINVAL);
@@ -238,12 +240,17 @@ static int get_video_buffer(AVFrame *frame, int align)
             frame->linesize[i] = FFALIGN(frame->linesize[i], align);
     }
 
+    for (i = 0; i < 4; i++)
+        linesizes[i] = frame->linesize[i];
+
     padded_height = FFALIGN(frame->height, 32);
-    if ((ret = av_image_fill_pointers(frame->data, frame->format, padded_height,
-                                      NULL, frame->linesize)) < 0)
-        return ret;
+    if ((total_size = av_image_fill_plane_sizes(size, frame->format, padded_height,
+                                                linesizes)) < 0)
+        return total_size;
+    if (total_size > INT_MAX - 4*plane_padding)
+        return AVERROR(EINVAL);
 
-    frame->buf[0] = av_buffer_alloc(ret + 4*plane_padding);
+    frame->buf[0] = av_buffer_alloc(total_size + 4*plane_padding);
     if (!frame->buf[0]) {
         ret = AVERROR(ENOMEM);
         goto fail;
diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c
index 7f9c1b632c..082229cfaf 100644
--- a/libavutil/imgutils.c
+++ b/libavutil/imgutils.c
@@ -108,26 +108,26 @@ int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int wi
     return 0;
 }
 
-int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height,
-                           uint8_t *ptr, const int linesizes[4])
+ptrdiff_t av_image_fill_plane_sizes(size_t size[4], enum AVPixelFormat pix_fmt,
+                                    int height, const ptrdiff_t linesizes[4])
 {
-    int i, total_size, size[4] = { 0 }, has_plane[4] = { 0 };
+    int i, has_plane[4] = { 0 };
+    ptrdiff_t total_size;
 
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
-    memset(data     , 0, sizeof(data[0])*4);
+    memset(size     , 0, sizeof(size[0])*4);
 
     if (!desc || desc->flags & AV_PIX_FMT_FLAG_HWACCEL)
         return AVERROR(EINVAL);
 
-    data[0] = ptr;
-    if (linesizes[0] > (INT_MAX - 1024) / height)
+    if (linesizes[0] > (PTRDIFF_MAX - 1024) / height)
         return AVERROR(EINVAL);
     size[0] = linesizes[0] * height;
 
     if (desc->flags & AV_PIX_FMT_FLAG_PAL ||
         desc->flags & FF_PSEUDOPAL) {
-        data[1] = ptr + size[0]; /* palette is stored here as 256 32 bits words */
-        return size[0] + 256 * 4;
+        size[1] = 256 * 4; /* palette is stored here as 256 32 bits words */
+        return size[0] + size[1];
     }
 
     for (i = 0; i < 4; i++)
@@ -136,12 +136,11 @@ int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int hei
     total_size = size[0];
     for (i = 1; i < 4 && has_plane[i]; i++) {
         int h, s = (i == 1 || i == 2) ? desc->log2_chroma_h : 0;
-        data[i] = data[i-1] + size[i-1];
         h = (height + (1 << s) - 1) >> s;
-        if (linesizes[i] > INT_MAX / h)
+        if (linesizes[i] > PTRDIFF_MAX / h)
             return AVERROR(EINVAL);
         size[i] = h * linesizes[i];
-        if (total_size > INT_MAX - size[i])
+        if (total_size > PTRDIFF_MAX - size[i])
             return AVERROR(EINVAL);
         total_size += size[i];
     }
@@ -149,6 +148,31 @@ int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int hei
     return total_size;
 }
 
+int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int height,
+                           uint8_t *ptr, const int linesizes[4])
+{
+    int i;
+    ptrdiff_t ret, linesizes1[4];
+    size_t size[4];
+
+    for (i = 0; i < 4; i++)
+        linesizes1[i] = linesizes[i];
+
+    ret = av_image_fill_plane_sizes(size, pix_fmt, height, linesizes1);
+    if (ret < 0)
+        return ret;
+    if (ret > INT_MAX)
+        return AVERROR(EINVAL);
+
+    memset(data , 0, sizeof(data[0])*4);
+
+    data[0] = ptr;
+    for (i = 1; i < 4 && size[i - 1] > 0; i++)
+        data[i] = data[i - 1] + size[i - 1];
+
+    return ret;
+}
+
 int avpriv_set_systematic_pal2(uint32_t pal[256], enum AVPixelFormat pix_fmt)
 {
     int i;
@@ -194,6 +218,8 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
 {
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
     int i, ret;
+    ptrdiff_t total_size, linesizes1[4];
+    size_t size[4];
     uint8_t *buf;
 
     if (!desc)
@@ -204,12 +230,14 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
     if ((ret = av_image_fill_linesizes(linesizes, pix_fmt, align>7 ? FFALIGN(w, 8) : w)) < 0)
         return ret;
 
-    for (i = 0; i < 4; i++)
+    for (i = 0; i < 4; i++) {
         linesizes[i] = FFALIGN(linesizes[i], align);
+        linesizes1[i] = linesizes[i];
+    }
 
-    if ((ret = av_image_fill_pointers(pointers, pix_fmt, h, NULL, linesizes)) < 0)
-        return ret;
-    buf = av_malloc(ret + align);
+    if ((total_size = av_image_fill_plane_sizes(size, pix_fmt, h, linesizes1)) < 0)
+        return total_size;
+    buf = av_malloc(total_size + align);
     if (!buf)
         return AVERROR(ENOMEM);
     if ((ret = av_image_fill_pointers(pointers, pix_fmt, h, buf, linesizes)) < 0) {
@@ -220,6 +248,7 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4],
         avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt);
         if (align < 4) {
             av_log(NULL, AV_LOG_ERROR, "Formats with a palette require a minimum alignment of 4\n");
+            av_free(buf);
             return AVERROR(EINVAL);
         }
     }
@@ -431,9 +460,10 @@ int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4],
 int av_image_get_buffer_size(enum AVPixelFormat pix_fmt,
                              int width, int height, int align)
 {
-    uint8_t *data[4];
+    int ret, i;
     int linesize[4];
-    int ret;
+    ptrdiff_t aligned_linesize[4];
+    size_t size[4];
     const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
     if (!desc)
         return AVERROR(EINVAL);
@@ -446,8 +476,14 @@ int av_image_get_buffer_size(enum AVPixelFormat pix_fmt,
     if (desc->flags & FF_PSEUDOPAL)
         return FFALIGN(width, align) * height;
 
-    return av_image_fill_arrays(data, linesize, NULL, pix_fmt,
-                                width, height, align);
+    ret = av_image_fill_linesizes(linesize, pix_fmt, width);
+    if (ret < 0)
+        return ret;
+
+    for (i = 0; i < 4; i++)
+        aligned_linesize[i] = FFALIGN(linesize[i], align);
+
+    return av_image_fill_plane_sizes(size, pix_fmt, height, aligned_linesize);
 }
 
 int av_image_copy_to_buffer(uint8_t *dst, int dst_size,
diff --git a/libavutil/imgutils.h b/libavutil/imgutils.h
index 5b790ecf0a..99772357ae 100644
--- a/libavutil/imgutils.h
+++ b/libavutil/imgutils.h
@@ -67,6 +67,18 @@ int av_image_get_linesize(enum AVPixelFormat pix_fmt, int width, int plane);
  */
 int av_image_fill_linesizes(int linesizes[4], enum AVPixelFormat pix_fmt, int width);
 
+/**
+ * Fill plane sizes for an image with pixel format pix_fmt and height height.
+ *
+ * @param size the array to be filled with the size of each image plane
+ * @param linesizes the array containing the linesize for each
+ * plane, should be filled by av_image_fill_linesizes()
+ * @return the size in bytes required for the image buffer, a negative
+ * error code in case of failure
+ */
+ptrdiff_t av_image_fill_plane_sizes(size_t size[4], enum AVPixelFormat pix_fmt,
+                                    int height, const ptrdiff_t linesizes[4]);
+
 /**
  * Fill plane data pointers for an image with pixel format pix_fmt and
  * height height.
diff --git a/libavutil/version.h b/libavutil/version.h
index 3ce9b1831e..a63f79feb1 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  56
-#define LIBAVUTIL_VERSION_MINOR  55
+#define LIBAVUTIL_VERSION_MINOR  56
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
2.27.0.383.g050319c2ae-goog

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to