diff mbox

[FFmpeg-devel] lavc: Mark functions where ignoring returned error code is always wrong

Message ID 3ed2d4ae-1790-50f8-c95d-cbd9618501d4@jkqxz.net
State Superseded
Headers show

Commit Message

Mark Thompson Sept. 14, 2017, 9:16 p.m. UTC
---
There are more around, but this marks all of the obvious ones in avcodec.h.

(Prompted by my own stupid error in <01ec4b44-1857-fdf4-ba1d-84fcac474afd@jkqxz.net>.)


 libavcodec/avcodec.h | 13 +++++++++++++
 1 file changed, 13 insertions(+)

Comments

Marton Balint Sept. 14, 2017, 9:54 p.m. UTC | #1
On Thu, 14 Sep 2017, Mark Thompson wrote:

> ---
> There are more around, but this marks all of the obvious ones in avcodec.h.
>

[...]

> +av_warn_unused_result
> int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);

>  */
> +av_warn_unused_result
> int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);

I am not sure about these, these can only fail with ENOMEM if the user 
always gets all available frames/packets, but even if there is no memory, 
no state will be changed, the ownership of the packet/frame will remain 
with the caller, no null pointer will be returned, so if ignoring 
these is what the user wants, then so be it, no "undefined" behaviour will 
occur and we are not breaking the API contract by continuing like nothing 
happened.

Regards,
Marton
Mark Thompson Sept. 14, 2017, 10:17 p.m. UTC | #2
On 14/09/17 22:54, Marton Balint wrote:
> 
> On Thu, 14 Sep 2017, Mark Thompson wrote:
> 
>> ---
>> There are more around, but this marks all of the obvious ones in avcodec.h.
>>
> 
> [...]
> 
>> +av_warn_unused_result
>> int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
> 
>>  */
>> +av_warn_unused_result
>> int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
> 
> I am not sure about these, these can only fail with ENOMEM if the user always gets all available frames/packets, but even if there is no memory, no state will be changed, the ownership of the packet/frame will remain with the caller, no null pointer will be returned, so if ignoring these is what the user wants, then so be it, no "undefined" behaviour will occur and we are not breaking the API contract by continuing like nothing happened.

I was primarily thinking of the EAGAIN case, where the input data will just have been silently discarded if the user ignores the return value.  I admit that isn't quite the same as the failed-allocation ones which result in undefined behaviour, but I don't think ignoring the return value of any of the send/receive functions is sane on the part of the user.

What do you think?  (I could also split the patch into ENOMEM and other cases if that helps.)

- Mark
Marton Balint Sept. 14, 2017, 10:35 p.m. UTC | #3
On Thu, 14 Sep 2017, Mark Thompson wrote:

> On 14/09/17 22:54, Marton Balint wrote:
>> 
>> On Thu, 14 Sep 2017, Mark Thompson wrote:
>> 
>>> ---
>>> There are more around, but this marks all of the obvious ones in avcodec.h.
>>>
>> 
>> [...]
>> 
>>> +av_warn_unused_result
>>> int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
>> 
>>>  */
>>> +av_warn_unused_result
>>> int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
>> 
>> I am not sure about these, these can only fail with ENOMEM if the user 
>> always gets all available frames/packets, but even if there is no 
>> memory, no state will be changed, the ownership of the packet/frame 
>> will remain with the caller, no null pointer will be returned, so if 
>> ignoring these is what the user wants, then so be it, no "undefined" 
>> behaviour will occur and we are not breaking the API contract by 
>> continuing like nothing happened.
>
> I was primarily thinking of the EAGAIN case, where the input data will 
> just have been silently discarded if the user ignores the return value. 
> I admit that isn't quite the same as the failed-allocation ones which 
> result in undefined behaviour, but I don't think ignoring the return 
> value of any of the send/receive functions is sane on the part of the 
> user.
>
> What do you think?  (I could also split the patch into ENOMEM and other 
> cases if that helps.)

If the send/receive API is used in a way that receive is called in a loop 
until EAGAIN is returned after each send, that ensures that no EAGAIN can 
occur in send.

ffplay does exactly that and the only reason it does not ignore the 
return value of send_packet is to be able to warn the user about API 
violations, which - in theory - should not happen.

So I'd rather not tag these functions as warn_unused_result, but if others 
disagree, I don't mind too much if the patch goes in as is.

Regards,
Marton
Mark Thompson Sept. 14, 2017, 10:52 p.m. UTC | #4
On 14/09/17 23:35, Marton Balint wrote:
> 
> On Thu, 14 Sep 2017, Mark Thompson wrote:
> 
>> On 14/09/17 22:54, Marton Balint wrote:
>>>
>>> On Thu, 14 Sep 2017, Mark Thompson wrote:
>>>
>>>> ---
>>>> There are more around, but this marks all of the obvious ones in avcodec.h.
>>>>
>>>
>>> [...]
>>>
>>>> +av_warn_unused_result
>>>> int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
>>>
>>>>  */
>>>> +av_warn_unused_result
>>>> int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
>>>
>>> I am not sure about these, these can only fail with ENOMEM if the user always gets all available frames/packets, but even if there is no memory, no state will be changed, the ownership of the packet/frame will remain with the caller, no null pointer will be returned, so if ignoring these is what the user wants, then so be it, no "undefined" behaviour will occur and we are not breaking the API contract by continuing like nothing happened.
>>
>> I was primarily thinking of the EAGAIN case, where the input data will just have been silently discarded if the user ignores the return value. I admit that isn't quite the same as the failed-allocation ones which result in undefined behaviour, but I don't think ignoring the return value of any of the send/receive functions is sane on the part of the user.
>>
>> What do you think?  (I could also split the patch into ENOMEM and other cases if that helps.)
> 
> If the send/receive API is used in a way that receive is called in a loop until EAGAIN is returned after each send, that ensures that no EAGAIN can occur in send.
> 
> ffplay does exactly that and the only reason it does not ignore the return value of send_packet is to be able to warn the user about API violations, which - in theory - should not happen.
> 
> So I'd rather not tag these functions as warn_unused_result, but if others disagree, I don't mind too much if the patch goes in as is.

Ok, that's fair.  I've removed the annotation from the the send functions - these two and also av_bsf_send_packet().

Thanks,

- Mark
diff mbox

Patch

diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 5c84974e03..758686af23 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -4483,6 +4483,7 @@  int avcodec_parameters_to_context(AVCodecContext *codec,
  * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(),
  *      av_dict_set(), av_opt_find().
  */
+av_warn_unused_result
 int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options);
 
 /**
@@ -4568,6 +4569,7 @@  void av_init_packet(AVPacket *pkt);
  * @param size wanted payload size
  * @return 0 if OK, AVERROR_xxx otherwise
  */
+av_warn_unused_result
 int av_new_packet(AVPacket *pkt, int size);
 
 /**
@@ -4584,6 +4586,7 @@  void av_shrink_packet(AVPacket *pkt, int size);
  * @param pkt packet
  * @param grow_by number of bytes by which to increase the size of the packet
  */
+av_warn_unused_result
 int av_grow_packet(AVPacket *pkt, int grow_by);
 
 /**
@@ -4736,6 +4739,7 @@  void av_packet_free_side_data(AVPacket *pkt);
  *
  * @return 0 on success, a negative AVERROR on error.
  */
+av_warn_unused_result
 int av_packet_ref(AVPacket *dst, const AVPacket *src);
 
 /**
@@ -4814,6 +4818,7 @@  AVCodec *avcodec_find_decoder_by_name(const char *name);
  * it can be called by custom get_buffer2() implementations for decoders without
  * AV_CODEC_CAP_DR1 set.
  */
+av_warn_unused_result
 int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags);
 
 #if FF_API_EMU_EDGE
@@ -5060,6 +5065,7 @@  int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
  *      AVERROR(ENOMEM):   failed to add packet to internal queue, or similar
  *      other errors: legitimate decoding errors
  */
+av_warn_unused_result
 int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
 
 /**
@@ -5080,6 +5086,7 @@  int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt);
  *      AVERROR(EINVAL):   codec not opened, or it is an encoder
  *      other negative values: legitimate decoding errors
  */
+av_warn_unused_result
 int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
 
 /**
@@ -5117,6 +5124,7 @@  int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame);
  *      AVERROR(ENOMEM):   failed to add packet to internal queue, or similar
  *      other errors: legitimate decoding errors
  */
+av_warn_unused_result
 int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
 
 /**
@@ -5134,6 +5142,7 @@  int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame);
  *      AVERROR(EINVAL):   codec not opened, or it is an encoder
  *      other errors: legitimate decoding errors
  */
+av_warn_unused_result
 int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt);
 
 
@@ -6091,12 +6100,14 @@  const AVBitStreamFilter *av_bsf_next(void **opaque);
  *
  * @return 0 on success, a negative AVERROR code on failure
  */
+av_warn_unused_result
 int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx);
 
 /**
  * Prepare the filter for use, after all the parameters and options have been
  * set.
  */
+av_warn_unused_result
 int av_bsf_init(AVBSFContext *ctx);
 
 /**
@@ -6114,6 +6125,7 @@  int av_bsf_init(AVBSFContext *ctx);
  *
  * @return 0 on success, a negative AVERROR on error.
  */
+av_warn_unused_result
 int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt);
 
 /**
@@ -6140,6 +6152,7 @@  int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt);
  * output fewer packets than were sent to it, so this function may return
  * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call.
  */
+av_warn_unused_result
 int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt);
 
 /**