[FFmpeg-devel] [PATCH 12/13] avformat/matroskadec: Improve read error/EOF checks II
James Almer
jamrial at gmail.com
Tue Jun 25 04:33:34 EEST 2019
On 6/23/2019 8:42 PM, Andreas Rheinhardt wrote:
> This commit fixes a number of bugs:
>
> 1. There was no check that no read error/EOF occured during
> ebml_read_uint, ebml_read_sint and ebml_read_float.
> 2. ebml_read_ascii and ebml_read_binary did sometimes not forward
> error codes; instead they simply returned AVERROR(EIO).
> 3. In particular, AVERROR_EOF hasn't been used and no dedicated error
> message for it existed. This has been changed.
>
> In order to reduce code duplication, the new error code NEEDS_CHECKING
> has been introduced which makes ebml_parse check the AVIOContext's
> status for errors.
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt at gmail.com>
> ---
> I did not combine the two lines via FFMIN as FFMIN might call avio_skip
> twice.
>
> libavformat/matroskadec.c | 59 +++++++++++++++++++++++++++------------
> 1 file changed, 41 insertions(+), 18 deletions(-)
>
> diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c
> index b923a9edff..1db7471440 100644
> --- a/libavformat/matroskadec.c
> +++ b/libavformat/matroskadec.c
> @@ -69,6 +69,8 @@
> #include "qtpalette.h"
>
> #define EBML_UNKNOWN_LENGTH UINT64_MAX /* EBML unknown length, in uint64_t */
> +#define NEEDS_CHECKING 2 /* Indicates that some error checks
> + * still need to be performed */
>
> typedef enum {
> EBML_NONE,
> @@ -869,7 +871,7 @@ static int ebml_read_length(MatroskaDemuxContext *matroska, AVIOContext *pb,
>
> /*
> * Read the next element as an unsigned int.
> - * 0 is success, < 0 is failure.
> + * Returns NEEDS_CHECKING.
> */
> static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
> {
> @@ -880,12 +882,12 @@ static int ebml_read_uint(AVIOContext *pb, int size, uint64_t *num)
> while (n++ < size)
> *num = (*num << 8) | avio_r8(pb);
>
> - return 0;
> + return NEEDS_CHECKING;
> }
>
> /*
> * Read the next element as a signed int.
> - * 0 is success, < 0 is failure.
> + * Returns NEEDS_CHECKING.
> */
> static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
> {
> @@ -901,12 +903,12 @@ static int ebml_read_sint(AVIOContext *pb, int size, int64_t *num)
> *num = ((uint64_t)*num << 8) | avio_r8(pb);
> }
>
> - return 0;
> + return NEEDS_CHECKING;
> }
>
> /*
> * Read the next element as a float.
> - * 0 is success, < 0 is failure.
> + * Returns NEEDS_CHECKING or < 0 on obvious failure.
> */
> static int ebml_read_float(AVIOContext *pb, int size, double *num)
> {
> @@ -919,24 +921,25 @@ static int ebml_read_float(AVIOContext *pb, int size, double *num)
> else
> return AVERROR_INVALIDDATA;
>
> - return 0;
> + return NEEDS_CHECKING;
> }
>
> /*
> * Read the next element as an ASCII string.
> - * 0 is success, < 0 is failure.
> + * 0 is success, < 0 or NEEDS_CHECKING is failure.
> */
> static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
> {
> char *res;
> + int ret;
>
> /* EBML strings are usually not 0-terminated, so we allocate one
> * byte more, read the string and NULL-terminate it ourselves. */
> if (!(res = av_malloc(size + 1)))
> return AVERROR(ENOMEM);
> - if (avio_read(pb, (uint8_t *) res, size) != size) {
> + if ((ret = avio_read(pb, (uint8_t *) res, size)) != size) {
> av_free(res);
> - return AVERROR(EIO);
> + return ret < 0 ? ret : NEEDS_CHECKING;
> }
> (res)[size] = '\0';
> av_free(*str);
> @@ -947,7 +950,7 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str)
>
> /*
> * Read the next element as binary data.
> - * 0 is success, < 0 is failure.
> + * 0 is success, < 0 or NEEDS_CHECKING is failure.
> */
> static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
> {
> @@ -961,11 +964,11 @@ static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin)
> bin->data = bin->buf->data;
> bin->size = length;
> bin->pos = avio_tell(pb);
> - if (avio_read(pb, bin->data, length) != length) {
> + if ((ret = avio_read(pb, bin->data, length)) != length) {
> av_buffer_unref(&bin->buf);
> bin->data = NULL;
> bin->size = 0;
> - return AVERROR(EIO);
> + return ret < 0 ? ret : NEEDS_CHECKING;
> }
>
> return 0;
> @@ -1253,14 +1256,34 @@ static int ebml_parse_elem(MatroskaDemuxContext *matroska,
> case EBML_STOP:
> return 1;
> default:
> - if (ffio_limit(pb, length) != length)
> + if (ffio_limit(pb, length) != length) {
> + // ffio_limit emits its own error message,
> + // so we don't have to.
> return AVERROR(EIO);
> - return avio_skip(pb, length) < 0 ? AVERROR(EIO) : 0;
> + }
> + res = avio_skip(pb, length);
> + res = res < 0 ? res : 0;
> + }
> + if (res) {
> + if (res == NEEDS_CHECKING) {
> + if (pb->eof_reached) {
> + if (pb->error)
> + res = pb->error;
> + else
> + res = AVERROR_EOF;
> + } else
> + res = 0;
> + }
> +
> + if (res == AVERROR_INVALIDDATA)
> + av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n");
> + else if (res == AVERROR(EIO))
> + av_log(matroska->ctx, AV_LOG_ERROR, "Read error\n");
> + else if (res == AVERROR_EOF) {
> + av_log(matroska->ctx, AV_LOG_ERROR, "File ended prematurely\n");
> + res = AVERROR(EIO);
> + }
> }
> - if (res == AVERROR_INVALIDDATA)
> - av_log(matroska->ctx, AV_LOG_ERROR, "Invalid element\n");
> - else if (res == AVERROR(EIO))
> - av_log(matroska->ctx, AV_LOG_ERROR, "Read error\n");
> return res;
> }
Applied, thanks.
More information about the ffmpeg-devel
mailing list