diff mbox series

[FFmpeg-devel,2/7] avutil/bprint: Allow size == 0 in av_bprint_init_for_buffer()

Message ID AS8P250MB07441B7917A010E04C642A5D8F0FA@AS8P250MB0744.EURP250.PROD.OUTLOOK.COM
State Accepted
Headers show
Series [FFmpeg-devel,1/7] avutil/bprint: Don't use value of AV_BPRINT_SIZE_AUTOMATIC directly | 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 Aug. 6, 2023, 10:13 a.m. UTC
The AVBPrint API guarantees that the string buffer is always
zero-terminated; in order to honour this guarantee, there
obviously must be a string buffer at all and it must have
a size >= 1. Therefore av_bprint_init_for_buffer() treats
passing a NULL buffer or size == 0 as invalid data that
leads to undefined behaviour, namely NPD in case NULL is provided
or a write to a buffer of size 0 in case size == 0.

But it would be easy to support this, namely by using the internal
buffer with AV_BPRINT_SIZE_COUNT_ONLY in case size == 0.

There is a reason to allow this: Several functions like
av_channel_(description|name) are actually wrappers
around corresponding AVBPrint functions. They accept user
provided buffers and are supposed to return the required
size of the buffer, which would allow the user to call
it once to get the required buffer size and call it once
more after having allocated the buffer.
If av_bprint_init_for_buffer() treats size == 0 as invalid,
all these users would need to check for this themselves
and basically add the same codeblock that this patch
adds to av_bprint_init_for_buffer().

This change is in line with e.g. snprintf() which also allows
the pointer to be NULL in case size is zero.

This fixes Coverity issues #1503074, #1503076 and #1503082;
all of these issues are about providing NULL to the channel-layout
functions that are wrappers around AVBPrint versions.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
Missing lavu minor version bump.

 libavutil/bprint.c | 5 +++++
 libavutil/bprint.h | 3 +++
 2 files changed, 8 insertions(+)

Comments

Andreas Rheinhardt Aug. 9, 2023, 9 a.m. UTC | #1
Andreas Rheinhardt:
> The AVBPrint API guarantees that the string buffer is always
> zero-terminated; in order to honour this guarantee, there
> obviously must be a string buffer at all and it must have
> a size >= 1. Therefore av_bprint_init_for_buffer() treats
> passing a NULL buffer or size == 0 as invalid data that
> leads to undefined behaviour, namely NPD in case NULL is provided
> or a write to a buffer of size 0 in case size == 0.
> 
> But it would be easy to support this, namely by using the internal
> buffer with AV_BPRINT_SIZE_COUNT_ONLY in case size == 0.
> 
> There is a reason to allow this: Several functions like
> av_channel_(description|name) are actually wrappers
> around corresponding AVBPrint functions. They accept user
> provided buffers and are supposed to return the required
> size of the buffer, which would allow the user to call
> it once to get the required buffer size and call it once
> more after having allocated the buffer.
> If av_bprint_init_for_buffer() treats size == 0 as invalid,
> all these users would need to check for this themselves
> and basically add the same codeblock that this patch
> adds to av_bprint_init_for_buffer().
> 
> This change is in line with e.g. snprintf() which also allows
> the pointer to be NULL in case size is zero.
> 
> This fixes Coverity issues #1503074, #1503076 and #1503082;
> all of these issues are about providing NULL to the channel-layout
> functions that are wrappers around AVBPrint versions.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> Missing lavu minor version bump.
> 
>  libavutil/bprint.c | 5 +++++
>  libavutil/bprint.h | 3 +++
>  2 files changed, 8 insertions(+)
> 
> diff --git a/libavutil/bprint.c b/libavutil/bprint.c
> index 23998a8b02..4e9571715c 100644
> --- a/libavutil/bprint.c
> +++ b/libavutil/bprint.c
> @@ -84,6 +84,11 @@ void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
>  
>  void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
>  {
> +    if (size == 0) {
> +        av_bprint_init(buf, 0, AV_BPRINT_SIZE_COUNT_ONLY);
> +        return;
> +    }
> +
>      buf->str      = buffer;
>      buf->len      = 0;
>      buf->size     = size;
> diff --git a/libavutil/bprint.h b/libavutil/bprint.h
> index f27d30f723..8559745478 100644
> --- a/libavutil/bprint.h
> +++ b/libavutil/bprint.h
> @@ -144,6 +144,9 @@ void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
>   * Init a print buffer using a pre-existing buffer.
>   *
>   * The buffer will not be reallocated.
> + * In case size equals zero, the AVBPrint will be initialized to use
> + * the internal buffer as if using AV_BPRINT_SIZE_COUNT_ONLY with
> + * av_bprint_init().
>   *
>   * @param buf     buffer structure to init
>   * @param buffer  byte buffer to use for the string data

Ping for this patch (and the rest of this patchset). Will apply patches
2-5 in two days unless there are objections; will apply the rest today.

- Andreas
Nicolas George Aug. 9, 2023, 10:08 a.m. UTC | #2
Andreas Rheinhardt (12023-08-06):
> The AVBPrint API guarantees that the string buffer is always
> zero-terminated; in order to honour this guarantee, there
> obviously must be a string buffer at all and it must have
> a size >= 1. Therefore av_bprint_init_for_buffer() treats
> passing a NULL buffer or size == 0 as invalid data that
> leads to undefined behaviour, namely NPD in case NULL is provided
> or a write to a buffer of size 0 in case size == 0.
> 
> But it would be easy to support this, namely by using the internal
> buffer with AV_BPRINT_SIZE_COUNT_ONLY in case size == 0.
> 
> There is a reason to allow this: Several functions like
> av_channel_(description|name) are actually wrappers
> around corresponding AVBPrint functions. They accept user
> provided buffers and are supposed to return the required
> size of the buffer, which would allow the user to call
> it once to get the required buffer size and call it once
> more after having allocated the buffer.
> If av_bprint_init_for_buffer() treats size == 0 as invalid,
> all these users would need to check for this themselves
> and basically add the same codeblock that this patch
> adds to av_bprint_init_for_buffer().
> 
> This change is in line with e.g. snprintf() which also allows
> the pointer to be NULL in case size is zero.
> 
> This fixes Coverity issues #1503074, #1503076 and #1503082;
> all of these issues are about providing NULL to the channel-layout
> functions that are wrappers around AVBPrint versions.
> 
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
> Missing lavu minor version bump.

Looks good to me.

The other patches in the series too, but I do not maintain the channel
layouts.

Regards,
James Almer Aug. 9, 2023, 11:32 a.m. UTC | #3
On 8/9/2023 7:08 AM, Nicolas George wrote:
> Andreas Rheinhardt (12023-08-06):
>> The AVBPrint API guarantees that the string buffer is always
>> zero-terminated; in order to honour this guarantee, there
>> obviously must be a string buffer at all and it must have
>> a size >= 1. Therefore av_bprint_init_for_buffer() treats
>> passing a NULL buffer or size == 0 as invalid data that
>> leads to undefined behaviour, namely NPD in case NULL is provided
>> or a write to a buffer of size 0 in case size == 0.
>>
>> But it would be easy to support this, namely by using the internal
>> buffer with AV_BPRINT_SIZE_COUNT_ONLY in case size == 0.
>>
>> There is a reason to allow this: Several functions like
>> av_channel_(description|name) are actually wrappers
>> around corresponding AVBPrint functions. They accept user
>> provided buffers and are supposed to return the required
>> size of the buffer, which would allow the user to call
>> it once to get the required buffer size and call it once
>> more after having allocated the buffer.
>> If av_bprint_init_for_buffer() treats size == 0 as invalid,
>> all these users would need to check for this themselves
>> and basically add the same codeblock that this patch
>> adds to av_bprint_init_for_buffer().
>>
>> This change is in line with e.g. snprintf() which also allows
>> the pointer to be NULL in case size is zero.
>>
>> This fixes Coverity issues #1503074, #1503076 and #1503082;
>> all of these issues are about providing NULL to the channel-layout
>> functions that are wrappers around AVBPrint versions.
>>
>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>> ---
>> Missing lavu minor version bump.
> 
> Looks good to me.
> 
> The other patches in the series too, but I do not maintain the channel
> layouts.
> 
> Regards,

The layout patches are ok too.
Andreas Rheinhardt Aug. 9, 2023, 12:58 p.m. UTC | #4
James Almer:
> On 8/9/2023 7:08 AM, Nicolas George wrote:
>> Andreas Rheinhardt (12023-08-06):
>>> The AVBPrint API guarantees that the string buffer is always
>>> zero-terminated; in order to honour this guarantee, there
>>> obviously must be a string buffer at all and it must have
>>> a size >= 1. Therefore av_bprint_init_for_buffer() treats
>>> passing a NULL buffer or size == 0 as invalid data that
>>> leads to undefined behaviour, namely NPD in case NULL is provided
>>> or a write to a buffer of size 0 in case size == 0.
>>>
>>> But it would be easy to support this, namely by using the internal
>>> buffer with AV_BPRINT_SIZE_COUNT_ONLY in case size == 0.
>>>
>>> There is a reason to allow this: Several functions like
>>> av_channel_(description|name) are actually wrappers
>>> around corresponding AVBPrint functions. They accept user
>>> provided buffers and are supposed to return the required
>>> size of the buffer, which would allow the user to call
>>> it once to get the required buffer size and call it once
>>> more after having allocated the buffer.
>>> If av_bprint_init_for_buffer() treats size == 0 as invalid,
>>> all these users would need to check for this themselves
>>> and basically add the same codeblock that this patch
>>> adds to av_bprint_init_for_buffer().
>>>
>>> This change is in line with e.g. snprintf() which also allows
>>> the pointer to be NULL in case size is zero.
>>>
>>> This fixes Coverity issues #1503074, #1503076 and #1503082;
>>> all of these issues are about providing NULL to the channel-layout
>>> functions that are wrappers around AVBPrint versions.
>>>
>>> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
>>> ---
>>> Missing lavu minor version bump.
>>
>> Looks good to me.
>>
>> The other patches in the series too, but I do not maintain the channel
>> layouts.
>>
>> Regards,
> 
> The layout patches are ok too.

Ok, then I'll already apply them tomorrow. Thanks for the reviews.

- Andreas
diff mbox series

Patch

diff --git a/libavutil/bprint.c b/libavutil/bprint.c
index 23998a8b02..4e9571715c 100644
--- a/libavutil/bprint.c
+++ b/libavutil/bprint.c
@@ -84,6 +84,11 @@  void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
 
 void av_bprint_init_for_buffer(AVBPrint *buf, char *buffer, unsigned size)
 {
+    if (size == 0) {
+        av_bprint_init(buf, 0, AV_BPRINT_SIZE_COUNT_ONLY);
+        return;
+    }
+
     buf->str      = buffer;
     buf->len      = 0;
     buf->size     = size;
diff --git a/libavutil/bprint.h b/libavutil/bprint.h
index f27d30f723..8559745478 100644
--- a/libavutil/bprint.h
+++ b/libavutil/bprint.h
@@ -144,6 +144,9 @@  void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max);
  * Init a print buffer using a pre-existing buffer.
  *
  * The buffer will not be reallocated.
+ * In case size equals zero, the AVBPrint will be initialized to use
+ * the internal buffer as if using AV_BPRINT_SIZE_COUNT_ONLY with
+ * av_bprint_init().
  *
  * @param buf     buffer structure to init
  * @param buffer  byte buffer to use for the string data