diff mbox series

[FFmpeg-devel,02/21] avcodec/zlib_wrapper: Add wrappers for zlib inflateInit, inflateEnd

Message ID AS1PR01MB95648094D8A35D5C772293AD8F109@AS1PR01MB9564.eurprd01.prod.exchangelabs.com
State Accepted
Commit dd8a55cb3e2014934a176a9962010a3c87d12704
Headers show
Series [FFmpeg-devel,01/21] avcodec/pngenc: Avoid potentially truncating integers | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Andreas Rheinhardt March 15, 2022, 8:05 p.m. UTC
It is not documented to be safe to call inflateEnd() on a z_stream
that has never been successfully been initialized by inflateInit(),
but just zeroed. It just happens to work and several codecs rely
on this (they have FF_CODEC_CAP_INIT_CLEANUP set and even call
inflateEnd() when inflateInit() failed or has never been called).
To avoid this, other codecs recorded whether their zstream has been
initialized successfully or not.

This commit adds wrappers for inflateInit() and inflateEnd() that
do what these other codecs do; furthermore, they also take care of
properly setting up the zstream before inflateInit() and emit
an error message in case of error.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 configure                 |  2 ++
 libavcodec/Makefile       |  1 +
 libavcodec/zlib_wrapper.c | 57 +++++++++++++++++++++++++++++++++++++++
 libavcodec/zlib_wrapper.h | 51 +++++++++++++++++++++++++++++++++++
 4 files changed, 111 insertions(+)
 create mode 100644 libavcodec/zlib_wrapper.c
 create mode 100644 libavcodec/zlib_wrapper.h

Comments

Tomas Härdin March 16, 2022, 7:24 p.m. UTC | #1
> +int ff_inflate_init(FFZStream *z, void *logctx)
> +{
> +    z_stream *const zstream = &z->zstream;
> +    int zret;
> +
> +    z->inited = 0;
> +    zstream->next_in  = Z_NULL;
> +    zstream->avail_in = 0;
> +    zstream->zalloc   = Z_NULL;
> +    zstream->zfree    = Z_NULL;
> +    zstream->opaque   = Z_NULL;

why not bzero()?

Rest of the patch looks fine

/Tomas
Andreas Rheinhardt March 16, 2022, 7:32 p.m. UTC | #2
Tomas Härdin:
>> +int ff_inflate_init(FFZStream *z, void *logctx)
>> +{
>> +    z_stream *const zstream = &z->zstream;
>> +    int zret;
>> +
>> +    z->inited = 0;
>> +    zstream->next_in  = Z_NULL;
>> +    zstream->avail_in = 0;
>> +    zstream->zalloc   = Z_NULL;
>> +    zstream->zfree    = Z_NULL;
>> +    zstream->opaque   = Z_NULL;
> 
> why not bzero()?
> 
> Rest of the patch looks fine
> 

bzero()? You mean memset to zero? The reason that I initialize exactly
these fields is because these are exactly the fields required to be
initialized by zlib (for inflate; next_in and avail_in are not required
to be initialized for deflate): "The fields next_in, avail_in, zalloc,
zfree and opaque must be initialized before by the caller." zlib treats
all the other fields as uninitialized, so why should we initialize them
(Actually reinitialize them -- most FFZStreams are already zeroed
initially as part of a codec's private context.)? The way it is done in
this patch shows directly which elements zlib expects to be set; setting
everything would not achieve the same.

- Andreas
Tomas Härdin March 16, 2022, 8:07 p.m. UTC | #3
ons 2022-03-16 klockan 20:32 +0100 skrev Andreas Rheinhardt:
> Tomas Härdin:
> > > +int ff_inflate_init(FFZStream *z, void *logctx)
> > > +{
> > > +    z_stream *const zstream = &z->zstream;
> > > +    int zret;
> > > +
> > > +    z->inited = 0;
> > > +    zstream->next_in  = Z_NULL;
> > > +    zstream->avail_in = 0;
> > > +    zstream->zalloc   = Z_NULL;
> > > +    zstream->zfree    = Z_NULL;
> > > +    zstream->opaque   = Z_NULL;
> > 
> > why not bzero()?
> > 
> > Rest of the patch looks fine
> > 
> 
> bzero()? You mean memset to zero? The reason that I initialize
> exactly
> these fields is because these are exactly the fields required to be
> initialized by zlib (for inflate; next_in and avail_in are not
> required
> to be initialized for deflate): "The fields next_in, avail_in,
> zalloc,
> zfree and opaque must be initialized before by the caller." zlib
> treats
> all the other fields as uninitialized, so why should we initialize
> them
> (Actually reinitialize them -- most FFZStreams are already zeroed
> initially as part of a codec's private context.)? The way it is done
> in
> this patch shows directly which elements zlib expects to be set;
> setting
> everything would not achieve the same.

Right. Looks OK then

/Tomas
Andreas Rheinhardt March 17, 2022, 7:29 a.m. UTC | #4
Tomas Härdin:
> ons 2022-03-16 klockan 20:32 +0100 skrev Andreas Rheinhardt:
>> Tomas Härdin:
>>>> +int ff_inflate_init(FFZStream *z, void *logctx)
>>>> +{
>>>> +    z_stream *const zstream = &z->zstream;
>>>> +    int zret;
>>>> +
>>>> +    z->inited = 0;
>>>> +    zstream->next_in  = Z_NULL;
>>>> +    zstream->avail_in = 0;
>>>> +    zstream->zalloc   = Z_NULL;
>>>> +    zstream->zfree    = Z_NULL;
>>>> +    zstream->opaque   = Z_NULL;
>>>
>>> why not bzero()?
>>>
>>> Rest of the patch looks fine
>>>
>>
>> bzero()? You mean memset to zero? The reason that I initialize
>> exactly
>> these fields is because these are exactly the fields required to be
>> initialized by zlib (for inflate; next_in and avail_in are not
>> required
>> to be initialized for deflate): "The fields next_in, avail_in,
>> zalloc,
>> zfree and opaque must be initialized before by the caller." zlib
>> treats
>> all the other fields as uninitialized, so why should we initialize
>> them
>> (Actually reinitialize them -- most FFZStreams are already zeroed
>> initially as part of a codec's private context.)? The way it is done
>> in
>> this patch shows directly which elements zlib expects to be set;
>> setting
>> everything would not achieve the same.
> 
> Right. Looks OK then
> 

Thanks for the review. Will apply this patchset tonight unless there are
objections.

- Andreas
diff mbox series

Patch

diff --git a/configure b/configure
index 82642deabe..6254dc9dc1 100755
--- a/configure
+++ b/configure
@@ -2461,6 +2461,7 @@  CONFIG_EXTRA="
     idctdsp
     iirfilter
     mdct15
+    inflate_wrapper
     intrax8
     iso_media
     ividsp
@@ -2722,6 +2723,7 @@  faanidct_select="idctdsp"
 h264dsp_select="startcode"
 hevcparse_select="atsc_a53 golomb"
 frame_thread_encoder_deps="encoders threads"
+inflate_wrapper_deps="zlib"
 intrax8_select="blockdsp idctdsp"
 iso_media_select="mpeg4audio"
 mdct_select="fft"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index f36b2e992d..62c8e34963 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -104,6 +104,7 @@  OBJS-$(CONFIG_HUFFYUVENCDSP)           += huffyuvencdsp.o
 OBJS-$(CONFIG_IDCTDSP)                 += idctdsp.o simple_idct.o jrevdct.o
 OBJS-$(CONFIG_IIRFILTER)               += iirfilter.o
 OBJS-$(CONFIG_MDCT15)                  += mdct15.o
+OBJS-$(CONFIG_INFLATE_WRAPPER)         += zlib_wrapper.o
 OBJS-$(CONFIG_INTRAX8)                 += intrax8.o intrax8dsp.o msmpeg4data.o
 OBJS-$(CONFIG_IVIDSP)                  += ivi_dsp.o
 OBJS-$(CONFIG_JNI)                     += ffjni.o jni.o
diff --git a/libavcodec/zlib_wrapper.c b/libavcodec/zlib_wrapper.c
new file mode 100644
index 0000000000..b15d5be2b8
--- /dev/null
+++ b/libavcodec/zlib_wrapper.c
@@ -0,0 +1,57 @@ 
+/*
+ * Wrappers for zlib
+ * Copyright (C) 2022 Andreas Rheinhardt
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zlib.h>
+
+#include "libavutil/error.h"
+#include "libavutil/log.h"
+#include "zlib_wrapper.h"
+
+int ff_inflate_init(FFZStream *z, void *logctx)
+{
+    z_stream *const zstream = &z->zstream;
+    int zret;
+
+    z->inited = 0;
+    zstream->next_in  = Z_NULL;
+    zstream->avail_in = 0;
+    zstream->zalloc   = Z_NULL;
+    zstream->zfree    = Z_NULL;
+    zstream->opaque   = Z_NULL;
+
+    zret = inflateInit(zstream);
+    if (zret == Z_OK) {
+        z->inited = 1;
+    } else {
+        av_log(logctx, AV_LOG_ERROR, "inflateInit error %d, message: %s\n",
+               zret, zstream->msg ? zstream->msg : "");
+        return AVERROR_EXTERNAL;
+    }
+    return 0;
+}
+
+void ff_inflate_end(FFZStream *z)
+{
+    if (z->inited) {
+        z->inited = 0;
+        inflateEnd(&z->zstream);
+    }
+}
diff --git a/libavcodec/zlib_wrapper.h b/libavcodec/zlib_wrapper.h
new file mode 100644
index 0000000000..0e91713b25
--- /dev/null
+++ b/libavcodec/zlib_wrapper.h
@@ -0,0 +1,51 @@ 
+/*
+ * Wrappers for zlib
+ * Copyright (C) 2022 Andreas Rheinhardt
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_ZLIB_WRAPPER_H
+#define AVCODEC_ZLIB_WRAPPER_H
+
+#include <zlib.h>
+
+typedef struct FFZStream {
+    z_stream zstream;
+    int inited;
+} FFZStream;
+
+/**
+ * Wrapper around inflateInit(). It initializes the fields that zlib
+ * requires to be initialized before inflateInit().
+ * In case of error it also returns an error message to the provided logctx;
+ * in any case, it sets zstream->inited to indicate whether inflateInit()
+ * succeeded.
+ * @return Returns 0 on success or a negative error code on failure
+ */
+int ff_inflate_init(FFZStream *zstream, void *logctx);
+
+/**
+ * Wrapper around inflateEnd(). It calls inflateEnd() iff
+ * zstream->inited is set and resets zstream->inited.
+ * It is therefore safe to be called even if
+ * ff_inflate_init() has never been called on it (or errored out)
+ * provided that the FFZStream (or just FFZStream.inited) has been zeroed.
+ */
+void ff_inflate_end(FFZStream *zstream);
+
+#endif /* AVCODEC_ZLIB_WRAPPER_H */